-- Tiago Vignatti C3SL - Centro de Computação Científica e Software Livre www.c3sl.ufpr.br
>From 856d2e3906a9a3f1ea55249f43e1ea1310f22d2d Mon Sep 17 00:00:00 2001 From: Tiago Vignatti <[EMAIL PROTECTED]> Date: Wed, 1 Oct 2008 21:13:26 -0300 Subject: [PATCH] The input-thread core file implementation.
Signed-off-by: Tiago Vignatti <[EMAIL PROTECTED]> --- os/inputthread.c | 280 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 280 insertions(+), 0 deletions(-) create mode 100644 os/inputthread.c diff --git a/os/inputthread.c b/os/inputthread.c new file mode 100644 index 0000000..e2eb15f --- /dev/null +++ b/os/inputthread.c @@ -0,0 +1,280 @@ +/* inputthread.c -- The input thread implementation. + * + * Copyright 2007-2008 Tiago Vignatti <[EMAIL PROTECTED]> + * + * 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. + * + * Except as contained in this notice, the name of the copyright holder(s) + * and author(s) shall not be used in advertising or otherwise to promote + * the sale, use or other dealings in this Software without prior written + * authorization from the copyright holder(s) and author(s). + */ + +#ifdef HAVE_DIX_CONFIG_H +#include <dix-config.h> +#endif + +#include <pthread.h> +#include <signal.h> +#include <errno.h> +#include <X11/Xpoll.h> + +#include "inputstr.h" +#include "opaque.h" + + +static int WaitForInput(void* argument); + +typedef struct _InputDeviceFunc { + void (*f) (void *); + int fd; + void *closure; +} InputDeviceFunc; + +InputDeviceFunc DevFunc[MAX_DEVICES]; + +fd_set InputThreadFd; /* Devices monitored by the input thread */ +int MainThreadReadPipe = -1; +int MainThreadWritePipe = -1; +int InputThreadReadPipe = -1; +int InputThreadWritePipe = -1; + +pthread_t tid_input; + + +void +InitInputThread(void) +{ + int i, main_to_input[2], input_to_main[2]; + + /* The "communication channel" between the input and main thread in + * both ways.*/ + if (pipe(main_to_input) < 0) { + perror("pipe"); + exit(1); + } + if (pipe(input_to_main) < 0) { + perror("pipe"); + exit(1); + } + + /* Make the pipes nonblocking */ + fcntl(main_to_input[0], F_SETFL, O_NONBLOCK); + fcntl(main_to_input[1], F_SETFL, O_NONBLOCK); + fcntl(input_to_main[0], F_SETFL, O_NONBLOCK); + fcntl(input_to_main[1], F_SETFL, O_NONBLOCK); + + MainThreadReadPipe = main_to_input[0]; + MainThreadWritePipe = main_to_input[1]; + InputThreadReadPipe = input_to_main[0]; + InputThreadWritePipe = input_to_main[1]; + + + FD_ZERO(&InputThreadFd); + + for (i = 0; i < MAX_DEVICES; i++) + DevFunc[i].fd = 0; +} + +/* + * Called by the dix to create the input thread. + */ +void +CreateInputThread (void) +{ + pthread_t input_thread; + pthread_attr_t attr; + + pthread_attr_init(&attr); + + /* In OSes that differentiates processes and threads this could have some + * sense. Linux uses 1:1 thread model. The scheduler handles every thread + * as if it were a process. Therefore this bellow have no meaning if your + * OS is Linux. + */ + if (pthread_attr_setscope(&attr, PTHREAD_SCOPE_SYSTEM) != 0) + perror("error setting input thread scope"); + + if (pthread_attr_setstacksize(&attr, PTHREAD_STACK_MIN) != 0) + perror("error setting input thread stack size"); + + pthread_create(&input_thread, &attr, (void *)&WaitForInput, NULL); + pthread_attr_destroy (&attr); +} + +/* + * Called by the dix to close the input thread cleanly. + * + * TODO: This is a blinded implementation due X server regenaration + * is currently broken. + */ +void +CloseInputThread (void) +{ + RemoveEnabledDevice(MainThreadReadPipe); + FD_ZERO(&InputThreadFd); + + pthread_kill(tid_input, SIGKILL); +} + +/* + * Create connections in the input thread. Must be called by the + * DDX implementation. + */ +void +AddEnabledDeviceThreaded(int fd, void (*f)(void *), void *closure) +{ + int i; + + FD_SET(fd, &InputThreadFd); + + for (i = 0; DevFunc[i].fd != 0; i++) + ; /* intentional */ + + DevFunc[i].fd = fd; + DevFunc[i].f = f; + DevFunc[i].closure = closure; + +#ifdef THREAD_DEBUG + ErrorF("Input thread: Using PTHREAD for input device %d\n", fd); +#endif + + /* wake up input thread to notify the new device */ + PipeWrite(InputThreadWritePipe); +} + +/* + * Destroy device connection. + */ +void +RemoveEnabledDeviceThreaded(int fd) +{ + int i = 0; + + FD_CLR(fd, &InputThreadFd); + + while (DevFunc[i].fd != fd && i < MAX_DEVICES) + i++; + + if (i < MAX_DEVICES) + DevFunc[i].fd = 0; + /*else TODO: things can be wrong */ + + /* wake up input thread to notify the new device */ + PipeWrite(InputThreadWritePipe); +} + +/* + * Input events routed through another thread/process can have bad effects on + * latency because we canât guarantee that it will get scheduled at the right + * moment. Although this is hard to see happening with the current + * implementation, we must design something to avoid it. One way to improve + * the responsiveness is to give a high priority to the input thread and also + * adjust the CPU scheduling. + * A detailed discussion can be found here: + * http://vignatti.wordpress.com/2008/08/07/priorities-and-scheduling-hints-for-x-server-threads/ + * + * TODO: incorporate this with cgroup, a feature which allows to limit the + * amount of CPU time real-time processes and threads may consume. + */ +#if 0 +static void +AdjustThreadScheduling(int tid) +{ + struct sched_param param; + int policy = SCHED_FIFO; + + + pthread_t p_tid = pthread_self(); + + param.sched_priority = sched_get_priority_max(policy); + + if (pthread_setschedparam(p_tid, policy, ¶m) != 0) + perror("error setting thread scheduling"); + +#ifdef THREAD_DEBUG + sched_getparam(tid, ¶m); + ErrorF("thread %d: policy: %d, priority: %d\n", tid, + sched_getscheduler(tid_generation), param.sched_priority); +#endif +} +#endif + +/* + * The 'WaitForSomething' of the input thread. + * + * @return exit code for the child process which currently is none. The child + * process exits only when the main thread (parent) send a signal or a + * fatal error occurs. + */ +static int +WaitForInput(void* argument) +{ + int i; + fd_set InputDevices; + + tid_input = pthread_self(); + +/* AdjustThreadScheduling(tid_generation); */ + + FD_ZERO(&InputDevices); + + ErrorF("Input thread present\n"); + while (1) + { + /* Empty the signaling pipe */ + if (PipeRead(InputThreadReadPipe) > 0) + FD_SET(InputThreadReadPipe, &InputThreadFd); + + XFD_COPYSET (&InputThreadFd, &InputDevices); + i = Select(MaxInputDevices, &InputDevices, NULL, NULL, NULL); +#ifdef THREAD_DEBUG + fprintf(stderr, "thread (input generation)\n"); +#endif + if (i <= 0) /* An error or timeout occurred */ + { + if (i < 0) /* This logic are stolen from WaitFor.c */ + { + if (errno == EINVAL) + { + FatalError("WaitForInput(): select: %s\n", + strerror(errno)); + } + else if (errno != EINTR && errno != EAGAIN) + { + ErrorF("WaitForInput(): select: %s\n", + strerror(errno)); + } + } + } + else + { + for (i = 0; i <= MAX_DEVICES; i++) + if (DevFunc[i].fd != 0 && + FD_ISSET(DevFunc[i].fd, &InputThreadFd) && + DevFunc[i].f) + (*DevFunc[i].f)(DevFunc[i].closure); + + } + + /* Send a null byte to the main thread so it wakes select up to + * process the events in mieqProcessInputEvents() */ + PipeWrite(MainThreadWritePipe); + } +} -- 1.5.4.3
_______________________________________________ xorg mailing list xorg@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/xorg