1 /* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
4 * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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.
33 #include <sys/types.h>
34 #ifdef HAVE_SYS_TIME_H
37 #include <sys/_libevent_time.h>
39 #ifdef HAVE_SYS_SELECT_H
40 #include <sys/select.h>
42 #include <sys/queue.h>
49 #ifdef CHECK_INVARIANTS
55 #include "event-internal.h"
60 #define howmany(x, y) (((x)+((y)-1))/(y))
63 #ifndef _EVENT_HAVE_FD_MASK
64 /* This type is mandatory, but Android doesn't define it. */
66 #define NFDBITS (sizeof(long)*8)
67 typedef unsigned long fd_mask
;
71 int event_fds
; /* Highest fd in fd set */
73 fd_set
*event_readset_in
;
74 fd_set
*event_writeset_in
;
75 fd_set
*event_readset_out
;
76 fd_set
*event_writeset_out
;
77 struct event
**event_r_by_fd
;
78 struct event
**event_w_by_fd
;
81 static void *select_init (struct event_base
*);
82 static int select_add (void *, struct event
*);
83 static int select_del (void *, struct event
*);
84 static int select_dispatch (struct event_base
*, void *, struct timeval
*);
85 static void select_dealloc (struct event_base
*, void *);
87 const struct eventop selectops
= {
97 static int select_resize(struct selectop
*sop
, int fdsz
);
100 select_init(struct event_base
*base
)
102 struct selectop
*sop
;
104 /* Disable select when this environment variable is set */
105 if (evutil_getenv("EVENT_NOSELECT"))
108 if (!(sop
= calloc(1, sizeof(struct selectop
))))
111 select_resize(sop
, howmany(32 + 1, NFDBITS
)*sizeof(fd_mask
));
118 #ifdef CHECK_INVARIANTS
120 check_selectop(struct selectop
*sop
)
123 for (i
= 0; i
<= sop
->event_fds
; ++i
) {
124 if (FD_ISSET(i
, sop
->event_readset_in
)) {
125 assert(sop
->event_r_by_fd
[i
]);
126 assert(sop
->event_r_by_fd
[i
]->ev_events
& EV_READ
);
127 assert(sop
->event_r_by_fd
[i
]->ev_fd
== i
);
129 assert(! sop
->event_r_by_fd
[i
]);
131 if (FD_ISSET(i
, sop
->event_writeset_in
)) {
132 assert(sop
->event_w_by_fd
[i
]);
133 assert(sop
->event_w_by_fd
[i
]->ev_events
& EV_WRITE
);
134 assert(sop
->event_w_by_fd
[i
]->ev_fd
== i
);
136 assert(! sop
->event_w_by_fd
[i
]);
142 #define check_selectop(sop) do { (void) sop; } while (0)
146 select_dispatch(struct event_base
*base
, void *arg
, struct timeval
*tv
)
149 struct selectop
*sop
= arg
;
153 memcpy(sop
->event_readset_out
, sop
->event_readset_in
,
155 memcpy(sop
->event_writeset_out
, sop
->event_writeset_in
,
158 res
= select(sop
->event_fds
+ 1, sop
->event_readset_out
,
159 sop
->event_writeset_out
, NULL
, tv
);
164 if (errno
!= EINTR
) {
165 event_warn("select");
169 evsignal_process(base
);
171 } else if (base
->sig
.evsignal_caught
) {
172 evsignal_process(base
);
175 event_debug(("%s: select reports %d", __func__
, res
));
178 i
= random() % (sop
->event_fds
+1);
179 for (j
= 0; j
<= sop
->event_fds
; ++j
) {
180 struct event
*r_ev
= NULL
, *w_ev
= NULL
;
181 if (++i
>= sop
->event_fds
+1)
185 if (FD_ISSET(i
, sop
->event_readset_out
)) {
186 r_ev
= sop
->event_r_by_fd
[i
];
189 if (FD_ISSET(i
, sop
->event_writeset_out
)) {
190 w_ev
= sop
->event_w_by_fd
[i
];
193 if (r_ev
&& (res
& r_ev
->ev_events
)) {
194 event_active(r_ev
, res
& r_ev
->ev_events
, 1);
196 if (w_ev
&& w_ev
!= r_ev
&& (res
& w_ev
->ev_events
)) {
197 event_active(w_ev
, res
& w_ev
->ev_events
, 1);
207 select_resize(struct selectop
*sop
, int fdsz
)
209 int n_events
, n_events_old
;
211 fd_set
*readset_in
= NULL
;
212 fd_set
*writeset_in
= NULL
;
213 fd_set
*readset_out
= NULL
;
214 fd_set
*writeset_out
= NULL
;
215 struct event
**r_by_fd
= NULL
;
216 struct event
**w_by_fd
= NULL
;
218 n_events
= (fdsz
/sizeof(fd_mask
)) * NFDBITS
;
219 n_events_old
= (sop
->event_fdsz
/sizeof(fd_mask
)) * NFDBITS
;
221 if (sop
->event_readset_in
)
224 if ((readset_in
= realloc(sop
->event_readset_in
, fdsz
)) == NULL
)
226 sop
->event_readset_in
= readset_in
;
227 if ((readset_out
= realloc(sop
->event_readset_out
, fdsz
)) == NULL
)
229 sop
->event_readset_out
= readset_out
;
230 if ((writeset_in
= realloc(sop
->event_writeset_in
, fdsz
)) == NULL
)
232 sop
->event_writeset_in
= writeset_in
;
233 if ((writeset_out
= realloc(sop
->event_writeset_out
, fdsz
)) == NULL
)
235 sop
->event_writeset_out
= writeset_out
;
236 if ((r_by_fd
= realloc(sop
->event_r_by_fd
,
237 n_events
*sizeof(struct event
*))) == NULL
)
239 sop
->event_r_by_fd
= r_by_fd
;
240 if ((w_by_fd
= realloc(sop
->event_w_by_fd
,
241 n_events
* sizeof(struct event
*))) == NULL
)
243 sop
->event_w_by_fd
= w_by_fd
;
245 memset((char *)sop
->event_readset_in
+ sop
->event_fdsz
, 0,
246 fdsz
- sop
->event_fdsz
);
247 memset((char *)sop
->event_writeset_in
+ sop
->event_fdsz
, 0,
248 fdsz
- sop
->event_fdsz
);
249 memset(sop
->event_r_by_fd
+ n_events_old
, 0,
250 (n_events
-n_events_old
) * sizeof(struct event
*));
251 memset(sop
->event_w_by_fd
+ n_events_old
, 0,
252 (n_events
-n_events_old
) * sizeof(struct event
*));
254 sop
->event_fdsz
= fdsz
;
260 event_warn("malloc");
266 select_add(void *arg
, struct event
*ev
)
268 struct selectop
*sop
= arg
;
270 if (ev
->ev_events
& EV_SIGNAL
)
271 return (evsignal_add(ev
));
275 * Keep track of the highest fd, so that we can calculate the size
276 * of the fd_sets for select(2)
278 if (sop
->event_fds
< ev
->ev_fd
) {
279 int fdsz
= sop
->event_fdsz
;
281 if (fdsz
< sizeof(fd_mask
))
282 fdsz
= sizeof(fd_mask
);
285 (howmany(ev
->ev_fd
+ 1, NFDBITS
) * sizeof(fd_mask
)))
288 if (fdsz
!= sop
->event_fdsz
) {
289 if (select_resize(sop
, fdsz
)) {
295 sop
->event_fds
= ev
->ev_fd
;
298 if (ev
->ev_events
& EV_READ
) {
299 FD_SET(ev
->ev_fd
, sop
->event_readset_in
);
300 sop
->event_r_by_fd
[ev
->ev_fd
] = ev
;
302 if (ev
->ev_events
& EV_WRITE
) {
303 FD_SET(ev
->ev_fd
, sop
->event_writeset_in
);
304 sop
->event_w_by_fd
[ev
->ev_fd
] = ev
;
312 * Nothing to be done here.
316 select_del(void *arg
, struct event
*ev
)
318 struct selectop
*sop
= arg
;
321 if (ev
->ev_events
& EV_SIGNAL
)
322 return (evsignal_del(ev
));
324 if (sop
->event_fds
< ev
->ev_fd
) {
329 if (ev
->ev_events
& EV_READ
) {
330 FD_CLR(ev
->ev_fd
, sop
->event_readset_in
);
331 sop
->event_r_by_fd
[ev
->ev_fd
] = NULL
;
334 if (ev
->ev_events
& EV_WRITE
) {
335 FD_CLR(ev
->ev_fd
, sop
->event_writeset_in
);
336 sop
->event_w_by_fd
[ev
->ev_fd
] = NULL
;
344 select_dealloc(struct event_base
*base
, void *arg
)
346 struct selectop
*sop
= arg
;
348 evsignal_dealloc(base
);
349 if (sop
->event_readset_in
)
350 free(sop
->event_readset_in
);
351 if (sop
->event_writeset_in
)
352 free(sop
->event_writeset_in
);
353 if (sop
->event_readset_out
)
354 free(sop
->event_readset_out
);
355 if (sop
->event_writeset_out
)
356 free(sop
->event_writeset_out
);
357 if (sop
->event_r_by_fd
)
358 free(sop
->event_r_by_fd
);
359 if (sop
->event_w_by_fd
)
360 free(sop
->event_w_by_fd
);
362 memset(sop
, 0, sizeof(struct selectop
));