summaryrefslogtreecommitdiff
path: root/THREADS
diff options
context:
space:
mode:
authorJames Henstridge <james@daa.com.au>2000-10-30 13:06:10 +0000
committerJames Henstridge <jamesh@src.gnome.org>2000-10-30 13:06:10 +0000
commit0c32414b39986040efacffdc9c8b7125521a9922 (patch)
treeee4d103d08e87e68779b3982a1051f1b9214a3c4 /THREADS
parent8fd6cdb4d0f14581f535368b4c6e29ca42e6b1dd (diff)
downloadpygtk-0c32414b39986040efacffdc9c8b7125521a9922.tar.gz
init as module gtk._gtk. Using just _gtk doesn't seem to work with python
2000-10-30 James Henstridge <james@daa.com.au> * gtk/gtkmodule.c (init_gtk): init as module gtk._gtk. Using just _gtk doesn't seem to work with python 2.0 2000-10-29 James Henstridge <james@james.daa.com.au> * examples/ide/gtkcons.py: small changes to make example run. * gtk/gtk-types.c: add GtkTextIter.forward_search implementation. * gtk/gtk.override: more override functions. * gtk/gtkobject-support.c: remove some of the unused functions from this file. 2000-10-28 James Henstridge <james@james.daa.com.au> * gtk/gtk.override: override the functions used to initialise GtkTextIter objects so that they return the iterator rather than setting up an static GtkTextIter structure. * gtk/gtk.defs (TextMark): add missing GtkTextMark object. Don't know why h2defs missed it. ("gtk-extrafuncs.defs"): include gtk-extrafuncs.defs. * codegen/argtypes.py: add GdkDevice and GtkTextIter to list of recognised boxed types. * gtk/gtk-types.c: add skeleton implementation of GtkTextIter. * gtk/pygtk.h, gtk/pygtk-private.h: add prototypes for GtkTextIter wrapper. * gtk/gtk.override: ref and sink GtkObjects which have their constructors listed in the overrides file. This should get rid of the last few warnings on exit related to reference counting. * codegen/codegen.py: use the keyword module to check for method and argument names that conflict with the python keywords. By using this module, we shouldn't have problems with new keywords in future versions of python. 2000-10-27 James Henstridge <james@james.daa.com.au> * gobjectmodule.c (pygobject_emit): support for emiting signals on GObjects from python. * codegen/codegen.py (write_constructor): sink GtkObjects. This prevents us losing our reference to the object if it is sunk. * codegen/argtypes.py (ArgMatcher.object_is_a): function to check if one object type is another type. * codegen/codegen.py (register_types): pass the parent type when registering a new GObject type. * gtk/gtk-types.c (_pygtk_register_boxed_types): register marshalers for the various boxed types, so that they work as expected inside the signal handlers. * gobjectmodule.c (pygobject_repr): small change to match style of other repr functions in python. * gtk/gtkmodule.c (init_gtk): only call g_thread_init() if pygtk threading support is enabled. * configure.in (enable_thread): add configure checks so that threading support can be disabled even if python was compiled with it. It defaults to off for now because GSignal has some mutex deadlocks at the moment.
Diffstat (limited to 'THREADS')
-rw-r--r--THREADS119
1 files changed, 119 insertions, 0 deletions
diff --git a/THREADS b/THREADS
new file mode 100644
index 00000000..f45b2b16
--- /dev/null
+++ b/THREADS
@@ -0,0 +1,119 @@
+-*- mode: text; mode: auto-fill -*-
+
+Requirements to get threading to work with pygtk2
+=================================================
+
+Python side
+-----------
+* Python has a global interpreter lock, so no two threads can execute
+ code at the same time.
+
+* In order to execute python code, you need to hold the interpreter
+ lock, and have the correct PyThreadState object set
+ (PyThreadState_Swap is used for this). As a convenience, the
+ following functions can be used:
+ void PyEval_AcquireThread(PyThreadState *tstate);
+ void PyEval_ReleaseThread(PyThreadState *tstate);
+
+* When C functions are called from python, the global interpreter lock
+ is held. If the function blocks, then no python code can execute in
+ other threads during this time. Python provides two macros to allow
+ threads to run while the function executes:
+ Py_BEGIN_ALLOW_THREADS
+ Py_END_ALLOW_THREADS
+ between these two macro calls, the global interpreter lock is
+ released, and the current thread state is set to NULL. This means
+ that in order to execute python code, AcquireThread must be called.
+
+GLib side
+---------
+* The glib main loop function blocks, so we need to allow threads so
+ that other threads don't hang while in the event loop.
+
+* Destroy notifies and signal handlers may be called in response to
+ some function call (such as GObject.set_data or GtkButton.clicked),
+ or while the main loop is running. In the first case, the global
+ interpreter lock will be held, and a thread state will be acquired.
+ In the second case, the global interpreter lock will not be held by
+ us and there will be a NULL thread state. Example:
+---- Cut Here ----
+ import gtk
+ ...
+ b = gtk.GtkButton("Click me")
+ def f(button):
+ ... some python code ...
+ b.connect("clicked", f)
+ b.clicked() # the signal handler f is called with the interpreter
+ # lock held
+ ...
+ gtk.main() # if the button is clicked while in the main loop, the
+ # interpreter lock may be held by someone else
+---- Cut Here ----
+
+* We need to have a valid thread state before executing one of these
+ callbacks, or bad things happen.
+
+* Ideally, the solution chosen should work at the GObject level,
+ rather than GTK/GDK level.
+
+* In gtk 1.2 based PyGTK, we used a bit of code from Paul Fisher to
+ handle this problem. It relied on the global GDK lock to serialise
+ requests to unblock threading. As the GObject functions do not rely
+ on a global lock being held, we can't use this. Here is the
+ existing code:
+---- Cut Here ----
+/* The threading code has been enhanced to be a little better with multiple
+ * threads accessing GTK+. Here are some notes on the changes by
+ * Paul Fisher:
+ *
+ * If threading is enabled, we create a recursive version of Python's
+ * global interpreter mutex using TSD. This scheme makes it possible,
+ * although rather hackish, for any thread to make a call into PyGTK,
+ * as long as the GDK lock is held (that is, Python code is wrapped
+ * around a threads_{enter,leave} pair).
+ *
+ * A viable alternative would be to wrap each and every GTK call, at
+ * the Python/C level, with Py_{BEGIN,END}_ALLOW_THREADS. However,
+ * given the nature of Python threading, this option is not
+ * particularly appealing.
+ */
+
+static GStaticPrivate pythreadstate_key = G_STATIC_PRIVATE_INIT;
+static GStaticPrivate counter_key = G_STATIC_PRIVATE_INIT;
+
+/* The global Python lock will be grabbed by Python when entering a
+ * Python/C function; thus, the initial lock count will always be one.
+ */
+# define INITIAL_LOCK_COUNT 1
+# define PyGTK_BLOCK_THREADS \
+ { \
+ gint counter = GPOINTER_TO_INT(g_static_private_get(&counter_key)); \
+ if (counter == -INITIAL_LOCK_COUNT) { \
+ PyThreadState *_save; \
+ _save = g_static_private_get(&pythreadstate_key); \
+ Py_BLOCK_THREADS; \
+ } \
+ counter++; \
+ g_static_private_set(&counter_key, GINT_TO_POINTER(counter), NULL); \
+ }
+
+# define PyGTK_UNBLOCK_THREADS \
+ { \
+ gint counter = GPOINTER_TO_INT(g_static_private_get(&counter_key)); \
+ counter--; \
+ if (counter == -INITIAL_LOCK_COUNT) { \
+ PyThreadState *_save; \
+ Py_UNBLOCK_THREADS; \
+ g_static_private_set(&pythreadstate_key, _save, NULL); \
+ } \
+ g_static_private_set(&counter_key, GINT_TO_POINTER(counter), NULL); \
+ }
+---- Cut Here ----
+
+* One possible solution is to wrap every single pygtk call in
+ Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS calls. This would
+ probably be quite slow.
+
+* Can Paul Fisher's code be modified to work without needing the GDK
+ lock for serialisation?
+