b6b9d458 |
1 | .\" -*-nroff-*- |
fbf20b5b |
2 | .TH sel 3 "22 May 1999" "Straylight/Edgeware" "mLib utilities library" |
b6b9d458 |
3 | .SH NAME |
4 | sel \- low level interface for waiting for I/O |
08da152e |
5 | .\" @sel_init |
6 | .\" @sel_initfile |
7 | .\" @sel_addfile |
1101f87a |
8 | .\" @sel_force |
08da152e |
9 | .\" @sel_rmfile |
10 | .\" @sel_addtimer |
11 | .\" @sel_rmtimer |
b78d1e6d |
12 | .\" @sel_addhook |
13 | .\" @sel_rmhook |
14 | .\" @sel_fdmerge |
08da152e |
15 | .\" @sel_select |
b6b9d458 |
16 | .SH SYNOPSIS |
17 | .nf |
18 | .B "#include <mLib/sel.h>" |
19 | |
20 | .BI "void sel_init(sel_state *" s ); |
21 | |
22 | .BI "void sel_initfile(sel_state *" s ", sel_file *" f , |
23 | .BI " int " fd ", unsigned " mode , |
24 | .BI " void (*" func ")(int " fd ", unsigned " mode ", void *" p ), |
25 | .BI " void *" p ); |
26 | .BI "void sel_addfile(sel_file *" f ); |
1101f87a |
27 | .BI "void sel_force(sel_file *" f ); |
b6b9d458 |
28 | .BI "void sel_rmfile(sel_file *" f ); |
29 | |
30 | .BI "void sel_addtimer(sel_state *" s ", sel_timer *" t , |
31 | .BI " struct timeval *" tv , |
32 | .BI " void (*" func ")(struct timeval *" tv ", void *" p ), |
4ca87020 |
33 | .BI " void *" p ); |
b6b9d458 |
34 | .BI "void sel_rmtimer(sel_timer *" t ); |
35 | |
b78d1e6d |
36 | .BI "void sel_addhook(sel_state *" s ", sel_hook *" h , |
37 | .BI " sel_hookfn " before ", sel_hookfn " after , |
38 | .BI " void *" p ); |
39 | .BI "void sel_rmhook(sel_hook *" h ); |
40 | |
41 | .BI "int sel_fdmerge(fd_set *" dest ", fd_set *" fd ", int " maxfd ); |
42 | |
b6b9d458 |
43 | .BI "int sel_select(sel_state *" s ); |
44 | .fi |
45 | .SH "OVERVIEW" |
46 | The |
47 | .B sel |
48 | subsystem provides a structured way of handling I/O in a non-blocking |
49 | event-driven sort of a way, for single-threaded programs. (Although |
d4efbcd9 |
50 | there's no reason at all why multithreaded programs shouldn't use |
b6b9d458 |
51 | .BR sel , |
52 | it's much less useful.) |
53 | .PP |
54 | The |
55 | .B sel |
56 | subsystem does no memory allocation, and has no static state. All |
57 | of its data is stored in structures allocated by the caller. I'll |
58 | explain how this fits in nicely with typical calling sequences below. |
59 | .PP |
60 | Although all the data structures are exposed in the header file, you |
61 | should consider |
62 | .BR sel 's |
63 | data structures to be opaque except where described here, and not fiddle |
64 | around inside them. Some things may become more sophisticated later. |
65 | .SH "IMPORTANT CONCEPTS" |
66 | The system is based around two concepts: |
67 | .I multiplexors |
68 | and |
69 | .IR selectors . |
70 | .PP |
71 | A |
72 | .I selector |
73 | is interested in some sort of I/O event, which might be something like |
74 | `my socket has become readable', or `the time is now half past three on |
75 | the third of June 2013'. It has a handler function attached to it, |
76 | which is called when the appropriate event occurs. Some events happen |
77 | once only ever; some events happen over and over again. For example, a |
78 | socket might become readable many times, but it's only half-past three |
79 | on the third of June 2013 once. |
80 | .PP |
81 | When a selector is initialized, the caller describes the event the |
82 | selector is interested in, and specifies which function should handle |
83 | the event. Also, it must specify an arbitrary pointer which is passed |
84 | to the handler function when the event occurs. This is typically some |
85 | sort of pointer to instance data of some kind, providing more |
86 | information about the event (`it's |
87 | .I this |
88 | socket that's become readable'), or what to do about it. |
89 | .PP |
90 | A multiplexor gathers information about who's interested in what. It |
91 | maintains lists of selectors. Selectors must be added to a |
92 | mulitplexor before the events they're interested in are actually watched |
93 | for. Selectors can be removed again when their events aren't |
94 | interesting any more. Apart from adding and removing selectors, you can |
95 | .I select |
96 | on a multiplexor. This waits for something interesting to happen and |
97 | then fires off all the selectors which have events waiting for them. |
98 | .PP |
99 | You can have lots of multiplexors in your program if you like. You can |
100 | only ask for events from one of them at a time, though. |
101 | .PP |
102 | There are currently two types of selector understood by the low-level |
103 | .B sel |
104 | system: file selectors and timer selectors. These two types of |
105 | selectors react to corresponding different types of events. A file |
106 | event indicates that a file is now ready for reading or writing. A |
107 | timer event indicates that a particular time has now passed (useful for |
108 | implementing timeouts). More sophisticated selectors can be constructed |
109 | using |
110 | .BR sel 's |
111 | interface. For examples, see |
08da152e |
112 | .BR selbuf (3) |
b6b9d458 |
113 | and |
08da152e |
114 | .BR conn (3). |
b6b9d458 |
115 | .SH "PROGRAMMING INTERFACE" |
1101f87a |
116 | .SS "Multiplexors" |
b6b9d458 |
117 | A multiplexor is represented using the type |
118 | .B sel_state |
119 | defined in the |
120 | .B <mLib/sel.h> |
121 | header file. Before use, a |
122 | .B sel_state |
123 | must be initialized, by passing it to the |
124 | .B sel_init |
125 | function. The header file talks about `state blocks' a lot \- that's |
126 | because it was written before I thought the word `multiplexor' was |
127 | nicer. |
128 | .PP |
129 | File selectors are represented by the type |
130 | .BR sel_file . |
131 | The interface provides three operations on file selectors: |
132 | initialization, addition to multiplexor, and removal from a |
133 | multiplexor. It's convenient to separate addition and removal from |
134 | initialization because file selectors often get added and removed many |
135 | times over during their lifetimes. |
1101f87a |
136 | .SS "File selectors" |
b6b9d458 |
137 | A file selector is initialized by the |
138 | .B sel_initfile |
139 | function. This requires a large number of arguments: |
140 | .TP |
b78d1e6d |
141 | .BI "sel_state *" s |
b6b9d458 |
142 | A pointer to the multiplexor with which the file selector will be |
143 | associated. This is stored in the selector so that the multiplexor |
144 | argument can be omitted from later calls. |
145 | .TP |
b78d1e6d |
146 | .BI "sel_file *" f |
b6b9d458 |
147 | Pointer to the file selector object to be initialized. |
148 | .TP |
b78d1e6d |
149 | .BI "int " fd |
b6b9d458 |
150 | The file descriptor which the selector is meant to watch. |
151 | .TP |
b78d1e6d |
152 | .BI "unsigned " mode |
b6b9d458 |
153 | A constant describing which condition the selector is interested in. |
154 | This must be one of the |
155 | .B SEL_ |
156 | constants described below. |
157 | .TP |
b78d1e6d |
158 | .BI "void (*" func ")(int " fd ", unsigned " mode ", void *" p ); |
b6b9d458 |
159 | The handler function which is called when the appropriate condition |
160 | occurs on the file. This function's interface is described in more |
161 | detail below. |
162 | .TP |
b78d1e6d |
163 | .BI "void *" p |
b6b9d458 |
164 | An arbitrary pointer argument passed to |
165 | .I func |
166 | when it's called. Beyond this, no meaning is attached to the value of |
167 | the pointer. If you don't care about it, just leave it as null. |
168 | .PP |
169 | The mode argument is one of the following constants: |
170 | .TP |
171 | .B SEL_READ |
172 | Raise an event when the file is ready to be read from. |
173 | .TP |
174 | .B SEL_WRITE |
175 | Raise an event when the file is ready to be written to. |
176 | .TP |
177 | .B SEL_EXC |
178 | Raise an event when the file has an `exceptional condition'. |
179 | .PP |
180 | The constant |
181 | .B SEL_MODES |
182 | contains the number of possible file modes. This is useful internally |
183 | for allocating arrays of the right size. |
184 | .PP |
185 | The functions |
186 | .B sel_addfile |
187 | and |
188 | .B sel_rmfile |
189 | perform the addition and removal operations on file selectors. They are |
190 | passed only the actual selector object, since the selector already knows |
191 | which multiplexor it's associated with. A newly initialized file |
192 | selector is not added to its multiplexor: this must be done explicitly. |
193 | .PP |
194 | The handler function for a file multiplexor is passed three arguments: |
d2a91066 |
195 | the file descriptor for the file, a mode argument which describes the |
b6b9d458 |
196 | file's new condition, and the pointer argument set up at initialization |
197 | time. |
198 | .PP |
1101f87a |
199 | The function |
200 | .B sel_force |
201 | will sometimes be useful while a |
202 | .B sel_select |
203 | call (see below) is in progress. It marks a file selector as being |
204 | ready even if it's not really. This is most useful when dynamically |
205 | adding a write selector: it's likely that the write will succeed |
206 | immediately, so it's worth trying. This will only work properly if |
207 | the write is non-blocking. |
208 | .PP |
b6b9d458 |
209 | The member |
210 | .B fd |
211 | of the |
212 | .B sel_file |
213 | structure is exported. It contains the file descriptor in which the |
214 | selector is interested. You may not modify this value, but it's useful |
215 | to be able to read it out \- it saves having to keep a copy. |
1101f87a |
216 | .SS "Timer selectors" |
b6b9d458 |
217 | Timer selectors are simpler. There are only two operations provided on |
218 | timer selectors: addition and removal. Initialization is performed as |
219 | part of the addition operation. |
220 | .PP |
221 | A timer selector is represented by an object of time |
222 | .BR sel_timer . |
223 | .PP |
224 | The function |
225 | .B sel_addtimer |
226 | requires lots of arguments: |
227 | .TP |
b78d1e6d |
228 | .BI "sel_state *" s |
b6b9d458 |
229 | Pointer to the multiplexor to which the selector is to be added. |
230 | .TP |
b78d1e6d |
231 | .BI "sel_timer *" t |
b6b9d458 |
232 | Pointer to the timer selector object being initialized and added. |
233 | .TP |
b78d1e6d |
234 | .BI "struct timeval " tv |
235 | When the selector should raise its event. This is an |
b6b9d458 |
236 | .I absolute |
237 | time, not a relative time as required by the traditional |
238 | .BR select (2) |
239 | and |
240 | .BR poll (2) |
241 | system calls. |
242 | .TP |
b78d1e6d |
243 | .BI "void (*" func ")(struct timeval *" tv ", void *" p ) |
b6b9d458 |
244 | A handler function to be called when the event occurs. The function is |
245 | passed the |
246 | .I current |
247 | time, and the arbitrary pointer passed to |
248 | .B sel_addtimer |
249 | as the |
250 | .I p |
251 | argument. |
252 | .TP |
b78d1e6d |
253 | .BI "void *" p |
b6b9d458 |
254 | A pointer passed to |
255 | .I func |
256 | when the timer event occurs. Beyond this, the value of the pointer is |
257 | not inspected. |
258 | .PP |
259 | The function |
260 | .B sel_rmtimer |
261 | removes a timer selector. It is passed only the selector object. |
262 | .PP |
263 | Note that timer events are a one-shot thing. Once they've happened, the |
264 | timer selector is removed and the event can't happen again. This is |
265 | normally what you want. Removing a timer is only useful (or safe!) |
266 | before the timer event has been sent. |
1101f87a |
267 | .SS "Performing I/O" |
b6b9d458 |
268 | Finally, the function |
269 | .B sel_select |
270 | is passed a multiplexor object. It waits for something interesting to |
271 | happen, informs the appropriate selector handlers, and returns. If |
272 | everything went according to plan, |
273 | .B sel_select |
e142b5dd |
274 | returns zero. Otherwise it returns \-1, and the global variable |
b6b9d458 |
275 | .B errno |
276 | is set appropriately. |
1101f87a |
277 | .SS "Hook functions" |
b78d1e6d |
278 | In order to interface other I/O multiplexing systems to this one, it's |
279 | possible to register |
280 | .I hook |
281 | functions which are called before and after each |
282 | .BR select (2) |
283 | system call. |
284 | .PP |
285 | The function |
286 | .B sel_addhook |
287 | registers a pair of hook functions. It is passed the pointer to the |
288 | multiplexor which is being hooked, the address of a |
289 | .B sel_hook |
290 | structure which will be used to record the hook information, the two |
291 | hook functions (either of which may be a null pointer, signifying no |
292 | action to be taken), and a pointer argument to be passed to the hook |
293 | functions. |
294 | .PP |
295 | The function |
296 | .B sel_rmhook |
297 | removes a pair of hooks given the address of the |
298 | .B sel_hook |
299 | structure which recorded their registration. |
300 | .PP |
301 | A |
302 | .I "hook function" |
303 | is passed three arguments: |
304 | .TP |
305 | .BI "sel_state *" s |
306 | A pointer to the multiplexor block. This probably isn't very useful, |
307 | actually. |
308 | .TP |
309 | .BI "sel_args *" a |
310 | A pointer to a block containing proposed arguments for, or results from, |
311 | .BR select (2). |
312 | The format of this block is described below. |
313 | .TP |
314 | .BI "void *" p |
315 | A pointer argument set up in the call to |
316 | .B sel_addhook |
317 | to provide the hook function with some context. |
318 | .PP |
319 | The argument block contains the following members: |
320 | .TP |
321 | .B "int maxfd" |
322 | One greater than the highest-numbered file descriptor to be examined. |
323 | This may need to be modified if the file descriptor sets are altered. |
324 | .TP |
325 | .B "fd_set fd[SEL_MODES]" |
326 | A file descriptor set for each of |
327 | .BR SEL_READ , |
328 | .B SEL_WRITE |
329 | and |
330 | .BR SEL_EXC . |
331 | Before the |
332 | .B select |
333 | call, these may be modified to register an interest in other file |
334 | descriptors. Afterwards, they may be examined to decide which file |
335 | descriptors are active. |
336 | .TP |
337 | .B "struct timeval tv, *tvp" |
338 | Before the |
339 | .B select |
340 | call, these specify the time after which to return even if no files are |
341 | active. If |
342 | .B tvp |
343 | is null, there is no timeout, and |
344 | .B select |
345 | should wait forever if necessary. Otherwise |
346 | .B tvp |
347 | should contain the address of |
348 | .BR tv , |
349 | and |
350 | .B tv |
351 | should contain the timeout. After the |
352 | .B select |
353 | call, the contents of |
354 | .B tv |
355 | are undefined. |
356 | .TP |
357 | .B "struct timeval now" |
358 | Before the |
359 | .B select |
360 | call, contains the current time. After the call, this will have been |
361 | updated to reflect the new current time only if there was a timeout |
362 | set before the call. |
363 | .PP |
364 | Hook functions may find the call |
365 | .B sel_fdmerge |
366 | useful. Given two file descriptor sets |
367 | .I dest |
368 | and |
369 | .IR fd , |
370 | and a possibly overestimated highest file descriptor in |
371 | .IR fd , |
372 | the function sets in |
373 | .I dest |
374 | all of the descriptors set in |
375 | .I fd |
376 | and returns an accurate file descriptor count as its result. |
b6b9d458 |
377 | .SH "OTHER NOTES" |
378 | Although the naming seems to suggest that this is all |
379 | based around the BSD-ish |
380 | .BR select (2) |
381 | system call (and indeed it is), the interface is actually a good deal |
382 | more general than that. An implementation which worked off System V-ish |
383 | .BR poll (2) |
b78d1e6d |
384 | instead would be possible to make, and would look just the same from the |
385 | outside. Some work would be needed to make the hook functions work, |
386 | though. |
08da152e |
387 | .SH "SEE ALSO" |
388 | .BR select (2), |
389 | .BR poll (2), |
1101f87a |
390 | .BR conn (3), |
391 | .BR selbuf (3), |
08da152e |
392 | .BR mLib (3). |
b6b9d458 |
393 | .SH AUTHOR |
9b5ac6ff |
394 | Mark Wooding, <mdw@distorted.org.uk> |