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