From: Daniel Drake <dsd@laptop.org>
http://bugzilla.gnome.org/show_bug.cgi?id=481569

Fix the PySignal_SetWakeupFd() implementation:
 - Prepare file descriptors and call PySignal_SetWakeupFd() just once, outside
   of the mainloop iterations
 - Fix source_prepare semantics
 - Fix source_check semantics, and actually read from the pipe
 - Make the write-end of the pipe non-blocking

Index: pygobject-2.15.4/glib/pygmainloop.c
===================================================================
--- pygobject-2.15.4.orig/glib/pygmainloop.c
+++ pygobject-2.15.4/glib/pygmainloop.c
@@ -24,6 +24,7 @@
 #ifdef HAVE_CONFIG_H
 #  include <config.h>
 #endif
+#include <fcntl.h>
 
 #include <Python.h>
 #include <pythread.h>
@@ -119,16 +120,15 @@ static gboolean
 pyg_signal_watch_prepare(GSource *source,
 			 int     *timeout)
 {
-#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
-    PySignalWatchSource *real_source = (PySignalWatchSource *)source;
-#endif
-    
     /* Python only invokes signal handlers from the main thread,
      * so if a thread other than the main thread receives the signal
      * from the kernel, PyErr_CheckSignals() from that thread will
      * 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.
@@ -136,37 +136,16 @@ pyg_signal_watch_prepare(GSource *source
 #ifndef PLATFORM_WIN32
     if (!pyglib_threads_enabled())
 	return FALSE;
-#endif
-
-#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
-    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));
+#endif /* PLATFORM_WIN32 */
 
-    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);
-
-    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
@@ -175,6 +154,14 @@ pyg_signal_watch_check(GSource *source)
     PyGILState_STATE state;
     GMainLoop *main_loop;
 
+#ifdef HAVE_PYSIGNAL_SETWAKEUPFD
+    PySignalWatchSource *real_source = (PySignalWatchSource *)source;
+    GPollFD *poll_fd = &real_source->fd;
+    unsigned char dummy;
+    if (poll_fd->revents & G_IO_IN)
+	read(poll_fd->fd, &dummy, 1);
+#endif
+
     state = pyglib_gil_state_ensure();
 
     main_loop = pyg_get_current_main_loop();
@@ -224,7 +211,36 @@ static GSourceFuncs pyg_signal_watch_fun
 static GSource *
 pyg_signal_watch_new(void)
 {
-    return g_source_new(&pyg_signal_watch_funcs, sizeof(PySignalWatchSource));
+    GSource *source = g_source_new(&pyg_signal_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.
+     */
+    if (pipe(real_source->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(real_source->fds[1], F_GETFL, 0);
+    flag |= O_NONBLOCK;
+    fcntl(real_source->fds[1], F_SETFL, flag);
+
+    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);
+
+    PySignal_SetWakeupFd(real_source->fds[1]);
+#endif
+    return source;
 }
 
 PYGLIB_DEFINE_TYPE("glib.MainLoop", PyGMainLoop_Type, PyGMainLoop)
