16 Jun 2002 fejj   » (Master)

to hell with what you're thinking and to hell with your petty mind, you're so distracted from the real thing you should leave your life behind

Foolishly I've begun hacking on Spruce again.

This time around, though, I'm using the JavaMail API as a reference for designing the new backend architecture for Spruce. However, since Spruce uses the Gtk+ toolkit (please disreguard the redundancy), the backend will have to block because Gtk+ is not a very pthread-friendly toolkit (which is how JavaMail achieves it's 'async' behavior). This is obviously unacceptable to users.

Possible solutions?

(I've been told that GObject is "thread-safe" by sopwith but seem to recall being told the opposite by owen. I'm going to assume that they are both "right" for the purpose of this little problem solving exercise. Here's what I think we can assume: GObject can be thread-safe supposing that you do proper locking, but the signal system is not.)

  1. My first thought was to use pthreads but avoid signals in the backend and instead write a Listener class that emulates signals by communicating with the main thread via a socket. The main thread could register an idle-handler for each Listener object and read whatever is on the socket and do whatever is the appropriate action. This sounds rather hackish so I think I'll probably avoid it.

  2. My second idea was to make the backend one big state machine. This makes design a bit more complex, but I think you can achieve a much more elegant design/API this way. This can be done in multiple ways, but here is my current idea for implementing this:

    All operations that can require file or network I/O should return a SpruceAsyncHandle object:

    abstract class SpruceAsyncHandle {
    	GObject object;
    	void *state;
    	void begin (handle, object, state);

    public: int step (handle, object, state); int cancel (handle, object, state);

    signals: void finished (handle, object, user_data); void cancelled (handle, object, user_data); };

    /* client API */ int spruce_async_handle_step (handle); int spruce_async_handle_cancel (handle);

    All methods returning a SpruceAsyncHandle object will immediately call the begin method to initialise the state and then call it's parent implementation. The abstract class implementation will simply register the ::step() in an idle-handler. When either the async operation is completed or cancelled, the abstract AsyncHandler class will also take responsibility for de-registering itself from any idle handlers.

    Unfortunately this means I'll have to write a ton more code, simply because I'll now have to write AsyncHandler's for each and every method that can possibly block. Ugh.

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!