6 March 2003
Got approval and checked in my glib changes. I also have intltool
make distcheck with newer
automakes, which should make upgrading other modules a lot easier.
Talked to malcolm who has apparently been working on some docs for updating packages to newer versions of the build tools, so I won't be writing my own document.
PyGTK, Reference Counting and Cyclic GC
When I started working on the 1.99.x branch of PyGTK, I added a feature to make sure that there was at most one Python wrapper object for each GObject, and that the wrapper would stay alive for as long as the GObject did and vice vesa.
This is implemented using a bit of a hack, which I needed to update as Python 2.2 developped. It essentially goes like this:
- The Python wrapper holds a reference to the GObject
- The GObject holds a pointer to the wrapper, but doesn't own a reference.
- If the refcount on the wrapper goes down to zero and it gets freed, and the GObject's ref count was greater than 1 (ie. something other than the wrapper holds a ref to the GObject), the tp_dealloc() routine would resurrect the wrapper. The GObject would now own a reference to the Python object.
- If some other code tried to get the wrapper for the GObject, the saved reference would be transferred to it (ie. the GObject would no longer own the last reference).
- If the GObject later gets disposed, the wrapper will be freed.
This worked okay for a while, until I started work on adding cycle GC support for wrappers. Since the GObject didn't hold a real reference to the wrapper, if the only references on the wrapper were parts of cycles, the GC might think it okay to free the wrapper. Due to a small bug in pygtk, the wrapper itself wasn't being cleared, but its instance dictionary was. This led to the unfortunate situation where all the instance attributes would sometimes disapear.
The obvious solution (in retrospect) is to work with the cycle GC when implementing the single-wrapper-per-GObject code, rather than ignoring it. Instead of the current hacks, I make the GObject hold a reference to the wrapper and the wrapper hold a refernce to the GObject, forming a cycle.
Since the Python cycle GC only applies to PyObjects, I still needed some way to communicate information about references on the GObject to the GC code. If there are references to the GObject other than the one its wrapper holds, then we obviously don't want to free either.
I came up with a smart solution that seems to handle this very nicely: If the GObject reference count is equal to 1, then the wrapper will visit itself as part of the GC traverse, otherwise it won't visit itself. Essentially this means:
- If anything other than the wrapper holds a reference to the GObject, make the reference the GObject holds on the wrapper look like an external reference.
- If the only reference on the GObject is held by its wrapper, make the reference the GObject holds on the wrapper look like a cycle.
This seems to solve the problem very nicely.
I just found out about the imapflags sieve extension implemented in the Cyrus IMAP server. This allows me to set IMAP flags on messages as part of the server side mail filtering.
Since the mozilla message labels are implemented as IMAP flags
$Label5, I am able to set message labels as part of the delivery.
This is quite useful for highlighting certain messages in a folder
without sorting them into a separate folder. For example, I can
highlight bugmail about new bugs in my bugzilla folder. Looks like it
will be very useful.