2 /* $OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $ */
5 * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 #include <sys/types.h>
35 #ifdef HAVE_SYS_TIME_H
38 #include <sys/_time.h>
40 #ifdef HAVE_SYS_SELECT_H
41 #include <sys/select.h>
43 #include <sys/queue.h>
50 #ifdef CHECK_INVARIANTS
55 #include "event-internal.h"
60 #define howmany(x, y) (((x)+((y)-1))/(y))
64 int event_fds
; /* Highest fd in fd set */
66 fd_set
*event_readset_in
;
67 fd_set
*event_writeset_in
;
68 fd_set
*event_readset_out
;
69 fd_set
*event_writeset_out
;
70 struct event
**event_r_by_fd
;
71 struct event
**event_w_by_fd
;
74 static void *select_init (struct event_base
*);
75 static int select_add (void *, struct event
*);
76 static int select_del (void *, struct event
*);
77 static int select_dispatch (struct event_base
*, void *, struct timeval
*);
78 static void select_dealloc (struct event_base
*, void *);
80 const struct eventop selectops
= {
90 static int select_resize(struct selectop
*sop
, int fdsz
);
93 select_init(struct event_base
*base
)
97 /* Disable select when this environment variable is set */
98 if (getenv("EVENT_NOSELECT"))
101 if (!(sop
= calloc(1, sizeof(struct selectop
))))
104 select_resize(sop
, howmany(32 + 1, NFDBITS
)*sizeof(fd_mask
));
111 #ifdef CHECK_INVARIANTS
113 check_selectop(struct selectop
*sop
)
116 for (i
= 0; i
<= sop
->event_fds
; ++i
) {
117 if (FD_ISSET(i
, sop
->event_readset_in
)) {
118 assert(sop
->event_r_by_fd
[i
]);
119 assert(sop
->event_r_by_fd
[i
]->ev_events
& EV_READ
);
120 assert(sop
->event_r_by_fd
[i
]->ev_fd
== i
);
122 assert(! sop
->event_r_by_fd
[i
]);
124 if (FD_ISSET(i
, sop
->event_writeset_in
)) {
125 assert(sop
->event_w_by_fd
[i
]);
126 assert(sop
->event_w_by_fd
[i
]->ev_events
& EV_WRITE
);
127 assert(sop
->event_w_by_fd
[i
]->ev_fd
== i
);
129 assert(! sop
->event_w_by_fd
[i
]);
135 #define check_selectop(sop) do { (void) sop; } while (0)
139 select_dispatch(struct event_base
*base
, void *arg
, struct timeval
*tv
)
142 struct selectop
*sop
= arg
;
146 memcpy(sop
->event_readset_out
, sop
->event_readset_in
,
148 memcpy(sop
->event_writeset_out
, sop
->event_writeset_in
,
151 res
= select(sop
->event_fds
+ 1, sop
->event_readset_out
,
152 sop
->event_writeset_out
, NULL
, tv
);
157 if (errno
!= EINTR
) {
158 event_warn("select");
162 evsignal_process(base
);
164 } else if (base
->sig
.evsignal_caught
) {
165 evsignal_process(base
);
168 event_debug(("%s: select reports %d", __func__
, res
));
171 i
= random() % (sop
->event_fds
+1);
172 for (j
= 0; j
<= sop
->event_fds
; ++j
) {
173 struct event
*r_ev
= NULL
, *w_ev
= NULL
;
174 if (++i
>= sop
->event_fds
+1)
178 if (FD_ISSET(i
, sop
->event_readset_out
)) {
179 r_ev
= sop
->event_r_by_fd
[i
];
182 if (FD_ISSET(i
, sop
->event_writeset_out
)) {
183 w_ev
= sop
->event_w_by_fd
[i
];
186 if (r_ev
&& (res
& r_ev
->ev_events
)) {
187 event_active(r_ev
, res
& r_ev
->ev_events
, 1);
189 if (w_ev
&& w_ev
!= r_ev
&& (res
& w_ev
->ev_events
)) {
190 event_active(w_ev
, res
& w_ev
->ev_events
, 1);
200 select_resize(struct selectop
*sop
, int fdsz
)
202 int n_events
, n_events_old
;
204 fd_set
*readset_in
= NULL
;
205 fd_set
*writeset_in
= NULL
;
206 fd_set
*readset_out
= NULL
;
207 fd_set
*writeset_out
= NULL
;
208 struct event
**r_by_fd
= NULL
;
209 struct event
**w_by_fd
= NULL
;
211 n_events
= (fdsz
/sizeof(fd_mask
)) * NFDBITS
;
212 n_events_old
= (sop
->event_fdsz
/sizeof(fd_mask
)) * NFDBITS
;
214 if (sop
->event_readset_in
)
217 if ((readset_in
= realloc(sop
->event_readset_in
, fdsz
)) == NULL
)
219 sop
->event_readset_in
= readset_in
;
220 if ((readset_out
= realloc(sop
->event_readset_out
, fdsz
)) == NULL
)
222 sop
->event_readset_out
= readset_out
;
223 if ((writeset_in
= realloc(sop
->event_writeset_in
, fdsz
)) == NULL
)
225 sop
->event_writeset_in
= writeset_in
;
226 if ((writeset_out
= realloc(sop
->event_writeset_out
, fdsz
)) == NULL
)
228 sop
->event_writeset_out
= writeset_out
;
229 if ((r_by_fd
= realloc(sop
->event_r_by_fd
,
230 n_events
*sizeof(struct event
*))) == NULL
)
232 sop
->event_r_by_fd
= r_by_fd
;
233 if ((w_by_fd
= realloc(sop
->event_w_by_fd
,
234 n_events
* sizeof(struct event
*))) == NULL
)
236 sop
->event_w_by_fd
= w_by_fd
;
238 memset((char *)sop
->event_readset_in
+ sop
->event_fdsz
, 0,
239 fdsz
- sop
->event_fdsz
);
240 memset((char *)sop
->event_writeset_in
+ sop
->event_fdsz
, 0,
241 fdsz
- sop
->event_fdsz
);
242 memset(sop
->event_r_by_fd
+ n_events_old
, 0,
243 (n_events
-n_events_old
) * sizeof(struct event
*));
244 memset(sop
->event_w_by_fd
+ n_events_old
, 0,
245 (n_events
-n_events_old
) * sizeof(struct event
*));
247 sop
->event_fdsz
= fdsz
;
253 event_warn("malloc");
259 select_add(void *arg
, struct event
*ev
)
261 struct selectop
*sop
= arg
;
263 if (ev
->ev_events
& EV_SIGNAL
)
264 return (evsignal_add(ev
));
268 * Keep track of the highest fd, so that we can calculate the size
269 * of the fd_sets for select(2)
271 if (sop
->event_fds
< ev
->ev_fd
) {
272 int fdsz
= sop
->event_fdsz
;
274 if (fdsz
< sizeof(fd_mask
))
275 fdsz
= sizeof(fd_mask
);
278 (howmany(ev
->ev_fd
+ 1, NFDBITS
) * sizeof(fd_mask
)))
281 if (fdsz
!= sop
->event_fdsz
) {
282 if (select_resize(sop
, fdsz
)) {
288 sop
->event_fds
= ev
->ev_fd
;
291 if (ev
->ev_events
& EV_READ
) {
292 FD_SET(ev
->ev_fd
, sop
->event_readset_in
);
293 sop
->event_r_by_fd
[ev
->ev_fd
] = ev
;
295 if (ev
->ev_events
& EV_WRITE
) {
296 FD_SET(ev
->ev_fd
, sop
->event_writeset_in
);
297 sop
->event_w_by_fd
[ev
->ev_fd
] = ev
;
305 * Nothing to be done here.
309 select_del(void *arg
, struct event
*ev
)
311 struct selectop
*sop
= arg
;
314 if (ev
->ev_events
& EV_SIGNAL
)
315 return (evsignal_del(ev
));
317 if (sop
->event_fds
< ev
->ev_fd
) {
322 if (ev
->ev_events
& EV_READ
) {
323 FD_CLR(ev
->ev_fd
, sop
->event_readset_in
);
324 sop
->event_r_by_fd
[ev
->ev_fd
] = NULL
;
327 if (ev
->ev_events
& EV_WRITE
) {
328 FD_CLR(ev
->ev_fd
, sop
->event_writeset_in
);
329 sop
->event_w_by_fd
[ev
->ev_fd
] = NULL
;
337 select_dealloc(struct event_base
*base
, void *arg
)
339 struct selectop
*sop
= arg
;
341 evsignal_dealloc(base
);
342 if (sop
->event_readset_in
)
343 free(sop
->event_readset_in
);
344 if (sop
->event_writeset_in
)
345 free(sop
->event_writeset_in
);
346 if (sop
->event_readset_out
)
347 free(sop
->event_readset_out
);
348 if (sop
->event_writeset_out
)
349 free(sop
->event_writeset_out
);
350 if (sop
->event_r_by_fd
)
351 free(sop
->event_r_by_fd
);
352 if (sop
->event_w_by_fd
)
353 free(sop
->event_w_by_fd
);
355 memset(sop
, 0, sizeof(struct selectop
));