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