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