--- /dev/null
+The IRC server is built around an event loop. Until the u2.10.11
+release, this event loop has been rather ad-hoc; timed events are
+hard-coded in, signals are handled inside the signal handler, etc.
+All of this has changed with u2.10.11. A new subsystem, the events
+subsystem, has been introduced; the new subsystem contains a
+generalization of the concept of an event. An event is a signal, the
+expiration of a timer, or some form of activity on a network socket.
+This new subsystem has the potential to vastly simplify the code that
+is arguably the core of any network program, and makes it much simpler
+to support more exotic forms of network activity monitoring than the
+conventional select() and poll() calls.
+
+The primary concepts that the events subsystem works with are the
+"event," represented by a struct Event, and the "generator." There
+are three types of generators: sockets, represented by struct Socket;
+signals, represented by struct Signal; and timers, represented by
+struct Timer. Each of these generators will be described in turn.
+
+Signals
+
+The signal is perhaps the simplest generator in the entire events
+subsystem. Basically, instead of setting a signal handler, the
+function signal_add() is called, specifying a function to be called
+when a given signal is detected. Most importantly, that call-back
+function is called _outside_ the context of a signal handler,
+permitting the call-back to use more exotic functions that are
+anathema within a signal handler, such as MyMalloc(). Once a
+call-back for a signal has been established, it cannot be deleted;
+this design decision was driven by the fact that ircd never changes
+its signal handlers.
+
+Whenever a signal is received, an event of type ET_SIGNAL is
+generated, and that event is passed to the event call-back function
+specified in the signal_add() call.
+
+Timers
+
+Execution of the call-back functions for a timer occur when that timer
+_expires_; when a timer expires depends on the type of timer and the
+expiration time that was used for that timer. A TT_ABSOLUTE timer,
+for instance, expires at exactly the time given as the expiration
+time. This time is a standard UNIX time_t value, measuring seconds
+since the UNIX epoch. The TT_ABSOLUTE timer type is complemented by
+the TT_RELATIVE timer; the time passed as its expiration time is
+relative to the current time. If a TT_RELATIVE timer is given an
+expiration time of 5, for instance, it will expire 5 seconds after the
+present time. Internally, TT_RELATIVE timers are converted into
+TT_ABSOLUTE timers, with the expiration time adjusted by addition of
+the current time.
+
+Those two types of timers, TT_ABSOLUTE and TT_RELATIVE, are
+single-shot timers. Once they expire, they are removed from the timer
+list unless re-added by the event call-back or through some other
+mechanism. There is another type of timer, however, the TT_PERIODIC
+timer, that is not removed from the timer list. TT_PERIODIC timers
+are similar to TT_RELATIVE timers, in that one passes in the expire
+time as a relative number of seconds, but when they expire, they are
+re-added to the timer list with the same relative expire time. This
+means that a TT_PERIODIC timer with an expire time of 5 seconds that
+is set at 11:50:00 will have its call-back called at 11:50:05,
+11:50:10, 11:50:15, and so on.
+
+Timers have to be run by the event engines explicitly by calling
+timer_run() on the generator list passed to the engine event loop.
+In addition, engines may determine the next (absolute) time that a
+timer needs to be run by calling the timer_next() macro; this may be
+used to set a timeout on the engine's network activity monitoring
+function. Engines are described in detail below.
+
+When a timer expires, an event of ET_EXPIRE is generated, and the
+call-back function is called. When a timer is destroyed, either as
+the result of an expiration or as a result of an explicit timer_del()
+call, an event of ET_DESTROY is generated, notifying the call-back
+that the struct Timer can be deallocated.
+
+Sockets
+
+Perhaps the most complicated event generator in all of the event
+system is the socket, as described by struct Socket. This single
+classification covers datagram sockets and stream sockets. To
+differentiate the different kinds of sockets, there is a socket state
+associated with each socket. The available states are SS_CONNECTING,
+which indicates that a particular socket is in the process of
+completing a non-blocking connect(); SS_LISTENING, which indicates
+that a particular socket is a listening socket; SS_CONNECTED, which is
+the state of every other stream socket; SS_DATAGRAM, which is an
+ordinary datagram socket, and SS_CONNECTDG, which describes a
+connected datagram socket. (The SS_NOTSOCK state is for the internal
+use of the events system and will not be described here.)
+
+In addition to the socket states, there's also an event mask for each
+socket; this set of flags is used to tell the events subsystem what
+events the application is interested in for the socket. For
+SS_CONNECTING and SS_LISTENING sockets, this events mask has no
+meaning, but on the other socket states, the event mask is used to
+determine if the application is interested in readable
+(SOCK_EVENT_READABLE) or writable (SOCK_EVENT_WRITABLE) indications.
+
+Most of the defined event types have to do with socket generators.
+When a socket turns up readable, for instance, an event of type
+ET_READ is generated. Similarly, ET_WRITE is generated when a socket
+can be written to. The ET_ACCEPT event is generated when a listening
+socket indicates that there is a connection to be accepted; ET_CONNECT
+is generated when a non-blocking connect is completed. Finally, if an
+end-of-file indication is detected, ET_EOF is generated, whereas if an
+error has occurred on the socket, ET_ERROR is generated. Of course,
+when a socket has been deleted by the socket_del() function, an event
+of ET_DESTROY is generated when it is safe for the memory used by the
+struct Socket to be reclaimed.
+
+Events
+
+An event, represented by a struct Event, describes in detail all of
+the particulars of an event. Each event has a type, and an optional
+integer piece of data may be passed with some events--in particular,
+ET_SIGNAL events pass the signal number, and ET_ERROR events pass the
+errno value. The struct Event also contains a pointer to the
+structure describing the generated event--although it should be noted
+that the only way to disambiguate which type of generator is contained
+within the struct Event is by which call-back function has been
+called.
+
+All generators have a void pointer which can be used to pass important
+information to the call-back, such as a pointer to a struct Client.
+Additionally, generators have a reference count, and a union of a void
+pointer and an integer that should only be utilized by the event
+engine. Finally, there is also a field for flags, although the only
+flag of concern to the application (or the engine) is the active flag,
+which may be tested using the test macros described below.
+
+Whatever the generator, the call-back function is a function returning
+nothing (void) and taking as its sole argument a pointer to struct
+Event. This call-back function may be implemented as a single switch
+statement that calls out to appropriate external functions as needed.
+
+Engines
+
+Engines implement the actual socket event loop, and may also have some
+means of receiving signal events. Each engine has a name, which
+should describe what its core function is; for instance, the engine
+based on the standard select() function is named, simply, "select()."
+Each engine must implement several call-backs which are used to
+initialize the engine, notify the engine of sockets the application is
+interested in, etc. All of this data is described by a single struct
+Engine, which should be the only non-static variable or function in
+the engine's source file.
+
+The engine's event loop, pointed to by the eng_loop field of the
+struct Engine, must consist of a single while loop predicated on the
+global variable _running_. Additionally, this loop's final statement
+must be a call to timer_run(), to execute all timers that have become
+due. Ideally, this construction should be pulled out of each engine's
+eng_loop and put in the event_loop() function of the events
+subsystem.
+
+Reference Counts
+
+As mentioned previously, all generators keep a reference count.
+Should timer_del() or socket_del() be called on a generator with a
+non-zero reference count, for whatever reason, the actual destruction
+of the generator will be delayed until the reference count again
+reaches zero. This is used by the event loop to keep sockets that it
+is currently referencing from being deallocated before it is done
+checking all pending events on them. To increment the reference count
+by one, call gen_ref_inc() on the generator; the corresponding macro
+gen_ref_dec() decrements the reference counts, and will automatically
+destroy the generator if the appropriate conditions are met.
+
+Debugging Functions
+
+It can be difficult to debug an engines if, say, a socket state can
+only be expressed as a meaningless number. Therefore, when DEBUGMODE
+is #define'd, five number-to-name functions are also defined to make
+the debugging data more meaningful. These functions must only be
+called when DEBUGMODE is #define'd. Calling them from within Debug()
+macro calls is safe; calling them from log_write() calls is not.
+
+<typedef>
+typedef void (*EventCallBack)(struct Event*);
+
+The _EventCallBack_ type is used to simplify declaration of event
+call-back functions. It is used in timer_add(), signal_add(), and
+socket_add(). The event call-back should process the event, taking
+whatever actions are necessary. The function should be declared as
+returning void.
+</typedef>
+
+<typedef>
+typedef int (*EngineInit)(int);
+
+The _EngineInit_ function takes an integer specifying the maximum
+number of sockets the event system is expecting to handle. This
+number may be used by the engine initialization function for memory
+allocation computations. If initialization succeeds, this function
+must return 1. If initialization fails, the function should clean up
+after itself and return 0. The events subsystem has the ability to
+fall back upon another engine, should an engine initialization fail.
+Needless to say, the engines based upon poll() and select() should
+never fail in this way.
+</typedef>
+
+<typedef>
+typedef void (*EngineSignal)(struct Signal*);
+
+If an engine has the capability to directly detect signals, it should
+set the eng_signal field of struct Engine non-zero. When the
+application indicates interest in a particular signal, the
+_EngineSignal_ function will be called with the filled-in struct
+Signal, in order to register interest in that signal with the engine.
+</typedef>
+
+<typedef>
+typedef int (*EngineAdd)(struct Socket*);
+
+All engines must define an _EngineAdd_ function, which is used to
+inform the engine of the application's interest in the socket. If the
+new socket cannot be accommodated by the engine for whatever reason,
+this function must return 0. Otherwise, the function must return 1,
+informing the events subsystem that the interest has been noted.
+</typedef>
+
+<typedef>
+typedef void (*EngineState)(struct Socket*, enum SocketState new_state);
+
+Sockets can change state. SS_CONNECTING sockets, for instance, can
+become SS_CONNECTED. Whenever a socket state changes, the engine is
+informed, since some states require different notification procedures
+than others. This is accomplished by calling the _EngineState_
+function with the new state. The struct Socket passed to the engine
+will still have the old state, if the engine must reference that.
+</typedef>
+
+<typedef>
+typedef void (*EngineEvents)(struct Socket*, unsigned int new_events);
+
+Applications may only be interested in given events on a socket for a
+limited time. When the application's interest shifts, a new events
+mask is set for the socket. The engine is informed of this change by
+a call to its _EngineEvents_ function.
+</typedef>
+
+<typedef>
+typedef void (*EngineDelete)(struct Socket*);
+
+Eventually, an application will close all the sockets it has opened.
+When a socket is closed, and the corresponding struct Socket deleted
+with a call to socket_del(), the _EngineDelete_ function will be
+called to notify the engine of the change.
+</typedef>
+
+<typedef>
+typedef void (*EngineLoop)(struct Generators*);
+
+The workhorse of the entire events subsystem is the event loop,
+implemented by each engine as the _EngineLoop_ function. This
+function is called with a single argument that may be passed to
+timer_next() to calculate the next time a timer will expire.
+</typedef>
+
+<enum>
+enum SocketState {
+ SS_CONNECTING, /* Connection in progress on socket */
+ SS_LISTENING, /* Socket is a listening socket */
+ SS_CONNECTED, /* Socket is a connected socket */
+ SS_DATAGRAM, /* Socket is a datagram socket */
+ SS_CONNECTDG, /* Socket is a connected datagram socket */
+ SS_NOTSOCK /* Socket isn't a socket at all */
+};
+
+This enumeration contains a list of all possible states a socket can
+be in. Applications should not use SS_NOTSOCK; engines should treat
+it as a special socket state for non-sockets. The only event that
+should be watched for on a struct Socket in the SS_NOTSOCK state is
+readability. This socket state is used to implement the fall-back
+signal event generation.
+</enum>
+
+<enum>
+enum TimerType {
+ TT_ABSOLUTE, /* timer that runs at a specific time */
+ TT_RELATIVE, /* timer that runs so many seconds in the future */
+ TT_PERIODIC /* timer that runs periodically */
+};
+
+The three possible timer types are defined by the TimerType
+enumeration. More details can be found in the "Timers" sub-section.
+</enum>
+
+<enum>
+enum EventType {
+ ET_READ, /* Readable event detected */
+ ET_WRITE, /* Writable event detected */
+ ET_ACCEPT, /* Connection can be accepted */
+ ET_CONNECT, /* Connection completed */
+ ET_EOF, /* End-of-file on connection */
+ ET_ERROR, /* Error condition detected */
+ ET_SIGNAL, /* A signal was received */
+ ET_EXPIRE, /* A timer expired */
+ ET_DESTROY /* The generator is being destroyed */
+};
+
+This enumeration contains all the types of events that can be
+generated by the events subsystem. The first 6 are generated by
+socket generators, the next by signal generators, and the next by
+timer generators. ET_DESTROY is generated by both socket and timer
+generators when the events subsystem is finished with the memory
+allocated by both.
+</enum>
+
+<struct>
+struct Socket;
+
+This structure describes everything the events subsystem knows about a
+given socket. All of its fields may be accessed through the s_*
+macros described below.
+</struct>
+
+<struct>
+struct Timer;
+
+The struct Timer structure describes everything the events subsystem
+knows about a given timer. Again, all of its fields may be accessed
+through the t_* macros described below.
+</struct>
+
+<struct>
+struct Signal;
+
+Signal generators are described by a struct Signal. All of the fields
+of a struct Signal may be accessed by the sig_* macros described
+below.
+</struct>
+
+<struct>
+struct Event;
+
+Each event is described by a struct Event. Its fields may be examined
+using the ev_* macros described below.
+</struct>
+
+<struct>
+struct Generators;
+
+Each engine is passed a list of all generators when the engine's
+_EngineLoop_ function is called. The only valid way to access this
+structure is via the timer_next() function described below.
+</struct>
+
+<struct>
+struct Engine {
+ const char* eng_name; /* a name for the engine */
+ EngineInit eng_init; /* initialize engine */
+ EngineSignal eng_signal; /* express interest in a signal */
+ EngineAdd eng_add; /* express interest in a socket */
+ EngineState eng_state; /* mention a change in state to engine */
+ EngineEvents eng_events; /* express interest in socket events */
+ EngineDelete eng_closing; /* socket is being closed */
+ EngineLoop eng_loop; /* actual event loop */
+};
+
+Each engine is described by the struct Engine structure. Each engine
+must define all of the functions described above except for the
+_EngineSignal_ function, which is optional.
+</struct>
+
+<macro>
+#define SOCK_EVENT_READABLE 0x0001 /* interested in readable */
+
+The SOCK_EVENT_READABLE flag indicates to the engine that the
+application is interested in readability on this particular socket.
+</macro>
+
+<macro>
+#define SOCK_EVENT_WRITABLE 0x0002 /* interested in writable */
+
+The SOCK_EVENT_WRITABLE flag indicates to the engine that the
+application is interested in this socket being writable.
+</macro>
+
+<macro>
+#define SOCK_EVENT_MASK (SOCK_EVENT_READABLE | SOCK_EVENT_WRITABLE)
+
+SOCK_EVENT_MASK may be used to extract only the event interest flags
+from an event interest set.
+</macro>
+
+<macro>
+#define SOCK_ACTION_SET 0x0000 /* set interest set as follows */
+
+When socket_events() is called with a set of event interest flags and
+SOCK_ACTION_SET, the socket's event interest flags are set to those
+passed into socket_events().
+</macro>
+
+<macro>
+#define SOCK_ACTION_ADD 0x1000 /* add to interest set */
+
+When SOCK_ACTION_ADD is used in a call to socket_events(), the event
+interest flags passed in are added to the existing event interest
+flags for the socket.
+</macro>
+
+<macro>
+#define SOCK_ACTION_DEL 0x2000 /* remove from interest set */
+
+When SOCK_ACTION_DEL is used in a call to socket_events(), the event
+interest flags passed in are removed from the existing event interest
+flags for the socket.
+</macro>
+
+<macro>
+#define SOCK_ACTION_MASK 0x3000 /* mask out the actions */
+
+SOCK_ACTION_MASK is used to isolate the socket action desired.
+</macro>
+
+<function>
+enum SocketState s_state(struct Socket* sock);
+
+This macro returns the state of the given socket.
+</function>
+
+<function>
+unsigned int s_events(struct Socket* sock);
+
+This macro returns the current event interest mask for a given
+socket. Note that if the socket is in the SS_CONNECTING or
+SS_LISTENING states, this mask has no meaning.
+</function>
+
+<function>
+int s_fd(struct Socket* sock);
+
+This macro simply returns the file descriptor for the given socket.
+</function>
+
+<function>
+void* s_data(struct Socket* sock);
+
+When a struct Socket is initialized, data that the call-back function
+may find useful, such as a pointer to a struct Connection, is stored
+in the struct Socket. This macro returns that pointer.
+</function>
+
+<function>
+int s_ed_int(struct Socket* sock);
+
+Engines may find it convenient to associate an integer with a struct
+Socket. This macro may be used to retrieve that integer or, when used
+as an lvalue, to assign a value to it. Engine data must be either an
+int or a void*; use of both is prohibited.
+</function>
+
+<function>
+void* s_ed_ptr(struct Socket* sock);
+
+Engines may find it convenient to associate a void* pointer with a
+struct Socket. This macro may be used to retrieve that pointer or,
+when used as an lvalue, to assign a value to it. Engine data must be
+either an int or a void*; use of both is prohibited.
+</function>
+
+<function>
+int s_active(struct Socket* sock);
+
+A socket's active flag is set when initialized by socket_add(), and is
+cleared immediately prior to generating an event of type ET_DESTROY.
+This may be used by the application to determine whether or not the
+socket is still in use by the events subsystem. If it is, s_active()
+returns a non-zero value; otherwise, its value is 0.
+</function>
+
+<function>
+int socket_add(struct Socket* sock, EventCallBack call, void* data,
+ enum SocketState state, unsigned int events, int fd);
+
+This function is called to add a socket to the list of sockets to be
+monitored. The _sock_ parameter is a pointer to a struct Socket that
+is allocated by the application. The _call_ parameter is a pointer to
+a function to process any events on the socket. The _data_ parameter
+is for use of the socket call-back and may be zero. The _state_
+parameter must be one of the valid socket states. The _events_
+parameter must be a valid events interest mask--0, or the binary OR of
+SOCK_EVENT_READABLE or SOCK_EVENT_WRITABLE. Finally, the _fd_
+parameter specifies the socket's file descriptor. This function
+returns 1 if successful or 0 otherwise.
+</function>
+
+<function>
+void socket_del(struct Socket* sock);
+
+When the application is no longer interested in a particular socket,
+it should call the socket_del() function. This function must be
+called no later than when the socket has been closed, to avoid
+attempting to call select() or similar functions on closed sockets.
+</function>
+
+<function>
+void socket_state(struct Socket* sock, enum SocketState state);
+
+Occasionally, a socket's state will change. This function is used to
+inform the events subsystem of that change. Only certain state
+transitions are valid--a socket in the SS_LISTENING or SS_CONNECTED
+states cannot change states, nor can an SS_CONNECTING socket change to
+some state other than SS_CONNECTED. Of course, SS_DATAGRAM sockets
+may change state only to SS_CONNECTDG, and SS_CONNECTDG sockets may
+only change states to SS_DATAGRAM.
+</function>
+
+<function>
+void socket_events(struct Socket* sock, unsigned int events);
+
+When the application changes the events it is interested in, it uses
+socket_events() to notify the events subsystem of that change. The
+_events_ parameter is the binary OR of one of SOCK_ACTION_SET,
+SOCK_ACTION_ADD, or SOCK_ACTION_DEL with an events mask. See the
+documentation for the SOCK_* macros for more information.
+</function>
+
+<function>
+const char* state_to_name(enum SocketState state);
+
+This function is defined only when DEBUGMODE is #define'd. It takes
+the given _state_ and returns a string giving that state's name. This
+function may safely be called from Debug() macros.
+</function>
+
+<function>
+const char* sock_flags(unsigned int flags);
+
+This function is defined only when DEBUGMODE is #define'd. It takes
+the given event interest flags and returns a string naming each of
+those flags. This function may safely be called from Debug() macros,
+but may only be called once, since it uses function static storage to
+store the flag strings.
+</function>
+
+<function>
+int sig_signal(struct Signal* sig);
+
+This macro returns the signal number for the given struct Signal.
+</function>
+
+<function>
+void* sig_data(struct Signal* sig);
+
+When a struct Signal is initialized, data that the call-back function
+may find useful is stored in the struct Signal. This macro returns
+that pointer.
+</function>
+
+<function>
+int sig_ed_int(struct Signal* sig);
+
+Engines may find it convenient to associate an integer with a struct
+Signal. This macro may be used to retrieve that integer or, when used
+as an lvalue, to assign a value to it. Engine data must be either an
+int or a void*; use of both is prohibited.
+</function>
+
+<function>
+void* sig_ed_ptr(struct Signal* sig);
+
+Engines may find it convenient to associate a void* pointer with a
+struct Signal. This macro may be used to retrieve that pointer or,
+when used as an lvalue, to assign a value to it. Engine data must be
+either an int or a void*; use of both is prohibited.
+</function>
+
+<function>
+int sig_active(struct Signal* sig);
+
+A signal's active flag is set when initialized by signal_add(). This
+may be used by the application to determine whether or not the signal
+has been initialized yet. If it is, sig_active() returns a non-zero
+value; otherwise, its value is 0.
+</function>
+
+<function>
+void signal_add(struct Signal* signal, EventCallBack call, void* data,
+ int sig);
+
+This function is called to add a signal to the list of signals to be
+monitored. The _signal_ parameter is a pointer is a pointer to a
+struct Signal that is allocated by the application. The _call_
+parameter is a pointer to a function to process any signal events.
+The _data_ parameter is for use of the signal call-back and may be
+zero. The _sig_ parameter is the integer value of the signal to be
+monitored.
+</function>
+
+<function>
+enum TimerType t_type(struct Timer* tim);
+
+This macro returns the type of the given timer.
+</function>
+
+<function>
+time_t t_value(struct Timer* tim);
+
+This macro returns the value that was used when the given timer was
+initialized by the events subsystem. It will contain an absolute time
+if the timer type is TT_ABSOLUTE, and a relative time otherwise.
+</function>
+
+<function>
+time_t t_expire(struct Timer* tim);
+
+This macro returns the absolute time at which the timer will next
+expire.
+</function>
+
+<function>
+void* t_data(struct Timer* tim);
+
+When a struct Timer is initialized, data that the call-back function
+may find useful is stored in the struct Socket. This macro returns
+that pointer.
+</function>
+
+<function>
+int t_ed_int(struct Timer *tim);
+
+Engines may find it convenient to associate an integer with a struct
+Timer. This macro may be used to retrieve that integer or, when used
+as an lvalue, to assign a value to it. Engine data must be either an
+int or a void*; use of both is prohibited.
+</function>
+
+<function>
+void* t_ed_ptr(struct Timer *tim);
+
+Engines may find it convenient to associate a void* pointer with a
+struct Timer. This macro may be used to retrieve that pointer or,
+when used as an lvalue, to assign a value to it. Engine data must be
+either an int or a void*; use of both is prohibited.
+</function>
+
+<function>
+int t_active(struct Timer *tim);
+
+A timer's active flag is set when initialized by timer_add(), and is
+cleared immediately prior to generating an event of type ET_DESTROY.
+This may be used by the application to determine whether or not the
+timer is still in use by the events subsystem. If it is, s_active()
+returns a non-zero value; otherwise, its value is 0.
+</function>
+
+<function>
+void timer_add(struct Timer* timer, EventCallBack call, void* data,
+ enum TimerType type, time_t value);
+
+This function is called to initialize and queue a timer. The _timer_
+parameter is a pointer to a struct Timer that is allocated by the
+application. The _call_ parameter is a pointer to a function to
+process the timer's expiration. The _data_ parameter is for use of
+the timer call-back and may be zero. The _type_ parameter must be one
+of the valid timer types--TT_ABSOLUTE, TT_RELATIVE, or TT_PERIODIC.
+Finally, _value_ is the value for the timer's expiration.
+</function>
+
+<function>
+void timer_del(struct Timer* timer);
+
+When the application no longer needs a TT_PERIODIC timer, or when it
+wishes to stop a TT_ABSOLUTE or TT_RELATIVE timer before its
+expiration, it should call the timer_del() function.
+</function>
+
+<function>
+void timer_chg(struct Timer* timer, enum TimerType type, time_t value);
+
+Occasionally, an application may wish to delay an existing TT_ABSOLUTE
+or TT_RELATIVE timer; this may be done with the timer_chg() function.
+The _type_ parameter must be one of TT_ABSOLUTE or
+TT_RELATIVE--changing the values of TT_PERIODIC timers is not
+supported. The _value_ parameter is the same as would be given to
+timer_add() for that particular type of timer.
+</function>
+
+<function>
+void timer_run(void);
+
+When an engine has finished processing the results of its socket and
+signal checks--just before it loops around to test for more events--it
+should call the timer_run() function to expire any waiting timers.
+</function>
+
+<function>
+time_t timer_next(struct Generators* gen);
+
+Most engines will use a blocking call with a timeout to check for
+socket activity. To determine when the next timer needs to be run,
+and thus to calculate how long the call should block, the engine
+should call timer_next() with the _gen_ parameter passed to the
+_EngineLoop_ function. The timer_next() function returns an absolute
+time, which may have to be massaged into a relative time before the
+engine may use it.
+</function>
+
+<function>
+const char* timer_to_name(enum TimerType type);
+
+This function is defined only when DEBUGMODE is #define'd. It takes
+the given _type_ and returns a string giving that type's name. This
+function may safely be called from Debug() macros.
+</function>
+
+<function>
+enum EventType ev_type(struct Event* ev);
+
+This macro simply returns the type of the event _ev_.
+</function>
+
+<function>
+int ev_data(struct Event* ev);
+
+When an event is generated, a single integer can be passed along as a
+piece of extra information. This can be used, for instance, to carry
+an errno value when an ET_ERROR is generated. This macro simply
+returns that integer.
+</function>
+
+<function>
+struct Socket* ev_socket(struct Event* ev);
+
+If the event was generated by a socket, this macro returns a pointer
+to the struct Socket that generated the event. The results are
+undefined if the event was not generated by a socket.
+</function>
+
+<function>
+struct Signal* ev_signal(struct Event* ev);
+
+If the event was generated by a signal, this macro returns a pointer
+to the struct Signal that generated the event. The results are
+undefined if the event was not generated by a signal.
+</function>
+
+<function>
+struct Timer* ev_timer(struct Event* ev);
+
+If the event was generated by a timer, this macro returns a pointer to
+the struct Timer that generated the event. The results are undefined
+if the event was not generated by a timer.
+</function>
+
+<function>
+void event_init(int max_sockets);
+
+Before any of the functions or macros described here can be called,
+the events subsystem must be initialized by calling event_init(). The
+_max_sockets_ parameter specifies to the events subsystem how many
+sockets it must be able to support; this figure may be used for memory
+allocation by the engines.
+</function>
+
+<function>
+void event_loop(void);
+
+Once the initial sockets are open, signals added, and timers queued,
+the application must call the event_loop() function in order to
+actually begin monitoring those sockets, signals, and timers.
+</function>
+
+<function>
+void event_generate(enum EventType type, void* arg, int data);
+
+This is the function called by the events subsystem to generate
+particular events. The _type_ parameter specifies the type of event
+to generate, and the _arg_ parameter must be a pointer to the event's
+generator. The _data_ parameter may be used for passing such things
+as signal numbers or errno values.
+</function>
+
+<function>
+const char* event_to_name(enum EventType type);
+
+This function is defined only when DEBUGMODE is #define'd. It takes
+the given _type_ and returns a string giving that event type's name.
+This function may safely be called from Debug() macros.
+</function>
+
+<function>
+const char* engine_name(void);
+
+This function is used to retrieve the name of the engine presently
+being used by the events subsystem.
+</function>
+
+<function>
+void gen_ref_inc(void* gen);
+
+This macro increments the reference count of the generator _gen_,
+preventing it from simply disappearing without warning.
+</function>
+
+<function>
+void gen_ref_dec(void* gen);
+
+This macro decrements the reference count of the generator _gen_, and
+releases the memory associated with it by generating at ET_DESTROY
+event if the reference count falls to zero and the generator is marked
+for destruction. No references should be made to the generator after
+calling this macro.
+</function>
+
+<authors>
+Kev <klmitch@mit.edu>
+</authors>
+
+<changelog>
+[2001-6-14 Kev] Finished initial description of the events subsystem.
+
+[2001-6-13 Kev] Initial description of the events subsystem.
+</changelog>