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