Merge branch 'u2_10_12_branch' of git://git.code.sf.net/p/undernet-ircu/ircu2
[ircu2.10.12-pk.git] / doc / api / events.txt
diff --git a/doc/api/events.txt b/doc/api/events.txt
new file mode 100644 (file)
index 0000000..cadfa70
--- /dev/null
@@ -0,0 +1,816 @@
+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>