[Python-Dev] GC and ExtensionClass - a summary of the problem and a workaround

skip@pobox.com (Skip Montanaro) skip@pobox.com (Skip Montanaro)
Thu, 17 May 2001 01:42:41 -0500


Over the past couple days I've included python-dev on various messages in an
ongoing thread about a segmentation violation I was getting with the new
PyGtk2 wrappers.  With some excellent assistance from the GC maestro, Neil
Schemenauer, I finally know what's going on and I have a simple workaround
that lets me get back to work.  Here's a summary of the problem.

When defining ExtensionClass types, you need to create and initialize a
PyExtensionClass struct.  It looks something like so:

    PyExtensionClass PyGtkTreeSortable_Type = {
	PyObject_HEAD_INIT(NULL)
	0,				/* ob_size */
	"GtkTreeSortable",			/* tp_name */
	sizeof(PyPureMixinObject),	/* tp_basicsize */
	...
    };

Note that the parameter to the PyObject_HEAD_INIT macro is NULL.  It would
normally be the address of a type object (e.g. &PyType_Type).  However, Jim
Fulton pointed out that on Windows you can't get the address of &PyType_Type
object at compile time.  Accordingly, ExtensionClass provides a
PyExtensionClass_Export macro whose responsibility is, in part, to set the
ob_type field appropriately at runtime.  (I'm not sure why this Windows nit
doesn't afflict other type declarations like PyTuple_Type.  I'm sure others
will know why.  I just accept Jim's word as gospel and move on...)

A problem arises if the garbage collector runs while the module
initialization function is running, but before all the ob_type fields have
been assigned their correct values.  In this case, a one-element tuple
representing the bases of a particular PyGtk extension class was traversed
by the garbage collector.

The workaround turns out to be exceedingly simple:

    import gc
    gc.disable()
    import gtk
    gc.enable()

I can handle doing that from Python code for the time being and will leave
it up to others to decide how, if at all, ExtensionClass should be changed
to correct the problem.

Skip