b6b9d458 |
1 | .\" -*-nroff-*- |
08da152e |
2 | .TH sel 3 "22 May 1999" mLib |
b6b9d458 |
3 | .SH NAME |
4 | sel \- low level interface for waiting for I/O |
08da152e |
5 | .\" @sel_init |
6 | .\" @sel_initfile |
7 | .\" @sel_addfile |
8 | .\" @sel_rmfile |
9 | .\" @sel_addtimer |
10 | .\" @sel_rmtimer |
11 | .\" @sel_select |
b6b9d458 |
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 |
08da152e |
99 | .BR selbuf (3) |
b6b9d458 |
100 | and |
08da152e |
101 | .BR conn (3). |
b6b9d458 |
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. |
08da152e |
264 | .SH "SEE ALSO" |
265 | .BR select (2), |
266 | .BR poll (2), |
267 | .BR mLib (3). |
b6b9d458 |
268 | .SH AUTHOR |
269 | Mark Wooding, <mdw@nsict.org> |