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.
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
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.
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
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.