/bitcoin/depends/work/build/x86_64-pc-linux-gnu/libevent/2.1.12-stable-7656baec08e/select.c
Line | Count | Source |
1 | | /* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */ |
2 | | |
3 | | /* |
4 | | * Copyright 2000-2007 Niels Provos <provos@citi.umich.edu> |
5 | | * Copyright 2007-2012 Niels Provos and Nick Mathewson |
6 | | * |
7 | | * Redistribution and use in source and binary forms, with or without |
8 | | * modification, are permitted provided that the following conditions |
9 | | * are met: |
10 | | * 1. Redistributions of source code must retain the above copyright |
11 | | * notice, this list of conditions and the following disclaimer. |
12 | | * 2. Redistributions in binary form must reproduce the above copyright |
13 | | * notice, this list of conditions and the following disclaimer in the |
14 | | * documentation and/or other materials provided with the distribution. |
15 | | * 3. The name of the author may not be used to endorse or promote products |
16 | | * derived from this software without specific prior written permission. |
17 | | * |
18 | | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR |
19 | | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES |
20 | | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
21 | | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, |
22 | | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT |
23 | | * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
24 | | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
25 | | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
26 | | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
27 | | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
28 | | */ |
29 | | #include "event2/event-config.h" |
30 | | #include "evconfig-private.h" |
31 | | |
32 | | #ifdef EVENT__HAVE_SELECT |
33 | | |
34 | | #ifdef __APPLE__ |
35 | | /* Apple wants us to define this if we might ever pass more than |
36 | | * FD_SETSIZE bits to select(). */ |
37 | | #define _DARWIN_UNLIMITED_SELECT |
38 | | #endif |
39 | | |
40 | | #include <sys/types.h> |
41 | | #ifdef EVENT__HAVE_SYS_TIME_H |
42 | | #include <sys/time.h> |
43 | | #endif |
44 | | #ifdef EVENT__HAVE_SYS_SELECT_H |
45 | | #include <sys/select.h> |
46 | | #endif |
47 | | #include <sys/queue.h> |
48 | | #include <signal.h> |
49 | | #include <stdio.h> |
50 | | #include <stdlib.h> |
51 | | #include <string.h> |
52 | | #include <unistd.h> |
53 | | #include <errno.h> |
54 | | |
55 | | #include "event-internal.h" |
56 | | #include "evsignal-internal.h" |
57 | | #include "event2/thread.h" |
58 | | #include "evthread-internal.h" |
59 | | #include "log-internal.h" |
60 | | #include "evmap-internal.h" |
61 | | |
62 | | #ifndef EVENT__HAVE_FD_MASK |
63 | | /* This type is mandatory, but Android doesn't define it. */ |
64 | | typedef unsigned long fd_mask; |
65 | | #endif |
66 | | |
67 | | #ifndef NFDBITS |
68 | | #define NFDBITS (sizeof(fd_mask)*8) |
69 | | #endif |
70 | | |
71 | | /* Divide positive x by y, rounding up. */ |
72 | 0 | #define DIV_ROUNDUP(x, y) (((x)+((y)-1))/(y)) |
73 | | |
74 | | /* How many bytes to allocate for N fds? */ |
75 | | #define SELECT_ALLOC_SIZE(n) \ |
76 | 0 | (DIV_ROUNDUP(n, NFDBITS) * sizeof(fd_mask)) |
77 | | |
78 | | struct selectop { |
79 | | int event_fds; /* Highest fd in fd set */ |
80 | | int event_fdsz; |
81 | | int resize_out_sets; |
82 | | fd_set *event_readset_in; |
83 | | fd_set *event_writeset_in; |
84 | | fd_set *event_readset_out; |
85 | | fd_set *event_writeset_out; |
86 | | }; |
87 | | |
88 | | static void *select_init(struct event_base *); |
89 | | static int select_add(struct event_base *, int, short old, short events, void*); |
90 | | static int select_del(struct event_base *, int, short old, short events, void*); |
91 | | static int select_dispatch(struct event_base *, struct timeval *); |
92 | | static void select_dealloc(struct event_base *); |
93 | | |
94 | | const struct eventop selectops = { |
95 | | "select", |
96 | | select_init, |
97 | | select_add, |
98 | | select_del, |
99 | | select_dispatch, |
100 | | select_dealloc, |
101 | | 1, /* need_reinit. */ |
102 | | EV_FEATURE_FDS, |
103 | | 0, |
104 | | }; |
105 | | |
106 | | static int select_resize(struct selectop *sop, int fdsz); |
107 | | static void select_free_selectop(struct selectop *sop); |
108 | | |
109 | | static void * |
110 | | select_init(struct event_base *base) |
111 | 0 | { |
112 | 0 | struct selectop *sop; |
113 | |
|
114 | 0 | if (!(sop = mm_calloc(1, sizeof(struct selectop)))) Branch (114:6): [True: 0, False: 0]
|
115 | 0 | return (NULL); |
116 | | |
117 | 0 | if (select_resize(sop, SELECT_ALLOC_SIZE(32 + 1))) { Branch (117:6): [True: 0, False: 0]
|
118 | 0 | select_free_selectop(sop); |
119 | 0 | return (NULL); |
120 | 0 | } |
121 | | |
122 | 0 | evsig_init_(base); |
123 | |
|
124 | 0 | evutil_weakrand_seed_(&base->weakrand_seed, 0); |
125 | |
|
126 | 0 | return (sop); |
127 | 0 | } |
128 | | |
129 | | #ifdef CHECK_INVARIANTS |
130 | | static void |
131 | | check_selectop(struct selectop *sop) |
132 | | { |
133 | | /* nothing to be done here */ |
134 | | } |
135 | | #else |
136 | 0 | #define check_selectop(sop) do { (void) sop; } while (0) |
137 | | #endif |
138 | | |
139 | | static int |
140 | | select_dispatch(struct event_base *base, struct timeval *tv) |
141 | 0 | { |
142 | 0 | int res=0, i, j, nfds; |
143 | 0 | struct selectop *sop = base->evbase; |
144 | |
|
145 | 0 | check_selectop(sop); |
146 | 0 | if (sop->resize_out_sets) { Branch (146:6): [True: 0, False: 0]
|
147 | 0 | fd_set *readset_out=NULL, *writeset_out=NULL; |
148 | 0 | size_t sz = sop->event_fdsz; |
149 | 0 | if (!(readset_out = mm_realloc(sop->event_readset_out, sz))) Branch (149:7): [True: 0, False: 0]
|
150 | 0 | return (-1); |
151 | 0 | sop->event_readset_out = readset_out; |
152 | 0 | if (!(writeset_out = mm_realloc(sop->event_writeset_out, sz))) { Branch (152:7): [True: 0, False: 0]
|
153 | | /* We don't free readset_out here, since it was |
154 | | * already successfully reallocated. The next time |
155 | | * we call select_dispatch, the realloc will be a |
156 | | * no-op. */ |
157 | 0 | return (-1); |
158 | 0 | } |
159 | 0 | sop->event_writeset_out = writeset_out; |
160 | 0 | sop->resize_out_sets = 0; |
161 | 0 | } |
162 | | |
163 | 0 | memcpy(sop->event_readset_out, sop->event_readset_in, |
164 | 0 | sop->event_fdsz); |
165 | 0 | memcpy(sop->event_writeset_out, sop->event_writeset_in, |
166 | 0 | sop->event_fdsz); |
167 | |
|
168 | 0 | nfds = sop->event_fds+1; |
169 | |
|
170 | 0 | EVBASE_RELEASE_LOCK(base, th_base_lock); |
171 | |
|
172 | 0 | res = select(nfds, sop->event_readset_out, |
173 | 0 | sop->event_writeset_out, NULL, tv); |
174 | |
|
175 | 0 | EVBASE_ACQUIRE_LOCK(base, th_base_lock); |
176 | |
|
177 | 0 | check_selectop(sop); |
178 | |
|
179 | 0 | if (res == -1) { Branch (179:6): [True: 0, False: 0]
|
180 | 0 | if (errno != EINTR) { Branch (180:7): [True: 0, False: 0]
|
181 | 0 | event_warn("select"); |
182 | 0 | return (-1); |
183 | 0 | } |
184 | | |
185 | 0 | return (0); |
186 | 0 | } |
187 | | |
188 | 0 | event_debug(("%s: select reports %d", __func__, res)); |
189 | |
|
190 | 0 | check_selectop(sop); |
191 | 0 | i = evutil_weakrand_range_(&base->weakrand_seed, nfds); |
192 | 0 | for (j = 0; j < nfds; ++j) { Branch (192:14): [True: 0, False: 0]
|
193 | 0 | if (++i >= nfds) Branch (193:7): [True: 0, False: 0]
|
194 | 0 | i = 0; |
195 | 0 | res = 0; |
196 | 0 | if (FD_ISSET(i, sop->event_readset_out)) Branch (196:7): [True: 0, False: 0]
|
197 | 0 | res |= EV_READ; |
198 | 0 | if (FD_ISSET(i, sop->event_writeset_out)) Branch (198:7): [True: 0, False: 0]
|
199 | 0 | res |= EV_WRITE; |
200 | |
|
201 | 0 | if (res == 0) Branch (201:7): [True: 0, False: 0]
|
202 | 0 | continue; |
203 | | |
204 | 0 | evmap_io_active_(base, i, res); |
205 | 0 | } |
206 | 0 | check_selectop(sop); |
207 | |
|
208 | 0 | return (0); |
209 | 0 | } |
210 | | |
211 | | static int |
212 | | select_resize(struct selectop *sop, int fdsz) |
213 | 0 | { |
214 | 0 | fd_set *readset_in = NULL; |
215 | 0 | fd_set *writeset_in = NULL; |
216 | |
|
217 | 0 | if (sop->event_readset_in) Branch (217:6): [True: 0, False: 0]
|
218 | 0 | check_selectop(sop); |
219 | |
|
220 | 0 | if ((readset_in = mm_realloc(sop->event_readset_in, fdsz)) == NULL) Branch (220:6): [True: 0, False: 0]
|
221 | 0 | goto error; |
222 | 0 | sop->event_readset_in = readset_in; |
223 | 0 | if ((writeset_in = mm_realloc(sop->event_writeset_in, fdsz)) == NULL) { Branch (223:6): [True: 0, False: 0]
|
224 | | /* Note that this will leave event_readset_in expanded. |
225 | | * That's okay; we wouldn't want to free it, since that would |
226 | | * change the semantics of select_resize from "expand the |
227 | | * readset_in and writeset_in, or return -1" to "expand the |
228 | | * *set_in members, or trash them and return -1." |
229 | | */ |
230 | 0 | goto error; |
231 | 0 | } |
232 | 0 | sop->event_writeset_in = writeset_in; |
233 | 0 | sop->resize_out_sets = 1; |
234 | |
|
235 | 0 | memset((char *)sop->event_readset_in + sop->event_fdsz, 0, |
236 | 0 | fdsz - sop->event_fdsz); |
237 | 0 | memset((char *)sop->event_writeset_in + sop->event_fdsz, 0, |
238 | 0 | fdsz - sop->event_fdsz); |
239 | |
|
240 | 0 | sop->event_fdsz = fdsz; |
241 | 0 | check_selectop(sop); |
242 | |
|
243 | 0 | return (0); |
244 | | |
245 | 0 | error: |
246 | 0 | event_warn("malloc"); |
247 | 0 | return (-1); |
248 | 0 | } |
249 | | |
250 | | |
251 | | static int |
252 | | select_add(struct event_base *base, int fd, short old, short events, void *p) |
253 | 0 | { |
254 | 0 | struct selectop *sop = base->evbase; |
255 | 0 | (void) p; |
256 | |
|
257 | 0 | EVUTIL_ASSERT((events & EV_SIGNAL) == 0); |
258 | 0 | check_selectop(sop); |
259 | | /* |
260 | | * Keep track of the highest fd, so that we can calculate the size |
261 | | * of the fd_sets for select(2) |
262 | | */ |
263 | 0 | if (sop->event_fds < fd) { Branch (263:6): [True: 0, False: 0]
|
264 | 0 | int fdsz = sop->event_fdsz; |
265 | |
|
266 | 0 | if (fdsz < (int)sizeof(fd_mask)) Branch (266:7): [True: 0, False: 0]
|
267 | 0 | fdsz = (int)sizeof(fd_mask); |
268 | | |
269 | | /* In theory we should worry about overflow here. In |
270 | | * reality, though, the highest fd on a unixy system will |
271 | | * not overflow here. XXXX */ |
272 | 0 | while (fdsz < (int) SELECT_ALLOC_SIZE(fd + 1)) Branch (272:10): [True: 0, False: 0]
|
273 | 0 | fdsz *= 2; |
274 | |
|
275 | 0 | if (fdsz != sop->event_fdsz) { Branch (275:7): [True: 0, False: 0]
|
276 | 0 | if (select_resize(sop, fdsz)) { Branch (276:8): [True: 0, False: 0]
|
277 | 0 | check_selectop(sop); |
278 | 0 | return (-1); |
279 | 0 | } |
280 | 0 | } |
281 | | |
282 | 0 | sop->event_fds = fd; |
283 | 0 | } |
284 | | |
285 | 0 | if (events & EV_READ) Branch (285:6): [True: 0, False: 0]
|
286 | 0 | FD_SET(fd, sop->event_readset_in); |
287 | 0 | if (events & EV_WRITE) Branch (287:6): [True: 0, False: 0]
|
288 | 0 | FD_SET(fd, sop->event_writeset_in); |
289 | 0 | check_selectop(sop); |
290 | |
|
291 | 0 | return (0); |
292 | 0 | } |
293 | | |
294 | | /* |
295 | | * Nothing to be done here. |
296 | | */ |
297 | | |
298 | | static int |
299 | | select_del(struct event_base *base, int fd, short old, short events, void *p) |
300 | 0 | { |
301 | 0 | struct selectop *sop = base->evbase; |
302 | 0 | (void)p; |
303 | |
|
304 | 0 | EVUTIL_ASSERT((events & EV_SIGNAL) == 0); |
305 | 0 | check_selectop(sop); |
306 | |
|
307 | 0 | if (sop->event_fds < fd) { Branch (307:6): [True: 0, False: 0]
|
308 | 0 | check_selectop(sop); |
309 | 0 | return (0); |
310 | 0 | } |
311 | | |
312 | 0 | if (events & EV_READ) Branch (312:6): [True: 0, False: 0]
|
313 | 0 | FD_CLR(fd, sop->event_readset_in); |
314 | |
|
315 | 0 | if (events & EV_WRITE) Branch (315:6): [True: 0, False: 0]
|
316 | 0 | FD_CLR(fd, sop->event_writeset_in); |
317 | |
|
318 | 0 | check_selectop(sop); |
319 | 0 | return (0); |
320 | 0 | } |
321 | | |
322 | | static void |
323 | | select_free_selectop(struct selectop *sop) |
324 | 0 | { |
325 | 0 | if (sop->event_readset_in) Branch (325:6): [True: 0, False: 0]
|
326 | 0 | mm_free(sop->event_readset_in); |
327 | 0 | if (sop->event_writeset_in) Branch (327:6): [True: 0, False: 0]
|
328 | 0 | mm_free(sop->event_writeset_in); |
329 | 0 | if (sop->event_readset_out) Branch (329:6): [True: 0, False: 0]
|
330 | 0 | mm_free(sop->event_readset_out); |
331 | 0 | if (sop->event_writeset_out) Branch (331:6): [True: 0, False: 0]
|
332 | 0 | mm_free(sop->event_writeset_out); |
333 | |
|
334 | 0 | memset(sop, 0, sizeof(struct selectop)); |
335 | 0 | mm_free(sop); |
336 | 0 | } |
337 | | |
338 | | static void |
339 | | select_dealloc(struct event_base *base) |
340 | 0 | { |
341 | 0 | evsig_dealloc_(base); |
342 | |
|
343 | 0 | select_free_selectop(base->evbase); |
344 | 0 | } |
345 | | |
346 | | #endif /* EVENT__HAVE_SELECT */ |