summaryrefslogtreecommitdiff
path: root/doc/libstddjb/iopause.html
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2014-09-18 18:55:44 +0000
committerLaurent Bercot <ska-skaware@skarnet.org>2014-09-18 18:55:44 +0000
commit3534b428629be185e096be99e3bd5fdfe32d5544 (patch)
tree210ef3198ed66bc7f7b7bf6a85e4579f455e5a36 /doc/libstddjb/iopause.html
downloadskalibs-3534b428629be185e096be99e3bd5fdfe32d5544.tar.xz
initial commit with rc for skalibs-2.0.0.0
Diffstat (limited to 'doc/libstddjb/iopause.html')
-rw-r--r--doc/libstddjb/iopause.html196
1 files changed, 196 insertions, 0 deletions
diff --git a/doc/libstddjb/iopause.html b/doc/libstddjb/iopause.html
new file mode 100644
index 0000000..72eedde
--- /dev/null
+++ b/doc/libstddjb/iopause.html
@@ -0,0 +1,196 @@
+<html>
+ <head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
+ <meta http-equiv="Content-Language" content="en" />
+ <title>skalibs: the iopause library interface</title>
+ <meta name="Description" content="skalibs: the iopause library interface" />
+ <meta name="Keywords" content="skalibs c unix iopause library libstddjb" />
+ <!-- <link rel="stylesheet" type="text/css" href="http://skarnet.org/default.css" /> -->
+ </head>
+<body>
+
+<p>
+<a href="index.html">libstddjb</a><br />
+<a href="../libskarnet.html">libskarnet</a><br />
+<a href="../index.html">skalibs</a><br />
+<a href="http://skarnet.org/software/">Software</a><br />
+<a href="http://skarnet.org/">skarnet.org</a>
+</p>
+
+<h1> The <tt>iopause</tt> library interface </h1>
+
+<p>
+ The following functions are declared in the <tt>skalibs/iopause.h</tt> header,
+and implemented in the <tt>libskarnet.a</tt> or <tt>libskarnet.so</tt> library.
+</p>
+
+<h2> General information </h2>
+
+<p>
+ <tt>iopause</tt> is the skalibs API for event loop selection. It's a
+wrapper around the system's
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/poll.html">poll()</a>
+(if available) or
+<a href="http://www.opengroup.org/onlinepubs/9699919799/functions/select.html">select()</a>
+(if <tt>poll()</tt> is unavailable) function. It
+works around some system-dependent quirks; also it works with
+<em>absolute dates</em> instead of timeouts. This is a good thing:
+see below.
+</p>
+
+<p>
+ <tt>iopause</tt> is a derived work from Dan J. Bernstein's
+<a href="http://cr.yp.to/lib/iopause.html">iopause</a> library, but the
+skalibs implementation is subtly different.
+</p>
+
+<h2> Data structures </h2>
+
+<p>
+ An <tt>iopause_fd</tt> structure is similar to a
+<a href="http://www.opengroup.org/onlinepubs/9699919799/basedefs/poll.h.html">struct pollfd</a>
+structure, and must be filled the same way. Usually, the user declares
+an array of <tt>iopause_fd</tt> and fills it, one element per descriptor
+to select on. If <em>x</em> is an <tt>iopause_fd</tt>:
+</p>
+
+<ul>
+ <li> <em>x</em>.fd must be set to the fd number to select on. </li>
+ <li> <em>x</em>.events must be a disjunction of the following flags:
+ <ul>
+ <li> IOPAUSE_READ if the fd is to be selected for reading. </li>
+ <li> IOPAUSE_WRITE if the fd is to be selected for writing. </li>
+ </ul> </li>
+ <li> When the selection function returns, <em>x</em>.revents contains
+a disjunction of the following flags:
+ <ul>
+ <li> IOPAUSE_READ if the fd is readable (this include reception of an EOF). </li>
+ <li> IOPAUSE_WRITE if the fd is writable. </li>
+ <li> IOPAUSE_EXCEPT if an exception (such as EOF or an error) occurred on the fd. </li>
+ </ul> </li>
+</ul>
+
+<p>
+ Unlike <tt>poll()</tt> or <tt>select()</tt>, which use a <em>timeout</em>
+argument, the <tt>iopause()</tt> function uses a <em>deadline</em> argument,
+i.e. an absolute time at which it must return 0 if no event has happened
+so far, as well as a <em>stamp</em> argument, i.e. an absolute time meaning
+<em>now</em>. Those arguments are stored in
+<a href="tai.html">tain_t</a>s. Here is why:
+</p>
+
+<p>
+ The event loop pattern is mostly used to multiplex several asynchronous
+events that can happen independently, at the same time or not. Let's
+say you have 3 events, <em>x</em>, <em>y</em> and <em>z</em>. Each of
+those has a separate timeout: if <em>x</em> happens before <em>x-timeout</em>
+milliseconds, you call the <em>x-event-handler</em> function, but
+if <em>x-timeout</em> milliseconds elapse without <em>x</em> happening,
+you call <em>x-timeout-handler</em> function. And similarly with <em>y</em>
+and <em>z</em>.
+</p>
+
+<p>
+ But the selection function returning does not mean <em>x</em> has happened
+or that <em>x</em> has timed out. It might also mean that <em>y</em> has
+happened, that <em>y</em> has timed out, that <em>z</em> has happened, that
+<em>z</em> has timed out, or something else entirely. In the post-selection
+part of the loop, the proper handler is called for the event or timeout
+that has happened; then the loop is executed again, and in the
+pre-selection part of the loop, the array describing the events is filled,
+and the selection timeout is computed.
+</p>
+
+<p>
+ How are you going to compute that global selection timeout? Easy: it's the
+shortest of the three. But we just spent some amount of time waiting, so the
+individual timeouts must be recomputed! This means:
+<ul>
+ <li> You need a way to know the time spent in a selection primitive, which
+basically means getting a timestamp before the selection and once again
+after the timestamp. </li>
+ <li> You need to recompute every individual timeout everytime you enter
+the loop. </li>
+</ul>
+
+<p>
+ That is really cumbersome. A much simpler way of doing things is:
+</p>
+
+<ul>
+ <li> Always keep a reasonably accurate estimation of the current
+time in a <em>stamp</em> variable. That means getting the current time
+at the start of the process, and updating it <em>right after</em> any
+action that takes a significant amount of time. When to update <em>stamp</em>
+can be difficult to estimate in CPU-bound processes; fortunately, most
+processes using an event loop are IO-bound, and the only actions that take
+a non-negligible amount of time in an IO-bound process are the blocking
+primitives. So, <em>stamp</em> must be updated <em>right after a selection
+function returns</em>, and if the program has been correctly written and
+cannot block anywhere else, it's the only place where it needs to be. </li>
+ <li> For every event, compute the <em>deadline</em> of that event:
+<em>x-deadline</em> is <em>x-timeout</em> added to the current <em>stamp</em>
+value when <em>x</em> enters the loop. This is done only once per event:
+you never have to recompute event deadlines - unlike timeouts, which diminish
+over time, deadlines do not change. </li>
+ <li> At every iteration, the selection deadline is the earliest of all the
+available event deadlines. </li>
+ <li> As an added bonus: after the selection function returns and
+ <em>stamp</em> has been updated, it is easy to check which events have
+timed out and which have not: <em>x</em> has timed out iff <em>x-deadline</em>
+is earlier than <em>stamp</em>. </li>
+</ul>
+
+<p>
+ Maintaining a global timestamp and using absolute times instead of relative
+times really is the right way to work with event loops, and the <tt>iopause</tt>
+interface reflects that. Of course, you need a reliable, bug-free time library
+and a monotonic, constant system clock to handle absolute times correctly;
+that is why <tt>iopause</tt> relies on the <a href="tai.html">tai</a> library.
+</p>
+
+<h2> Functions </h2>
+
+<p>
+<code> int iopause (iopause_fd *x, unsigned int len, tain_t const *deadline, tain_t const *stamp) </code> <br />
+Blocks until one of the events described in the <em>x</em> array, of length
+<em>len</em>, happens, or until the absolute date *<em>deadline</em> is
+reached. <em>deadline</em> may be null, in which case the function blocks
+indefinitely until an event happens. If <em>deadline</em> is not null, then
+<em>stamp</em> must not be null, and must contain an accurate estimation
+of the current time. The function returns the number of events that have
+happened, 0 for a timeout, or -1 (and sets errno) for an error.
+</p>
+
+<p>
+<code> int iopause_stamp (iopause_fd *x, unsigned int len, tain_t const *deadline, tain_t *stamp) </code> <br />
+Like <tt>iopause()</tt>, but if <em>stamp</em> is not null, it is updated
+right before the function returns. This helps the user always keep a
+reasonably accurate estimation of the current time in <em>stamp</em>;
+it is recommended to use this function instead of the lower-level
+<tt>iopause()</tt>.
+</p>
+
+<h3> Underlying implementations </h3>
+
+<p>
+ <tt>iopause</tt> is an alias to either <tt>iopause_poll</tt> or
+or <tt>iopause_select</tt>. By default, it is aliased to <tt>iopause_poll</tt>; to
+alias it to <tt>iopause_select</tt> instead, configure skalibs with the
+<tt>--enable-iopause-select</tt> option.
+</p>
+
+<p>
+Both <tt>iopause_poll</tt> and <tt>iopause_select</tt> are implemented on top of the
+<a href="http://man7.org/linux/man-pages/man2/ppoll.2.html">ppoll()</a> system call
+if it is available; but if it is not, then <tt>iopause_poll</tt> defaults to
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/poll.html">poll()</a>,
+which has a more comfortable API than
+<a href="http://pubs.opengroup.org/onlinepubs/9699919799/functions/select.html">select()</a>,
+but a maximum precision of 1 millisecond which might not be enough for some applications; whereas
+<tt>iopause_select<tt> defaults to select(), which incurs some CPU overhead for the
+API conversion, but has a 1 microsecond precision.
+</p>
+
+</body>
+</html>