This document is intended to describe the current architecture of libevent. This information will be necessary to complete implementation and to understand how the library works, and will serve as the first draft of the interface documentation.
The basic libevent architecture consists of two pieces. The first piece is the library itself, which implements the basic API that the caller uses. Most of those API calls will call further into a backend engine--libevent's term for the piece of code wrapped around poll() or other similar interfaces. At this time, all available engines will be compiled in to the library, but future versions of libevent may use dynamically loaded modules for this.
The basic API consists of four major subdivisions: event, socket, signal, and timer. Each function has a prefix derived from the subdivision it acts upon--for instance, all functions that manipulate sockets have the prefix "socket_" (possibly preceeded by an "_" if the function is not intended to be used by the caller). These subdivisions are documented below.
Each engine has a textual name that describes what interface it uses. For instance, the engine based on Solaris's /dev/poll interface has the name "/dev/poll," whereas the engine based on poll() is named "poll()." In the source tree, each engine is contained in a single file. This file contains a struct _event_engine, which contains the textual name for the engine, as well as function pointers for the various functions the engine must implement.
Engines do not need to worry about the implementation of timers--those details are handled by the library itself. Engines have the option of handling signals--this functionality is used by the kqueue()-based engine, for instance. Engines must be prepared to not have to deal with signals.
What all of this means is that engines are wrapped around an interface specifically geared to sockets and pipes. All engines must define functions to add, modify, and delete a socket, as well as a function that performs a timed poll. There is also an initialization and finalization function, which may be used by the engine to manage any necessary memory for the engine.
The Event Library calls the engine's poll function in a loop, passing it an argument to indicate how long the poll function may sleep. When the engine's poll function indicates network events, it must process the pipes and sockets in question to determine what events have occurred and dispatch the appropriate event, generally by calling _socket_event(). If the engine is detecting signals, though, it should call _event_generate().
Engines that can catch signals should also provide the functions to add and delete signals, and should be prepared to permit the library to handle signals itself. This will generally only occur when threading is in use: See the section on threading behavior below.
The most important part of the Events Library is, well, events. Events are described by the type Event--pointers to structures of this type are passed to the event handlers declared by the caller. The functions in this class are event_init(), which initializes the library and allocates a context; event_loop(), which is the core event loop; event_shutdown(), which is called to shut down the event loop; event_cleanup(), which is called to deallocate any memory that the Events Library is caching; and event_destroy(), which is called to destroy and deallocate the event context. Additionally, there is a function, event_type_name(), which retrieves the name for an event of a given type, and engine_name(), which retrieves the name of the running engine.