[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