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>
This commit is contained in:
parent
f993091e7d
commit
30bc0732f9
120
os/inputthread.c
120
os/inputthread.c
|
@ -35,7 +35,6 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <pthread.h>
|
#include <pthread.h>
|
||||||
|
|
||||||
#include <X11/Xpoll.h>
|
|
||||||
#include "inputstr.h"
|
#include "inputstr.h"
|
||||||
#include "opaque.h"
|
#include "opaque.h"
|
||||||
#include "osdep.h"
|
#include "osdep.h"
|
||||||
|
@ -47,11 +46,19 @@ Bool InputThreadEnable = TRUE;
|
||||||
/**
|
/**
|
||||||
* An input device as seen by the threaded input facility
|
* 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 {
|
typedef struct _InputThreadDevice {
|
||||||
struct xorg_list node;
|
struct xorg_list node;
|
||||||
NotifyFdProcPtr readInputProc;
|
NotifyFdProcPtr readInputProc;
|
||||||
void *readInputArgs;
|
void *readInputArgs;
|
||||||
int fd;
|
int fd;
|
||||||
|
InputDeviceState state;
|
||||||
} InputThreadDevice;
|
} InputThreadDevice;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -62,9 +69,11 @@ typedef struct _InputThreadDevice {
|
||||||
typedef struct {
|
typedef struct {
|
||||||
pthread_t thread;
|
pthread_t thread;
|
||||||
struct xorg_list devs;
|
struct xorg_list devs;
|
||||||
fd_set fds;
|
struct ospoll *fds;
|
||||||
int readPipe;
|
int readPipe;
|
||||||
int writePipe;
|
int writePipe;
|
||||||
|
Bool changed;
|
||||||
|
Bool running;
|
||||||
} InputThreadInfo;
|
} InputThreadInfo;
|
||||||
|
|
||||||
static InputThreadInfo *inputThreadInfo;
|
static InputThreadInfo *inputThreadInfo;
|
||||||
|
@ -154,6 +163,17 @@ InputThreadReadPipe(int readHead)
|
||||||
return 1;
|
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
|
* Register an input device in the threaded input facility
|
||||||
*
|
*
|
||||||
|
@ -182,16 +202,18 @@ InputThreadRegisterDev(int fd,
|
||||||
dev->fd = fd;
|
dev->fd = fd;
|
||||||
dev->readInputProc = readInputProc;
|
dev->readInputProc = readInputProc;
|
||||||
dev->readInputArgs = readInputArgs;
|
dev->readInputArgs = readInputArgs;
|
||||||
|
dev->state = device_state_added;
|
||||||
|
|
||||||
input_lock();
|
input_lock();
|
||||||
xorg_list_add(&dev->node, &inputThreadInfo->devs);
|
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();
|
input_unlock();
|
||||||
|
|
||||||
|
DebugF("input-thread: registered device %d\n", fd);
|
||||||
|
InputThreadFillPipe(hotplugPipeWrite);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,20 +251,26 @@ InputThreadUnregisterDev(int fd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
xorg_list_del(&dev->node);
|
dev->state = device_state_removed;
|
||||||
|
inputThreadInfo->changed = TRUE;
|
||||||
FD_CLR(fd, &inputThreadInfo->fds);
|
|
||||||
|
|
||||||
input_unlock();
|
input_unlock();
|
||||||
|
|
||||||
free(dev);
|
|
||||||
|
|
||||||
InputThreadFillPipe(hotplugPipeWrite);
|
InputThreadFillPipe(hotplugPipeWrite);
|
||||||
DebugF("input-thread: unregistered device: %d\n", fd);
|
DebugF("input-thread: unregistered device: %d\n", fd);
|
||||||
|
|
||||||
return 1;
|
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.
|
* The workhorse of threaded input event generation.
|
||||||
*
|
*
|
||||||
|
@ -260,51 +288,66 @@ InputThreadUnregisterDev(int fd)
|
||||||
static void*
|
static void*
|
||||||
InputThreadDoWork(void *arg)
|
InputThreadDoWork(void *arg)
|
||||||
{
|
{
|
||||||
fd_set readyFds;
|
|
||||||
InputThreadDevice *dev, *next;
|
|
||||||
sigset_t set;
|
sigset_t set;
|
||||||
|
|
||||||
/* Don't handle any signals on this thread */
|
/* Don't handle any signals on this thread */
|
||||||
sigfillset(&set);
|
sigfillset(&set);
|
||||||
pthread_sigmask(SIG_BLOCK, &set, NULL);
|
pthread_sigmask(SIG_BLOCK, &set, NULL);
|
||||||
|
|
||||||
FD_ZERO(&readyFds);
|
inputThreadInfo->running = TRUE;
|
||||||
|
|
||||||
while (1)
|
ospoll_add(inputThreadInfo->fds, hotplugPipeRead,
|
||||||
|
ospoll_trigger_level,
|
||||||
|
InputThreadPipeNotify,
|
||||||
|
NULL);
|
||||||
|
ospoll_listen(inputThreadInfo->fds, hotplugPipeRead, X_NOTIFY_READ);
|
||||||
|
|
||||||
|
while (inputThreadInfo->running)
|
||||||
{
|
{
|
||||||
XFD_COPYSET(&inputThreadInfo->fds, &readyFds);
|
|
||||||
FD_SET(hotplugPipeRead, &readyFds);
|
|
||||||
|
|
||||||
DebugF("input-thread: %s waiting for devices\n", __func__);
|
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)
|
if (errno == EINVAL)
|
||||||
FatalError("input-thread: %s (%s)", __func__, strerror(errno));
|
FatalError("input-thread: %s (%s)", __func__, strerror(errno));
|
||||||
else if (errno != EINTR)
|
else if (errno != EINTR)
|
||||||
ErrorF("input-thread: %s (%s)\n", __func__, strerror(errno));
|
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
|
/* Kick main thread to process the generated input events and drain
|
||||||
* events from hotplug pipe */
|
* events from hotplug pipe */
|
||||||
InputThreadFillPipe(inputThreadInfo->writePipe);
|
InputThreadFillPipe(inputThreadInfo->writePipe);
|
||||||
|
}
|
||||||
|
|
||||||
|
ospoll_remove(inputThreadInfo->fds, hotplugPipeRead);
|
||||||
|
|
||||||
/* Empty pending input, shut down if the pipe has been closed */
|
|
||||||
if (FD_ISSET(hotplugPipeRead, &readyFds)) {
|
|
||||||
if (InputThreadReadPipe(hotplugPipeRead) == 0)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -338,7 +381,7 @@ InputThreadPreInit(void)
|
||||||
|
|
||||||
inputThreadInfo->thread = 0;
|
inputThreadInfo->thread = 0;
|
||||||
xorg_list_init(&inputThreadInfo->devs);
|
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
|
/* By making read head non-blocking, we ensure that while the main thread
|
||||||
* is busy servicing client requests, the dedicated input thread can work
|
* is busy servicing client requests, the dedicated input thread can work
|
||||||
|
@ -353,6 +396,7 @@ InputThreadPreInit(void)
|
||||||
hotplugPipeRead = hotplugPipe[0];
|
hotplugPipeRead = hotplugPipe[0];
|
||||||
fcntl(hotplugPipeRead, F_SETFL, O_NONBLOCK | O_CLOEXEC);
|
fcntl(hotplugPipeRead, F_SETFL, O_NONBLOCK | O_CLOEXEC);
|
||||||
hotplugPipeWrite = hotplugPipe[1];
|
hotplugPipeWrite = hotplugPipe[1];
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -407,11 +451,11 @@ InputThreadFini(void)
|
||||||
pthread_join(inputThreadInfo->thread, NULL);
|
pthread_join(inputThreadInfo->thread, NULL);
|
||||||
|
|
||||||
xorg_list_for_each_entry_safe(dev, next, &inputThreadInfo->devs, node) {
|
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);
|
free(dev);
|
||||||
}
|
}
|
||||||
xorg_list_init(&inputThreadInfo->devs);
|
xorg_list_init(&inputThreadInfo->devs);
|
||||||
FD_ZERO(&inputThreadInfo->fds);
|
ospoll_destroy(inputThreadInfo->fds);
|
||||||
|
|
||||||
RemoveNotifyFd(inputThreadInfo->readPipe);
|
RemoveNotifyFd(inputThreadInfo->readPipe);
|
||||||
close(inputThreadInfo->readPipe);
|
close(inputThreadInfo->readPipe);
|
||||||
|
|
Loading…
Reference in New Issue
Block a user