summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark McLoughlin <mark@skynet.ie>2005-02-09 11:32:42 +0000
committerMark McLoughlin <markmc@src.gnome.org>2005-02-09 11:32:42 +0000
commitfa8fde62639f0237cd39f4c06f3ff4e8c2ff5158 (patch)
tree97e3ddcd8d3082c809fad2e9c8d21c1f24cbb3f5
parentf0ff018ae9f5fbb5223ec4fbc70092f185ff83d5 (diff)
downloadpygobject-fa8fde62639f0237cd39f4c06f3ff4e8c2ff5158.tar.gz
pygobject-fa8fde62639f0237cd39f4c06f3ff4e8c2ff5158.tar.xz
pygobject-fa8fde62639f0237cd39f4c06f3ff4e8c2ff5158.zip
Fix for bug #154779 - Python signal handlers don't get executed while
2005-02-09 Mark McLoughlin <mark@skynet.ie> Fix for bug #154779 - Python signal handlers don't get executed while you're sitting in the main loop. * gobject/pygmainloop.c: (pyg_save_current_main_loop), (pyg_restore_current_main_loop), (pyg_get_current_main_loop): functions for keeping track of the currently running main loop. A version using TLS and another using a global variable, depending on whether DISABLE_THREADING is defined (pyg_signal_watch_prepare), (pyg_signal_watch_check), (pyg_signal_watch_dispatch), (pyg_signal_watch_new): a GSource which runs the python signal handlers whenever the mainloop is interrupted by signal delivery. (pyg_main_loop_new), (pyg_main_loop_dealloc): add and remove the source. (_wrap_g_main_loop_run): push/pop the currently running main loop. * gobject/pygobject-private.h: add a pointer for the source to PyGMainLoop. * gobject/Makefile.am: add -DPLATFORM_WIN32 to cflags if building on Windows.
-rw-r--r--gobject/Makefile.am5
-rw-r--r--gobject/pygmainloop.c171
-rw-r--r--gobject/pygobject-private.h1
3 files changed, 175 insertions, 2 deletions
diff --git a/gobject/Makefile.am b/gobject/Makefile.am
index a3e5e87..286626f 100644
--- a/gobject/Makefile.am
+++ b/gobject/Makefile.am
@@ -13,6 +13,7 @@ if PLATFORM_WIN32
common_ldflags += -no-undefined
endif
+gobject_la_CFLAGS = $(GLIB_CFLAGS)
gobject_la_LDFLAGS = $(common_ldflags) -export-symbols-regex initgobject
gobject_la_LIBADD = $(GLIB_LIBS)
gobject_la_SOURCES = \
@@ -28,3 +29,7 @@ gobject_la_SOURCES = \
pygparamspec.c \
pygpointer.c \
pygtype.c
+
+if PLATFORM_WIN32
+gobject_la_CFLAGS += -DPLATFORM_WIN32
+endif
diff --git a/gobject/pygmainloop.c b/gobject/pygmainloop.c
index 7a6b1c1..2c65cac 100644
--- a/gobject/pygmainloop.c
+++ b/gobject/pygmainloop.c
@@ -26,6 +26,144 @@
#endif
#include "pygobject-private.h"
+#include "pythread.h"
+
+#ifdef DISABLE_THREADING
+static GMainLoop *pyg_current_main_loop = NULL;;
+
+static inline GMainLoop *
+pyg_save_current_main_loop (GMainLoop *main_loop)
+{
+ GMainLoop *retval = pyg_current_main_loop;
+
+ g_return_val_if_fail(main_loop != NULL, NULL);
+
+ pyg_current_main_loop = g_main_loop_ref(main_loop);
+
+ return retval;
+}
+
+static inline void
+pyg_restore_current_main_loop (GMainLoop *main_loop)
+{
+ if (pyg_current_main_loop != NULL)
+ g_main_loop_unref(pyg_current_main_loop);
+ pyg_current_main_loop = main_loop;
+}
+
+static inline GMainLoop *
+pyg_get_current_main_loop (void)
+{
+ return pyg_current_main_loop;
+}
+#else /* !defined(#ifndef DISABLE_THREADING) */
+
+static int pyg_current_main_loop_key = -1;
+
+static inline GMainLoop *
+pyg_save_current_main_loop (GMainLoop *main_loop)
+{
+ GMainLoop *retval;
+
+ g_return_val_if_fail(main_loop != NULL, NULL);
+
+ if (pyg_current_main_loop_key == -1)
+ pyg_current_main_loop_key = PyThread_create_key();
+
+ retval = PyThread_get_key_value(pyg_current_main_loop_key);
+ PyThread_delete_key_value(pyg_current_main_loop_key);
+ PyThread_set_key_value(pyg_current_main_loop_key,
+ g_main_loop_ref(main_loop));
+
+ return retval;
+}
+
+static inline void
+pyg_restore_current_main_loop (GMainLoop *main_loop)
+{
+ GMainLoop *prev;
+
+ g_return_if_fail (pyg_current_main_loop_key != -1);
+
+ prev = PyThread_get_key_value(pyg_current_main_loop_key);
+ if (prev != NULL)
+ g_main_loop_unref(prev);
+ PyThread_delete_key_value(pyg_current_main_loop_key);
+ PyThread_set_key_value(pyg_current_main_loop_key, main_loop);
+}
+
+static inline GMainLoop *
+pyg_get_current_main_loop (void)
+{
+ if (pyg_current_main_loop_key == -1)
+ return NULL;
+ return PyThread_get_key_value(pyg_current_main_loop_key);
+}
+#endif /* DISABLE_THREADING */
+
+static gboolean
+pyg_signal_watch_prepare(GSource *source,
+ int *timeout)
+{
+ /* 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. So, we need to time out and check for signals
+ * regularily too.
+ * Also, on Windows g_poll() won't be interrupted by a signal
+ * (AFAIK), so we need the timeout there too.
+ */
+#ifndef PLATFORM_WIN32
+ if (pyg_threads_enabled)
+#endif
+ *timeout = 100;
+
+ return FALSE;
+}
+
+static gboolean
+pyg_signal_watch_check(GSource *source)
+{
+ PyGILState_STATE state;
+ GMainLoop *main_loop;
+
+ state = pyg_gil_state_ensure();
+
+ main_loop = pyg_get_current_main_loop();
+
+ if (PyErr_CheckSignals() == -1 && main_loop != NULL) {
+ PyErr_SetNone(PyExc_KeyboardInterrupt);
+ g_main_loop_quit(main_loop);
+ }
+
+ pyg_gil_state_release(state);
+
+ return FALSE;
+}
+
+static gboolean
+pyg_signal_watch_dispatch(GSource *source,
+ GSourceFunc callback,
+ gpointer user_data)
+{
+ /* We should never be dispatched */
+ g_assert_not_reached();
+ return TRUE;
+}
+
+static GSourceFuncs pyg_signal_watch_funcs =
+{
+ pyg_signal_watch_prepare,
+ pyg_signal_watch_check,
+ pyg_signal_watch_dispatch,
+ NULL
+};
+
+static GSource *
+pyg_signal_watch_new(void)
+{
+ return g_source_new(&pyg_signal_watch_funcs, sizeof(GSource));
+}
static int
pyg_main_loop_new(PyGMainLoop *self, PyObject *args, PyObject *kwargs)
@@ -55,9 +193,29 @@ pyg_main_loop_new(PyGMainLoop *self, PyObject *args, PyObject *kwargs)
}
self->loop = g_main_loop_new(context, is_running);
+
+ self->signal_source = pyg_signal_watch_new();
+ g_source_attach(self->signal_source, context);
+
return 0;
}
+static void
+pyg_main_loop_dealloc(PyGMainLoop *self)
+{
+ if (self->signal_source != NULL) {
+ g_source_destroy(self->signal_source);
+ self->signal_source = NULL;
+ }
+
+ if (self->loop != NULL) {
+ g_main_loop_unref(self->loop);
+ self->loop = NULL;
+ }
+
+ PyObject_Del(self);
+}
+
static int
pyg_main_loop_compare(PyGMainLoop *self, PyGMainLoop *v)
{
@@ -100,10 +258,19 @@ _wrap_g_main_loop_quit (PyGMainLoop *self)
static PyObject *
_wrap_g_main_loop_run (PyGMainLoop *self)
{
+ GMainLoop *prev_loop;
+
+ prev_loop = pyg_save_current_main_loop(self->loop);
+
pyg_begin_allow_threads;
g_main_loop_run(self->loop);
pyg_end_allow_threads;
-
+
+ pyg_restore_current_main_loop(prev_loop);
+
+ if (PyErr_Occurred())
+ return NULL;
+
Py_INCREF(Py_None);
return Py_None;
}
@@ -123,7 +290,7 @@ PyTypeObject PyGMainLoop_Type = {
sizeof(PyGMainLoop),
0,
/* methods */
- (destructor)0,
+ (destructor)pyg_main_loop_dealloc,
(printfunc)0,
(getattrfunc)0,
(setattrfunc)0,
diff --git a/gobject/pygobject-private.h b/gobject/pygobject-private.h
index d826f92..c5852e8 100644
--- a/gobject/pygobject-private.h
+++ b/gobject/pygobject-private.h
@@ -145,6 +145,7 @@ extern PyObject * pyg_enum_from_gtype (GType gtype,
typedef struct {
PyObject_HEAD
GMainLoop *loop;
+ GSource *signal_source;
} PyGMainLoop;
extern PyTypeObject PyGMainLoop_Type;