| 1 | .\" -*-nroff-*- |
| 2 | .TH sel 3 "22 May 1999" "Straylight/Edgeware" "mLib utilities library" |
| 3 | .SH NAME |
| 4 | sel \- low level interface for waiting for I/O |
| 5 | .\" @sel_init |
| 6 | .\" @sel_initfile |
| 7 | .\" @sel_addfile |
| 8 | .\" @sel_force |
| 9 | .\" @sel_rmfile |
| 10 | .\" @sel_addtimer |
| 11 | .\" @sel_rmtimer |
| 12 | .\" @sel_addhook |
| 13 | .\" @sel_rmhook |
| 14 | .\" @sel_fdmerge |
| 15 | .\" @sel_select |
| 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 ); |
| 27 | .BI "void sel_force(sel_file *" f ); |
| 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 ), |
| 33 | .BI " void *" p ); |
| 34 | .BI "void sel_rmtimer(sel_timer *" t ); |
| 35 | |
| 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 | |
| 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 |
| 50 | there's no reason at all why multithreaded programs shouldn't use |
| 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 |
| 112 | .BR selbuf (3) |
| 113 | and |
| 114 | .BR conn (3). |
| 115 | .SH "PROGRAMMING INTERFACE" |
| 116 | .SS "Multiplexors" |
| 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. |
| 136 | .SS "File selectors" |
| 137 | A file selector is initialized by the |
| 138 | .B sel_initfile |
| 139 | function. This requires a large number of arguments: |
| 140 | .TP |
| 141 | .BI "sel_state *" s |
| 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 |
| 146 | .BI "sel_file *" f |
| 147 | Pointer to the file selector object to be initialized. |
| 148 | .TP |
| 149 | .BI "int " fd |
| 150 | The file descriptor which the selector is meant to watch. |
| 151 | .TP |
| 152 | .BI "unsigned " mode |
| 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 |
| 158 | .BI "void (*" func ")(int " fd ", unsigned " mode ", void *" p ); |
| 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 |
| 163 | .BI "void *" p |
| 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: |
| 195 | the file descriptor for the file, a mode argument which describes the |
| 196 | file's new condition, and the pointer argument set up at initialization |
| 197 | time. |
| 198 | .PP |
| 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 |
| 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. |
| 216 | .SS "Timer selectors" |
| 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 |
| 228 | .BI "sel_state *" s |
| 229 | Pointer to the multiplexor to which the selector is to be added. |
| 230 | .TP |
| 231 | .BI "sel_timer *" t |
| 232 | Pointer to the timer selector object being initialized and added. |
| 233 | .TP |
| 234 | .BI "struct timeval " tv |
| 235 | When the selector should raise its event. This is an |
| 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 |
| 243 | .BI "void (*" func ")(struct timeval *" tv ", void *" p ) |
| 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 |
| 253 | .BI "void *" p |
| 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. |
| 267 | .SS "Performing I/O" |
| 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 |
| 274 | returns zero. Otherwise it returns \-1, and the global variable |
| 275 | .B errno |
| 276 | is set appropriately. |
| 277 | .SS "Hook functions" |
| 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. |
| 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) |
| 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. |
| 387 | .SH "SEE ALSO" |
| 388 | .BR select (2), |
| 389 | .BR poll (2), |
| 390 | .BR conn (3), |
| 391 | .BR selbuf (3), |
| 392 | .BR mLib (3). |
| 393 | .SH AUTHOR |
| 394 | Mark Wooding, <mdw@distorted.org.uk> |