ci: Check for DDXen to be built
[xserver.git] / os / inputthread.c
blob623648256c9e09418cc41aa25c057eb799d869bb
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>
30 #include <stdio.h>
31 #include <errno.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <pthread.h>
36 #include "dix/input_priv.h"
37 #include "os/ddx_priv.h"
39 #include "inputstr.h"
40 #include "opaque.h"
41 #include "osdep.h"
43 #if INPUTTHREAD
45 Bool InputThreadEnable = TRUE;
47 /**
48 * An input device as seen by the threaded input facility
51 typedef enum _InputDeviceState {
52 device_state_added,
53 device_state_running,
54 device_state_removed
55 } InputDeviceState;
57 typedef struct _InputThreadDevice {
58 struct xorg_list node;
59 NotifyFdProcPtr readInputProc;
60 void *readInputArgs;
61 int fd;
62 InputDeviceState state;
63 } InputThreadDevice;
65 /**
66 * The threaded input facility.
68 * For now, we have one instance for all input devices.
70 typedef struct {
71 pthread_t thread;
72 struct xorg_list devs;
73 struct ospoll *fds;
74 int readPipe;
75 int writePipe;
76 Bool changed;
77 Bool running;
78 } InputThreadInfo;
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;
89 #else
90 static pthread_mutex_t input_mutex;
91 static Bool input_mutex_initialized;
92 #endif
94 int
95 in_input_thread(void)
97 return inputThreadInfo &&
98 pthread_equal(pthread_self(), inputThreadInfo->thread);
101 void
102 input_lock(void)
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);
113 #endif
114 pthread_mutex_lock(&input_mutex);
115 ++input_mutex_count;
118 void
119 input_unlock(void)
121 --input_mutex_count;
122 pthread_mutex_unlock(&input_mutex);
125 void
126 input_force_unlock(void)
128 if (pthread_mutex_trylock(&input_mutex) == 0) {
129 input_mutex_count++;
130 /* unlock +1 times for the trylock */
131 while (input_mutex_count > 0)
132 input_unlock();
137 * Notify a thread about the availability of new asynchronously enqueued input
138 * events.
140 * @see WaitForSomething()
142 static void
143 InputThreadFillPipe(int writeHead)
145 int ret;
146 char byte = 0;
148 do {
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()
159 static int
160 InputThreadReadPipe(int readHead)
162 int ret, array[10];
164 ret = read(readHead, &array, sizeof(array));
165 if (ret >= 0)
166 return ret;
168 if (errno != EAGAIN)
169 FatalError("input-thread: draining pipe (%d)", errno);
171 return 1;
174 static void
175 InputReady(int fd, int xevents, void *data)
177 InputThreadDevice *dev = data;
179 input_lock();
180 if (dev->state == device_state_running)
181 dev->readInputProc(fd, xevents, dev->readInputArgs);
182 input_unlock();
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,
197 void *readInputArgs)
199 InputThreadDevice *dev, *old;
201 if (!inputThreadInfo)
202 return SetNotifyFd(fd, readInputProc, X_NOTIFY_READ, readInputArgs);
204 input_lock();
206 dev = NULL;
207 xorg_list_for_each_entry(old, &inputThreadInfo->devs, node) {
208 if (old->fd == fd && old->state != device_state_removed) {
209 dev = old;
210 break;
214 if (dev) {
215 dev->readInputProc = readInputProc;
216 dev->readInputArgs = readInputArgs;
217 } else {
218 dev = calloc(1, sizeof(InputThreadDevice));
219 if (dev == NULL) {
220 DebugF("input-thread: could not register device\n");
221 input_unlock();
222 return 0;
225 dev->fd = fd;
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;
237 input_unlock();
239 DebugF("input-thread: registered device %d\n", fd);
240 InputThreadFillPipe(hotplugPipeWrite);
242 return 1;
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) {
262 RemoveNotifyFd(fd);
263 return 1;
266 input_lock();
267 xorg_list_for_each_entry(dev, &inputThreadInfo->devs, node)
268 if (dev->fd == fd) {
269 found_device = TRUE;
270 break;
273 /* fd didn't match any registered device. */
274 if (!found_device) {
275 input_unlock();
276 return 0;
279 dev->state = device_state_removed;
280 inputThreadInfo->changed = TRUE;
282 input_unlock();
284 InputThreadFillPipe(hotplugPipeWrite);
285 DebugF("input-thread: unregistered device: %d\n", fd);
287 return 1;
290 static void
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()
313 static void*
314 InputThreadDoWork(void *arg)
316 sigset_t set;
318 /* Don't handle any signals on this thread */
319 sigfillset(&set);
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");
330 #endif
332 ospoll_add(inputThreadInfo->fds, hotplugPipeRead,
333 ospoll_trigger_level,
334 InputThreadPipeNotify,
335 NULL);
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;
346 input_lock();
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,
353 InputReady,
354 dev);
355 ospoll_listen(inputThreadInfo->fds, dev->fd, X_NOTIFY_READ);
356 dev->state = device_state_running;
357 break;
358 case device_state_running:
359 break;
360 case device_state_removed:
361 ospoll_remove(inputThreadInfo->fds, dev->fd);
362 xorg_list_del(&dev->node);
363 free(dev);
364 break;
367 input_unlock();
370 if (ospoll_wait(inputThreadInfo->fds, -1) < 0) {
371 if (errno == EINVAL)
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);
384 return NULL;
387 static void
388 InputThreadNotifyPipe(int fd, int mask, void *data)
390 InputThreadReadPipe(fd);
394 * Pre-initialize the facility used for threaded generation of input events
397 void
398 InputThreadPreInit(void)
400 int fds[2], hotplugPipe[2];
401 int flags;
403 if (!InputThreadEnable)
404 return;
406 if (pipe(fds) < 0)
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
424 * in parallel.
426 inputThreadInfo->readPipe = fds[0];
427 fcntl(inputThreadInfo->readPipe, F_SETFL, O_NONBLOCK);
428 flags = fcntl(inputThreadInfo->readPipe, F_GETFD);
429 if (flags != -1) {
430 flags |= FD_CLOEXEC;
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);
440 if (flags != -1) {
441 flags |= FD_CLOEXEC;
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");
451 #endif
452 #endif
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.
462 void
463 InputThreadInit(void)
465 pthread_attr_t attr;
467 /* If the driver hasn't asked for input thread support by calling
468 * InputThreadPreInit, then do nothing here
470 if (!inputThreadInfo)
471 return;
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.
495 void
496 InputThreadFini(void)
498 InputThreadDevice *dev, *next;
500 if (!inputThreadInfo)
501 return;
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);
510 free(dev);
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,
549 void *readInputArgs)
551 return SetNotifyFd(fd, readInputProc, X_NOTIFY_READ, readInputArgs);
554 extern int InputThreadUnregisterDev(int fd)
556 RemoveNotifyFd(fd);
557 return 1;
560 int xthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
562 #ifdef HAVE_SIGPROCMASK
563 return sigprocmask(how, set, oldset);
564 #else
565 return 0;
566 #endif
569 #endif