Commit 30ac7567 authored by Keith Packard's avatar Keith Packard

Create a threaded mechanism for input [v7]

The current SIGIO signal handler method, used at generation of input events,
has a bunch of oddities. This patch introduces an alternative way using a
thread, which is used to select() all input device file descriptors.

A mutex was used to control the access to input structures by the main and input
threads. Two pipes to emit alert events (such hotplug ones) and guarantee the
proper communication between them was also used.
Co-authored-by: default avatarFernando Carrijo <fcarrijo@freedesktop.org>
Signed-off-by: default avatarTiago Vignatti <tiago.vignatti@nokia.com>

v2: Fix non-Xorg link. Enable where supported by default.

    This also splits out the actual enabling of input threads to
    DDX-specific patches which follow

v3: Make the input lock recursive

v4: Use regular RECURSIVE_MUTEXes instead of rolling our own
    Respect the --disable-input-thread configuration option by
    providing stubs that expose the same API/ABI.

    Respond to style comments from Peter Hutterer.

v5: use __func__ in inputthread debug and error mesages.

    Respond to style comments from Peter Hutterer.

v6: use AX_PTHREAD instead of inlining pthread tests.

    Suggested by Emil Velikov <emil.l.velikov@gmail.com>

v7: Use pthread_sigmask instead of sigprocmask when using threads

    Suggested by Adam Jackson <ajax@redhat.com>
Signed-off-by: Adam Jackson's avatarAdam Jackson <ajax@redhat.com>
Signed-off-by: Keith Packard's avatarKeith Packard <keithp@keithp.com>
Reviewed-by: Adam Jackson's avatarAdam Jackson <ajax@redhat.com>
parent 728c9570
......@@ -832,6 +832,25 @@ SDK_REQUIRED_MODULES="$XPROTO $RANDRPROTO $RENDERPROTO $XEXTPROTO $INPUTPROTO $K
# Make SDK_REQUIRED_MODULES available for inclusion in xorg-server.pc
AC_SUBST(SDK_REQUIRED_MODULES)
AC_CHECK_DECL([PTHREAD_MUTEX_RECURSIVE], [HAVE_RECURSIVE_MUTEX=yes], [HAVE_RECURSIVE_MUTEX=no], [[#include <pthread.h>]])
THREAD_DEFAULT=no
if test "x$HAVE_RECURSIVE_MUTEX" = "xyes" ; then
THREAD_DEFAULT=yes
fi
AC_ARG_ENABLE(input-thread, AS_HELP_STRING([--enable-input-thread],
[Enable input threads]),
[INPUTTHREAD=$enableval], [INPUTTHREAD=$THREAD_DEFAULT])
if test "x$INPUTTHREAD" = "xyes" ; then
AX_PTHREAD(,AC_MSG_ERROR([threaded input requested but no pthread support has been found]))
SYS_LIBS="$SYS_LIBS $PTHREAD_LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
AC_DEFINE(INPUTTHREAD, 1, [Use a separate input thread])
fi
REQUIRED_MODULES="$FIXESPROTO $DAMAGEPROTO $XCMISCPROTO $XTRANS $BIGREQSPROTO $SDK_REQUIRED_MODULES"
dnl systemd socket activation
......
......@@ -132,3 +132,12 @@ Bool explicit_display = FALSE;
char *ConnectionInfo;
CARD32 TimeOutValue = DEFAULT_TIMEOUT * MILLI_PER_SECOND;
#if DEBUG_INPUT_MUTEX
#define INPUT_MUTEX_INITIALIZER PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP
#else
#define INPUT_MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER
#endif
pthread_mutex_t input_mutex = INPUT_MUTEX_INITIALIZER;
__thread int input_mutex_count;
......@@ -121,12 +121,9 @@ Equipment Corporation.
extern void Dispatch(void);
#ifdef XQUARTZ
#include <pthread.h>
BOOL serverRunning = FALSE;
BOOL serverRunning;
pthread_mutex_t serverRunningMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t serverRunningCond = PTHREAD_COND_INITIALIZER;
#endif
CallbackListPtr RootWindowFinalizeCallback = NULL;
......@@ -299,6 +296,8 @@ dix_main(int argc, char *argv[], char *envp[])
NotifyParentProcess();
InputThreadInit();
Dispatch();
#ifdef XQUARTZ
......@@ -331,6 +330,8 @@ dix_main(int argc, char *argv[], char *envp[])
CloseInput();
InputThreadFini();
for (i = 0; i < screenInfo.numScreens; i++)
screenInfo.screens[i]->root = NullWindow;
......
......@@ -99,7 +99,7 @@ dmxSigioHook(void)
sigaction(SIGIO, &a, 0);
sigemptyset(&s);
sigprocmask(SIG_SETMASK, &s, 0);
xthread_sigmask(SIG_SETMASK, &s, 0);
}
static void
......
......@@ -137,7 +137,7 @@ xf86BlockSIGIO(void)
sigemptyset(&set);
sigaddset(&set, SIGIO);
sigprocmask(SIG_BLOCK, &set, NULL);
xthread_sigmask(SIG_BLOCK, &set, NULL);
}
static void
......@@ -147,7 +147,7 @@ xf86ReleaseSIGIO(void)
sigemptyset(&set);
sigaddset(&set, SIGIO);
sigprocmask(SIG_UNBLOCK, &set, NULL);
xthread_sigmask(SIG_UNBLOCK, &set, NULL);
}
int
......
......@@ -524,4 +524,7 @@
/* Have posix_fallocate() */
#undef HAVE_POSIX_FALLOCATE
/* Use input thread */
#undef INPUTTHREAD
#endif /* _DIX_CONFIG_H_ */
......@@ -56,6 +56,7 @@ SOFTWARE.
#include "xkbrules.h"
#include "events.h"
#include "list.h"
#include "os.h"
#include <X11/extensions/XI2.h>
#define DEVICE_INIT 0
......@@ -714,13 +715,20 @@ extern _X_HIDDEN void input_constrain_cursor(DeviceIntPtr pDev, ScreenPtr screen
int *out_x, int *out_y,
int *nevents, InternalEvent* events);
static inline void input_lock(void) {
}
extern _X_EXPORT void input_lock(void);
extern _X_EXPORT void input_unlock(void);
extern _X_EXPORT void input_force_unlock(void);
static inline void input_unlock(void) {
}
extern void InputThreadPreInit(void);
extern void InputThreadInit(void);
extern void InputThreadFini(void);
static inline void input_force_unlock(void) {
}
extern int InputThreadRegisterDev(int fd,
NotifyFdProcPtr readInputProc,
void *readInputArgs);
extern int InputThreadUnregisterDev(int fd);
extern _X_EXPORT Bool InputThreadEnable;
#endif /* INPUT_H */
......@@ -79,6 +79,7 @@ OF THIS SOFTWARE.
#include <stddef.h>
#include <stdint.h>
#include <pthread.h>
#ifndef MAXSCREENS
#define MAXSCREENS 16
......
......@@ -706,4 +706,9 @@ xorg_backtrace(void);
extern _X_EXPORT int
os_move_fd(int fd);
#include <signal.h>
extern _X_EXPORT int
xthread_sigmask(int how, const sigset_t *set, sigset_t *oldest);
#endif /* OS_H */
......@@ -88,9 +88,6 @@ typedef struct _EventQueue {
static EventQueueRec miEventQueue;
#ifdef XQUARTZ
#include <pthread.h>
static pthread_mutex_t miEventQueueMutex = PTHREAD_MUTEX_INITIALIZER;
extern BOOL serverRunning;
extern pthread_mutex_t serverRunningMutex;
extern pthread_cond_t serverRunningCond;
......@@ -252,7 +249,6 @@ mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
#ifdef XQUARTZ
wait_for_server_init();
pthread_mutex_lock(&miEventQueueMutex);
#endif
verify_internal_event(e);
......@@ -296,9 +292,6 @@ mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
xorg_backtrace();
}
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
return;
}
......@@ -319,9 +312,6 @@ mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
miEventQueue.lastMotion = isMotion;
miEventQueue.tail = (oldtail + 1) % miEventQueue.nevents;
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
}
/**
......@@ -342,31 +332,19 @@ mieqEnqueue(DeviceIntPtr pDev, InternalEvent *e)
void
mieqSwitchScreen(DeviceIntPtr pDev, ScreenPtr pScreen, Bool set_dequeue_screen)
{
#ifdef XQUARTZ
pthread_mutex_lock(&miEventQueueMutex);
#endif
EnqueueScreen(pDev) = pScreen;
if (set_dequeue_screen)
DequeueScreen(pDev) = pScreen;
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
}
void
mieqSetHandler(int event, mieqHandler handler)
{
#ifdef XQUARTZ
pthread_mutex_lock(&miEventQueueMutex);
#endif
if (handler && miEventQueue.handlers[event])
ErrorF("[mi] mieq: warning: overriding existing handler %p with %p for "
"event %d\n", miEventQueue.handlers[event], handler, event);
miEventQueue.handlers[event] = handler;
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
}
/**
......@@ -581,9 +559,7 @@ mieqProcessInputEvents(void)
size_t n_enqueued;
static Bool inProcessInputEvents = FALSE;
#ifdef XQUARTZ
pthread_mutex_lock(&miEventQueueMutex);
#endif
input_lock();
/*
* report an error if mieqProcessInputEvents() is called recursively;
......@@ -621,9 +597,7 @@ mieqProcessInputEvents(void)
miEventQueue.head = (miEventQueue.head + 1) % miEventQueue.nevents;
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
input_unlock();
master = (dev) ? GetMaster(dev, MASTER_ATTACHED) : NULL;
......@@ -647,14 +621,10 @@ mieqProcessInputEvents(void)
event.device_event.flags & TOUCH_POINTER_EMULATED)))
miPointerUpdateSprite(dev);
#ifdef XQUARTZ
pthread_mutex_lock(&miEventQueueMutex);
#endif
input_lock();
}
inProcessInputEvents = FALSE;
#ifdef XQUARTZ
pthread_mutex_unlock(&miEventQueueMutex);
#endif
input_unlock();
}
......@@ -14,6 +14,7 @@ libos_la_SOURCES = \
backtrace.c \
client.c \
connection.c \
inputthread.c \
io.c \
mitauth.c \
oscolor.c \
......
This diff is collapsed.
......@@ -586,7 +586,7 @@ UseMsg(void)
ErrorF("-xinerama Disable XINERAMA extension\n");
#endif
ErrorF
("-dumbSched Disable smart scheduling, enable old behavior\n");
("-dumbSched Disable smart scheduling and threaded input, enable old behavior\n");
ErrorF("-schedInterval int Set scheduler interval in msec\n");
ErrorF("-sigstop Enable SIGSTOP based startup\n");
ErrorF("+extension name Enable extension\n");
......@@ -1004,11 +1004,12 @@ ProcessCommandLine(int argc, char *argv[])
i = skip - 1;
}
#endif
#if HAVE_SETITIMER
else if (strcmp(argv[i], "-dumbSched") == 0) {
InputThreadEnable = FALSE;
#if HAVE_SETITIMER
SmartScheduleSignalEnable = FALSE;
}
#endif
}
else if (strcmp(argv[i], "-schedInterval") == 0) {
if (++i < argc) {
SmartScheduleInterval = atoi(argv[i]);
......@@ -1304,7 +1305,6 @@ OsBlockSignals(void)
if (BlockedSignalCount++ == 0) {
sigset_t set;
input_lock();
sigemptyset(&set);
sigaddset(&set, SIGALRM);
sigaddset(&set, SIGVTALRM);
......@@ -1315,7 +1315,7 @@ OsBlockSignals(void)
sigaddset(&set, SIGTTIN);
sigaddset(&set, SIGTTOU);
sigaddset(&set, SIGCHLD);
sigprocmask(SIG_BLOCK, &set, &PreviousSignalMask);
xthread_sigmask(SIG_BLOCK, &set, &PreviousSignalMask);
}
#endif
}
......@@ -1325,8 +1325,7 @@ OsReleaseSignals(void)
{
#ifdef SIG_BLOCK
if (--BlockedSignalCount == 0) {
sigprocmask(SIG_SETMASK, &PreviousSignalMask, 0);
input_unlock();
xthread_sigmask(SIG_SETMASK, &PreviousSignalMask, 0);
}
#endif
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment