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