summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKeith Packard <keithp@keithp.com>2016-05-24 21:12:33 -0700
committerAdam Jackson <ajax@redhat.com>2016-07-21 15:04:47 -0400
commit30bc0732f959bbc63f318c06d48de080d495da32 (patch)
tree567712ca3600be06c60b5b7f520ea970aad9b7d1
parentf993091e7db81b0420e23c485378cba112278839 (diff)
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 <keithp@keithp.com> Reviewed-by: Adam Jackson <ajax@redhat.com>
-rw-r--r--os/inputthread.c120
1 files changed, 82 insertions, 38 deletions
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 <unistd.h>
#include <pthread.h>
-#include <X11/Xpoll.h>
#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);