inputthread.c revision 1b5d61b8
11b5d61b8Smrg/* inputthread.c -- Threaded generation of input events.
21b5d61b8Smrg *
31b5d61b8Smrg * Copyright © 2007-2008 Tiago Vignatti <vignatti at freedesktop org>
41b5d61b8Smrg * Copyright © 2010 Nokia
51b5d61b8Smrg *
61b5d61b8Smrg * Permission is hereby granted, free of charge, to any person obtaining a
71b5d61b8Smrg * copy of this software and associated documentation files (the "Software"),
81b5d61b8Smrg * to deal in the Software without restriction, including without limitation
91b5d61b8Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
101b5d61b8Smrg * and/or sell copies of the Software, and to permit persons to whom the
111b5d61b8Smrg * Software is furnished to do so, subject to the following conditions:
121b5d61b8Smrg *
131b5d61b8Smrg * The above copyright notice and this permission notice shall be included in
141b5d61b8Smrg * all copies or substantial portions of the Software.
151b5d61b8Smrg *
161b5d61b8Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
171b5d61b8Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
181b5d61b8Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
191b5d61b8Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
201b5d61b8Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
211b5d61b8Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
221b5d61b8Smrg * OTHER DEALINGS IN THE SOFTWARE.
231b5d61b8Smrg *
241b5d61b8Smrg * Authors: Fernando Carrijo <fcarrijo at freedesktop org>
251b5d61b8Smrg *          Tiago Vignatti <vignatti at freedesktop org>
261b5d61b8Smrg */
271b5d61b8Smrg
281b5d61b8Smrg#ifdef HAVE_DIX_CONFIG_H
291b5d61b8Smrg#include <dix-config.h>
301b5d61b8Smrg#endif
311b5d61b8Smrg
321b5d61b8Smrg#include <stdio.h>
331b5d61b8Smrg#include <errno.h>
341b5d61b8Smrg#include <stdlib.h>
351b5d61b8Smrg#include <unistd.h>
361b5d61b8Smrg#include <pthread.h>
371b5d61b8Smrg
381b5d61b8Smrg#include "inputstr.h"
391b5d61b8Smrg#include "opaque.h"
401b5d61b8Smrg#include "osdep.h"
411b5d61b8Smrg
421b5d61b8Smrg#if INPUTTHREAD
431b5d61b8Smrg
441b5d61b8SmrgBool InputThreadEnable = TRUE;
451b5d61b8Smrg
461b5d61b8Smrg/**
471b5d61b8Smrg * An input device as seen by the threaded input facility
481b5d61b8Smrg */
491b5d61b8Smrg
501b5d61b8Smrgtypedef enum _InputDeviceState {
511b5d61b8Smrg    device_state_added,
521b5d61b8Smrg    device_state_running,
531b5d61b8Smrg    device_state_removed
541b5d61b8Smrg} InputDeviceState;
551b5d61b8Smrg
561b5d61b8Smrgtypedef struct _InputThreadDevice {
571b5d61b8Smrg    struct xorg_list node;
581b5d61b8Smrg    NotifyFdProcPtr readInputProc;
591b5d61b8Smrg    void *readInputArgs;
601b5d61b8Smrg    int fd;
611b5d61b8Smrg    InputDeviceState state;
621b5d61b8Smrg} InputThreadDevice;
631b5d61b8Smrg
641b5d61b8Smrg/**
651b5d61b8Smrg * The threaded input facility.
661b5d61b8Smrg *
671b5d61b8Smrg * For now, we have one instance for all input devices.
681b5d61b8Smrg */
691b5d61b8Smrgtypedef struct {
701b5d61b8Smrg    pthread_t thread;
711b5d61b8Smrg    struct xorg_list devs;
721b5d61b8Smrg    struct ospoll *fds;
731b5d61b8Smrg    int readPipe;
741b5d61b8Smrg    int writePipe;
751b5d61b8Smrg    Bool changed;
761b5d61b8Smrg    Bool running;
771b5d61b8Smrg} InputThreadInfo;
781b5d61b8Smrg
791b5d61b8Smrgstatic InputThreadInfo *inputThreadInfo;
801b5d61b8Smrg
811b5d61b8Smrgstatic int hotplugPipeRead = -1;
821b5d61b8Smrgstatic int hotplugPipeWrite = -1;
831b5d61b8Smrg
841b5d61b8Smrgstatic int input_mutex_count;
851b5d61b8Smrg
861b5d61b8Smrg#ifdef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
871b5d61b8Smrgstatic pthread_mutex_t input_mutex = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
881b5d61b8Smrg#else
891b5d61b8Smrgstatic pthread_mutex_t input_mutex;
901b5d61b8Smrgstatic Bool input_mutex_initialized;
911b5d61b8Smrg#endif
921b5d61b8Smrg
931b5d61b8Smrgint
941b5d61b8Smrgin_input_thread(void)
951b5d61b8Smrg{
961b5d61b8Smrg    return inputThreadInfo &&
971b5d61b8Smrg           pthread_equal(pthread_self(), inputThreadInfo->thread);
981b5d61b8Smrg}
991b5d61b8Smrg
1001b5d61b8Smrgvoid
1011b5d61b8Smrginput_lock(void)
1021b5d61b8Smrg{
1031b5d61b8Smrg#ifndef PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP
1041b5d61b8Smrg    if (!input_mutex_initialized) {
1051b5d61b8Smrg        pthread_mutexattr_t mutex_attr;
1061b5d61b8Smrg
1071b5d61b8Smrg        input_mutex_initialized = TRUE;
1081b5d61b8Smrg        pthread_mutexattr_init(&mutex_attr);
1091b5d61b8Smrg        pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_RECURSIVE);
1101b5d61b8Smrg        pthread_mutex_init(&input_mutex, &mutex_attr);
1111b5d61b8Smrg    }
1121b5d61b8Smrg#endif
1131b5d61b8Smrg    pthread_mutex_lock(&input_mutex);
1141b5d61b8Smrg    ++input_mutex_count;
1151b5d61b8Smrg}
1161b5d61b8Smrg
1171b5d61b8Smrgvoid
1181b5d61b8Smrginput_unlock(void)
1191b5d61b8Smrg{
1201b5d61b8Smrg    --input_mutex_count;
1211b5d61b8Smrg    pthread_mutex_unlock(&input_mutex);
1221b5d61b8Smrg}
1231b5d61b8Smrg
1241b5d61b8Smrgvoid
1251b5d61b8Smrginput_force_unlock(void)
1261b5d61b8Smrg{
1271b5d61b8Smrg    if (pthread_mutex_trylock(&input_mutex) == 0) {
1281b5d61b8Smrg        input_mutex_count++;
1291b5d61b8Smrg        /* unlock +1 times for the trylock */
1301b5d61b8Smrg        while (input_mutex_count > 0)
1311b5d61b8Smrg            input_unlock();
1321b5d61b8Smrg    }
1331b5d61b8Smrg}
1341b5d61b8Smrg
1351b5d61b8Smrg/**
1361b5d61b8Smrg * Notify a thread about the availability of new asynchronously enqueued input
1371b5d61b8Smrg * events.
1381b5d61b8Smrg *
1391b5d61b8Smrg * @see WaitForSomething()
1401b5d61b8Smrg */
1411b5d61b8Smrgstatic void
1421b5d61b8SmrgInputThreadFillPipe(int writeHead)
1431b5d61b8Smrg{
1441b5d61b8Smrg    int ret;
1451b5d61b8Smrg    char byte = 0;
1461b5d61b8Smrg
1471b5d61b8Smrg    do {
1481b5d61b8Smrg        ret = write(writeHead, &byte, 1);
1491b5d61b8Smrg    } while (ret < 0 && ETEST(errno));
1501b5d61b8Smrg}
1511b5d61b8Smrg
1521b5d61b8Smrg/**
1531b5d61b8Smrg * Consume eventual notifications left by a thread.
1541b5d61b8Smrg *
1551b5d61b8Smrg * @see WaitForSomething()
1561b5d61b8Smrg * @see InputThreadFillPipe()
1571b5d61b8Smrg */
1581b5d61b8Smrgstatic int
1591b5d61b8SmrgInputThreadReadPipe(int readHead)
1601b5d61b8Smrg{
1611b5d61b8Smrg    int ret, array[10];
1621b5d61b8Smrg
1631b5d61b8Smrg    ret = read(readHead, &array, sizeof(array));
1641b5d61b8Smrg    if (ret >= 0)
1651b5d61b8Smrg        return ret;
1661b5d61b8Smrg
1671b5d61b8Smrg    if (errno != EAGAIN)
1681b5d61b8Smrg        FatalError("input-thread: draining pipe (%d)", errno);
1691b5d61b8Smrg
1701b5d61b8Smrg    return 1;
1711b5d61b8Smrg}
1721b5d61b8Smrg
1731b5d61b8Smrgstatic void
1741b5d61b8SmrgInputReady(int fd, int xevents, void *data)
1751b5d61b8Smrg{
1761b5d61b8Smrg    InputThreadDevice *dev = data;
1771b5d61b8Smrg
1781b5d61b8Smrg    input_lock();
1791b5d61b8Smrg    if (dev->state == device_state_running)
1801b5d61b8Smrg        dev->readInputProc(fd, xevents, dev->readInputArgs);
1811b5d61b8Smrg    input_unlock();
1821b5d61b8Smrg}
1831b5d61b8Smrg
1841b5d61b8Smrg/**
1851b5d61b8Smrg * Register an input device in the threaded input facility
1861b5d61b8Smrg *
1871b5d61b8Smrg * @param fd File descriptor which identifies the input device
1881b5d61b8Smrg * @param readInputProc Procedure used to read input from the device
1891b5d61b8Smrg * @param readInputArgs Arguments to be consumed by the above procedure
1901b5d61b8Smrg *
1911b5d61b8Smrg * return 1 if success; 0 otherwise.
1921b5d61b8Smrg */
1931b5d61b8Smrgint
1941b5d61b8SmrgInputThreadRegisterDev(int fd,
1951b5d61b8Smrg                       NotifyFdProcPtr readInputProc,
1961b5d61b8Smrg                       void *readInputArgs)
1971b5d61b8Smrg{
1981b5d61b8Smrg    InputThreadDevice *dev, *old;
1991b5d61b8Smrg
2001b5d61b8Smrg    if (!inputThreadInfo)
2011b5d61b8Smrg        return SetNotifyFd(fd, readInputProc, X_NOTIFY_READ, readInputArgs);
2021b5d61b8Smrg
2031b5d61b8Smrg    input_lock();
2041b5d61b8Smrg
2051b5d61b8Smrg    dev = NULL;
2061b5d61b8Smrg    xorg_list_for_each_entry(old, &inputThreadInfo->devs, node) {
2071b5d61b8Smrg        if (old->fd == fd && old->state != device_state_removed) {
2081b5d61b8Smrg            dev = old;
2091b5d61b8Smrg            break;
2101b5d61b8Smrg        }
2111b5d61b8Smrg    }
2121b5d61b8Smrg
2131b5d61b8Smrg    if (dev) {
2141b5d61b8Smrg        dev->readInputProc = readInputProc;
2151b5d61b8Smrg        dev->readInputArgs = readInputArgs;
2161b5d61b8Smrg    } else {
2171b5d61b8Smrg        dev = calloc(1, sizeof(InputThreadDevice));
2181b5d61b8Smrg        if (dev == NULL) {
2191b5d61b8Smrg            DebugF("input-thread: could not register device\n");
2201b5d61b8Smrg            input_unlock();
2211b5d61b8Smrg            return 0;
2221b5d61b8Smrg        }
2231b5d61b8Smrg
2241b5d61b8Smrg        dev->fd = fd;
2251b5d61b8Smrg        dev->readInputProc = readInputProc;
2261b5d61b8Smrg        dev->readInputArgs = readInputArgs;
2271b5d61b8Smrg        dev->state = device_state_added;
2281b5d61b8Smrg
2291b5d61b8Smrg        /* Do not prepend, so that any dev->state == device_state_removed
2301b5d61b8Smrg         * with the same dev->fd get processed first. */
2311b5d61b8Smrg        xorg_list_append(&dev->node, &inputThreadInfo->devs);
2321b5d61b8Smrg    }
2331b5d61b8Smrg
2341b5d61b8Smrg    inputThreadInfo->changed = TRUE;
2351b5d61b8Smrg
2361b5d61b8Smrg    input_unlock();
2371b5d61b8Smrg
2381b5d61b8Smrg    DebugF("input-thread: registered device %d\n", fd);
2391b5d61b8Smrg    InputThreadFillPipe(hotplugPipeWrite);
2401b5d61b8Smrg
2411b5d61b8Smrg    return 1;
2421b5d61b8Smrg}
2431b5d61b8Smrg
2441b5d61b8Smrg/**
2451b5d61b8Smrg * Unregister a device in the threaded input facility
2461b5d61b8Smrg *
2471b5d61b8Smrg * @param fd File descriptor which identifies the input device
2481b5d61b8Smrg *
2491b5d61b8Smrg * @return 1 if success; 0 otherwise.
2501b5d61b8Smrg */
2511b5d61b8Smrgint
2521b5d61b8SmrgInputThreadUnregisterDev(int fd)
2531b5d61b8Smrg{
2541b5d61b8Smrg    InputThreadDevice *dev;
2551b5d61b8Smrg    Bool found_device = FALSE;
2561b5d61b8Smrg
2571b5d61b8Smrg    /* return silently if input thread is already finished (e.g., at
2581b5d61b8Smrg     * DisableDevice time, evdev tries to call this function again through
2591b5d61b8Smrg     * xf86RemoveEnabledDevice) */
2601b5d61b8Smrg    if (!inputThreadInfo) {
2611b5d61b8Smrg        RemoveNotifyFd(fd);
2621b5d61b8Smrg        return 1;
2631b5d61b8Smrg    }
2641b5d61b8Smrg
2651b5d61b8Smrg    input_lock();
2661b5d61b8Smrg    xorg_list_for_each_entry(dev, &inputThreadInfo->devs, node)
2671b5d61b8Smrg        if (dev->fd == fd) {
2681b5d61b8Smrg            found_device = TRUE;
2691b5d61b8Smrg            break;
2701b5d61b8Smrg        }
2711b5d61b8Smrg
2721b5d61b8Smrg    /* fd didn't match any registered device. */
2731b5d61b8Smrg    if (!found_device) {
2741b5d61b8Smrg        input_unlock();
2751b5d61b8Smrg        return 0;
2761b5d61b8Smrg    }
2771b5d61b8Smrg
2781b5d61b8Smrg    dev->state = device_state_removed;
2791b5d61b8Smrg    inputThreadInfo->changed = TRUE;
2801b5d61b8Smrg
2811b5d61b8Smrg    input_unlock();
2821b5d61b8Smrg
2831b5d61b8Smrg    InputThreadFillPipe(hotplugPipeWrite);
2841b5d61b8Smrg    DebugF("input-thread: unregistered device: %d\n", fd);
2851b5d61b8Smrg
2861b5d61b8Smrg    return 1;
2871b5d61b8Smrg}
2881b5d61b8Smrg
2891b5d61b8Smrgstatic void
2901b5d61b8SmrgInputThreadPipeNotify(int fd, int revents, void *data)
2911b5d61b8Smrg{
2921b5d61b8Smrg    /* Empty pending input, shut down if the pipe has been closed */
2931b5d61b8Smrg    if (InputThreadReadPipe(hotplugPipeRead) == 0) {
2941b5d61b8Smrg        inputThreadInfo->running = FALSE;
2951b5d61b8Smrg    }
2961b5d61b8Smrg}
2971b5d61b8Smrg
2981b5d61b8Smrg/**
2991b5d61b8Smrg * The workhorse of threaded input event generation.
3001b5d61b8Smrg *
3011b5d61b8Smrg * Or if you prefer: The WaitForSomething for input devices. :)
3021b5d61b8Smrg *
3031b5d61b8Smrg * Runs in parallel with the server main thread, listening to input devices in
3041b5d61b8Smrg * an endless loop. Whenever new input data is made available, calls the
3051b5d61b8Smrg * proper device driver's routines which are ultimately responsible for the
3061b5d61b8Smrg * generation of input events.
3071b5d61b8Smrg *
3081b5d61b8Smrg * @see InputThreadPreInit()
3091b5d61b8Smrg * @see InputThreadInit()
3101b5d61b8Smrg */
3111b5d61b8Smrg
3121b5d61b8Smrgstatic void*
3131b5d61b8SmrgInputThreadDoWork(void *arg)
3141b5d61b8Smrg{
3151b5d61b8Smrg    sigset_t set;
3161b5d61b8Smrg
3171b5d61b8Smrg    /* Don't handle any signals on this thread */
3181b5d61b8Smrg    sigfillset(&set);
3191b5d61b8Smrg    pthread_sigmask(SIG_BLOCK, &set, NULL);
3201b5d61b8Smrg
3211b5d61b8Smrg    inputThreadInfo->running = TRUE;
3221b5d61b8Smrg
3231b5d61b8Smrg#if defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID)
3241b5d61b8Smrg    pthread_setname_np (pthread_self(), "InputThread");
3251b5d61b8Smrg#elif defined(HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID)
3261b5d61b8Smrg    pthread_setname_np ("InputThread");
3271b5d61b8Smrg#endif
3281b5d61b8Smrg
3291b5d61b8Smrg    ospoll_add(inputThreadInfo->fds, hotplugPipeRead,
3301b5d61b8Smrg               ospoll_trigger_level,
3311b5d61b8Smrg               InputThreadPipeNotify,
3321b5d61b8Smrg               NULL);
3331b5d61b8Smrg    ospoll_listen(inputThreadInfo->fds, hotplugPipeRead, X_NOTIFY_READ);
3341b5d61b8Smrg
3351b5d61b8Smrg    while (inputThreadInfo->running)
3361b5d61b8Smrg    {
3371b5d61b8Smrg        DebugF("input-thread: %s waiting for devices\n", __func__);
3381b5d61b8Smrg
3391b5d61b8Smrg        /* Check for hotplug changes and modify the ospoll structure to suit */
3401b5d61b8Smrg        if (inputThreadInfo->changed) {
3411b5d61b8Smrg            InputThreadDevice *dev, *tmp;
3421b5d61b8Smrg
3431b5d61b8Smrg            input_lock();
3441b5d61b8Smrg            inputThreadInfo->changed = FALSE;
3451b5d61b8Smrg            xorg_list_for_each_entry_safe(dev, tmp, &inputThreadInfo->devs, node) {
3461b5d61b8Smrg                switch (dev->state) {
3471b5d61b8Smrg                case device_state_added:
3481b5d61b8Smrg                    ospoll_add(inputThreadInfo->fds, dev->fd,
3491b5d61b8Smrg                               ospoll_trigger_level,
3501b5d61b8Smrg                               InputReady,
3511b5d61b8Smrg                               dev);
3521b5d61b8Smrg                    ospoll_listen(inputThreadInfo->fds, dev->fd, X_NOTIFY_READ);
3531b5d61b8Smrg                    dev->state = device_state_running;
3541b5d61b8Smrg                    break;
3551b5d61b8Smrg                case device_state_running:
3561b5d61b8Smrg                    break;
3571b5d61b8Smrg                case device_state_removed:
3581b5d61b8Smrg                    ospoll_remove(inputThreadInfo->fds, dev->fd);
3591b5d61b8Smrg                    xorg_list_del(&dev->node);
3601b5d61b8Smrg                    free(dev);
3611b5d61b8Smrg                    break;
3621b5d61b8Smrg                }
3631b5d61b8Smrg            }
3641b5d61b8Smrg            input_unlock();
3651b5d61b8Smrg        }
3661b5d61b8Smrg
3671b5d61b8Smrg        if (ospoll_wait(inputThreadInfo->fds, -1) < 0) {
3681b5d61b8Smrg            if (errno == EINVAL)
3691b5d61b8Smrg                FatalError("input-thread: %s (%s)", __func__, strerror(errno));
3701b5d61b8Smrg            else if (errno != EINTR)
3711b5d61b8Smrg                ErrorF("input-thread: %s (%s)\n", __func__, strerror(errno));
3721b5d61b8Smrg        }
3731b5d61b8Smrg
3741b5d61b8Smrg        /* Kick main thread to process the generated input events and drain
3751b5d61b8Smrg         * events from hotplug pipe */
3761b5d61b8Smrg        InputThreadFillPipe(inputThreadInfo->writePipe);
3771b5d61b8Smrg    }
3781b5d61b8Smrg
3791b5d61b8Smrg    ospoll_remove(inputThreadInfo->fds, hotplugPipeRead);
3801b5d61b8Smrg
3811b5d61b8Smrg    return NULL;
3821b5d61b8Smrg}
3831b5d61b8Smrg
3841b5d61b8Smrgstatic void
3851b5d61b8SmrgInputThreadNotifyPipe(int fd, int mask, void *data)
3861b5d61b8Smrg{
3871b5d61b8Smrg    InputThreadReadPipe(fd);
3881b5d61b8Smrg}
3891b5d61b8Smrg
3901b5d61b8Smrg/**
3911b5d61b8Smrg * Pre-initialize the facility used for threaded generation of input events
3921b5d61b8Smrg *
3931b5d61b8Smrg */
3941b5d61b8Smrgvoid
3951b5d61b8SmrgInputThreadPreInit(void)
3961b5d61b8Smrg{
3971b5d61b8Smrg    int fds[2], hotplugPipe[2];
3981b5d61b8Smrg    int flags;
3991b5d61b8Smrg
4001b5d61b8Smrg    if (!InputThreadEnable)
4011b5d61b8Smrg        return;
4021b5d61b8Smrg
4031b5d61b8Smrg    if (pipe(fds) < 0)
4041b5d61b8Smrg        FatalError("input-thread: could not create pipe");
4051b5d61b8Smrg
4061b5d61b8Smrg     if (pipe(hotplugPipe) < 0)
4071b5d61b8Smrg        FatalError("input-thread: could not create pipe");
4081b5d61b8Smrg
4091b5d61b8Smrg    inputThreadInfo = malloc(sizeof(InputThreadInfo));
4101b5d61b8Smrg    if (!inputThreadInfo)
4111b5d61b8Smrg        FatalError("input-thread: could not allocate memory");
4121b5d61b8Smrg
4131b5d61b8Smrg    inputThreadInfo->changed = FALSE;
4141b5d61b8Smrg
4151b5d61b8Smrg    inputThreadInfo->thread = 0;
4161b5d61b8Smrg    xorg_list_init(&inputThreadInfo->devs);
4171b5d61b8Smrg    inputThreadInfo->fds = ospoll_create();
4181b5d61b8Smrg
4191b5d61b8Smrg    /* By making read head non-blocking, we ensure that while the main thread
4201b5d61b8Smrg     * is busy servicing client requests, the dedicated input thread can work
4211b5d61b8Smrg     * in parallel.
4221b5d61b8Smrg     */
4231b5d61b8Smrg    inputThreadInfo->readPipe = fds[0];
4241b5d61b8Smrg    fcntl(inputThreadInfo->readPipe, F_SETFL, O_NONBLOCK);
4251b5d61b8Smrg    flags = fcntl(inputThreadInfo->readPipe, F_GETFD);
4261b5d61b8Smrg    if (flags != -1) {
4271b5d61b8Smrg        flags |= FD_CLOEXEC;
4281b5d61b8Smrg        (void)fcntl(inputThreadInfo->readPipe, F_SETFD, &flags);
4291b5d61b8Smrg    }
4301b5d61b8Smrg    SetNotifyFd(inputThreadInfo->readPipe, InputThreadNotifyPipe, X_NOTIFY_READ, NULL);
4311b5d61b8Smrg
4321b5d61b8Smrg    inputThreadInfo->writePipe = fds[1];
4331b5d61b8Smrg
4341b5d61b8Smrg    hotplugPipeRead = hotplugPipe[0];
4351b5d61b8Smrg    fcntl(hotplugPipeRead, F_SETFL, O_NONBLOCK);
4361b5d61b8Smrg    flags = fcntl(hotplugPipeRead, F_GETFD);
4371b5d61b8Smrg    if (flags != -1) {
4381b5d61b8Smrg        flags |= FD_CLOEXEC;
4391b5d61b8Smrg        (void)fcntl(hotplugPipeRead, F_SETFD, &flags);
4401b5d61b8Smrg    }
4411b5d61b8Smrg    hotplugPipeWrite = hotplugPipe[1];
4421b5d61b8Smrg
4431b5d61b8Smrg#ifndef __linux__ /* Linux does not deal well with renaming the main thread */
4441b5d61b8Smrg#if defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID)
4451b5d61b8Smrg    pthread_setname_np (pthread_self(), "MainThread");
4461b5d61b8Smrg#elif defined(HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID)
4471b5d61b8Smrg    pthread_setname_np ("MainThread");
4481b5d61b8Smrg#endif
4491b5d61b8Smrg#endif
4501b5d61b8Smrg
4511b5d61b8Smrg}
4521b5d61b8Smrg
4531b5d61b8Smrg/**
4541b5d61b8Smrg * Start the threaded generation of input events. This routine complements what
4551b5d61b8Smrg * was previously done by InputThreadPreInit(), being only responsible for
4561b5d61b8Smrg * creating the dedicated input thread.
4571b5d61b8Smrg *
4581b5d61b8Smrg */
4591b5d61b8Smrgvoid
4601b5d61b8SmrgInputThreadInit(void)
4611b5d61b8Smrg{
4621b5d61b8Smrg    pthread_attr_t attr;
4631b5d61b8Smrg
4641b5d61b8Smrg    /* If the driver hasn't asked for input thread support by calling
4651b5d61b8Smrg     * InputThreadPreInit, then do nothing here
4661b5d61b8Smrg     */
4671b5d61b8Smrg    if (!inputThreadInfo)
4681b5d61b8Smrg        return;
4691b5d61b8Smrg
4701b5d61b8Smrg    pthread_attr_init(&attr);
4711b5d61b8Smrg
4721b5d61b8Smrg    /* For OSes that differentiate between processes and threads, the following
4731b5d61b8Smrg     * lines have sense. Linux uses the 1:1 thread model. The scheduler handles
4741b5d61b8Smrg     * every thread as a normal process. Therefore this probably has no meaning
4751b5d61b8Smrg     * if we are under Linux.
4761b5d61b8Smrg     */
4771b5d61b8Smrg    if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0)
4781b5d61b8Smrg        ErrorF("input-thread: error setting thread scope\n");
4791b5d61b8Smrg
4801b5d61b8Smrg    DebugF("input-thread: creating thread\n");
4811b5d61b8Smrg    pthread_create(&inputThreadInfo->thread, &attr,
4821b5d61b8Smrg                   &InputThreadDoWork, NULL);
4831b5d61b8Smrg
4841b5d61b8Smrg    pthread_attr_destroy (&attr);
4851b5d61b8Smrg}
4861b5d61b8Smrg
4871b5d61b8Smrg/**
4881b5d61b8Smrg * Stop the threaded generation of input events
4891b5d61b8Smrg *
4901b5d61b8Smrg * This function is supposed to be called at server shutdown time only.
4911b5d61b8Smrg */
4921b5d61b8Smrgvoid
4931b5d61b8SmrgInputThreadFini(void)
4941b5d61b8Smrg{
4951b5d61b8Smrg    InputThreadDevice *dev, *next;
4961b5d61b8Smrg
4971b5d61b8Smrg    if (!inputThreadInfo)
4981b5d61b8Smrg        return;
4991b5d61b8Smrg
5001b5d61b8Smrg    /* Close the pipe to get the input thread to shut down */
5011b5d61b8Smrg    close(hotplugPipeWrite);
5021b5d61b8Smrg    input_force_unlock();
5031b5d61b8Smrg    pthread_join(inputThreadInfo->thread, NULL);
5041b5d61b8Smrg
5051b5d61b8Smrg    xorg_list_for_each_entry_safe(dev, next, &inputThreadInfo->devs, node) {
5061b5d61b8Smrg        ospoll_remove(inputThreadInfo->fds, dev->fd);
5071b5d61b8Smrg        free(dev);
5081b5d61b8Smrg    }
5091b5d61b8Smrg    xorg_list_init(&inputThreadInfo->devs);
5101b5d61b8Smrg    ospoll_destroy(inputThreadInfo->fds);
5111b5d61b8Smrg
5121b5d61b8Smrg    RemoveNotifyFd(inputThreadInfo->readPipe);
5131b5d61b8Smrg    close(inputThreadInfo->readPipe);
5141b5d61b8Smrg    close(inputThreadInfo->writePipe);
5151b5d61b8Smrg    inputThreadInfo->readPipe = -1;
5161b5d61b8Smrg    inputThreadInfo->writePipe = -1;
5171b5d61b8Smrg
5181b5d61b8Smrg    close(hotplugPipeRead);
5191b5d61b8Smrg    hotplugPipeRead = -1;
5201b5d61b8Smrg    hotplugPipeWrite = -1;
5211b5d61b8Smrg
5221b5d61b8Smrg    free(inputThreadInfo);
5231b5d61b8Smrg    inputThreadInfo = NULL;
5241b5d61b8Smrg}
5251b5d61b8Smrg
5261b5d61b8Smrgint xthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
5271b5d61b8Smrg{
5281b5d61b8Smrg    return pthread_sigmask(how, set, oldset);
5291b5d61b8Smrg}
5301b5d61b8Smrg
5311b5d61b8Smrg#else /* INPUTTHREAD */
5321b5d61b8Smrg
5331b5d61b8SmrgBool InputThreadEnable = FALSE;
5341b5d61b8Smrg
5351b5d61b8Smrgvoid input_lock(void) {}
5361b5d61b8Smrgvoid input_unlock(void) {}
5371b5d61b8Smrgvoid input_force_unlock(void) {}
5381b5d61b8Smrg
5391b5d61b8Smrgvoid InputThreadPreInit(void) {}
5401b5d61b8Smrgvoid InputThreadInit(void) {}
5411b5d61b8Smrgvoid InputThreadFini(void) {}
5421b5d61b8Smrgint in_input_thread(void) { return 0; }
5431b5d61b8Smrg
5441b5d61b8Smrgint InputThreadRegisterDev(int fd,
5451b5d61b8Smrg                           NotifyFdProcPtr readInputProc,
5461b5d61b8Smrg                           void *readInputArgs)
5471b5d61b8Smrg{
5481b5d61b8Smrg    return SetNotifyFd(fd, readInputProc, X_NOTIFY_READ, readInputArgs);
5491b5d61b8Smrg}
5501b5d61b8Smrg
5511b5d61b8Smrgextern int InputThreadUnregisterDev(int fd)
5521b5d61b8Smrg{
5531b5d61b8Smrg    RemoveNotifyFd(fd);
5541b5d61b8Smrg    return 1;
5551b5d61b8Smrg}
5561b5d61b8Smrg
5571b5d61b8Smrgint xthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
5581b5d61b8Smrg{
5591b5d61b8Smrg    return sigprocmask(how, set, oldset);
5601b5d61b8Smrg}
5611b5d61b8Smrg
5621b5d61b8Smrg#endif
563