1 /* inputthread.c -- Threaded generation of input events.
3 * Copyright © 2007-2008 Tiago Vignatti <vignatti at freedesktop org>
4 * Copyright © 2010 Nokia
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
24 * Authors: Fernando Carrijo <fcarrijo at freedesktop org>
25 * Tiago Vignatti <vignatti at freedesktop org>
28 #include <dix-config.h>
36 #include "dix/input_priv.h"
37 #include "os/ddx_priv.h"
45 Bool InputThreadEnable
= TRUE
;
48 * An input device as seen by the threaded input facility
51 typedef enum _InputDeviceState
{
57 typedef struct _InputThreadDevice
{
58 struct xorg_list node
;
59 NotifyFdProcPtr readInputProc
;
62 InputDeviceState state
;
66 * The threaded input facility.
68 * For now, we have one instance for all input devices.
72 struct xorg_list devs
;
80 static InputThreadInfo
*inputThreadInfo
;
82 static int hotplugPipeRead
= -1;
83 static int hotplugPipeWrite
= -1;
85 static int input_mutex_count
;
87 #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
88 static pthread_mutex_t input_mutex
= PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
;
90 static pthread_mutex_t input_mutex
;
91 static Bool input_mutex_initialized
;
97 return inputThreadInfo
&&
98 pthread_equal(pthread_self(), inputThreadInfo
->thread
);
104 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
105 if (!input_mutex_initialized
) {
106 pthread_mutexattr_t mutex_attr
;
108 input_mutex_initialized
= TRUE
;
109 pthread_mutexattr_init(&mutex_attr
);
110 pthread_mutexattr_settype(&mutex_attr
, PTHREAD_MUTEX_RECURSIVE
);
111 pthread_mutex_init(&input_mutex
, &mutex_attr
);
114 pthread_mutex_lock(&input_mutex
);
122 pthread_mutex_unlock(&input_mutex
);
126 input_force_unlock(void)
128 if (pthread_mutex_trylock(&input_mutex
) == 0) {
130 /* unlock +1 times for the trylock */
131 while (input_mutex_count
> 0)
137 * Notify a thread about the availability of new asynchronously enqueued input
140 * @see WaitForSomething()
143 InputThreadFillPipe(int writeHead
)
149 ret
= write(writeHead
, &byte
, 1);
150 } while (ret
< 0 && ETEST(errno
));
154 * Consume eventual notifications left by a thread.
156 * @see WaitForSomething()
157 * @see InputThreadFillPipe()
160 InputThreadReadPipe(int readHead
)
164 ret
= read(readHead
, &array
, sizeof(array
));
169 FatalError("input-thread: draining pipe (%d)", errno
);
175 InputReady(int fd
, int xevents
, void *data
)
177 InputThreadDevice
*dev
= data
;
180 if (dev
->state
== device_state_running
)
181 dev
->readInputProc(fd
, xevents
, dev
->readInputArgs
);
186 * Register an input device in the threaded input facility
188 * @param fd File descriptor which identifies the input device
189 * @param readInputProc Procedure used to read input from the device
190 * @param readInputArgs Arguments to be consumed by the above procedure
192 * return 1 if success; 0 otherwise.
195 InputThreadRegisterDev(int fd
,
196 NotifyFdProcPtr readInputProc
,
199 InputThreadDevice
*dev
, *old
;
201 if (!inputThreadInfo
)
202 return SetNotifyFd(fd
, readInputProc
, X_NOTIFY_READ
, readInputArgs
);
207 xorg_list_for_each_entry(old
, &inputThreadInfo
->devs
, node
) {
208 if (old
->fd
== fd
&& old
->state
!= device_state_removed
) {
215 dev
->readInputProc
= readInputProc
;
216 dev
->readInputArgs
= readInputArgs
;
218 dev
= calloc(1, sizeof(InputThreadDevice
));
220 DebugF("input-thread: could not register device\n");
226 dev
->readInputProc
= readInputProc
;
227 dev
->readInputArgs
= readInputArgs
;
228 dev
->state
= device_state_added
;
230 /* Do not prepend, so that any dev->state == device_state_removed
231 * with the same dev->fd get processed first. */
232 xorg_list_append(&dev
->node
, &inputThreadInfo
->devs
);
235 inputThreadInfo
->changed
= TRUE
;
239 DebugF("input-thread: registered device %d\n", fd
);
240 InputThreadFillPipe(hotplugPipeWrite
);
246 * Unregister a device in the threaded input facility
248 * @param fd File descriptor which identifies the input device
250 * @return 1 if success; 0 otherwise.
253 InputThreadUnregisterDev(int fd
)
255 InputThreadDevice
*dev
;
256 Bool found_device
= FALSE
;
258 /* return silently if input thread is already finished (e.g., at
259 * DisableDevice time, evdev tries to call this function again through
260 * xf86RemoveEnabledDevice) */
261 if (!inputThreadInfo
) {
267 xorg_list_for_each_entry(dev
, &inputThreadInfo
->devs
, node
)
273 /* fd didn't match any registered device. */
279 dev
->state
= device_state_removed
;
280 inputThreadInfo
->changed
= TRUE
;
284 InputThreadFillPipe(hotplugPipeWrite
);
285 DebugF("input-thread: unregistered device: %d\n", fd
);
291 InputThreadPipeNotify(int fd
, int revents
, void *data
)
293 /* Empty pending input, shut down if the pipe has been closed */
294 if (InputThreadReadPipe(hotplugPipeRead
) == 0) {
295 inputThreadInfo
->running
= FALSE
;
300 * The workhorse of threaded input event generation.
302 * Or if you prefer: The WaitForSomething for input devices. :)
304 * Runs in parallel with the server main thread, listening to input devices in
305 * an endless loop. Whenever new input data is made available, calls the
306 * proper device driver's routines which are ultimately responsible for the
307 * generation of input events.
309 * @see InputThreadPreInit()
310 * @see InputThreadInit()
314 InputThreadDoWork(void *arg
)
318 /* Don't handle any signals on this thread */
320 pthread_sigmask(SIG_BLOCK
, &set
, NULL
);
322 ddxInputThreadInit();
324 inputThreadInfo
->running
= TRUE
;
326 #if defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID)
327 pthread_setname_np (pthread_self(), "InputThread");
328 #elif defined(HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID)
329 pthread_setname_np ("InputThread");
332 ospoll_add(inputThreadInfo
->fds
, hotplugPipeRead
,
333 ospoll_trigger_level
,
334 InputThreadPipeNotify
,
336 ospoll_listen(inputThreadInfo
->fds
, hotplugPipeRead
, X_NOTIFY_READ
);
338 while (inputThreadInfo
->running
)
340 DebugF("input-thread: %s waiting for devices\n", __func__
);
342 /* Check for hotplug changes and modify the ospoll structure to suit */
343 if (inputThreadInfo
->changed
) {
344 InputThreadDevice
*dev
, *tmp
;
347 inputThreadInfo
->changed
= FALSE
;
348 xorg_list_for_each_entry_safe(dev
, tmp
, &inputThreadInfo
->devs
, node
) {
349 switch (dev
->state
) {
350 case device_state_added
:
351 ospoll_add(inputThreadInfo
->fds
, dev
->fd
,
352 ospoll_trigger_level
,
355 ospoll_listen(inputThreadInfo
->fds
, dev
->fd
, X_NOTIFY_READ
);
356 dev
->state
= device_state_running
;
358 case device_state_running
:
360 case device_state_removed
:
361 ospoll_remove(inputThreadInfo
->fds
, dev
->fd
);
362 xorg_list_del(&dev
->node
);
370 if (ospoll_wait(inputThreadInfo
->fds
, -1) < 0) {
372 FatalError("input-thread: %s (%s)", __func__
, strerror(errno
));
373 else if (errno
!= EINTR
)
374 ErrorF("input-thread: %s (%s)\n", __func__
, strerror(errno
));
377 /* Kick main thread to process the generated input events and drain
378 * events from hotplug pipe */
379 InputThreadFillPipe(inputThreadInfo
->writePipe
);
382 ospoll_remove(inputThreadInfo
->fds
, hotplugPipeRead
);
388 InputThreadNotifyPipe(int fd
, int mask
, void *data
)
390 InputThreadReadPipe(fd
);
394 * Pre-initialize the facility used for threaded generation of input events
398 InputThreadPreInit(void)
400 int fds
[2], hotplugPipe
[2];
403 if (!InputThreadEnable
)
407 FatalError("input-thread: could not create pipe");
409 if (pipe(hotplugPipe
) < 0)
410 FatalError("input-thread: could not create pipe");
412 inputThreadInfo
= malloc(sizeof(InputThreadInfo
));
413 if (!inputThreadInfo
)
414 FatalError("input-thread: could not allocate memory");
416 inputThreadInfo
->changed
= FALSE
;
418 inputThreadInfo
->thread
= 0;
419 xorg_list_init(&inputThreadInfo
->devs
);
420 inputThreadInfo
->fds
= ospoll_create();
422 /* By making read head non-blocking, we ensure that while the main thread
423 * is busy servicing client requests, the dedicated input thread can work
426 inputThreadInfo
->readPipe
= fds
[0];
427 fcntl(inputThreadInfo
->readPipe
, F_SETFL
, O_NONBLOCK
);
428 flags
= fcntl(inputThreadInfo
->readPipe
, F_GETFD
);
431 (void)fcntl(inputThreadInfo
->readPipe
, F_SETFD
, flags
);
433 SetNotifyFd(inputThreadInfo
->readPipe
, InputThreadNotifyPipe
, X_NOTIFY_READ
, NULL
);
435 inputThreadInfo
->writePipe
= fds
[1];
437 hotplugPipeRead
= hotplugPipe
[0];
438 fcntl(hotplugPipeRead
, F_SETFL
, O_NONBLOCK
);
439 flags
= fcntl(hotplugPipeRead
, F_GETFD
);
442 (void)fcntl(hotplugPipeRead
, F_SETFD
, flags
);
444 hotplugPipeWrite
= hotplugPipe
[1];
446 #ifndef __linux__ /* Linux does not deal well with renaming the main thread */
447 #if defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID)
448 pthread_setname_np (pthread_self(), "MainThread");
449 #elif defined(HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID)
450 pthread_setname_np ("MainThread");
457 * Start the threaded generation of input events. This routine complements what
458 * was previously done by InputThreadPreInit(), being only responsible for
459 * creating the dedicated input thread.
463 InputThreadInit(void)
467 /* If the driver hasn't asked for input thread support by calling
468 * InputThreadPreInit, then do nothing here
470 if (!inputThreadInfo
)
473 pthread_attr_init(&attr
);
475 /* For OSes that differentiate between processes and threads, the following
476 * lines have sense. Linux uses the 1:1 thread model. The scheduler handles
477 * every thread as a normal process. Therefore this probably has no meaning
478 * if we are under Linux.
480 if (pthread_attr_setscope(&attr
, PTHREAD_SCOPE_SYSTEM
) != 0)
481 ErrorF("input-thread: error setting thread scope\n");
483 DebugF("input-thread: creating thread\n");
484 pthread_create(&inputThreadInfo
->thread
, &attr
,
485 &InputThreadDoWork
, NULL
);
487 pthread_attr_destroy (&attr
);
491 * Stop the threaded generation of input events
493 * This function is supposed to be called at server shutdown time only.
496 InputThreadFini(void)
498 InputThreadDevice
*dev
, *next
;
500 if (!inputThreadInfo
)
503 /* Close the pipe to get the input thread to shut down */
504 close(hotplugPipeWrite
);
505 input_force_unlock();
506 pthread_join(inputThreadInfo
->thread
, NULL
);
508 xorg_list_for_each_entry_safe(dev
, next
, &inputThreadInfo
->devs
, node
) {
509 ospoll_remove(inputThreadInfo
->fds
, dev
->fd
);
512 xorg_list_init(&inputThreadInfo
->devs
);
513 ospoll_destroy(inputThreadInfo
->fds
);
515 RemoveNotifyFd(inputThreadInfo
->readPipe
);
516 close(inputThreadInfo
->readPipe
);
517 close(inputThreadInfo
->writePipe
);
518 inputThreadInfo
->readPipe
= -1;
519 inputThreadInfo
->writePipe
= -1;
521 close(hotplugPipeRead
);
522 hotplugPipeRead
= -1;
523 hotplugPipeWrite
= -1;
525 free(inputThreadInfo
);
526 inputThreadInfo
= NULL
;
529 int xthread_sigmask(int how
, const sigset_t
*set
, sigset_t
*oldset
)
531 return pthread_sigmask(how
, set
, oldset
);
534 #else /* INPUTTHREAD */
536 Bool InputThreadEnable
= FALSE
;
538 void input_lock(void) {}
539 void input_unlock(void) {}
540 void input_force_unlock(void) {}
542 void InputThreadPreInit(void) {}
543 void InputThreadInit(void) {}
544 void InputThreadFini(void) {}
545 int in_input_thread(void) { return 0; }
547 int InputThreadRegisterDev(int fd
,
548 NotifyFdProcPtr readInputProc
,
551 return SetNotifyFd(fd
, readInputProc
, X_NOTIFY_READ
, readInputArgs
);
554 extern int InputThreadUnregisterDev(int fd
)
560 int xthread_sigmask(int how
, const sigset_t
*set
, sigset_t
*oldset
)
562 #ifdef HAVE_SIGPROCMASK
563 return sigprocmask(how
, set
, oldset
);