chiark / gitweb /
Infrastructure: Split the files into subdirectories.
[mLib] / sel / sel.3
diff --git a/sel/sel.3 b/sel/sel.3
new file mode 100644 (file)
index 0000000..a1f86a5
--- /dev/null
+++ b/sel/sel.3
@@ -0,0 +1,394 @@
+.\" -*-nroff-*-
+.TH sel 3 "22 May 1999" "Straylight/Edgeware" "mLib utilities library"
+.SH NAME
+sel \- low level interface for waiting for I/O
+.\" @sel_init
+.\" @sel_initfile
+.\" @sel_addfile
+.\" @sel_force
+.\" @sel_rmfile
+.\" @sel_addtimer
+.\" @sel_rmtimer
+.\" @sel_addhook
+.\" @sel_rmhook
+.\" @sel_fdmerge
+.\" @sel_select
+.SH SYNOPSIS
+.nf
+.B "#include <mLib/sel.h>"
+
+.BI "void sel_init(sel_state *" s );
+
+.BI "void sel_initfile(sel_state *" s ", sel_file *" f ,
+.BI "                  int " fd ", unsigned " mode ,
+.BI "                  void (*" func ")(int " fd ", unsigned " mode ", void *" p ),
+.BI "                  void *" p );
+.BI "void sel_addfile(sel_file *" f );
+.BI "void sel_force(sel_file *" f );
+.BI "void sel_rmfile(sel_file *" f );
+
+.BI "void sel_addtimer(sel_state *" s ", sel_timer *" t ,
+.BI "                  struct timeval *" tv ,
+.BI "                  void (*" func ")(struct timeval *" tv ", void *" p ),
+.BI "                  void *" p );
+.BI "void sel_rmtimer(sel_timer *" t );
+
+.BI "void sel_addhook(sel_state *" s ", sel_hook *" h ,
+.BI "                 sel_hookfn " before ", sel_hookfn " after ,
+.BI "                 void *" p );
+.BI "void sel_rmhook(sel_hook *" h );
+
+.BI "int sel_fdmerge(fd_set *" dest ", fd_set *" fd ", int " maxfd );
+
+.BI "int sel_select(sel_state *" s );
+.fi
+.SH "OVERVIEW"
+The
+.B sel
+subsystem provides a structured way of handling I/O in a non-blocking
+event-driven sort of a way, for single-threaded programs.  (Although
+there's no reason at all why multithreaded programs shouldn't use
+.BR sel ,
+it's much less useful.)
+.PP
+The
+.B sel
+subsystem does no memory allocation, and has no static state.  All
+of its data is stored in structures allocated by the caller.  I'll
+explain how this fits in nicely with typical calling sequences below.
+.PP
+Although all the data structures are exposed in the header file, you
+should consider
+.BR sel 's
+data structures to be opaque except where described here, and not fiddle
+around inside them.  Some things may become more sophisticated later.
+.SH "IMPORTANT CONCEPTS"
+The system is based around two concepts:
+.I multiplexors
+and
+.IR selectors .
+.PP
+A
+.I selector
+is interested in some sort of I/O event, which might be something like
+`my socket has become readable', or `the time is now half past three on
+the third of June 2013'.  It has a handler function attached to it,
+which is called when the appropriate event occurs.  Some events happen
+once only ever; some events happen over and over again.  For example, a
+socket might become readable many times, but it's only half-past three
+on the third of June 2013 once.
+.PP
+When a selector is initialized, the caller describes the event the
+selector is interested in, and specifies which function should handle
+the event.  Also, it must specify an arbitrary pointer which is passed
+to the handler function when the event occurs.  This is typically some
+sort of pointer to instance data of some kind, providing more
+information about the event (`it's
+.I this
+socket that's become readable'), or what to do about it.
+.PP
+A multiplexor gathers information about who's interested in what.  It
+maintains lists of selectors.  Selectors must be added to a
+mulitplexor before the events they're interested in are actually watched
+for.  Selectors can be removed again when their events aren't
+interesting any more.  Apart from adding and removing selectors, you can
+.I select
+on a multiplexor.  This waits for something interesting to happen and
+then fires off all the selectors which have events waiting for them.
+.PP
+You can have lots of multiplexors in your program if you like.  You can
+only ask for events from one of them at a time, though.
+.PP
+There are currently two types of selector understood by the low-level
+.B sel
+system: file selectors and timer selectors.  These two types of
+selectors react to corresponding different types of events.  A file
+event indicates that a file is now ready for reading or writing.  A
+timer event indicates that a particular time has now passed (useful for
+implementing timeouts).  More sophisticated selectors can be constructed
+using
+.BR sel 's
+interface.  For examples, see
+.BR selbuf (3)
+and
+.BR conn (3).
+.SH "PROGRAMMING INTERFACE"
+.SS "Multiplexors"
+A multiplexor is represented using the type
+.B sel_state
+defined in the
+.B <mLib/sel.h>
+header file.  Before use, a
+.B sel_state
+must be initialized, by passing it to the
+.B sel_init
+function.  The header file talks about `state blocks' a lot \- that's
+because it was written before I thought the word `multiplexor' was
+nicer.
+.PP
+File selectors are represented by the type
+.BR sel_file .
+The interface provides three operations on file selectors:
+initialization, addition to multiplexor, and removal from a
+multiplexor.  It's convenient to separate addition and removal from
+initialization because file selectors often get added and removed many
+times over during their lifetimes.
+.SS "File selectors"
+A file selector is initialized by the
+.B sel_initfile
+function.  This requires a large number of arguments:
+.TP
+.BI "sel_state *" s
+A pointer to the multiplexor with which the file selector will be
+associated.  This is stored in the selector so that the multiplexor
+argument can be omitted from later calls.
+.TP
+.BI "sel_file *" f
+Pointer to the file selector object to be initialized.
+.TP
+.BI "int " fd
+The file descriptor which the selector is meant to watch.
+.TP
+.BI "unsigned " mode
+A constant describing which condition the selector is interested in.
+This must be one of the
+.B SEL_
+constants described below.
+.TP
+.BI "void (*" func ")(int " fd ", unsigned " mode ", void *" p );
+The handler function which is called when the appropriate condition
+occurs on the file.  This function's interface is described in more
+detail below.
+.TP
+.BI "void *" p
+An arbitrary pointer argument passed to
+.I func
+when it's called.  Beyond this, no meaning is attached to the value of
+the pointer.  If you don't care about it, just leave it as null.
+.PP
+The mode argument is one of the following constants:
+.TP
+.B SEL_READ
+Raise an event when the file is ready to be read from.
+.TP
+.B SEL_WRITE
+Raise an event when the file is ready to be written to.
+.TP
+.B SEL_EXC
+Raise an event when the file has an `exceptional condition'.
+.PP
+The constant
+.B SEL_MODES
+contains the number of possible file modes.  This is useful internally
+for allocating arrays of the right size.
+.PP
+The functions
+.B sel_addfile
+and
+.B sel_rmfile
+perform the addition and removal operations on file selectors.  They are
+passed only the actual selector object, since the selector already knows
+which multiplexor it's associated with.  A newly initialized file
+selector is not added to its multiplexor: this must be done explicitly.
+.PP
+The handler function for a file multiplexor is passed three arguments:
+the file descriptor for the file, a mode argument which describes the
+file's new condition, and the pointer argument set up at initialization
+time.
+.PP
+The function
+.B sel_force
+will sometimes be useful while a
+.B sel_select
+call (see below) is in progress.  It marks a file selector as being
+ready even if it's not really.  This is most useful when dynamically
+adding a write selector: it's likely that the write will succeed
+immediately, so it's worth trying.  This will only work properly if
+the write is non-blocking.
+.PP
+The member
+.B fd
+of the
+.B sel_file
+structure is exported.  It contains the file descriptor in which the
+selector is interested.  You may not modify this value, but it's useful
+to be able to read it out \- it saves having to keep a copy.
+.SS "Timer selectors"
+Timer selectors are simpler.  There are only two operations provided on
+timer selectors: addition and removal.  Initialization is performed as
+part of the addition operation.
+.PP
+A timer selector is represented by an object of time
+.BR sel_timer .
+.PP
+The function
+.B sel_addtimer
+requires lots of arguments:
+.TP
+.BI "sel_state *" s
+Pointer to the multiplexor to which the selector is to be added.
+.TP
+.BI "sel_timer *" t
+Pointer to the timer selector object being initialized and added.
+.TP
+.BI "struct timeval " tv
+When the selector should raise its event.  This is an
+.I absolute
+time, not a relative time as required by the traditional
+.BR select (2)
+and
+.BR poll (2)
+system calls.
+.TP
+.BI "void (*" func ")(struct timeval *" tv ", void *" p )
+A handler function to be called when the event occurs.  The function is
+passed the
+.I current
+time, and the arbitrary pointer passed to
+.B sel_addtimer
+as the
+.I p
+argument.
+.TP
+.BI "void *" p
+A pointer passed to
+.I func
+when the timer event occurs.  Beyond this, the value of the pointer is
+not inspected.
+.PP
+The function
+.B sel_rmtimer
+removes a timer selector.  It is passed only the selector object.
+.PP
+Note that timer events are a one-shot thing.  Once they've happened, the
+timer selector is removed and the event can't happen again.  This is
+normally what you want.  Removing a timer is only useful (or safe!)
+before the timer event has been sent.
+.SS "Performing I/O"
+Finally, the function
+.B sel_select
+is passed a multiplexor object.  It waits for something interesting to
+happen, informs the appropriate selector handlers, and returns.  If
+everything went according to plan,
+.B sel_select
+returns zero.  Otherwise it returns \-1, and the global variable
+.B errno
+is set appropriately.
+.SS "Hook functions"
+In order to interface other I/O multiplexing systems to this one, it's
+possible to register
+.I hook
+functions which are called before and after each
+.BR select (2)
+system call.
+.PP
+The function
+.B sel_addhook
+registers a pair of hook functions.  It is passed the pointer to the
+multiplexor which is being hooked, the address of a
+.B sel_hook
+structure which will be used to record the hook information, the two
+hook functions (either of which may be a null pointer, signifying no
+action to be taken), and a pointer argument to be passed to the hook
+functions.
+.PP
+The function
+.B sel_rmhook
+removes a pair of hooks given the address of the
+.B sel_hook
+structure which recorded their registration.
+.PP
+A
+.I "hook function"
+is passed three arguments:
+.TP
+.BI "sel_state *" s
+A pointer to the multiplexor block.  This probably isn't very useful,
+actually.
+.TP
+.BI "sel_args *" a
+A pointer to a block containing proposed arguments for, or results from,
+.BR select (2).
+The format of this block is described below.
+.TP
+.BI "void *" p
+A pointer argument set up in the call to
+.B sel_addhook
+to provide the hook function with some context.
+.PP
+The argument block contains the following members:
+.TP
+.B "int maxfd"
+One greater than the highest-numbered file descriptor to be examined.
+This may need to be modified if the file descriptor sets are altered.
+.TP
+.B "fd_set fd[SEL_MODES]"
+A file descriptor set for each of
+.BR SEL_READ ,
+.B SEL_WRITE
+and
+.BR SEL_EXC .
+Before the
+.B select
+call, these may be modified to register an interest in other file
+descriptors.  Afterwards, they may be examined to decide which file
+descriptors are active.
+.TP
+.B "struct timeval tv, *tvp"
+Before the
+.B select
+call, these specify the time after which to return even if no files are
+active.  If
+.B tvp
+is null, there is no timeout, and
+.B select
+should wait forever if necessary.  Otherwise
+.B tvp
+should contain the address of
+.BR tv ,
+and
+.B tv
+should contain the timeout.  After the
+.B select
+call, the contents of
+.B tv
+are undefined.
+.TP
+.B "struct timeval now"
+Before the
+.B select
+call, contains the current time.  After the call, this will have been
+updated to reflect the new current time only if there was a timeout
+set before the call.
+.PP
+Hook functions may find the call
+.B sel_fdmerge
+useful.  Given two file descriptor sets
+.I dest
+and
+.IR fd ,
+and a possibly overestimated highest file descriptor in
+.IR fd ,
+the function sets in
+.I dest
+all of the descriptors set in
+.I fd
+and returns an accurate file descriptor count as its result.
+.SH "OTHER NOTES"
+Although the naming seems to suggest that this is all
+based around the BSD-ish
+.BR select (2)
+system call (and indeed it is), the interface is actually a good deal
+more general than that.  An implementation which worked off System V-ish
+.BR poll (2)
+instead would be possible to make, and would look just the same from the
+outside.  Some work would be needed to make the hook functions work,
+though.
+.SH "SEE ALSO"
+.BR select (2),
+.BR poll (2),
+.BR conn (3),
+.BR selbuf (3),
+.BR mLib (3).
+.SH AUTHOR
+Mark Wooding, <mdw@distorted.org.uk>