diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2014-09-18 18:55:44 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2014-09-18 18:55:44 +0000 |
commit | 3534b428629be185e096be99e3bd5fdfe32d5544 (patch) | |
tree | 210ef3198ed66bc7f7b7bf6a85e4579f455e5a36 /doc/libstddjb/iopause.html | |
download | skalibs-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.html | 196 |
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> |