[pygobject] pygmainloop: fix use of PySignal_WakeUpFD API for nested loops
- From: Edward Hervey <edwardrv src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [pygobject] pygmainloop: fix use of PySignal_WakeUpFD API for nested loops
- Date: Wed, 21 Oct 2009 16:07:03 +0000 (UTC)
commit a9c168c58cc6a449b51653417bf3f58bdd41457c
Author: Philippe Normad <phil base-art net>
Date: Wed Oct 21 18:01:16 2009 +0200
pygmainloop: fix use of PySignal_WakeUpFD API for nested loops
Fixes bug #481569
glib/pygmainloop.c | 95 +++++++++++++++++++++++++++------------------------
1 files changed, 50 insertions(+), 45 deletions(-)
---
diff --git a/glib/pygmainloop.c b/glib/pygmainloop.c
index de24649..d9f048c 100644
--- a/glib/pygmainloop.c
+++ b/glib/pygmainloop.c
@@ -24,6 +24,7 @@
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
+#include <fcntl.h>
#include <Python.h>
#include <pythread.h>
@@ -34,10 +35,10 @@
#include "pyglib.h"
#include "pyglib-private.h"
+static int pipe_fds[2];
typedef struct {
GSource source;
- int fds[2];
GPollFD fd;
} PySignalWatchSource;
@@ -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));
-
- 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 /* PLATFORM_WIN32 */
-#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();
@@ -199,32 +186,50 @@ pyg_signal_watch_dispatch(GSource *source,
return TRUE;
}
-static void
-pyg_signal_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)
- close(real_source->fds[1]);
- }
-}
-
static GSourceFuncs pyg_signal_watch_funcs =
{
pyg_signal_watch_prepare,
pyg_signal_watch_check,
- pyg_signal_watch_dispatch,
- pyg_signal_watch_finalize
+ pyg_signal_watch_dispatch
};
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.
+ */
+ 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;
}
PYGLIB_DEFINE_TYPE("glib.MainLoop", PyGMainLoop_Type, PyGMainLoop)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]