summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTiago Vignatti <tiago.vignatti@nokia.com>2010-07-09 21:04:20 +0300
committerTiago Vignatti <tiago.vignatti@nokia.com>2010-07-11 23:58:06 +0300
commit2fb21af30c35c4118bf1d6fe42ff49ff4e4a9b07 (patch)
tree066c4c3232f74442e501b6e478e5e6b9ce8f43d8
parent2307ab5bc9365ebbe04568edb7c7620a23689b70 (diff)
os: inputthread: the input thread implementation
Signed-off-by: Tiago Vignatti <tiago.vignatti@nokia.com>
-rw-r--r--os/inputthread.c223
1 files changed, 223 insertions, 0 deletions
diff --git a/os/inputthread.c b/os/inputthread.c
new file mode 100644
index 000000000..470370603
--- /dev/null
+++ b/os/inputthread.c
@@ -0,0 +1,223 @@
+/* inputthread.c -- The input thread implementation.
+ *
+ * Copyright 2007-2008 Tiago Vignatti <vignatti at freedesktop org>
+ *
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+#include <errno.h>
+#include <X11/Xpoll.h>
+
+#include "inputstr.h"
+#include "opaque.h"
+
+
+typedef struct _ThreadDeviceFunc {
+ void (*f) (void *);
+ int fd;
+ void *closure;
+} ThreadDeviceFunc;
+
+ThreadDeviceFunc ThreadDevFunc[MAXDEVICES];
+
+extern fd_set InputThreadFd;
+extern int NumDevicesThreaded;
+extern int InputThreadReadPipe;
+extern int InputThreadWritePipe;
+
+static pid_t tid_generation;
+
+int InputReadPipe = -1;
+int InputWritePipe = -1;
+
+/*
+ * Create connections in the input thread. Must be called by the
+ * DDX implementation.
+ */
+_X_EXPORT void
+AddEnabledDeviceThreaded(int fd, void (*f)(void *), void *closure)
+{
+ FD_SET(fd, &InputThreadFd);
+
+ ThreadDevFunc[NumDevicesThreaded].fd = fd;
+ ThreadDevFunc[NumDevicesThreaded].f = f;
+ ThreadDevFunc[NumDevicesThreaded].closure = closure;
+
+ NumDevicesThreaded++;
+
+ DebugF("Input thread: Using PTHREAD for input device %d\n", fd);
+}
+
+/*
+ * 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, &param) != 0)
+ perror("error setting thread scheduling");
+
+#ifdef THREAD_DEBUG
+ sched_getparam(tid, &param);
+ ErrorF("thread %d: policy: %d, priority: %d\n", tid,
+ sched_getscheduler(tid_generation), param.sched_priority);
+#endif
+}
+#endif
+
+/*
+ * @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;
+ int i_pipe[2];
+
+
+ tid_generation = syscall(__NR_gettid);
+
+ /* AdjustThreadScheduling(tid_generation); */
+
+ FD_ZERO(&InputDevices);
+
+ /* The "communication channel" between the input and main thread */
+ if (pipe(i_pipe) < 0) {
+ perror("pipe");
+ exit(-1);
+ }
+
+ /* Make pipes nonblocking */
+ fcntl(i_pipe[0], F_SETFL, O_NONBLOCK);
+ fcntl(i_pipe[1], F_SETFL, O_NONBLOCK);
+
+ InputReadPipe = i_pipe[0];
+ InputWritePipe = i_pipe[1];
+
+ while (1)
+ {
+ XFD_COPYSET (&InputThreadFd, &InputDevices);
+ i = Select(MaxInputDevices, &InputDevices, NULL, NULL, NULL);
+ DebugF("threading input generation)\n");
+ 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 <= NumDevicesThreaded; i++)
+ if ((FD_ISSET(ThreadDevFunc[i].fd, &InputThreadFd))
+ && ThreadDevFunc[i].f)
+ (*ThreadDevFunc[i].f)(ThreadDevFunc[i].closure);
+
+ }
+
+ /* Send a null byte to the main thread so it wakes select up to
+ * process the events in mieqProcessInputEvents() */
+ PipeWrite(InputThreadWritePipe);
+ }
+}
+
+/*
+ * 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 differentiate processes and threads this bellow may have
+ * some sense. Linux uses 1:1 thread model. The scheduler handles every
+ * thread as a normal process. Therefore this probably have no meaning
+ * if you are under 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.
+ */
+void
+CloseInputThread (void)
+{
+ RemoveEnabledDevice(InputThreadReadPipe);
+ FD_ZERO(&InputThreadFd);
+ NumDevicesThreaded = 0;
+
+ syscall(__NR_tkill, tid_generation);
+}