summaryrefslogtreecommitdiff
path: root/doc/libstddjb/iopause.html
blob: 72eeddea8116e63a685cc6c57d530ba478fb9fb8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
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>