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
44Bool InputThreadEnable = TRUE;
45
46/**
47 * An input device as seen by the threaded input facility
48 */
49
50typedef enum _InputDeviceState {
51    device_state_added,
52    device_state_running,
53    device_state_removed
54} InputDeviceState;
55
56typedef 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 */
69typedef 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
79static InputThreadInfo *inputThreadInfo;
80
81static int hotplugPipeRead = -1;
82static int hotplugPipeWrite = -1;
83
84static int input_mutex_count;
85
86#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
87static pthread_mutex_t input_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
88#else
89static pthread_mutex_t input_mutex;
90static Bool input_mutex_initialized;
91#endif
92
93int
94in_input_thread(void)
95{
96    return inputThreadInfo &&
97           pthread_equal(pthread_self(), inputThreadInfo->thread);
98}
99
100void
101input_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
117void
118input_unlock(void)
119{
120    --input_mutex_count;
121    pthread_mutex_unlock(&input_mutex);
122}
123
124void
125input_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 */
141static void
142InputThreadFillPipe(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 */
158static int
159InputThreadReadPipe(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
173static void
174InputReady(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 */
193int
194InputThreadRegisterDev(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 */
251int
252InputThreadUnregisterDev(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
289static void
290InputThreadPipeNotify(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
312static void*
313InputThreadDoWork(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
386static void
387InputThreadNotifyPipe(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 */
396void
397InputThreadPreInit(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 */
461void
462InputThreadInit(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 */
494void
495InputThreadFini(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
528int 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
535Bool InputThreadEnable = FALSE;
536
537void input_lock(void) {}
538void input_unlock(void) {}
539void input_force_unlock(void) {}
540
541void InputThreadPreInit(void) {}
542void InputThreadInit(void) {}
543void InputThreadFini(void) {}
544int in_input_thread(void) { return 0; }
545
546int InputThreadRegisterDev(int fd,
547                           NotifyFdProcPtr readInputProc,
548                           void *readInputArgs)
549{
550    return SetNotifyFd(fd, readInputProc, X_NOTIFY_READ, readInputArgs);
551}
552
553extern int InputThreadUnregisterDev(int fd)
554{
555    RemoveNotifyFd(fd);
556    return 1;
557}
558
559int xthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
560{
561#ifdef HAVE_SIGPROCMASK
562    return sigprocmask(how, set, oldset);
563#else
564    return 0;
565#endif
566}
567
568#endif
569