1 /* inputthread.c -- Threaded generation of input events.
2 *
3 * Copyright © 2007-2008 Tiago Vignatti <vignatti at freedesktop org>
4 * Copyright © 2010 Nokia
5 *
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:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
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.
23 *
24 * Authors: Fernando Carrijo <fcarrijo at freedesktop org>
25 * Tiago Vignatti <vignatti at freedesktop org>
26 */
27
28 #ifdef HAVE_DIX_CONFIG_H
29 #include <dix-config.h>
30 #endif
31
32 #include <stdio.h>
33 #include <errno.h>
34 #include <stdlib.h>
35 #include <unistd.h>
36 #include <pthread.h>
37
38 #include "inputstr.h"
39 #include "opaque.h"
40 #include "osdep.h"
41
42 #if INPUTTHREAD
43
44 Bool InputThreadEnable = TRUE;
45
46 /**
47 * An input device as seen by the threaded input facility
48 */
49
50 typedef enum _InputDeviceState {
51 device_state_added,
52 device_state_running,
53 device_state_removed
54 } InputDeviceState;
55
56 typedef struct _InputThreadDevice {
57 struct xorg_list node;
58 NotifyFdProcPtr readInputProc;
59 void *readInputArgs;
60 int fd;
61 InputDeviceState state;
62 } InputThreadDevice;
63
64 /**
65 * The threaded input facility.
66 *
67 * For now, we have one instance for all input devices.
68 */
69 typedef struct {
70 pthread_t thread;
71 struct xorg_list devs;
72 struct ospoll *fds;
73 int readPipe;
74 int writePipe;
75 Bool changed;
76 Bool running;
77 } InputThreadInfo;
78
79 static InputThreadInfo *inputThreadInfo;
80
81 static int hotplugPipeRead = -1;
82 static int hotplugPipeWrite = -1;
83
84 static int input_mutex_count;
85
86 #ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
87 static pthread_mutex_t input_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
88 #else
89 static pthread_mutex_t input_mutex;
90 static Bool input_mutex_initialized;
91 #endif
92
93 int
in_input_thread(void)94 in_input_thread(void)
95 {
96 return inputThreadInfo &&
97 pthread_equal(pthread_self(), inputThreadInfo->thread);
98 }
99
100 void
input_lock(void)101 input_lock(void)
102 {
103 #ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
104 if (!input_mutex_initialized) {
105 pthread_mutexattr_t mutex_attr;
106
107 input_mutex_initialized = TRUE;
108 pthread_mutexattr_init(&mutex_attr);
109 pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);
110 pthread_mutex_init(&input_mutex, &mutex_attr);
111 }
112 #endif
113 pthread_mutex_lock(&input_mutex);
114 ++input_mutex_count;
115 }
116
117 void
input_unlock(void)118 input_unlock(void)
119 {
120 --input_mutex_count;
121 pthread_mutex_unlock(&input_mutex);
122 }
123
124 void
input_force_unlock(void)125 input_force_unlock(void)
126 {
127 if (pthread_mutex_trylock(&input_mutex) == 0) {
128 input_mutex_count++;
129 /* unlock +1 times for the trylock */
130 while (input_mutex_count > 0)
131 input_unlock();
132 }
133 }
134
135 /**
136 * Notify a thread about the availability of new asynchronously enqueued input
137 * events.
138 *
139 * @see WaitForSomething()
140 */
141 static void
InputThreadFillPipe(int writeHead)142 InputThreadFillPipe(int writeHead)
143 {
144 int ret;
145 char byte = 0;
146
147 do {
148 ret = write(writeHead, &byte, 1);
149 } while (ret < 0 && ETEST(errno));
150 }
151
152 /**
153 * Consume eventual notifications left by a thread.
154 *
155 * @see WaitForSomething()
156 * @see InputThreadFillPipe()
157 */
158 static int
InputThreadReadPipe(int readHead)159 InputThreadReadPipe(int readHead)
160 {
161 int ret, array[10];
162
163 ret = read(readHead, &array, sizeof(array));
164 if (ret >= 0)
165 return ret;
166
167 if (errno != EAGAIN)
168 FatalError("input-thread: draining pipe (%d)", errno);
169
170 return 1;
171 }
172
173 static void
InputReady(int fd,int xevents,void * data)174 InputReady(int fd, int xevents, void *data)
175 {
176 InputThreadDevice *dev = data;
177
178 input_lock();
179 if (dev->state == device_state_running)
180 dev->readInputProc(fd, xevents, dev->readInputArgs);
181 input_unlock();
182 }
183
184 /**
185 * Register an input device in the threaded input facility
186 *
187 * @param fd File descriptor which identifies the input device
188 * @param readInputProc Procedure used to read input from the device
189 * @param readInputArgs Arguments to be consumed by the above procedure
190 *
191 * return 1 if success; 0 otherwise.
192 */
193 int
InputThreadRegisterDev(int fd,NotifyFdProcPtr readInputProc,void * readInputArgs)194 InputThreadRegisterDev(int fd,
195 NotifyFdProcPtr readInputProc,
196 void *readInputArgs)
197 {
198 InputThreadDevice *dev, *old;
199
200 if (!inputThreadInfo)
201 return SetNotifyFd(fd, readInputProc, X_NOTIFY_READ, readInputArgs);
202
203 input_lock();
204
205 dev = NULL;
206 xorg_list_for_each_entry(old, &inputThreadInfo->devs, node) {
207 if (old->fd == fd && old->state != device_state_removed) {
208 dev = old;
209 break;
210 }
211 }
212
213 if (dev) {
214 dev->readInputProc = readInputProc;
215 dev->readInputArgs = readInputArgs;
216 } else {
217 dev = calloc(1, sizeof(InputThreadDevice));
218 if (dev == NULL) {
219 DebugF("input-thread: could not register device\n");
220 input_unlock();
221 return 0;
222 }
223
224 dev->fd = fd;
225 dev->readInputProc = readInputProc;
226 dev->readInputArgs = readInputArgs;
227 dev->state = device_state_added;
228
229 /* Do not prepend, so that any dev->state == device_state_removed
230 * with the same dev->fd get processed first. */
231 xorg_list_append(&dev->node, &inputThreadInfo->devs);
232 }
233
234 inputThreadInfo->changed = TRUE;
235
236 input_unlock();
237
238 DebugF("input-thread: registered device %d\n", fd);
239 InputThreadFillPipe(hotplugPipeWrite);
240
241 return 1;
242 }
243
244 /**
245 * Unregister a device in the threaded input facility
246 *
247 * @param fd File descriptor which identifies the input device
248 *
249 * @return 1 if success; 0 otherwise.
250 */
251 int
InputThreadUnregisterDev(int fd)252 InputThreadUnregisterDev(int fd)
253 {
254 InputThreadDevice *dev;
255 Bool found_device = FALSE;
256
257 /* return silently if input thread is already finished (e.g., at
258 * DisableDevice time, evdev tries to call this function again through
259 * xf86RemoveEnabledDevice) */
260 if (!inputThreadInfo) {
261 RemoveNotifyFd(fd);
262 return 1;
263 }
264
265 input_lock();
266 xorg_list_for_each_entry(dev, &inputThreadInfo->devs, node)
267 if (dev->fd == fd) {
268 found_device = TRUE;
269 break;
270 }
271
272 /* fd didn't match any registered device. */
273 if (!found_device) {
274 input_unlock();
275 return 0;
276 }
277
278 dev->state = device_state_removed;
279 inputThreadInfo->changed = TRUE;
280
281 input_unlock();
282
283 InputThreadFillPipe(hotplugPipeWrite);
284 DebugF("input-thread: unregistered device: %d\n", fd);
285
286 return 1;
287 }
288
289 static void
InputThreadPipeNotify(int fd,int revents,void * data)290 InputThreadPipeNotify(int fd, int revents, void *data)
291 {
292 /* Empty pending input, shut down if the pipe has been closed */
293 if (InputThreadReadPipe(hotplugPipeRead) == 0) {
294 inputThreadInfo->running = FALSE;
295 }
296 }
297
298 /**
299 * The workhorse of threaded input event generation.
300 *
301 * Or if you prefer: The WaitForSomething for input devices. :)
302 *
303 * Runs in parallel with the server main thread, listening to input devices in
304 * an endless loop. Whenever new input data is made available, calls the
305 * proper device driver's routines which are ultimately responsible for the
306 * generation of input events.
307 *
308 * @see InputThreadPreInit()
309 * @see InputThreadInit()
310 */
311
312 static void*
InputThreadDoWork(void * arg)313 InputThreadDoWork(void *arg)
314 {
315 sigset_t set;
316
317 /* Don't handle any signals on this thread */
318 sigfillset(&set);
319 pthread_sigmask(SIG_BLOCK, &set, NULL);
320
321 ddxInputThreadInit();
322
323 inputThreadInfo->running = TRUE;
324
325 #if defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID)
326 pthread_setname_np (pthread_self(), "InputThread");
327 #elif defined(HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID)
328 pthread_setname_np ("InputThread");
329 #endif
330
331 ospoll_add(inputThreadInfo->fds, hotplugPipeRead,
332 ospoll_trigger_level,
333 InputThreadPipeNotify,
334 NULL);
335 ospoll_listen(inputThreadInfo->fds, hotplugPipeRead, X_NOTIFY_READ);
336
337 while (inputThreadInfo->running)
338 {
339 DebugF("input-thread: %s waiting for devices\n", __func__);
340
341 /* Check for hotplug changes and modify the ospoll structure to suit */
342 if (inputThreadInfo->changed) {
343 InputThreadDevice *dev, *tmp;
344
345 input_lock();
346 inputThreadInfo->changed = FALSE;
347 xorg_list_for_each_entry_safe(dev, tmp, &inputThreadInfo->devs, node) {
348 switch (dev->state) {
349 case device_state_added:
350 ospoll_add(inputThreadInfo->fds, dev->fd,
351 ospoll_trigger_level,
352 InputReady,
353 dev);
354 ospoll_listen(inputThreadInfo->fds, dev->fd, X_NOTIFY_READ);
355 dev->state = device_state_running;
356 break;
357 case device_state_running:
358 break;
359 case device_state_removed:
360 ospoll_remove(inputThreadInfo->fds, dev->fd);
361 xorg_list_del(&dev->node);
362 free(dev);
363 break;
364 }
365 }
366 input_unlock();
367 }
368
369 if (ospoll_wait(inputThreadInfo->fds, -1) < 0) {
370 if (errno == EINVAL)
371 FatalError("input-thread: %s (%s)", __func__, strerror(errno));
372 else if (errno != EINTR)
373 ErrorF("input-thread: %s (%s)\n", __func__, strerror(errno));
374 }
375
376 /* Kick main thread to process the generated input events and drain
377 * events from hotplug pipe */
378 InputThreadFillPipe(inputThreadInfo->writePipe);
379 }
380
381 ospoll_remove(inputThreadInfo->fds, hotplugPipeRead);
382
383 return NULL;
384 }
385
386 static void
InputThreadNotifyPipe(int fd,int mask,void * data)387 InputThreadNotifyPipe(int fd, int mask, void *data)
388 {
389 InputThreadReadPipe(fd);
390 }
391
392 /**
393 * Pre-initialize the facility used for threaded generation of input events
394 *
395 */
396 void
InputThreadPreInit(void)397 InputThreadPreInit(void)
398 {
399 int fds[2], hotplugPipe[2];
400 int flags;
401
402 if (!InputThreadEnable)
403 return;
404
405 if (pipe(fds) < 0)
406 FatalError("input-thread: could not create pipe");
407
408 if (pipe(hotplugPipe) < 0)
409 FatalError("input-thread: could not create pipe");
410
411 inputThreadInfo = malloc(sizeof(InputThreadInfo));
412 if (!inputThreadInfo)
413 FatalError("input-thread: could not allocate memory");
414
415 inputThreadInfo->changed = FALSE;
416
417 inputThreadInfo->thread = 0;
418 xorg_list_init(&inputThreadInfo->devs);
419 inputThreadInfo->fds = ospoll_create();
420
421 /* By making read head non-blocking, we ensure that while the main thread
422 * is busy servicing client requests, the dedicated input thread can work
423 * in parallel.
424 */
425 inputThreadInfo->readPipe = fds[0];
426 fcntl(inputThreadInfo->readPipe, F_SETFL, O_NONBLOCK);
427 flags = fcntl(inputThreadInfo->readPipe, F_GETFD);
428 if (flags != -1) {
429 flags |= FD_CLOEXEC;
430 (void)fcntl(inputThreadInfo->readPipe, F_SETFD, &flags);
431 }
432 SetNotifyFd(inputThreadInfo->readPipe, InputThreadNotifyPipe, X_NOTIFY_READ, NULL);
433
434 inputThreadInfo->writePipe = fds[1];
435
436 hotplugPipeRead = hotplugPipe[0];
437 fcntl(hotplugPipeRead, F_SETFL, O_NONBLOCK);
438 flags = fcntl(hotplugPipeRead, F_GETFD);
439 if (flags != -1) {
440 flags |= FD_CLOEXEC;
441 (void)fcntl(hotplugPipeRead, F_SETFD, &flags);
442 }
443 hotplugPipeWrite = hotplugPipe[1];
444
445 #ifndef __linux__ /* Linux does not deal well with renaming the main thread */
446 #if defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID)
447 pthread_setname_np (pthread_self(), "MainThread");
448 #elif defined(HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID)
449 pthread_setname_np ("MainThread");
450 #endif
451 #endif
452
453 }
454
455 /**
456 * Start the threaded generation of input events. This routine complements what
457 * was previously done by InputThreadPreInit(), being only responsible for
458 * creating the dedicated input thread.
459 *
460 */
461 void
InputThreadInit(void)462 InputThreadInit(void)
463 {
464 pthread_attr_t attr;
465
466 /* If the driver hasn't asked for input thread support by calling
467 * InputThreadPreInit, then do nothing here
468 */
469 if (!inputThreadInfo)
470 return;
471
472 pthread_attr_init(&attr);
473
474 /* For OSes that differentiate between processes and threads, the following
475 * lines have sense. Linux uses the 1:1 thread model. The scheduler handles
476 * every thread as a normal process. Therefore this probably has no meaning
477 * if we are under Linux.
478 */
479 if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0)
480 ErrorF("input-thread: error setting thread scope\n");
481
482 DebugF("input-thread: creating thread\n");
483 pthread_create(&inputThreadInfo->thread, &attr,
484 &InputThreadDoWork, NULL);
485
486 pthread_attr_destroy (&attr);
487 }
488
489 /**
490 * Stop the threaded generation of input events
491 *
492 * This function is supposed to be called at server shutdown time only.
493 */
494 void
InputThreadFini(void)495 InputThreadFini(void)
496 {
497 InputThreadDevice *dev, *next;
498
499 if (!inputThreadInfo)
500 return;
501
502 /* Close the pipe to get the input thread to shut down */
503 close(hotplugPipeWrite);
504 input_force_unlock();
505 pthread_join(inputThreadInfo->thread, NULL);
506
507 xorg_list_for_each_entry_safe(dev, next, &inputThreadInfo->devs, node) {
508 ospoll_remove(inputThreadInfo->fds, dev->fd);
509 free(dev);
510 }
511 xorg_list_init(&inputThreadInfo->devs);
512 ospoll_destroy(inputThreadInfo->fds);
513
514 RemoveNotifyFd(inputThreadInfo->readPipe);
515 close(inputThreadInfo->readPipe);
516 close(inputThreadInfo->writePipe);
517 inputThreadInfo->readPipe = -1;
518 inputThreadInfo->writePipe = -1;
519
520 close(hotplugPipeRead);
521 hotplugPipeRead = -1;
522 hotplugPipeWrite = -1;
523
524 free(inputThreadInfo);
525 inputThreadInfo = NULL;
526 }
527
xthread_sigmask(int how,const sigset_t * set,sigset_t * oldset)528 int xthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
529 {
530 return pthread_sigmask(how, set, oldset);
531 }
532
533 #else /* INPUTTHREAD */
534
535 Bool InputThreadEnable = FALSE;
536
input_lock(void)537 void input_lock(void) {}
input_unlock(void)538 void input_unlock(void) {}
input_force_unlock(void)539 void input_force_unlock(void) {}
540
InputThreadPreInit(void)541 void InputThreadPreInit(void) {}
InputThreadInit(void)542 void InputThreadInit(void) {}
InputThreadFini(void)543 void InputThreadFini(void) {}
in_input_thread(void)544 int in_input_thread(void) { return 0; }
545
InputThreadRegisterDev(int fd,NotifyFdProcPtr readInputProc,void * readInputArgs)546 int InputThreadRegisterDev(int fd,
547 NotifyFdProcPtr readInputProc,
548 void *readInputArgs)
549 {
550 return SetNotifyFd(fd, readInputProc, X_NOTIFY_READ, readInputArgs);
551 }
552
InputThreadUnregisterDev(int fd)553 extern int InputThreadUnregisterDev(int fd)
554 {
555 RemoveNotifyFd(fd);
556 return 1;
557 }
558
xthread_sigmask(int how,const sigset_t * set,sigset_t * oldset)559 int xthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
560 {
561 return sigprocmask(how, set, oldset);
562 }
563
564 #endif
565