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