Notes on abort and status processing

These are somewhat quickie notes on how things are aborted in Gzilla.

One good way of thinking about the rendering process in Gzilla is as a pipeline, consisting of a chain of mostly autonomous modules (mostly bytesinks and imgsinks). The main communication is handled using a "push" model, i.e. each module calls a write method on the next module in the chain to push down data. Normal path processing is fairly straightforward, but exception handling can get quite tricky, in fact causing a good chunk of the instability and memory leaks so far in Gzilla.

There are a few factors that make exception handling difficult in Gzilla. First, exceptions can happen at most points in the pipeline (for example, network errors, stop signal from UI, or image decode error). Second, the pipelines are not always linear, as there can be branching. For example, when pages in two different windows share an image, a single cache entry drives both pipelines. Thus, designing an appropriate abort architecture takes some care.

Interestingly, the propagation of status information has similar requirements. Like aborting, status information may originate at modules at many different points in the chain (most commonly, network connection info, and link highlighting). Thus, I've decided to unify the abort/status processing.

Here's what I've decided to do in Gzilla. Like all design decisions in Gzilla, I make no claim that it's optimal, but I do believe it's a good compromise, affords fairly simple implementation, and has no serious performance issues.

Each module implements a "status" method that takes four arguments: (GzillaStatusDir direction, gboolean abort, GzillaStatusMeaning meaning, const char *text). The direction is one of GZILLA_DIR_UP, GZILLA_DIR_DOWN, or GZILLA_DIR_ORIG, and controls the propagation of the status signal. The abort flag is true if the module is to be aborted, false if it's just for status. The meaning enum indicates the meaning (or intended disposition) of the status signal. The main distinction is whether the text should be displayed in the status line at the bottom of the browser, although I'm leaving it as an enum rather than a bool for future expansion. It's possible that communication between ECMAScript stuff will go here, and as more of a short-term issue, content-type and content-size information from the gzilla_web module may go here as well, for appropriate screen display.

Propagation of status signals

Here's how propagation works. To inject a status (or an abort), invoke the status method with GZILLA_DIR_ORIG. This causes the status method to invoke the upstream module with GZILLA_DIR_UP, and the downstream module with GZILLA_DIR_DOWN. In turn, each of those modules propagates the status in the appropriate direction.

Downstream propagation is accomplished by just invoking the status method on the downstream module. Upstream propagation is accomplished by the upstream method hooking the status signal.

Thus, the first few lines code in a status method look something like this:

if (dir != GZILLA_DIR_UP)
   status (module->downstream, GZILLA_DIR_DOWN, abort, meaning, text);

Similarly, the status signal handler hooked by the upstream method will invoke the upstream module's status method if the direction is not GZILLA_DIR_DOWN.

Alternatively, the signal handler can actually do the aborting, in which case the status method should do nothing on GZILLA_DIR_UP. (I realize this section isn't very clear - I'm still working on it)

Aborting

The philosophy of abort handling is to free the resources as soon as possible. Thus, the abort method is responsible for destroying the object. The close method is also responsible for destroying the object, as nothing further can be done with the object after all bytes have been written into it.

Note that this represents something of a change from previous versions of Gzilla, in which the bytesink abstraction was overloaded with other stuff, including links and status. In previous versions, it was not possible to destroy the bytesink until the corresponding page was no longer displayed. Now that those functions have been taken over by the linkblock, the bytesink can be destroyed immediately after all bytes have been transferred, and the destruction of the linkblock is deferred until the page is no longer visible. I think this is a much cleaner approach.

The text field

The text field should be set to some explanatory string. If the meaning is SHOW, then the string will be displayed on the status line. If the meaning is DEBUG, then the string should still make sense, because it might be useful for debugging. The string is allocated and managed by the originator of the status signal, and the lifetime is no greater than the status signal invocation itself.