Overview of liboop.

The basic idea.

Liboop is primarily an interface definition. It defines an interface which components may use to request notification when an event (activity on a file descriptor, the real-time clock reaches a certain value, a particular signal is received) occurs. The component which owns the event loop -- the component whose code is active when the system is idle -- implements the interface; it is an event source. Components which are interested in events register themselves with the event source; they are event sinks. Event sinks may themselves source other, higher-level events, but that is outside liboop's scope.

Control flow.

During initialization, the event source is created. At least one event sink is also created, and registered with the event source. Once initialization completes, control is transferred to the event source, which (at its core) waits for events, usually using a system function like select() or poll(). When an event occurs, the event source gives a callback to all the event sinks which registered interest in that event.

During callbacks, the event sinks react to the event as appropriate (usually performing some I/O, or at least modifying internal state). Event sinks for events which are no longer relevant may be unregistered; new event sinks may be registered for additional events. Each event sink, when it finishes, returns a value which tells the event source whether to continue processing events or whether to terminate.

While the event source must be fully reentrant (registration and deregistration may, and indeed usually are, performed within the context of an event), event sinks need not be; no event sink will be called while another event sink is active.

If no event sink instructs the event source to terminate, the event source continues waiting for events. Otherwise, the event source returns to its caller, which usually shuts down the system.

The system event source.

Liboop comes with a single "reference" implementation of an event source. This event source uses select() to dispatch events. Most programs built around liboop will probably use the standard system event source; legacy programs with their own event loop, or programs with specialized needs may implement their own event source.

Adapters.

Liboop supports adapters to enable legacy components to use the liboop interface. For example, many widget sets have their own event loop and their own mechanism for registering callbacks on timeouts and file descriptor activity; liboop uses source adapters that accept registration, register corresponding callbacks with the widget set's event loop, and route events appropriately. Such adapters let general-purpose liboop-based components work in an application based on that widget set.

Similarly, some components are designed to work in a non-blocking fashion, and they might be used with a sink adapter to work with liboop. An asynchronous DNS query package, for example, could work as a liboop sink that ultimately generates a higher-level "success" or "failure" callback to the invoking routine.

Code.

Liboop's abstract event source interface is implemented as a structure containing C function pointers. These functions accept a pointer to the structure as their first argument; sources are expected to include their own data (in whatever format) with the core function pointers. Callbacks are also C function pointers, with "void *" arguments to pass data.

For more about the liboop interface, see the reference.


liboop home