[pygtk] gtk_main: fixed use of Python's SetWakeupFD API



commit f4cc1453896a891b8197a4ddbc1b7b9706c86996
Author: Philippe Normand <phil base-art net>
Date:   Thu Feb 25 10:54:18 2010 +0100

    gtk_main: fixed use of Python's SetWakeupFD API
    
    I backported the last patch from Bug 481569.

 gtk/gtk.override |  114 ++++++++++++++++++++++++++---------------------------
 1 files changed, 56 insertions(+), 58 deletions(-)
---
diff --git a/gtk/gtk.override b/gtk/gtk.override
index fa05771..35b0ec9 100644
--- a/gtk/gtk.override
+++ b/gtk/gtk.override
@@ -24,6 +24,7 @@ headers
 #define NO_IMPORT_PYGOBJECT
 #include "pygobject.h"
 
+#include <fcntl.h>
 #include <locale.h>
 
 #include <gtk/gtk.h>
@@ -1102,15 +1103,17 @@ override gtk_main noargs
 
   /* This code (pygtk main watch) was copied with minor changes from
    * pygobject/gobject/pygmainloop.c */
+
+static int pipe_fds[2];
+
 typedef struct {
     GSource source;
-    int fds[2];
     GPollFD fd;
 } PySignalWatchSource;
 
 static gboolean
 pygtk_main_watch_prepare(GSource *source,
-			 int     *timeout)
+                         int     *timeout)
 {
     /* Python only invokes signal handlers from the main thread,
      * so if a thread other than the main thread receives the signal
@@ -1118,47 +1121,26 @@ pygtk_main_watch_prepare(GSource *source,
      * do nothing.
      */
 
+#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
+    return FALSE;
+#else /* !HAVE_PYSIGNAL_SETWAKEUPFD */
     /* On Windows g_poll() won't be interrupted by a signal
      * (AFAIK), so we need the timeout there too, even if there's
      * only one thread.
      */
 #ifndef PLATFORM_WIN32
-    if (!pyg_threads_enabled)
-	return FALSE;
-#endif
-
-#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
-    {
-        PySignalWatchSource *real_source = (PySignalWatchSource *)source;
-
-        if (real_source->fds[0] != 0)
-            return FALSE;
-
-        /* Unfortunately we need to create a new pipe here instead of
-         * reusing the pipe inside the GMainContext.  Ideally an api
-         * should be added to GMainContext which allows us to reuse
-         * that pipe which would suit us perfectly fine.
-         */
-        if (pipe(real_source->fds) < 0)
-            g_error("Cannot create main loop pipe: %s\n",
-                    g_strerror(errno));
-
-        real_source->fd.fd = real_source->fds[0];
-        real_source->fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
-        g_source_add_poll(source, &real_source->fd);
+    if (!pyg_threads_enabled())
+        return FALSE;
+#endif /* PLATFORM_WIN32 */
 
-        PySignal_SetWakeupFd(real_source->fds[1]);
-    }
-#else /* !HAVE_PYSIGNAL_SETWAKEUPFD */
     /* If we're using 2.5 or an earlier version of python we
      * will default to a timeout every second, be aware,
      * this will cause unnecessary wakeups, see
      * http://bugzilla.gnome.org/show_bug.cgi?id=481569
      */
     *timeout = 1000;
-#endif /* HAVE_PYSIGNAL_SETWAKEUPFD */
-
     return FALSE;
+#endif /* HAVE_PYSIGNAL_SETWAKEUPFD */
 }
 
 static gboolean
@@ -1166,11 +1148,19 @@ pygtk_main_watch_check(GSource *source)
 {
     PyGILState_STATE state;
 
+#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
+    PySignalWatchSource *real_source = (PySignalWatchSource *)source;
+    GPollFD *poll_fd = &real_source->fd;
+    int data_size = 0;
+    if (poll_fd->revents & G_IO_IN)
+        data_size = read(poll_fd->fd, 0, 1);
+#endif
+
     state = pyg_gil_state_ensure();
 
     if (PyErr_CheckSignals() == -1 && gtk_main_level() > 0) {
-	PyErr_SetNone(PyExc_KeyboardInterrupt);
-	gtk_main_quit();
+        PyErr_SetNone(PyExc_KeyboardInterrupt);
+        gtk_main_quit();
     }
 
     pyg_gil_state_release(state);
@@ -1188,41 +1178,49 @@ pygtk_main_watch_dispatch(GSource    *source,
     return TRUE;
 }
 
-static void
-pygtk_main_watch_finalize(GSource *source)
-{
-    PySignalWatchSource *real_source = (PySignalWatchSource*)source;
-
-    if (source != NULL) {
-	if (real_source->fds[0] != 0)
-	    close(real_source->fds[0]);
-	
-	if (real_source->fds[1] != 0) {
-#if HAVE_PYSIGNAL_SETWAKEUPFD
-            int  wakeup_fd = PySignal_SetWakeupFd(-1);
-            if (wakeup_fd != real_source->fds[1]) {
-                /* Probably should never happen. */
-                PySignal_SetWakeupFd(wakeup_fd);
-            }
-#endif
-
-            close(real_source->fds[1]);
-        }
-    }
-}
-
 static GSourceFuncs pygtk_main_watch_funcs =
 {
     pygtk_main_watch_prepare,
     pygtk_main_watch_check,
-    pygtk_main_watch_dispatch,
-    pygtk_main_watch_finalize
+    pygtk_main_watch_dispatch
 };
 
 static GSource *
 pygtk_main_watch_new(void)
 {
-    return g_source_new(&pygtk_main_watch_funcs, sizeof(PySignalWatchSource));
+    GSource *source = g_source_new(&pygtk_main_watch_funcs, sizeof(PySignalWatchSource));
+
+#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
+    PySignalWatchSource *real_source = (PySignalWatchSource *)source;
+    int flag;
+
+    /* Unfortunately we need to create a new pipe here instead of
+     * reusing the pipe inside the GMainContext.
+     * Ideally an api should be added to GMainContext which allows us
+     * to reuse that pipe which would suit us perfectly fine.
+     * XXX More efficient than a pipe, we could use an eventfd on Linux
+     * kernels that support it.
+     */
+    gint already_piped = (pipe_fds[0] > 0);
+    if (!already_piped) {
+	if (pipe(pipe_fds) < 0)
+	    g_error("Cannot create main loop pipe: %s\n",
+	            g_strerror(errno));
+
+        /* Make the write end of the fd non blocking */
+        flag = fcntl(pipe_fds[1], F_GETFL, 0);
+        flag |= O_NONBLOCK;
+        fcntl(pipe_fds[1], F_SETFL, flag);
+    }
+
+    real_source->fd.fd = pipe_fds[0];
+    real_source->fd.events = G_IO_IN | G_IO_HUP | G_IO_ERR;
+    g_source_add_poll(source, &real_source->fd);
+
+    if (!already_piped)
+      PySignal_SetWakeupFd(pipe_fds[1]);
+#endif
+    return source;
 }
 
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]