Log in | Back to darenet.org

ircd/api/events

(Signals)
(Timers)
Line 20: Line 20:
When a timer expires, an event of <code>ET_EXPIRE</code> is generated, and the call-back function is called. When a timer is destroyed, either as the result of an expiration or as result of an explicit <code>timer_del()</code> call, am event of <code>ET_DESTROY</code> is generated, notifying the call-back that the <code>struct Timer</code> can be deallocated.
When a timer expires, an event of <code>ET_EXPIRE</code> is generated, and the call-back function is called. When a timer is destroyed, either as the result of an expiration or as result of an explicit <code>timer_del()</code> call, am event of <code>ET_DESTROY</code> is generated, notifying the call-back that the <code>struct Timer</code> can be deallocated.
 +
 +
== Sockets ==
 +
 +
Perhaps the most complicated event generator in all of the event subsystem is the socket, as described by <code>struct Socket</code>. 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 <code>SS_CONNECTING</code>, which indicates that a particular socket is in the process of completing a non-blocking <code>connect()</code>; <code>SS_LISTENING</code>, which indicates that a particular socket is a listening socket; <code>SS_CONNECTED</code>, which is the state of every other stream socket; <code>SS_DATAGRAM</code>, which is an ordinary datagram socket, and <code>SS_CONNECTDG</code>, which describes a connected datagram socket. The <code>SS_NOTSOCK</code> state is for the internal use of the event subsystem and will not be described here.
 +
 +
In addition to the socket states, there is 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 <code>SS_CONNECTING</code> and <code>SS_LISTENING</code> 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 (<code>SOCK_EVENT_READABLE</code>) or writable (<code>SOCK_EVENT_WRITABLE</code>) indications.
 +
 +
Most of the defined event types have to do with socket generators. When a socket turns up readable, for instance, an event type <code>ET_READ</code> is generated. Similarly, <code>ET_WRITE</code> is generated when a socket can be written to. The <code>ET_ACCEPT</code> event is generated when a listening socket indicates that there is a connection to be accepted; <code>ET_CONNECT</code> is generated when a non-blocking connect is completed. Finally, if an end-of-file indication is detected, <code>ET_EOF</code> is generated, whereas if an error has occurred on the socket, <code>ET_ERROR</code> is generated. Of course, when a socket has been deleted by the <code>socket_del()</code> function, an event of <code>ET_DESTROY</code> is generated when it is safe for the memory used by the <code>struct Socket</code> to be reclaimed.

Revision as of 19:12, 10 July 2010

In This Guide:

Overview

The IRC server is built around an event loop. Until the u2.10.11 release (which is what ircd-darenet 1.x is based off of), 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 changed with u2.10.11. A new subsystem, the events subsystem, was 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 a struct Socket; signals, represented by a 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 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.

These 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 time_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 result of an explicit timer_del() call, am 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 subsystem 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 event subsystem and will not be described here.

In addition to the socket states, there is 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 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.