--
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, &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
+
+/*
+ * 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

Reply via email to