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