Synchronous Event Demultiplexing

Synchronous Event Demultiplexing

A synchronous event demultiplexer is a function supplied by an OS that waits for specified events to occur on a set of event sources. When one or more of the event sources become active, the function returns to its caller. The caller can then process the events originating from many sources. Synchronous event demultiplexers are often used as the basis of reactive server event loops that examine and react to events from clients in a continuous and orderly way.

Most operating systems support one or more synchronous event demultiplexing functions, such as

  • The poll() function [Rag93], which stems from System V UNIX

  • The WaitForMultipleObjects() function [Sol98], which is provided by Win32 and

  • The select() function [Ste98], which demultiplexes event sources on I/O handles[1]

    [1] The Win32 version of select() works only on socket handles.

We focus on select() because it's the most common. Event-driven networked applications can use select() to determine which handles can have I/O operations invoked on them synchronously without blocking the application thread that calls them. The C API for the select() function is outlined below:

int select (int width,               // Maximum handle plus 1
            fd_set *read_fds,        // Set of "read" handles
            fd_set *write_fds,       // Set of "write" handles
            fd_set *except_fds,      // Set of "exception" handles
            struct timeval *timeout);// Time to wait for events

An fd_set is a structure representing a set of handles to check for I/O events (a handle set). The three fd_set parameters whose addresses are passed in read_fds, write_fds, and except_fds are examined by select() to see if any of their handles are active for reading, writing, or exceptional conditions (such as out-of-band data), respectively. The select() function informs its caller about active and inactive handles by modifying its fd_set arguments as outlined below:

  • If a handle value is not active in the fd_set, that handle is ignored and its value won't be active in the fd_set returned from select().

  • If a handle value is active in the fd_set, the corresponding handle is examined for pending events. If the handle has an event pending, its corresponding value will be active in the fd_set returned from select(). If the handle does not have a pending event, its value will be inactive in the returned fd_set.

Each OS platform supplies a basic set of operations that allows applications to query and manipulate fd_sets. Although these operations are macros on some platforms and functions on others, they have a consistent set of names and behaviors:

Function Description
FD_ZERO() Mark all handle values as inactive in an fd_set.
FD_CLR() Set a handle to be inactive in an fd_set.
FD_SET() Set a handle to be active in an fd_set.
FD_ISSET() Test to see if a specified handle is active in an fd_set.

The final parameter to select() is a pointer to struct timeval, which contains the following two fields:

struct timeval
  long tv_sec;  /* seconds */
  long tv_usec; /* microseconds */

The following three types of timeval values can be passed to select() to control its time-out behavior:

Value Behavior
NULL timeval pointer Indicates that select() should wait indefinitely, until at least one I/O event occurs or a signal interrupts the call.
Non-NULL timeval pointer whose tv_sec and tv_usec fields are 0 Indicates that select() should perform a "poll," that is, check all the handles and return immediately with any results.
timeval whose tv_sec or tv usec fields is > 0 Indicates that select() should wait up to that amount of time for I/O events to occur.

     Python   SQL   Java   php   Perl 
     game development   web development   internet   *nix   graphics   hardware 
     telecommunications   C++ 
     Flash   Active Directory   Windows