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 3215a7dfde8Smrg ddxInputThreadInit(); 3225a7dfde8Smrg 3231b5d61b8Smrg inputThreadInfo->running = TRUE; 3241b5d61b8Smrg 3251b5d61b8Smrg#if defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID) 3261b5d61b8Smrg pthread_setname_np (pthread_self(), "InputThread"); 3271b5d61b8Smrg#elif defined(HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID) 3281b5d61b8Smrg pthread_setname_np ("InputThread"); 3291b5d61b8Smrg#endif 3301b5d61b8Smrg 3311b5d61b8Smrg ospoll_add(inputThreadInfo->fds, hotplugPipeRead, 3321b5d61b8Smrg ospoll_trigger_level, 3331b5d61b8Smrg InputThreadPipeNotify, 3341b5d61b8Smrg NULL); 3351b5d61b8Smrg ospoll_listen(inputThreadInfo->fds, hotplugPipeRead, X_NOTIFY_READ); 3361b5d61b8Smrg 3371b5d61b8Smrg while (inputThreadInfo->running) 3381b5d61b8Smrg { 3391b5d61b8Smrg DebugF("input-thread: %s waiting for devices\n", __func__); 3401b5d61b8Smrg 3411b5d61b8Smrg /* Check for hotplug changes and modify the ospoll structure to suit */ 3421b5d61b8Smrg if (inputThreadInfo->changed) { 3431b5d61b8Smrg InputThreadDevice *dev, *tmp; 3441b5d61b8Smrg 3451b5d61b8Smrg input_lock(); 3461b5d61b8Smrg inputThreadInfo->changed = FALSE; 3471b5d61b8Smrg xorg_list_for_each_entry_safe(dev, tmp, &inputThreadInfo->devs, node) { 3481b5d61b8Smrg switch (dev->state) { 3491b5d61b8Smrg case device_state_added: 3501b5d61b8Smrg ospoll_add(inputThreadInfo->fds, dev->fd, 3511b5d61b8Smrg ospoll_trigger_level, 3521b5d61b8Smrg InputReady, 3531b5d61b8Smrg dev); 3541b5d61b8Smrg ospoll_listen(inputThreadInfo->fds, dev->fd, X_NOTIFY_READ); 3551b5d61b8Smrg dev->state = device_state_running; 3561b5d61b8Smrg break; 3571b5d61b8Smrg case device_state_running: 3581b5d61b8Smrg break; 3591b5d61b8Smrg case device_state_removed: 3601b5d61b8Smrg ospoll_remove(inputThreadInfo->fds, dev->fd); 3611b5d61b8Smrg xorg_list_del(&dev->node); 3621b5d61b8Smrg free(dev); 3631b5d61b8Smrg break; 3641b5d61b8Smrg } 3651b5d61b8Smrg } 3661b5d61b8Smrg input_unlock(); 3671b5d61b8Smrg } 3681b5d61b8Smrg 3691b5d61b8Smrg if (ospoll_wait(inputThreadInfo->fds, -1) < 0) { 3701b5d61b8Smrg if (errno == EINVAL) 3711b5d61b8Smrg FatalError("input-thread: %s (%s)", __func__, strerror(errno)); 3721b5d61b8Smrg else if (errno != EINTR) 3731b5d61b8Smrg ErrorF("input-thread: %s (%s)\n", __func__, strerror(errno)); 3741b5d61b8Smrg } 3751b5d61b8Smrg 3761b5d61b8Smrg /* Kick main thread to process the generated input events and drain 3771b5d61b8Smrg * events from hotplug pipe */ 3781b5d61b8Smrg InputThreadFillPipe(inputThreadInfo->writePipe); 3791b5d61b8Smrg } 3801b5d61b8Smrg 3811b5d61b8Smrg ospoll_remove(inputThreadInfo->fds, hotplugPipeRead); 3821b5d61b8Smrg 3831b5d61b8Smrg return NULL; 3841b5d61b8Smrg} 3851b5d61b8Smrg 3861b5d61b8Smrgstatic void 3871b5d61b8SmrgInputThreadNotifyPipe(int fd, int mask, void *data) 3881b5d61b8Smrg{ 3891b5d61b8Smrg InputThreadReadPipe(fd); 3901b5d61b8Smrg} 3911b5d61b8Smrg 3921b5d61b8Smrg/** 3931b5d61b8Smrg * Pre-initialize the facility used for threaded generation of input events 3941b5d61b8Smrg * 3951b5d61b8Smrg */ 3961b5d61b8Smrgvoid 3971b5d61b8SmrgInputThreadPreInit(void) 3981b5d61b8Smrg{ 3991b5d61b8Smrg int fds[2], hotplugPipe[2]; 4001b5d61b8Smrg int flags; 4011b5d61b8Smrg 4021b5d61b8Smrg if (!InputThreadEnable) 4031b5d61b8Smrg return; 4041b5d61b8Smrg 4051b5d61b8Smrg if (pipe(fds) < 0) 4061b5d61b8Smrg FatalError("input-thread: could not create pipe"); 4071b5d61b8Smrg 4081b5d61b8Smrg if (pipe(hotplugPipe) < 0) 4091b5d61b8Smrg FatalError("input-thread: could not create pipe"); 4101b5d61b8Smrg 4111b5d61b8Smrg inputThreadInfo = malloc(sizeof(InputThreadInfo)); 4121b5d61b8Smrg if (!inputThreadInfo) 4131b5d61b8Smrg FatalError("input-thread: could not allocate memory"); 4141b5d61b8Smrg 4151b5d61b8Smrg inputThreadInfo->changed = FALSE; 4161b5d61b8Smrg 4171b5d61b8Smrg inputThreadInfo->thread = 0; 4181b5d61b8Smrg xorg_list_init(&inputThreadInfo->devs); 4191b5d61b8Smrg inputThreadInfo->fds = ospoll_create(); 4201b5d61b8Smrg 4211b5d61b8Smrg /* By making read head non-blocking, we ensure that while the main thread 4221b5d61b8Smrg * is busy servicing client requests, the dedicated input thread can work 4231b5d61b8Smrg * in parallel. 4241b5d61b8Smrg */ 4251b5d61b8Smrg inputThreadInfo->readPipe = fds[0]; 4261b5d61b8Smrg fcntl(inputThreadInfo->readPipe, F_SETFL, O_NONBLOCK); 4271b5d61b8Smrg flags = fcntl(inputThreadInfo->readPipe, F_GETFD); 4281b5d61b8Smrg if (flags != -1) { 4291b5d61b8Smrg flags |= FD_CLOEXEC; 430ed6184dfSmrg (void)fcntl(inputThreadInfo->readPipe, F_SETFD, flags); 4311b5d61b8Smrg } 4321b5d61b8Smrg SetNotifyFd(inputThreadInfo->readPipe, InputThreadNotifyPipe, X_NOTIFY_READ, NULL); 4331b5d61b8Smrg 4341b5d61b8Smrg inputThreadInfo->writePipe = fds[1]; 4351b5d61b8Smrg 4361b5d61b8Smrg hotplugPipeRead = hotplugPipe[0]; 4371b5d61b8Smrg fcntl(hotplugPipeRead, F_SETFL, O_NONBLOCK); 4381b5d61b8Smrg flags = fcntl(hotplugPipeRead, F_GETFD); 4391b5d61b8Smrg if (flags != -1) { 4401b5d61b8Smrg flags |= FD_CLOEXEC; 441ed6184dfSmrg (void)fcntl(hotplugPipeRead, F_SETFD, flags); 4421b5d61b8Smrg } 4431b5d61b8Smrg hotplugPipeWrite = hotplugPipe[1]; 4441b5d61b8Smrg 4451b5d61b8Smrg#ifndef __linux__ /* Linux does not deal well with renaming the main thread */ 4461b5d61b8Smrg#if defined(HAVE_PTHREAD_SETNAME_NP_WITH_TID) 4471b5d61b8Smrg pthread_setname_np (pthread_self(), "MainThread"); 4481b5d61b8Smrg#elif defined(HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID) 4491b5d61b8Smrg pthread_setname_np ("MainThread"); 4501b5d61b8Smrg#endif 4511b5d61b8Smrg#endif 4521b5d61b8Smrg 4531b5d61b8Smrg} 4541b5d61b8Smrg 4551b5d61b8Smrg/** 4561b5d61b8Smrg * Start the threaded generation of input events. This routine complements what 4571b5d61b8Smrg * was previously done by InputThreadPreInit(), being only responsible for 4581b5d61b8Smrg * creating the dedicated input thread. 4591b5d61b8Smrg * 4601b5d61b8Smrg */ 4611b5d61b8Smrgvoid 4621b5d61b8SmrgInputThreadInit(void) 4631b5d61b8Smrg{ 4641b5d61b8Smrg pthread_attr_t attr; 4651b5d61b8Smrg 4661b5d61b8Smrg /* If the driver hasn't asked for input thread support by calling 4671b5d61b8Smrg * InputThreadPreInit, then do nothing here 4681b5d61b8Smrg */ 4691b5d61b8Smrg if (!inputThreadInfo) 4701b5d61b8Smrg return; 4711b5d61b8Smrg 4721b5d61b8Smrg pthread_attr_init(&attr); 4731b5d61b8Smrg 4741b5d61b8Smrg /* For OSes that differentiate between processes and threads, the following 4751b5d61b8Smrg * lines have sense. Linux uses the 1:1 thread model. The scheduler handles 4761b5d61b8Smrg * every thread as a normal process. Therefore this probably has no meaning 4771b5d61b8Smrg * if we are under Linux. 4781b5d61b8Smrg */ 4791b5d61b8Smrg if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0) 4801b5d61b8Smrg ErrorF("input-thread: error setting thread scope\n"); 4811b5d61b8Smrg 4821b5d61b8Smrg DebugF("input-thread: creating thread\n"); 4831b5d61b8Smrg pthread_create(&inputThreadInfo->thread, &attr, 4841b5d61b8Smrg &InputThreadDoWork, NULL); 4851b5d61b8Smrg 4861b5d61b8Smrg pthread_attr_destroy (&attr); 4871b5d61b8Smrg} 4881b5d61b8Smrg 4891b5d61b8Smrg/** 4901b5d61b8Smrg * Stop the threaded generation of input events 4911b5d61b8Smrg * 4921b5d61b8Smrg * This function is supposed to be called at server shutdown time only. 4931b5d61b8Smrg */ 4941b5d61b8Smrgvoid 4951b5d61b8SmrgInputThreadFini(void) 4961b5d61b8Smrg{ 4971b5d61b8Smrg InputThreadDevice *dev, *next; 4981b5d61b8Smrg 4991b5d61b8Smrg if (!inputThreadInfo) 5001b5d61b8Smrg return; 5011b5d61b8Smrg 5021b5d61b8Smrg /* Close the pipe to get the input thread to shut down */ 5031b5d61b8Smrg close(hotplugPipeWrite); 5041b5d61b8Smrg input_force_unlock(); 5051b5d61b8Smrg pthread_join(inputThreadInfo->thread, NULL); 5061b5d61b8Smrg 5071b5d61b8Smrg xorg_list_for_each_entry_safe(dev, next, &inputThreadInfo->devs, node) { 5081b5d61b8Smrg ospoll_remove(inputThreadInfo->fds, dev->fd); 5091b5d61b8Smrg free(dev); 5101b5d61b8Smrg } 5111b5d61b8Smrg xorg_list_init(&inputThreadInfo->devs); 5121b5d61b8Smrg ospoll_destroy(inputThreadInfo->fds); 5131b5d61b8Smrg 5141b5d61b8Smrg RemoveNotifyFd(inputThreadInfo->readPipe); 5151b5d61b8Smrg close(inputThreadInfo->readPipe); 5161b5d61b8Smrg close(inputThreadInfo->writePipe); 5171b5d61b8Smrg inputThreadInfo->readPipe = -1; 5181b5d61b8Smrg inputThreadInfo->writePipe = -1; 5191b5d61b8Smrg 5201b5d61b8Smrg close(hotplugPipeRead); 5211b5d61b8Smrg hotplugPipeRead = -1; 5221b5d61b8Smrg hotplugPipeWrite = -1; 5231b5d61b8Smrg 5241b5d61b8Smrg free(inputThreadInfo); 5251b5d61b8Smrg inputThreadInfo = NULL; 5261b5d61b8Smrg} 5271b5d61b8Smrg 5281b5d61b8Smrgint xthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) 5291b5d61b8Smrg{ 5301b5d61b8Smrg return pthread_sigmask(how, set, oldset); 5311b5d61b8Smrg} 5321b5d61b8Smrg 5331b5d61b8Smrg#else /* INPUTTHREAD */ 5341b5d61b8Smrg 5351b5d61b8SmrgBool InputThreadEnable = FALSE; 5361b5d61b8Smrg 5371b5d61b8Smrgvoid input_lock(void) {} 5381b5d61b8Smrgvoid input_unlock(void) {} 5391b5d61b8Smrgvoid input_force_unlock(void) {} 5401b5d61b8Smrg 5411b5d61b8Smrgvoid InputThreadPreInit(void) {} 5421b5d61b8Smrgvoid InputThreadInit(void) {} 5431b5d61b8Smrgvoid InputThreadFini(void) {} 5441b5d61b8Smrgint in_input_thread(void) { return 0; } 5451b5d61b8Smrg 5461b5d61b8Smrgint InputThreadRegisterDev(int fd, 5471b5d61b8Smrg NotifyFdProcPtr readInputProc, 5481b5d61b8Smrg void *readInputArgs) 5491b5d61b8Smrg{ 5501b5d61b8Smrg return SetNotifyFd(fd, readInputProc, X_NOTIFY_READ, readInputArgs); 5511b5d61b8Smrg} 5521b5d61b8Smrg 5531b5d61b8Smrgextern int InputThreadUnregisterDev(int fd) 5541b5d61b8Smrg{ 5551b5d61b8Smrg RemoveNotifyFd(fd); 5561b5d61b8Smrg return 1; 5571b5d61b8Smrg} 5581b5d61b8Smrg 5591b5d61b8Smrgint xthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) 5601b5d61b8Smrg{ 561ed6184dfSmrg#ifdef HAVE_SIGPROCMASK 5621b5d61b8Smrg return sigprocmask(how, set, oldset); 563ed6184dfSmrg#else 564ed6184dfSmrg return 0; 565ed6184dfSmrg#endif 5661b5d61b8Smrg} 5671b5d61b8Smrg 5681b5d61b8Smrg#endif 569