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/_time.h>
39 #ifdef HAVE_SYS_SELECT_H
40 #include <sys/select.h>
42 #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 void *select_init (struct event_base
*);
75 int select_add (void *, struct event
*);
76 int select_del (void *, struct event
*);
77 int select_recalc (struct event_base
*, void *, int);
78 int select_dispatch (struct event_base
*, void *, struct timeval
*);
79 void select_dealloc (struct event_base
*, void *);
81 const struct eventop selectops
= {
91 static int select_resize(struct selectop
*sop
, int fdsz
);
94 select_init(struct event_base
*base
)
98 /* Disable select when this environment variable is set */
99 if (getenv("EVENT_NOSELECT"))
102 if (!(sop
= calloc(1, sizeof(struct selectop
))))
105 select_resize(sop
, howmany(32 + 1, NFDBITS
)*sizeof(fd_mask
));
112 #ifdef CHECK_INVARIANTS
114 check_selectop(struct selectop
*sop
)
117 for (i
= 0; i
<= sop
->event_fds
; ++i
) {
118 if (FD_ISSET(i
, sop
->event_readset_in
)) {
119 assert(sop
->event_r_by_fd
[i
]);
120 assert(sop
->event_r_by_fd
[i
]->ev_events
& EV_READ
);
121 assert(sop
->event_r_by_fd
[i
]->ev_fd
== i
);
123 assert(! sop
->event_r_by_fd
[i
]);
125 if (FD_ISSET(i
, sop
->event_writeset_in
)) {
126 assert(sop
->event_w_by_fd
[i
]);
127 assert(sop
->event_w_by_fd
[i
]->ev_events
& EV_WRITE
);
128 assert(sop
->event_w_by_fd
[i
]->ev_fd
== i
);
130 assert(! sop
->event_w_by_fd
[i
]);
136 #define check_selectop(sop) do { (void) sop; } while (0)
140 * Called with the highest fd that we know about. If it is 0, completely
141 * recalculate everything.
145 select_recalc(struct event_base
*base
, void *arg
, int max
)
147 struct selectop
*sop
= arg
;
155 select_dispatch(struct event_base
*base
, void *arg
, struct timeval
*tv
)
158 struct selectop
*sop
= arg
;
162 memcpy(sop
->event_readset_out
, sop
->event_readset_in
,
164 memcpy(sop
->event_writeset_out
, sop
->event_writeset_in
,
167 res
= select(sop
->event_fds
+ 1, sop
->event_readset_out
,
168 sop
->event_writeset_out
, NULL
, tv
);
173 if (errno
!= EINTR
) {
174 event_warn("select");
178 evsignal_process(base
);
180 } else if (base
->sig
.evsignal_caught
) {
181 evsignal_process(base
);
184 event_debug(("%s: select reports %d", __func__
, res
));
187 for (i
= 0; i
<= sop
->event_fds
; ++i
) {
188 struct event
*r_ev
= NULL
, *w_ev
= NULL
;
190 if (FD_ISSET(i
, sop
->event_readset_out
)) {
191 r_ev
= sop
->event_r_by_fd
[i
];
194 if (FD_ISSET(i
, sop
->event_writeset_out
)) {
195 w_ev
= sop
->event_w_by_fd
[i
];
198 if (r_ev
&& (res
& r_ev
->ev_events
)) {
199 if (!(r_ev
->ev_events
& EV_PERSIST
))
201 event_active(r_ev
, res
& r_ev
->ev_events
, 1);
203 if (w_ev
&& w_ev
!= r_ev
&& (res
& w_ev
->ev_events
)) {
204 if (!(w_ev
->ev_events
& EV_PERSIST
))
206 event_active(w_ev
, res
& w_ev
->ev_events
, 1);
216 select_resize(struct selectop
*sop
, int fdsz
)
218 int n_events
, n_events_old
;
220 fd_set
*readset_in
= NULL
;
221 fd_set
*writeset_in
= NULL
;
222 fd_set
*readset_out
= NULL
;
223 fd_set
*writeset_out
= NULL
;
224 struct event
**r_by_fd
= NULL
;
225 struct event
**w_by_fd
= NULL
;
227 n_events
= (fdsz
/sizeof(fd_mask
)) * NFDBITS
;
228 n_events_old
= (sop
->event_fdsz
/sizeof(fd_mask
)) * NFDBITS
;
230 if (sop
->event_readset_in
)
233 if ((readset_in
= realloc(sop
->event_readset_in
, fdsz
)) == NULL
)
235 sop
->event_readset_in
= readset_in
;
236 if ((readset_out
= realloc(sop
->event_readset_out
, fdsz
)) == NULL
)
238 sop
->event_readset_out
= readset_out
;
239 if ((writeset_in
= realloc(sop
->event_writeset_in
, fdsz
)) == NULL
)
241 sop
->event_writeset_in
= writeset_in
;
242 if ((writeset_out
= realloc(sop
->event_writeset_out
, fdsz
)) == NULL
)
244 sop
->event_writeset_out
= writeset_out
;
245 if ((r_by_fd
= realloc(sop
->event_r_by_fd
,
246 n_events
*sizeof(struct event
*))) == NULL
)
248 sop
->event_r_by_fd
= r_by_fd
;
249 if ((w_by_fd
= realloc(sop
->event_w_by_fd
,
250 n_events
* sizeof(struct event
*))) == NULL
)
252 sop
->event_w_by_fd
= w_by_fd
;
254 memset((char *)sop
->event_readset_in
+ sop
->event_fdsz
, 0,
255 fdsz
- sop
->event_fdsz
);
256 memset((char *)sop
->event_writeset_in
+ sop
->event_fdsz
, 0,
257 fdsz
- sop
->event_fdsz
);
258 memset(sop
->event_r_by_fd
+ n_events_old
, 0,
259 (n_events
-n_events_old
) * sizeof(struct event
*));
260 memset(sop
->event_w_by_fd
+ n_events_old
, 0,
261 (n_events
-n_events_old
) * sizeof(struct event
*));
263 sop
->event_fdsz
= fdsz
;
269 event_warn("malloc");
275 select_add(void *arg
, struct event
*ev
)
277 struct selectop
*sop
= arg
;
279 if (ev
->ev_events
& EV_SIGNAL
)
280 return (evsignal_add(ev
));
284 * Keep track of the highest fd, so that we can calculate the size
285 * of the fd_sets for select(2)
287 if (sop
->event_fds
< ev
->ev_fd
) {
288 int fdsz
= sop
->event_fdsz
;
290 if (fdsz
< sizeof(fd_mask
))
291 fdsz
= sizeof(fd_mask
);
294 (howmany(ev
->ev_fd
+ 1, NFDBITS
) * sizeof(fd_mask
)))
297 if (fdsz
!= sop
->event_fdsz
) {
298 if (select_resize(sop
, fdsz
)) {
304 sop
->event_fds
= ev
->ev_fd
;
307 if (ev
->ev_events
& EV_READ
) {
308 FD_SET(ev
->ev_fd
, sop
->event_readset_in
);
309 sop
->event_r_by_fd
[ev
->ev_fd
] = ev
;
311 if (ev
->ev_events
& EV_WRITE
) {
312 FD_SET(ev
->ev_fd
, sop
->event_writeset_in
);
313 sop
->event_w_by_fd
[ev
->ev_fd
] = ev
;
321 * Nothing to be done here.
325 select_del(void *arg
, struct event
*ev
)
327 struct selectop
*sop
= arg
;
330 if (ev
->ev_events
& EV_SIGNAL
)
331 return (evsignal_del(ev
));
333 if (sop
->event_fds
< ev
->ev_fd
) {
338 if (ev
->ev_events
& EV_READ
) {
339 FD_CLR(ev
->ev_fd
, sop
->event_readset_in
);
340 sop
->event_r_by_fd
[ev
->ev_fd
] = NULL
;
343 if (ev
->ev_events
& EV_WRITE
) {
344 FD_CLR(ev
->ev_fd
, sop
->event_writeset_in
);
345 sop
->event_w_by_fd
[ev
->ev_fd
] = NULL
;
353 select_dealloc(struct event_base
*base
, void *arg
)
355 struct selectop
*sop
= arg
;
357 evsignal_dealloc(base
);
358 if (sop
->event_readset_in
)
359 free(sop
->event_readset_in
);
360 if (sop
->event_writeset_in
)
361 free(sop
->event_writeset_in
);
362 if (sop
->event_readset_out
)
363 free(sop
->event_readset_out
);
364 if (sop
->event_writeset_out
)
365 free(sop
->event_writeset_out
);
366 if (sop
->event_r_by_fd
)
367 free(sop
->event_r_by_fd
);
368 if (sop
->event_w_by_fd
)
369 free(sop
->event_w_by_fd
);
371 memset(sop
, 0, sizeof(struct selectop
));