1171169Smlaier/*	$OpenBSD: select.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
2171169Smlaier
3171169Smlaier/*
4171169Smlaier * Copyright 2000-2002 Niels Provos <provos@citi.umich.edu>
5171169Smlaier * All rights reserved.
6171169Smlaier *
7171169Smlaier * Redistribution and use in source and binary forms, with or without
8171169Smlaier * modification, are permitted provided that the following conditions
9171169Smlaier * are met:
10171169Smlaier * 1. Redistributions of source code must retain the above copyright
11171169Smlaier *    notice, this list of conditions and the following disclaimer.
12171169Smlaier * 2. Redistributions in binary form must reproduce the above copyright
13171169Smlaier *    notice, this list of conditions and the following disclaimer in the
14171169Smlaier *    documentation and/or other materials provided with the distribution.
15171169Smlaier * 3. The name of the author may not be used to endorse or promote products
16171169Smlaier *    derived from this software without specific prior written permission.
17171169Smlaier *
18171169Smlaier * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19171169Smlaier * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20171169Smlaier * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21171169Smlaier * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22171169Smlaier * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23171169Smlaier * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24171169Smlaier * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25171169Smlaier * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26171169Smlaier * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27171169Smlaier * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28171169Smlaier */
29171169Smlaier#ifdef HAVE_CONFIG_H
30171169Smlaier#include "config.h"
31171169Smlaier#endif
32171169Smlaier
33171169Smlaier#include <sys/types.h>
34171169Smlaier#ifdef HAVE_SYS_TIME_H
35171169Smlaier#include <sys/time.h>
36171169Smlaier#else
37171169Smlaier#include <sys/_time.h>
38171169Smlaier#endif
39171169Smlaier#include <sys/queue.h>
40171169Smlaier#include <sys/tree.h>
41171169Smlaier#include <signal.h>
42171169Smlaier#include <stdio.h>
43171169Smlaier#include <stdlib.h>
44171169Smlaier#include <string.h>
45171169Smlaier#include <unistd.h>
46171169Smlaier#include <errno.h>
47171169Smlaier#ifdef CHECK_INVARIANTS
48171169Smlaier#include <assert.h>
49171169Smlaier#endif
50171169Smlaier
51171169Smlaier#include "event.h"
52171169Smlaier#include "event-internal.h"
53171169Smlaier#include "evsignal.h"
54171169Smlaier#include "log.h"
55171169Smlaier
56171169Smlaier#ifndef howmany
57171169Smlaier#define        howmany(x, y)   (((x)+((y)-1))/(y))
58171169Smlaier#endif
59171169Smlaier
60171169Smlaierextern volatile sig_atomic_t evsignal_caught;
61171169Smlaier
62171169Smlaierstruct selectop {
63171169Smlaier	int event_fds;		/* Highest fd in fd set */
64171169Smlaier	int event_fdsz;
65171169Smlaier	fd_set *event_readset_in;
66171169Smlaier	fd_set *event_writeset_in;
67171169Smlaier	fd_set *event_readset_out;
68171169Smlaier	fd_set *event_writeset_out;
69171169Smlaier	struct event **event_r_by_fd;
70171169Smlaier	struct event **event_w_by_fd;
71171169Smlaier};
72171169Smlaier
73171169Smlaiervoid *select_init	(void);
74171169Smlaierint select_add		(void *, struct event *);
75171169Smlaierint select_del		(void *, struct event *);
76171169Smlaierint select_recalc	(struct event_base *, void *, int);
77171169Smlaierint select_dispatch	(struct event_base *, void *, struct timeval *);
78171169Smlaiervoid select_dealloc     (void *);
79171169Smlaier
80171169Smlaierconst struct eventop selectops = {
81171169Smlaier	"select",
82171169Smlaier	select_init,
83171169Smlaier	select_add,
84171169Smlaier	select_del,
85171169Smlaier	select_recalc,
86171169Smlaier	select_dispatch,
87171169Smlaier	select_dealloc
88171169Smlaier};
89171169Smlaier
90171169Smlaierstatic int select_resize(struct selectop *sop, int fdsz);
91171169Smlaier
92171169Smlaiervoid *
93171169Smlaierselect_init(void)
94171169Smlaier{
95171169Smlaier	struct selectop *sop;
96171169Smlaier
97171169Smlaier	/* Disable select when this environment variable is set */
98171169Smlaier	if (getenv("EVENT_NOSELECT"))
99171169Smlaier		return (NULL);
100171169Smlaier
101171169Smlaier	if (!(sop = calloc(1, sizeof(struct selectop))))
102171169Smlaier		return (NULL);
103171169Smlaier
104171169Smlaier	select_resize(sop, howmany(32 + 1, NFDBITS)*sizeof(fd_mask));
105171169Smlaier
106171169Smlaier	evsignal_init();
107171169Smlaier
108171169Smlaier	return (sop);
109171169Smlaier}
110171169Smlaier
111171169Smlaier#ifdef CHECK_INVARIANTS
112171169Smlaierstatic void
113171169Smlaiercheck_selectop(struct selectop *sop)
114171169Smlaier{
115171169Smlaier	int i;
116171169Smlaier	for (i=0;i<=sop->event_fds;++i) {
117171169Smlaier		if (FD_ISSET(i, sop->event_readset_in)) {
118171169Smlaier			assert(sop->event_r_by_fd[i]);
119171169Smlaier			assert(sop->event_r_by_fd[i]->ev_events & EV_READ);
120171169Smlaier			assert(sop->event_r_by_fd[i]->ev_fd == i);
121171169Smlaier		} else {
122171169Smlaier			assert(! sop->event_r_by_fd[i]);
123171169Smlaier		}
124171169Smlaier		if (FD_ISSET(i, sop->event_writeset_in)) {
125171169Smlaier			assert(sop->event_w_by_fd[i]);
126171169Smlaier			assert(sop->event_w_by_fd[i]->ev_events & EV_WRITE);
127171169Smlaier			assert(sop->event_w_by_fd[i]->ev_fd == i);
128171169Smlaier		} else {
129171169Smlaier			assert(! sop->event_w_by_fd[i]);
130171169Smlaier		}
131171169Smlaier	}
132171169Smlaier
133171169Smlaier}
134171169Smlaier#else
135171169Smlaier#define check_selectop(sop) do { (void) sop; } while (0)
136171169Smlaier#endif
137171169Smlaier
138171169Smlaier/*
139171169Smlaier * Called with the highest fd that we know about.  If it is 0, completely
140171169Smlaier * recalculate everything.
141171169Smlaier */
142171169Smlaier
143171169Smlaierint
144171169Smlaierselect_recalc(struct event_base *base, void *arg, int max)
145171169Smlaier{
146171169Smlaier	struct selectop *sop = arg;
147171169Smlaier
148171169Smlaier	check_selectop(sop);
149171169Smlaier
150171169Smlaier	return (0);
151171169Smlaier}
152171169Smlaier
153171169Smlaierint
154171169Smlaierselect_dispatch(struct event_base *base, void *arg, struct timeval *tv)
155171169Smlaier{
156171169Smlaier	int res, i;
157171169Smlaier	struct selectop *sop = arg;
158171169Smlaier
159171169Smlaier	check_selectop(sop);
160171169Smlaier
161171169Smlaier	memcpy(sop->event_readset_out, sop->event_readset_in,
162171169Smlaier	       sop->event_fdsz);
163171169Smlaier	memcpy(sop->event_writeset_out, sop->event_writeset_in,
164171169Smlaier	       sop->event_fdsz);
165171169Smlaier
166171169Smlaier	res = select(sop->event_fds + 1, sop->event_readset_out,
167171169Smlaier	    sop->event_writeset_out, NULL, tv);
168171169Smlaier
169171169Smlaier	check_selectop(sop);
170171169Smlaier
171171169Smlaier	if (res == -1) {
172171169Smlaier		if (errno != EINTR) {
173171169Smlaier			event_warn("select");
174171169Smlaier			return (-1);
175171169Smlaier		}
176171169Smlaier
177171169Smlaier		evsignal_process();
178171169Smlaier		return (0);
179171169Smlaier	} else if (evsignal_caught)
180171169Smlaier		evsignal_process();
181171169Smlaier
182171169Smlaier	event_debug(("%s: select reports %d", __func__, res));
183171169Smlaier
184171169Smlaier	check_selectop(sop);
185171169Smlaier	for (i = 0; i <= sop->event_fds; ++i) {
186171169Smlaier		struct event *r_ev = NULL, *w_ev = NULL;
187171169Smlaier		res = 0;
188171169Smlaier		if (FD_ISSET(i, sop->event_readset_out)) {
189171169Smlaier			r_ev = sop->event_r_by_fd[i];
190171169Smlaier			res |= EV_READ;
191171169Smlaier		}
192171169Smlaier		if (FD_ISSET(i, sop->event_writeset_out)) {
193171169Smlaier			w_ev = sop->event_w_by_fd[i];
194171169Smlaier			res |= EV_WRITE;
195171169Smlaier		}
196171169Smlaier		if (r_ev && (res & r_ev->ev_events)) {
197171169Smlaier			if (!(r_ev->ev_events & EV_PERSIST))
198171169Smlaier				event_del(r_ev);
199171169Smlaier			event_active(r_ev, res & r_ev->ev_events, 1);
200171169Smlaier		}
201171169Smlaier		if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
202171169Smlaier			if (!(w_ev->ev_events & EV_PERSIST))
203171169Smlaier				event_del(w_ev);
204171169Smlaier			event_active(w_ev, res & w_ev->ev_events, 1);
205171169Smlaier		}
206171169Smlaier	}
207171169Smlaier	check_selectop(sop);
208171169Smlaier
209171169Smlaier	return (0);
210171169Smlaier}
211171169Smlaier
212171169Smlaier
213171169Smlaierstatic int
214171169Smlaierselect_resize(struct selectop *sop, int fdsz)
215171169Smlaier{
216171169Smlaier	int n_events, n_events_old;
217171169Smlaier
218171169Smlaier	fd_set *readset_in = NULL;
219171169Smlaier	fd_set *writeset_in = NULL;
220171169Smlaier	fd_set *readset_out = NULL;
221171169Smlaier	fd_set *writeset_out = NULL;
222171169Smlaier	struct event **r_by_fd = NULL;
223171169Smlaier	struct event **w_by_fd = NULL;
224171169Smlaier
225171169Smlaier	n_events = (fdsz/sizeof(fd_mask)) * NFDBITS;
226171169Smlaier	n_events_old = (sop->event_fdsz/sizeof(fd_mask)) * NFDBITS;
227171169Smlaier
228171169Smlaier	if (sop->event_readset_in)
229171169Smlaier		check_selectop(sop);
230171169Smlaier
231171169Smlaier	if ((readset_in = realloc(sop->event_readset_in, fdsz)) == NULL)
232171169Smlaier		goto error;
233171169Smlaier	sop->event_readset_in = readset_in;
234171169Smlaier	if ((readset_out = realloc(sop->event_readset_out, fdsz)) == NULL)
235171169Smlaier		goto error;
236171169Smlaier	sop->event_readset_out = readset_out;
237171169Smlaier	if ((writeset_in = realloc(sop->event_writeset_in, fdsz)) == NULL)
238171169Smlaier		goto error;
239171169Smlaier	sop->event_writeset_in = writeset_in;
240171169Smlaier	if ((writeset_out = realloc(sop->event_writeset_out, fdsz)) == NULL)
241171169Smlaier		goto error;
242171169Smlaier	sop->event_writeset_out = writeset_out;
243171169Smlaier	if ((r_by_fd = realloc(sop->event_r_by_fd,
244171169Smlaier		 n_events*sizeof(struct event*))) == NULL)
245171169Smlaier		goto error;
246171169Smlaier	sop->event_r_by_fd = r_by_fd;
247171169Smlaier	if ((w_by_fd = realloc(sop->event_w_by_fd,
248171169Smlaier		 n_events * sizeof(struct event*))) == NULL)
249171169Smlaier		goto error;
250171169Smlaier	sop->event_w_by_fd = w_by_fd;
251171169Smlaier
252171169Smlaier	memset((char *)sop->event_readset_in + sop->event_fdsz, 0,
253171169Smlaier	    fdsz - sop->event_fdsz);
254171169Smlaier	memset((char *)sop->event_writeset_in + sop->event_fdsz, 0,
255171169Smlaier	    fdsz - sop->event_fdsz);
256171169Smlaier	memset(sop->event_r_by_fd + n_events_old, 0,
257171169Smlaier	    (n_events-n_events_old) * sizeof(struct event*));
258171169Smlaier	memset(sop->event_w_by_fd + n_events_old, 0,
259171169Smlaier	    (n_events-n_events_old) * sizeof(struct event*));
260171169Smlaier
261171169Smlaier	sop->event_fdsz = fdsz;
262171169Smlaier	check_selectop(sop);
263171169Smlaier
264171169Smlaier	return (0);
265171169Smlaier
266171169Smlaier error:
267171169Smlaier	event_warn("malloc");
268171169Smlaier	return (-1);
269171169Smlaier}
270171169Smlaier
271171169Smlaier
272171169Smlaierint
273171169Smlaierselect_add(void *arg, struct event *ev)
274171169Smlaier{
275171169Smlaier	struct selectop *sop = arg;
276171169Smlaier
277171169Smlaier	if (ev->ev_events & EV_SIGNAL)
278171169Smlaier		return (evsignal_add(ev));
279171169Smlaier
280171169Smlaier	check_selectop(sop);
281171169Smlaier	/*
282171169Smlaier	 * Keep track of the highest fd, so that we can calculate the size
283171169Smlaier	 * of the fd_sets for select(2)
284171169Smlaier	 */
285171169Smlaier	if (sop->event_fds < ev->ev_fd) {
286171169Smlaier		int fdsz = sop->event_fdsz;
287171169Smlaier
288171169Smlaier		if (fdsz < sizeof(fd_mask))
289171169Smlaier			fdsz = sizeof(fd_mask);
290171169Smlaier
291171169Smlaier		while (fdsz <
292171169Smlaier		    (howmany(ev->ev_fd + 1, NFDBITS) * sizeof(fd_mask)))
293171169Smlaier			fdsz *= 2;
294171169Smlaier
295171169Smlaier		if (fdsz != sop->event_fdsz) {
296171169Smlaier			if (select_resize(sop, fdsz)) {
297171169Smlaier				check_selectop(sop);
298171169Smlaier				return (-1);
299171169Smlaier			}
300171169Smlaier		}
301171169Smlaier
302171169Smlaier		sop->event_fds = ev->ev_fd;
303171169Smlaier	}
304171169Smlaier
305171169Smlaier	if (ev->ev_events & EV_READ) {
306171169Smlaier		FD_SET(ev->ev_fd, sop->event_readset_in);
307171169Smlaier		sop->event_r_by_fd[ev->ev_fd] = ev;
308171169Smlaier	}
309171169Smlaier	if (ev->ev_events & EV_WRITE) {
310171169Smlaier		FD_SET(ev->ev_fd, sop->event_writeset_in);
311171169Smlaier		sop->event_w_by_fd[ev->ev_fd] = ev;
312171169Smlaier	}
313171169Smlaier	check_selectop(sop);
314171169Smlaier
315171169Smlaier	return (0);
316171169Smlaier}
317171169Smlaier
318171169Smlaier/*
319171169Smlaier * Nothing to be done here.
320171169Smlaier */
321171169Smlaier
322171169Smlaierint
323171169Smlaierselect_del(void *arg, struct event *ev)
324171169Smlaier{
325171169Smlaier	struct selectop *sop = arg;
326171169Smlaier
327171169Smlaier	check_selectop(sop);
328171169Smlaier	if (ev->ev_events & EV_SIGNAL)
329171169Smlaier		return (evsignal_del(ev));
330171169Smlaier
331171169Smlaier	if (sop->event_fds < ev->ev_fd) {
332171169Smlaier		check_selectop(sop);
333171169Smlaier		return (0);
334171169Smlaier	}
335171169Smlaier
336171169Smlaier	if (ev->ev_events & EV_READ) {
337171169Smlaier		FD_CLR(ev->ev_fd, sop->event_readset_in);
338171169Smlaier		sop->event_r_by_fd[ev->ev_fd] = NULL;
339171169Smlaier	}
340171169Smlaier
341171169Smlaier	if (ev->ev_events & EV_WRITE) {
342171169Smlaier		FD_CLR(ev->ev_fd, sop->event_writeset_in);
343171169Smlaier		sop->event_w_by_fd[ev->ev_fd] = NULL;
344171169Smlaier	}
345171169Smlaier
346171169Smlaier	check_selectop(sop);
347171169Smlaier	return (0);
348171169Smlaier}
349171169Smlaier
350171169Smlaiervoid
351171169Smlaierselect_dealloc(void *arg)
352171169Smlaier{
353171169Smlaier	struct selectop *sop = arg;
354171169Smlaier
355171169Smlaier	if (sop->event_readset_in)
356171169Smlaier		free(sop->event_readset_in);
357171169Smlaier	if (sop->event_writeset_in)
358171169Smlaier		free(sop->event_writeset_in);
359171169Smlaier	if (sop->event_readset_out)
360171169Smlaier		free(sop->event_readset_out);
361171169Smlaier	if (sop->event_writeset_out)
362171169Smlaier		free(sop->event_writeset_out);
363171169Smlaier	if (sop->event_r_by_fd)
364171169Smlaier		free(sop->event_r_by_fd);
365171169Smlaier	if (sop->event_w_by_fd)
366171169Smlaier		free(sop->event_w_by_fd);
367171169Smlaier
368171169Smlaier	memset(sop, 0, sizeof(struct selectop));
369171169Smlaier	free(sop);
370171169Smlaier}
371