| 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_select |
| 12 | .SH SYNOPSIS |
| 13 | .nf |
| 14 | .B "#include <mLib/sel.h>" |
| 15 | |
| 16 | .BI "void sel_init(sel_state *" s ); |
| 17 | |
| 18 | .BI "void sel_initfile(sel_state *" s ", sel_file *" f , |
| 19 | .BI " int " fd ", unsigned " mode , |
| 20 | .BI " void (*" func ")(int " fd ", unsigned " mode ", void *" p ), |
| 21 | .BI " void *" p ); |
| 22 | .BI "void sel_addfile(sel_file *" f ); |
| 23 | .BI "void sel_rmfile(sel_file *" f ); |
| 24 | |
| 25 | .BI "void sel_addtimer(sel_state *" s ", sel_timer *" t , |
| 26 | .BI " struct timeval *" tv , |
| 27 | .BI " void (*" func ")(struct timeval *" tv ", void *" p ), |
| 28 | .BI "void sel_rmtimer(sel_timer *" t ); |
| 29 | |
| 30 | .BI "int sel_select(sel_state *" s ); |
| 31 | .fi |
| 32 | .SH "OVERVIEW" |
| 33 | The |
| 34 | .B sel |
| 35 | subsystem provides a structured way of handling I/O in a non-blocking |
| 36 | event-driven sort of a way, for single-threaded programs. (Although |
| 37 | there's no reason at all why multithreaded programs shouldn't use |
| 38 | .BR sel , |
| 39 | it's much less useful.) |
| 40 | .PP |
| 41 | The |
| 42 | .B sel |
| 43 | subsystem does no memory allocation, and has no static state. All |
| 44 | of its data is stored in structures allocated by the caller. I'll |
| 45 | explain how this fits in nicely with typical calling sequences below. |
| 46 | .PP |
| 47 | Although all the data structures are exposed in the header file, you |
| 48 | should consider |
| 49 | .BR sel 's |
| 50 | data structures to be opaque except where described here, and not fiddle |
| 51 | around inside them. Some things may become more sophisticated later. |
| 52 | .SH "IMPORTANT CONCEPTS" |
| 53 | The system is based around two concepts: |
| 54 | .I multiplexors |
| 55 | and |
| 56 | .IR selectors . |
| 57 | .PP |
| 58 | A |
| 59 | .I selector |
| 60 | is interested in some sort of I/O event, which might be something like |
| 61 | `my socket has become readable', or `the time is now half past three on |
| 62 | the third of June 2013'. It has a handler function attached to it, |
| 63 | which is called when the appropriate event occurs. Some events happen |
| 64 | once only ever; some events happen over and over again. For example, a |
| 65 | socket might become readable many times, but it's only half-past three |
| 66 | on the third of June 2013 once. |
| 67 | .PP |
| 68 | When a selector is initialized, the caller describes the event the |
| 69 | selector is interested in, and specifies which function should handle |
| 70 | the event. Also, it must specify an arbitrary pointer which is passed |
| 71 | to the handler function when the event occurs. This is typically some |
| 72 | sort of pointer to instance data of some kind, providing more |
| 73 | information about the event (`it's |
| 74 | .I this |
| 75 | socket that's become readable'), or what to do about it. |
| 76 | .PP |
| 77 | A multiplexor gathers information about who's interested in what. It |
| 78 | maintains lists of selectors. Selectors must be added to a |
| 79 | mulitplexor before the events they're interested in are actually watched |
| 80 | for. Selectors can be removed again when their events aren't |
| 81 | interesting any more. Apart from adding and removing selectors, you can |
| 82 | .I select |
| 83 | on a multiplexor. This waits for something interesting to happen and |
| 84 | then fires off all the selectors which have events waiting for them. |
| 85 | .PP |
| 86 | You can have lots of multiplexors in your program if you like. You can |
| 87 | only ask for events from one of them at a time, though. |
| 88 | .PP |
| 89 | There are currently two types of selector understood by the low-level |
| 90 | .B sel |
| 91 | system: file selectors and timer selectors. These two types of |
| 92 | selectors react to corresponding different types of events. A file |
| 93 | event indicates that a file is now ready for reading or writing. A |
| 94 | timer event indicates that a particular time has now passed (useful for |
| 95 | implementing timeouts). More sophisticated selectors can be constructed |
| 96 | using |
| 97 | .BR sel 's |
| 98 | interface. For examples, see |
| 99 | .BR selbuf (3) |
| 100 | and |
| 101 | .BR conn (3). |
| 102 | .SH "PROGRAMMING INTERFACE" |
| 103 | A multiplexor is represented using the type |
| 104 | .B sel_state |
| 105 | defined in the |
| 106 | .B <mLib/sel.h> |
| 107 | header file. Before use, a |
| 108 | .B sel_state |
| 109 | must be initialized, by passing it to the |
| 110 | .B sel_init |
| 111 | function. The header file talks about `state blocks' a lot \- that's |
| 112 | because it was written before I thought the word `multiplexor' was |
| 113 | nicer. |
| 114 | .PP |
| 115 | File selectors are represented by the type |
| 116 | .BR sel_file . |
| 117 | The interface provides three operations on file selectors: |
| 118 | initialization, addition to multiplexor, and removal from a |
| 119 | multiplexor. It's convenient to separate addition and removal from |
| 120 | initialization because file selectors often get added and removed many |
| 121 | times over during their lifetimes. |
| 122 | .PP |
| 123 | A file selector is initialized by the |
| 124 | .B sel_initfile |
| 125 | function. This requires a large number of arguments: |
| 126 | .TP |
| 127 | .I s |
| 128 | A pointer to the multiplexor with which the file selector will be |
| 129 | associated. This is stored in the selector so that the multiplexor |
| 130 | argument can be omitted from later calls. |
| 131 | .TP |
| 132 | .I f |
| 133 | Pointer to the file selector object to be initialized. |
| 134 | .TP |
| 135 | .I fd |
| 136 | The file descriptor which the selector is meant to watch. |
| 137 | .TP |
| 138 | .I mode |
| 139 | A constant describing which condition the selector is interested in. |
| 140 | This must be one of the |
| 141 | .B SEL_ |
| 142 | constants described below. |
| 143 | .TP |
| 144 | .I func |
| 145 | The handler function which is called when the appropriate condition |
| 146 | occurs on the file. This function's interface is described in more |
| 147 | detail below. |
| 148 | .TP |
| 149 | .I p |
| 150 | An arbitrary pointer argument passed to |
| 151 | .I func |
| 152 | when it's called. Beyond this, no meaning is attached to the value of |
| 153 | the pointer. If you don't care about it, just leave it as null. |
| 154 | .PP |
| 155 | The mode argument is one of the following constants: |
| 156 | .TP |
| 157 | .B SEL_READ |
| 158 | Raise an event when the file is ready to be read from. |
| 159 | .TP |
| 160 | .B SEL_WRITE |
| 161 | Raise an event when the file is ready to be written to. |
| 162 | .TP |
| 163 | .B SEL_EXC |
| 164 | Raise an event when the file has an `exceptional condition'. |
| 165 | .PP |
| 166 | The constant |
| 167 | .B SEL_MODES |
| 168 | contains the number of possible file modes. This is useful internally |
| 169 | for allocating arrays of the right size. |
| 170 | .PP |
| 171 | The functions |
| 172 | .B sel_addfile |
| 173 | and |
| 174 | .B sel_rmfile |
| 175 | perform the addition and removal operations on file selectors. They are |
| 176 | passed only the actual selector object, since the selector already knows |
| 177 | which multiplexor it's associated with. A newly initialized file |
| 178 | selector is not added to its multiplexor: this must be done explicitly. |
| 179 | .PP |
| 180 | The handler function for a file multiplexor is passed three arguments: |
| 181 | the file descriptor for the file, a mode argument which descibes the |
| 182 | file's new condition, and the pointer argument set up at initialization |
| 183 | time. |
| 184 | .PP |
| 185 | The member |
| 186 | .B fd |
| 187 | of the |
| 188 | .B sel_file |
| 189 | structure is exported. It contains the file descriptor in which the |
| 190 | selector is interested. You may not modify this value, but it's useful |
| 191 | to be able to read it out \- it saves having to keep a copy. |
| 192 | .PP |
| 193 | Timer selectors are simpler. There are only two operations provided on |
| 194 | timer selectors: addition and removal. Initialization is performed as |
| 195 | part of the addition operation. |
| 196 | .PP |
| 197 | A timer selector is represented by an object of time |
| 198 | .BR sel_timer . |
| 199 | .PP |
| 200 | The function |
| 201 | .B sel_addtimer |
| 202 | requires lots of arguments: |
| 203 | .TP |
| 204 | .I s |
| 205 | Pointer to the multiplexor to which the selector is to be added. |
| 206 | .TP |
| 207 | .I t |
| 208 | Pointer to the timer selector object being initialized and added. |
| 209 | .TP |
| 210 | .I tv |
| 211 | A |
| 212 | .B "struct timeval" |
| 213 | object describing when the selector should raise its event. This is an |
| 214 | .I absolute |
| 215 | time, not a relative time as required by the traditional |
| 216 | .BR select (2) |
| 217 | and |
| 218 | .BR poll (2) |
| 219 | system calls. |
| 220 | .TP |
| 221 | .I func |
| 222 | A handler function to be called when the event occurs. The function is |
| 223 | passed the |
| 224 | .I current |
| 225 | time, and the arbitrary pointer passed to |
| 226 | .B sel_addtimer |
| 227 | as the |
| 228 | .I p |
| 229 | argument. |
| 230 | .TP |
| 231 | .I p |
| 232 | A pointer passed to |
| 233 | .I func |
| 234 | when the timer event occurs. Beyond this, the value of the pointer is |
| 235 | not inspected. |
| 236 | .PP |
| 237 | The function |
| 238 | .B sel_rmtimer |
| 239 | removes a timer selector. It is passed only the selector object. |
| 240 | .PP |
| 241 | Note that timer events are a one-shot thing. Once they've happened, the |
| 242 | timer selector is removed and the event can't happen again. This is |
| 243 | normally what you want. Removing a timer is only useful (or safe!) |
| 244 | before the timer event has been sent. |
| 245 | .PP |
| 246 | Finally, the function |
| 247 | .B sel_select |
| 248 | is passed a multiplexor object. It waits for something interesting to |
| 249 | happen, informs the appropriate selector handlers, and returns. If |
| 250 | everything went according to plan, |
| 251 | .B sel_select |
| 252 | returns zero. Otherwise it returns -1, and the global variable |
| 253 | .B errno |
| 254 | is set appropriately. |
| 255 | .SH "OTHER NOTES" |
| 256 | Although the naming seems to suggest that this is all |
| 257 | based around the BSD-ish |
| 258 | .BR select (2) |
| 259 | system call (and indeed it is), the interface is actually a good deal |
| 260 | more general than that. An implementation which worked off System V-ish |
| 261 | .BR poll (2) |
| 262 | instead would be fairly trivial to make, and would look just the same |
| 263 | from the outside. |
| 264 | .SH "SEE ALSO" |
| 265 | .BR select (2), |
| 266 | .BR poll (2), |
| 267 | .BR mLib (3). |
| 268 | .SH AUTHOR |
| 269 | Mark Wooding, <mdw@nsict.org> |