[PATCH xserver 4/9] Create a threaded mechanism for input [v3]
Peter Hutterer
peter.hutterer at who-t.net
Thu Dec 17 21:01:43 PST 2015
On Thu, Dec 17, 2015 at 04:11:39PM -0800, Keith Packard wrote:
> 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()s all input device file descriptors.
drop the s after select()
> 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: Fernando Carrijo <fcarrijo at freedesktop.org>
> Signed-off-by: Tiago Vignatti <tiago.vignatti at nokia.com>
>
> v2: Fix non-Xorg link, and disable by default on non-Linux
>
> This also splits out the actual enabling of input threads to
> DDX-specific patches which follow
>
> v3: Make the input lock recursive
>
> Signed-off-by: Adam Jackson <ajax at redhat.com>
> Signed-off-by: Keith Packard <keithp at keithp.com>
>
> recursive lock
> ---
> configure.ac | 29 ++++
> dix/globals.c | 9 ++
> dix/main.c | 9 +-
> hw/xfree86/sdksyms.sh | 4 +
> include/input.h | 25 ++++
> include/misc.h | 1 +
> mi/mieq.c | 38 +----
> os/Makefile.am | 1 +
> os/inputthread.c | 379 ++++++++++++++++++++++++++++++++++++++++++++++++++
> os/utils.c | 9 +-
> 10 files changed, 461 insertions(+), 43 deletions(-)
> create mode 100644 os/inputthread.c
>
> diff --git a/configure.ac b/configure.ac
> index 5a43db3..bc15581 100644
> --- a/configure.ac
> +++ b/configure.ac
> @@ -821,6 +821,35 @@ 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)
>
> +# input thread setup
> +case $host_os in
> +linux*)
> + THREAD_DEFAULT=yes ;;
> +*)
> + THREAD_DEFAULT=no ;;
> +esac
> +AC_ARG_ENABLE(input-thread, AS_HELP_STRING([--enable-input-thread],
> + [Enable input threads]),
> + [INPUTTHREAD=$enableval], [INPUTTHREAD=$THREAD_DEFAULT])
shouldn't this set InputThreadEnable as well? afaict right now it's always
enabled, regardless what we say here (except that it'll probably fail the
build since the libs are missing).
> +if test "x$INPUTTHREAD" = "xyes" ; then
> + case $host_os in
> + linux*|openbsd*|gnu*|k*bsd*-gnu)
> + THREAD_LIB=-lpthread ;;
you're using quotes for the others but not here
> + netbsd*)
> + THREAD_CFLAGS="-D_POSIX_THREAD_SAFE_FUNCTIONS"
> + THREAD_LIB="-lpthread" ;;
> + freebsd*)
> + THREAD_CFLAGS="-D_THREAD_SAFE"
> + THREAD_LIB="-pthread" ;;
> + dragonfly*)
> + THREAD_LIB="-pthread" ;;
> + solaris*)
> + THREAD_CFLAGS="-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS" ;;
> + esac
> + SYS_LIBS="$SYS_LIBS $THREAD_LIB"
> + CFLAGS="$CFLAGS $THREAD_CFLAGS"
> +fi
> +
> REQUIRED_MODULES="$FIXESPROTO $DAMAGEPROTO $XCMISCPROTO $XTRANS $BIGREQSPROTO $SDK_REQUIRED_MODULES"
>
> dnl systemd socket activation
> diff --git a/dix/globals.c b/dix/globals.c
> index f36a938..e313930 100644
> --- a/dix/globals.c
> +++ b/dix/globals.c
> @@ -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;
> diff --git a/dix/main.c b/dix/main.c
> index 661ab03..1649e72 100644
> --- a/dix/main.c
> +++ b/dix/main.c
> @@ -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
>
> int
> @@ -296,6 +293,8 @@ dix_main(int argc, char *argv[], char *envp[])
>
> NotifyParentProcess();
>
> + InputThreadInit();
> +
indentation
> Dispatch();
>
> #ifdef XQUARTZ
> @@ -328,6 +327,8 @@ dix_main(int argc, char *argv[], char *envp[])
>
> CloseInput();
>
> + InputThreadFini();
> +
> for (i = 0; i < screenInfo.numScreens; i++)
> screenInfo.screens[i]->root = NullWindow;
>
> diff --git a/hw/xfree86/sdksyms.sh b/hw/xfree86/sdksyms.sh
> index 5391b72..fb2eaa1 100755
> --- a/hw/xfree86/sdksyms.sh
> +++ b/hw/xfree86/sdksyms.sh
> @@ -344,6 +344,10 @@ BEGIN {
> n = 1;
> }
>
> + if ($n ~ /__thread/) {
> + next;
> + }
> +
> # skip attribute, if any
> while ($n ~ /^(__attribute__|__global)/ ||
> # skip modifiers, if any
> diff --git a/include/input.h b/include/input.h
> index 75887b7..01ea4d9 100644
> --- a/include/input.h
> +++ b/include/input.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
> @@ -712,13 +713,37 @@ extern _X_HIDDEN void input_constrain_cursor(DeviceIntPtr pDev, ScreenPtr screen
> int *out_x, int *out_y,
> int *nevents, InternalEvent* events);
>
> +extern _X_EXPORT pthread_mutex_t input_mutex;
> +extern _X_EXPORT __thread int input_mutex_count;
> +
> static inline void input_lock(void) {
> + if (input_mutex_count++ == 0)
> + pthread_mutex_lock(&input_mutex);
> }
>
> static inline void input_unlock(void) {
> + if (--input_mutex_count == 0)
> + pthread_mutex_unlock(&input_mutex);
> + assert(input_mutex_count >= 0);
> }
>
> static inline void input_force_unlock(void) {
> + if (input_mutex_count > 0) {
> + input_mutex_count = 0;
> + pthread_mutex_unlock(&input_mutex);
> + }
> }
>
> +extern void InputThreadPreInit(void);
> +extern void InputThreadInit(void);
> +extern void InputThreadFini(void);
> +
> +extern int InputThreadRegisterDev(int fd,
> + NotifyFdProcPtr readInputProc,
> + void *readInputArgs);
> +
> +extern int InputThreadUnregisterDev(int fd);
> +
> +extern _X_EXPORT Bool InputThreadEnable;
> +
> #endif /* INPUT_H */
> diff --git a/include/misc.h b/include/misc.h
> index 56e138c..006f768 100644
> --- a/include/misc.h
> +++ b/include/misc.h
> @@ -79,6 +79,7 @@ OF THIS SOFTWARE.
>
> #include <stddef.h>
> #include <stdint.h>
> +#include <pthread.h>
>
> #ifndef MAXSCREENS
> #define MAXSCREENS 16
> diff --git a/mi/mieq.c b/mi/mieq.c
> index 8fbe6c3..8a67213 100644
> --- a/mi/mieq.c
> +++ b/mi/mieq.c
> @@ -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();
> }
> diff --git a/os/Makefile.am b/os/Makefile.am
> index a1bbb4d..fc49a73 100644
> --- a/os/Makefile.am
> +++ b/os/Makefile.am
> @@ -14,6 +14,7 @@ libos_la_SOURCES = \
> backtrace.c \
> client.c \
> connection.c \
> + inputthread.c \
> io.c \
> mitauth.c \
> oscolor.c \
> diff --git a/os/inputthread.c b/os/inputthread.c
> new file mode 100644
> index 0000000..7c87e87
> --- /dev/null
> +++ b/os/inputthread.c
> @@ -0,0 +1,379 @@
> +/* inputthread.c -- Threaded generation of input events.
> + *
> + * Copyright © 2007-2008 Tiago Vignatti <vignatti at freedesktop org>
> + * Copyright © 2010 Nokia
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + * Authors: Fernando Carrijo <fcarrijo at freedesktop org>
> + * Tiago Vignatti <vignatti at freedesktop org>
> + */
> +
> +#ifdef HAVE_DIX_CONFIG_H
> +#include <dix-config.h>
> +#endif
> +
> +#include <stdio.h>
> +#include <errno.h>
> +#include <stdlib.h>
> +#include <unistd.h>
> +#include <pthread.h>
> +
> +#include <X11/Xpoll.h>
> +#include "inputstr.h"
> +#include "opaque.h"
> +#include "osdep.h"
> +
> +Bool InputThreadEnable = TRUE;
> +
> +/**
> + * An input device as seen by the threaded input facility
> + */
> +typedef struct _InputThreadDevice {
> + struct xorg_list list;
I'd rename that to 'node' rather than list, to make it more obvious that
this is not a list head.
> + NotifyFdProcPtr readInputProc;
> + void *readInputArgs;
> + int fd;
> +} InputThreadDevice;
> +
> +/**
> + * The threaded input facility.
> + *
> + * For now, we have one instance for all input devices.
> + */
> +typedef struct {
> + pthread_t thread;
> + struct xorg_list devs;
> + fd_set fds;
> + int readPipe;
> + int writePipe;
> +} InputThreadInfo;
> +
> +static InputThreadInfo *inputThreadInfo;
> +
> +static int hotplugPipeRead = -1;
> +static int hotplugPipeWrite = -1;
> +
> +/**
> + * Notify a thread about the availability of new asynchronously enqueued input
> + * events.
> + *
> + * @see WaitForSomething()
> + */
> +static void
> +InputThreadFillPipe(int writeHead)
> +{
> + int ret;
> + char byte = 0;
> + fd_set writePipe;
> +
> + FD_ZERO(&writePipe);
> +
> + while (1) {
> + ret = write(writeHead, &byte, 1);
> + if (!ret)
> + FatalError("input-thread: write() returned 0");
> + if (ret > 0) {
> + break;
> + }
drop the {}
> + if (errno != EAGAIN)
> + FatalError("input-thread: filling pipe");
> +
> + DebugF("input-thread: pipe full\n");
> + FD_SET(writeHead, &writePipe);
> + Select(writeHead + 1, NULL, &writePipe, NULL, NULL);
> + }
> +}
> +
> +/**
> + * Consume eventual notifications left by a thread.
> + *
> + * @see WaitForSomething()
> + * @see InputThreadFillPipe()
> + */
> +static int
> +InputThreadReadPipe(int readHead)
> +{
> + int ret, array[10];
> +
> + ret = read(readHead, &array, sizeof(array));
> + if (ret >= 0)
> + return ret;
> +
> + if (errno != EAGAIN)
> + FatalError("input-thread: draining pipe (%d)", errno);
> +
> + return 1;
> +}
> +
> +/**
> + * Register an input device in the threaded input facility
> + *
> + * @param fd File descriptor which identifies the input device
> + * @param readInputProc Procedure used to read input from the device
> + * @param readInputArgs Arguments to be consumed by the above procedure
> + *
> + * return 1 if success; 0 otherwise.
> + */
> +int
> +InputThreadRegisterDev(int fd,
> + NotifyFdProcPtr readInputProc,
> + void *readInputArgs)
> +{
> + InputThreadDevice *new;
urgh, can we use "dev" or "new_device" here, rather than just "new"?
> +
> + if (!inputThreadInfo)
> + return SetNotifyFd(fd, readInputProc, X_NOTIFY_READ, readInputArgs);
> +
> + new = calloc(1, sizeof(InputThreadDevice));
> + if (new == NULL) {
> + DebugF("input-thread: could not register device\n");
> + return 0;
> + }
> +
> + new->fd = fd;
> + new->readInputProc = readInputProc;
> + new->readInputArgs = readInputArgs;
> +
> + xorg_list_add(&new->list, &inputThreadInfo->devs);
> +
> + FD_SET(fd, &inputThreadInfo->fds);
> +
> + InputThreadFillPipe(hotplugPipeWrite);
> + DebugF("input-thread: registered device %d\n", fd);
> +
> + return 1;
> +}
> +
> +/**
> + * Unregister a device in the threaded input facility
> + *
> + * @param fd File descriptor which identifies the input device
> + *
> + * @return 1 if success; 0 otherwise.
> + */
> +int
> +InputThreadUnregisterDev(int fd)
> +{
> + InputThreadDevice *dev;
> +
> + /* return silently if input thread is already finished (e.g., at
> + * DisableDevice time, evdev tries to call this function again through
> + * xf86RemoveEnabledDevice */
missing a closing )
> + if (!inputThreadInfo) {
> + RemoveNotifyFd(fd);
> + return 1;
> + }
> +
> + xorg_list_for_each_entry(dev, &inputThreadInfo->devs, list)
> + if (dev->fd == fd)
> + break;
> +
> + /* fd didn't match any registered device. */
> + if (&dev->list == &inputThreadInfo->devs)
> + return 0;
use a boolean "found_device" or so here, much nicer to grasp than the list
pointer comparison.
> +
> + xorg_list_del(&dev->list);
> +
> + FD_CLR(fd, &inputThreadInfo->fds);
> + free(dev);
> +
> + InputThreadFillPipe(hotplugPipeWrite);
> + DebugF("input-thread: unregistered device: %d\n", fd);
> +
> + return 1;
> +}
> +
> +/**
> + * The workhorse of threaded input event generation.
> + *
> + * Or if you prefer: The WaitForSomething for input devices. :)
> + *
> + * Runs in parallel with the server main thread, listening to input devices in
> + * an endless loop. Whenever new input data is made available, calls the
> + * proper device driver's routines which are ultimately responsible for the
> + * generation of input events.
> + *
> + * @see InputThreadPreInit()
> + * @see InputThreadInit()
> + */
> +
> +static void*
> +InputThreadDoWork(void *arg)
> +{
> + fd_set readyFds;
> + InputThreadDevice *dev, *next;
> +
> + FD_ZERO(&readyFds);
> +
> + while (1)
> + {
> + XFD_COPYSET(&inputThreadInfo->fds, &readyFds);
> + FD_SET(hotplugPipeRead, &readyFds);
> +
> + DebugF("input-thread: InputThreadDoWork waiting for devices\n");
> +
> + if (Select(MAXSELECT, &readyFds, NULL, NULL, NULL) < 0) {
> + if (errno == EINVAL)
> + FatalError("input-thread: InputThreadDoWork (%s)", strerror(errno));
> + else if (errno != EINTR)
> + ErrorF("input-thread: InputThreadDoWork (%s)\n", strerror(errno));
> + }
> +
> + DebugF("input-thread: InputThreadDoWork generating events\n");
__func__ for all three?
> +
> + /* Call the device drivers to generate input events for us */
> + xorg_list_for_each_entry_safe(dev, next, &inputThreadInfo->devs, list)
> + if (FD_ISSET(dev->fd, &readyFds) && dev->readInputProc) {
> + input_lock();
> + dev->readInputProc(dev->fd, X_NOTIFY_READ, dev->readInputArgs);
> + input_unlock();
> + }
please wrap the xorg_list loop in { }
Cheers,
Peter
> +
> + /* 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;
> + }
> + }
> + return NULL;
> +}
> +
> +static void
> +InputThreadNotifyPipe(int fd, int mask, void *data)
> +{
> + InputThreadReadPipe(fd);
> +}
> +
> +/**
> + * Pre-initialize the facility used for threaded generation of input events
> + *
> + */
> +void
> +InputThreadPreInit(void)
> +{
> + int fds[2], hotplugPipe[2];
> +
> + if (!InputThreadEnable)
> + return;
> +
> + if (pipe(fds) < 0)
> + FatalError("input-thread: could not create pipe");
> +
> + if (pipe(hotplugPipe) < 0)
> + FatalError("input-thread: could not create pipe");
> +
> + inputThreadInfo = malloc(sizeof(InputThreadInfo));
> + if (!inputThreadInfo)
> + FatalError("input-thread: could not allocate memory");
> +
> + inputThreadInfo->thread = 0;
> + xorg_list_init(&inputThreadInfo->devs);
> + FD_ZERO(&inputThreadInfo->fds);
> +
> + /* By making read head non-blocking, we ensure that while the main thread
> + * is busy servicing client requests, the dedicated input thread can work
> + * in parallel.
> + */
> + inputThreadInfo->readPipe = fds[0];
> + fcntl(inputThreadInfo->readPipe, F_SETFL, O_NONBLOCK | O_CLOEXEC);
> + SetNotifyFd(inputThreadInfo->readPipe, InputThreadNotifyPipe, X_NOTIFY_READ, NULL);
> +
> + inputThreadInfo->writePipe = fds[1];
> +
> + hotplugPipeRead = hotplugPipe[0];
> + fcntl(hotplugPipeRead, F_SETFL, O_NONBLOCK | O_CLOEXEC);
> + hotplugPipeWrite = hotplugPipe[1];
> +}
> +
> +/**
> + * Start the threaded generation of input events. This routine complements what
> + * was previously done by InputThreadPreInit(), being only responsible for
> + * creating the dedicated input thread.
> + *
> + */
> +void
> +InputThreadInit(void)
> +{
> + pthread_attr_t attr;
> +
> + /* If the driver hasn't asked for input thread support by calling
> + * InputThreadPreInit, then do nothing here
> + */
> + if (!inputThreadInfo)
> + return;
> +
> + pthread_attr_init(&attr);
> +
> + /* For OSes that differentiate between processes and threads, the following
> + * lines have sense. Linux uses the 1:1 thread model. The scheduler handles
> + * every thread as a normal process. Therefore this probably has no meaning
> + * if we are under Linux.
> + */
> + if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0)
> + ErrorF("input-thread: error setting thread scope\n");
> +
> + DebugF("input-thread: creating thread\n");
> + pthread_create(&inputThreadInfo->thread, &attr,
> + &InputThreadDoWork, NULL);
> +
> + pthread_attr_destroy (&attr);
> +}
> +
> +/**
> + * Stop the threaded generation of input events
> + *
> + * This function is supposed to be called at server shutdown time only.
> + */
> +void
> +InputThreadFini(void)
> +{
> + InputThreadDevice *dev, *next;
> +
> + if (!inputThreadInfo)
> + return;
> +
> + /* Close the pipe to get the input thread to shut down */
> + close(hotplugPipeWrite);
> + pthread_join(inputThreadInfo->thread, NULL);
> +
> + xorg_list_for_each_entry_safe(dev, next, &inputThreadInfo->devs, list) {
> + FD_CLR(dev->fd, &inputThreadInfo->fds);
> + free(dev);
> + }
> + xorg_list_init(&inputThreadInfo->devs);
> + FD_ZERO(&inputThreadInfo->fds);
> +
> + RemoveNotifyFd(inputThreadInfo->readPipe);
> + close(inputThreadInfo->readPipe);
> + close(inputThreadInfo->writePipe);
> + inputThreadInfo->readPipe = -1;
> + inputThreadInfo->writePipe = -1;
> +
> + close(hotplugPipeRead);
> + hotplugPipeRead = -1;
> + hotplugPipeWrite = -1;
> +
> + free(inputThreadInfo);
> + inputThreadInfo = NULL;
> +}
> diff --git a/os/utils.c b/os/utils.c
> index 7e8891d..c20ddfd 100644
> --- a/os/utils.c
> +++ b/os/utils.c
> @@ -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);
> @@ -1326,7 +1326,6 @@ OsReleaseSignals(void)
> #ifdef SIG_BLOCK
> if (--BlockedSignalCount == 0) {
> sigprocmask(SIG_SETMASK, &PreviousSignalMask, 0);
> - input_unlock();
> }
> #endif
> }
> --
> 2.6.4
>
> _______________________________________________
> xorg-devel at lists.x.org: X.Org development
> Archives: http://lists.x.org/archives/xorg-devel
> Info: http://lists.x.org/mailman/listinfo/xorg-devel
>
More information about the xorg-devel
mailing list