From 30bc0732f959bbc63f318c06d48de080d495da32 Mon Sep 17 00:00:00 2001 From: Keith Packard Date: Tue, 24 May 2016 21:12:33 -0700 Subject: os: Use ospoll for input thread [v2] Replace use of select(2) to avoid fd limits. Note that InputThreadFillPipe used select as well, but none of the files passed were non-blocking, so there was no need for that code at all. v2: Keep ospoll API usage single threaded to avoid re-entrancy issues Signed-off-by: Keith Packard Reviewed-by: Adam Jackson --- os/inputthread.c | 120 +++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 82 insertions(+), 38 deletions(-) (limited to 'os') diff --git a/os/inputthread.c b/os/inputthread.c index a4266e92d..e815319f7 100644 --- a/os/inputthread.c +++ b/os/inputthread.c @@ -35,7 +35,6 @@ #include #include -#include #include "inputstr.h" #include "opaque.h" #include "osdep.h" @@ -47,11 +46,19 @@ Bool InputThreadEnable = TRUE; /** * An input device as seen by the threaded input facility */ + +typedef enum _InputDeviceState { + device_state_added, + device_state_running, + device_state_removed +} InputDeviceState; + typedef struct _InputThreadDevice { struct xorg_list node; NotifyFdProcPtr readInputProc; void *readInputArgs; int fd; + InputDeviceState state; } InputThreadDevice; /** @@ -62,9 +69,11 @@ typedef struct _InputThreadDevice { typedef struct { pthread_t thread; struct xorg_list devs; - fd_set fds; + struct ospoll *fds; int readPipe; int writePipe; + Bool changed; + Bool running; } InputThreadInfo; static InputThreadInfo *inputThreadInfo; @@ -154,6 +163,17 @@ InputThreadReadPipe(int readHead) return 1; } +static void +InputReady(int fd, int xevents, void *data) +{ + InputThreadDevice *dev = data; + + input_lock(); + if (dev->state == device_state_running) + dev->readInputProc(fd, xevents, dev->readInputArgs); + input_unlock(); +} + /** * Register an input device in the threaded input facility * @@ -182,16 +202,18 @@ InputThreadRegisterDev(int fd, dev->fd = fd; dev->readInputProc = readInputProc; dev->readInputArgs = readInputArgs; + dev->state = device_state_added; input_lock(); xorg_list_add(&dev->node, &inputThreadInfo->devs); - FD_SET(fd, &inputThreadInfo->fds); + inputThreadInfo->changed = TRUE; - InputThreadFillPipe(hotplugPipeWrite); - DebugF("input-thread: registered device %d\n", fd); input_unlock(); + DebugF("input-thread: registered device %d\n", fd); + InputThreadFillPipe(hotplugPipeWrite); + return 1; } @@ -229,20 +251,26 @@ InputThreadUnregisterDev(int fd) return 0; } - xorg_list_del(&dev->node); - - FD_CLR(fd, &inputThreadInfo->fds); + dev->state = device_state_removed; + inputThreadInfo->changed = TRUE; input_unlock(); - free(dev); - InputThreadFillPipe(hotplugPipeWrite); DebugF("input-thread: unregistered device: %d\n", fd); return 1; } +static void +InputThreadPipeNotify(int fd, int revents, void *data) +{ + /* Empty pending input, shut down if the pipe has been closed */ + if (InputThreadReadPipe(hotplugPipeRead) == 0) { + inputThreadInfo->running = FALSE; + } +} + /** * The workhorse of threaded input event generation. * @@ -260,51 +288,66 @@ InputThreadUnregisterDev(int fd) static void* InputThreadDoWork(void *arg) { - fd_set readyFds; - InputThreadDevice *dev, *next; sigset_t set; /* Don't handle any signals on this thread */ sigfillset(&set); pthread_sigmask(SIG_BLOCK, &set, NULL); - FD_ZERO(&readyFds); + inputThreadInfo->running = TRUE; - while (1) - { - XFD_COPYSET(&inputThreadInfo->fds, &readyFds); - FD_SET(hotplugPipeRead, &readyFds); + ospoll_add(inputThreadInfo->fds, hotplugPipeRead, + ospoll_trigger_level, + InputThreadPipeNotify, + NULL); + ospoll_listen(inputThreadInfo->fds, hotplugPipeRead, X_NOTIFY_READ); + while (inputThreadInfo->running) + { DebugF("input-thread: %s waiting for devices\n", __func__); - if (Select(MAXSELECT, &readyFds, NULL, NULL, NULL) < 0) { + /* Check for hotplug changes and modify the ospoll structure to suit */ + if (inputThreadInfo->changed) { + InputThreadDevice *dev, *tmp; + + input_lock(); + inputThreadInfo->changed = FALSE; + xorg_list_for_each_entry_safe(dev, tmp, &inputThreadInfo->devs, node) { + switch (dev->state) { + case device_state_added: + ospoll_add(inputThreadInfo->fds, dev->fd, + ospoll_trigger_level, + InputReady, + dev); + ospoll_listen(inputThreadInfo->fds, dev->fd, X_NOTIFY_READ); + dev->state = device_state_running; + break; + case device_state_running: + break; + case device_state_removed: + ospoll_remove(inputThreadInfo->fds, dev->fd); + xorg_list_del(&dev->node); + free(dev); + break; + } + } + input_unlock(); + } + + if (ospoll_wait(inputThreadInfo->fds, -1) < 0) { if (errno == EINVAL) FatalError("input-thread: %s (%s)", __func__, strerror(errno)); else if (errno != EINTR) ErrorF("input-thread: %s (%s)\n", __func__, strerror(errno)); } - DebugF("input-thread: %s generating events\n", __func__); - - input_lock(); - /* Call the device drivers to generate input events for us */ - xorg_list_for_each_entry_safe(dev, next, &inputThreadInfo->devs, node) { - if (FD_ISSET(dev->fd, &readyFds) && dev->readInputProc) { - dev->readInputProc(dev->fd, X_NOTIFY_READ, dev->readInputArgs); - } - } - input_unlock(); - /* Kick main thread to process the generated input events and drain * events from hotplug pipe */ InputThreadFillPipe(inputThreadInfo->writePipe); - - /* Empty pending input, shut down if the pipe has been closed */ - if (FD_ISSET(hotplugPipeRead, &readyFds)) { - if (InputThreadReadPipe(hotplugPipeRead) == 0) - break; - } } + + ospoll_remove(inputThreadInfo->fds, hotplugPipeRead); + return NULL; } @@ -338,7 +381,7 @@ InputThreadPreInit(void) inputThreadInfo->thread = 0; xorg_list_init(&inputThreadInfo->devs); - FD_ZERO(&inputThreadInfo->fds); + inputThreadInfo->fds = ospoll_create(); /* By making read head non-blocking, we ensure that while the main thread * is busy servicing client requests, the dedicated input thread can work @@ -353,6 +396,7 @@ InputThreadPreInit(void) hotplugPipeRead = hotplugPipe[0]; fcntl(hotplugPipeRead, F_SETFL, O_NONBLOCK | O_CLOEXEC); hotplugPipeWrite = hotplugPipe[1]; + } /** @@ -407,11 +451,11 @@ InputThreadFini(void) pthread_join(inputThreadInfo->thread, NULL); xorg_list_for_each_entry_safe(dev, next, &inputThreadInfo->devs, node) { - FD_CLR(dev->fd, &inputThreadInfo->fds); + ospoll_remove(inputThreadInfo->fds, dev->fd); free(dev); } xorg_list_init(&inputThreadInfo->devs); - FD_ZERO(&inputThreadInfo->fds); + ospoll_destroy(inputThreadInfo->fds); RemoveNotifyFd(inputThreadInfo->readPipe); close(inputThreadInfo->readPipe); -- cgit v1.2.3