1171169Smlaier/*	$OpenBSD: poll.c,v 1.2 2002/06/25 15:50:15 mickey Exp $	*/
2171169Smlaier
3171169Smlaier/*
4171169Smlaier * Copyright 2000-2003 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 <poll.h>
42171169Smlaier#include <signal.h>
43171169Smlaier#include <stdio.h>
44171169Smlaier#include <stdlib.h>
45171169Smlaier#include <string.h>
46171169Smlaier#include <unistd.h>
47171169Smlaier#include <errno.h>
48171169Smlaier#ifdef CHECK_INVARIANTS
49171169Smlaier#include <assert.h>
50171169Smlaier#endif
51171169Smlaier
52171169Smlaier#include "event.h"
53171169Smlaier#include "event-internal.h"
54171169Smlaier#include "evsignal.h"
55171169Smlaier#include "log.h"
56171169Smlaier
57171169Smlaierextern volatile sig_atomic_t evsignal_caught;
58171169Smlaier
59171169Smlaierstruct pollop {
60171169Smlaier	int event_count;		/* Highest number alloc */
61171169Smlaier	int nfds;                       /* Size of event_* */
62171169Smlaier	int fd_count;                   /* Size of idxplus1_by_fd */
63171169Smlaier	struct pollfd *event_set;
64171169Smlaier	struct event **event_r_back;
65171169Smlaier	struct event **event_w_back;
66171169Smlaier	int *idxplus1_by_fd; /* Index into event_set by fd; we add 1 so
67171169Smlaier			      * that 0 (which is easy to memset) can mean
68171169Smlaier			      * "no entry." */
69171169Smlaier};
70171169Smlaier
71171169Smlaiervoid *poll_init	(void);
72171169Smlaierint poll_add		(void *, struct event *);
73171169Smlaierint poll_del		(void *, struct event *);
74171169Smlaierint poll_recalc		(struct event_base *, void *, int);
75171169Smlaierint poll_dispatch	(struct event_base *, void *, struct timeval *);
76171169Smlaiervoid poll_dealloc	(void *);
77171169Smlaier
78171169Smlaierconst struct eventop pollops = {
79171169Smlaier	"poll",
80171169Smlaier	poll_init,
81171169Smlaier	poll_add,
82171169Smlaier	poll_del,
83171169Smlaier	poll_recalc,
84171169Smlaier	poll_dispatch,
85171169Smlaier	poll_dealloc
86171169Smlaier};
87171169Smlaier
88171169Smlaiervoid *
89171169Smlaierpoll_init(void)
90171169Smlaier{
91171169Smlaier	struct pollop *pollop;
92171169Smlaier
93171169Smlaier	/* Disable poll when this environment variable is set */
94171169Smlaier	if (getenv("EVENT_NOPOLL"))
95171169Smlaier		return (NULL);
96171169Smlaier
97171169Smlaier	if (!(pollop = calloc(1, sizeof(struct pollop))))
98171169Smlaier		return (NULL);
99171169Smlaier
100171169Smlaier	evsignal_init();
101171169Smlaier
102171169Smlaier	return (pollop);
103171169Smlaier}
104171169Smlaier
105171169Smlaier/*
106171169Smlaier * Called with the highest fd that we know about.  If it is 0, completely
107171169Smlaier * recalculate everything.
108171169Smlaier */
109171169Smlaier
110171169Smlaierint
111171169Smlaierpoll_recalc(struct event_base *base, void *arg, int max)
112171169Smlaier{
113171169Smlaier	return (0);
114171169Smlaier}
115171169Smlaier
116171169Smlaier#ifdef CHECK_INVARIANTS
117171169Smlaierstatic void
118171169Smlaierpoll_check_ok(struct pollop *pop)
119171169Smlaier{
120171169Smlaier	int i, idx;
121171169Smlaier	struct event *ev;
122171169Smlaier
123171169Smlaier	for (i = 0; i < pop->fd_count; ++i) {
124171169Smlaier		idx = pop->idxplus1_by_fd[i]-1;
125171169Smlaier		if (idx < 0)
126171169Smlaier			continue;
127171169Smlaier		assert(pop->event_set[idx].fd == i);
128171169Smlaier		if (pop->event_set[idx].events & POLLIN) {
129171169Smlaier			ev = pop->event_r_back[idx];
130171169Smlaier			assert(ev);
131171169Smlaier			assert(ev->ev_events & EV_READ);
132171169Smlaier			assert(ev->ev_fd == i);
133171169Smlaier		}
134171169Smlaier		if (pop->event_set[idx].events & POLLOUT) {
135171169Smlaier			ev = pop->event_w_back[idx];
136171169Smlaier			assert(ev);
137171169Smlaier			assert(ev->ev_events & EV_WRITE);
138171169Smlaier			assert(ev->ev_fd == i);
139171169Smlaier		}
140171169Smlaier	}
141171169Smlaier	for (i = 0; i < pop->nfds; ++i) {
142171169Smlaier		struct pollfd *pfd = &pop->event_set[i];
143171169Smlaier		assert(pop->idxplus1_by_fd[pfd->fd] == i+1);
144171169Smlaier	}
145171169Smlaier}
146171169Smlaier#else
147171169Smlaier#define poll_check_ok(pop)
148171169Smlaier#endif
149171169Smlaier
150171169Smlaierint
151171169Smlaierpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
152171169Smlaier{
153171169Smlaier	int res, i, sec, nfds;
154171169Smlaier	struct pollop *pop = arg;
155171169Smlaier
156171169Smlaier	poll_check_ok(pop);
157171169Smlaier	sec = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
158171169Smlaier	nfds = pop->nfds;
159171169Smlaier	res = poll(pop->event_set, nfds, sec);
160171169Smlaier
161171169Smlaier	if (res == -1) {
162171169Smlaier		if (errno != EINTR) {
163171169Smlaier                        event_warn("poll");
164171169Smlaier			return (-1);
165171169Smlaier		}
166171169Smlaier
167171169Smlaier		evsignal_process();
168171169Smlaier		return (0);
169171169Smlaier	} else if (evsignal_caught)
170171169Smlaier		evsignal_process();
171171169Smlaier
172171169Smlaier	event_debug(("%s: poll reports %d", __func__, res));
173171169Smlaier
174171169Smlaier	if (res == 0)
175171169Smlaier		return (0);
176171169Smlaier
177171169Smlaier	for (i = 0; i < nfds; i++) {
178171169Smlaier		int what = pop->event_set[i].revents;
179171169Smlaier		struct event *r_ev = NULL, *w_ev = NULL;
180171169Smlaier		if (!what)
181171169Smlaier			continue;
182171169Smlaier
183171169Smlaier		res = 0;
184171169Smlaier
185171169Smlaier		/* If the file gets closed notify */
186171169Smlaier		if (what & (POLLHUP|POLLERR))
187171169Smlaier			what |= POLLIN|POLLOUT;
188171169Smlaier		if (what & POLLIN) {
189171169Smlaier			res |= EV_READ;
190171169Smlaier			r_ev = pop->event_r_back[i];
191171169Smlaier		}
192171169Smlaier		if (what & POLLOUT) {
193171169Smlaier			res |= EV_WRITE;
194171169Smlaier			w_ev = pop->event_w_back[i];
195171169Smlaier		}
196171169Smlaier		if (res == 0)
197171169Smlaier			continue;
198171169Smlaier
199171169Smlaier		if (r_ev && (res & r_ev->ev_events)) {
200171169Smlaier			if (!(r_ev->ev_events & EV_PERSIST))
201171169Smlaier				event_del(r_ev);
202171169Smlaier			event_active(r_ev, res & r_ev->ev_events, 1);
203171169Smlaier		}
204171169Smlaier		if (w_ev && w_ev != r_ev && (res & w_ev->ev_events)) {
205171169Smlaier			if (!(w_ev->ev_events & EV_PERSIST))
206171169Smlaier				event_del(w_ev);
207171169Smlaier			event_active(w_ev, res & w_ev->ev_events, 1);
208171169Smlaier		}
209171169Smlaier	}
210171169Smlaier
211171169Smlaier	return (0);
212171169Smlaier}
213171169Smlaier
214171169Smlaierint
215171169Smlaierpoll_add(void *arg, struct event *ev)
216171169Smlaier{
217171169Smlaier	struct pollop *pop = arg;
218171169Smlaier	struct pollfd *pfd = NULL;
219171169Smlaier	int i;
220171169Smlaier
221171169Smlaier	if (ev->ev_events & EV_SIGNAL)
222171169Smlaier		return (evsignal_add(ev));
223171169Smlaier	if (!(ev->ev_events & (EV_READ|EV_WRITE)))
224171169Smlaier		return (0);
225171169Smlaier
226171169Smlaier	poll_check_ok(pop);
227171169Smlaier	if (pop->nfds + 1 >= pop->event_count) {
228171169Smlaier		struct pollfd *tmp_event_set;
229171169Smlaier		struct event **tmp_event_r_back;
230171169Smlaier		struct event **tmp_event_w_back;
231171169Smlaier		int tmp_event_count;
232171169Smlaier
233171169Smlaier		if (pop->event_count < 32)
234171169Smlaier			tmp_event_count = 32;
235171169Smlaier		else
236171169Smlaier			tmp_event_count = pop->event_count * 2;
237171169Smlaier
238171169Smlaier		/* We need more file descriptors */
239171169Smlaier		tmp_event_set = realloc(pop->event_set,
240171169Smlaier				 tmp_event_count * sizeof(struct pollfd));
241171169Smlaier		if (tmp_event_set == NULL) {
242171169Smlaier			event_warn("realloc");
243171169Smlaier			return (-1);
244171169Smlaier		}
245171169Smlaier		pop->event_set = tmp_event_set;
246171169Smlaier
247171169Smlaier		tmp_event_r_back = realloc(pop->event_r_back,
248171169Smlaier			    tmp_event_count * sizeof(struct event *));
249171169Smlaier		if (tmp_event_r_back == NULL) {
250171169Smlaier			/* event_set overallocated; that's okay. */
251171169Smlaier			event_warn("realloc");
252171169Smlaier			return (-1);
253171169Smlaier		}
254171169Smlaier		pop->event_r_back = tmp_event_r_back;
255171169Smlaier
256171169Smlaier		tmp_event_w_back = realloc(pop->event_w_back,
257171169Smlaier			    tmp_event_count * sizeof(struct event *));
258171169Smlaier		if (tmp_event_w_back == NULL) {
259171169Smlaier			/* event_set and event_r_back overallocated; that's
260171169Smlaier			 * okay. */
261171169Smlaier			event_warn("realloc");
262171169Smlaier			return (-1);
263171169Smlaier		}
264171169Smlaier		pop->event_w_back = tmp_event_w_back;
265171169Smlaier
266171169Smlaier		pop->event_count = tmp_event_count;
267171169Smlaier	}
268171169Smlaier	if (ev->ev_fd >= pop->fd_count) {
269171169Smlaier		int *tmp_idxplus1_by_fd;
270171169Smlaier		int new_count;
271171169Smlaier		if (pop->fd_count < 32)
272171169Smlaier			new_count = 32;
273171169Smlaier		else
274171169Smlaier			new_count = pop->fd_count * 2;
275171169Smlaier		while (new_count <= ev->ev_fd)
276171169Smlaier			new_count *= 2;
277171169Smlaier		tmp_idxplus1_by_fd =
278171169Smlaier			realloc(pop->idxplus1_by_fd, new_count * sizeof(int));
279171169Smlaier		if (tmp_idxplus1_by_fd == NULL) {
280171169Smlaier			event_warn("realloc");
281171169Smlaier			return (-1);
282171169Smlaier		}
283171169Smlaier		pop->idxplus1_by_fd = tmp_idxplus1_by_fd;
284171169Smlaier		memset(pop->idxplus1_by_fd + pop->fd_count,
285171169Smlaier		       0, sizeof(int)*(new_count - pop->fd_count));
286171169Smlaier		pop->fd_count = new_count;
287171169Smlaier	}
288171169Smlaier
289171169Smlaier	i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
290171169Smlaier	if (i >= 0) {
291171169Smlaier		pfd = &pop->event_set[i];
292171169Smlaier	} else {
293171169Smlaier		i = pop->nfds++;
294171169Smlaier		pfd = &pop->event_set[i];
295171169Smlaier		pfd->events = 0;
296171169Smlaier		pfd->fd = ev->ev_fd;
297171169Smlaier		pop->event_w_back[i] = pop->event_r_back[i] = NULL;
298171169Smlaier		pop->idxplus1_by_fd[ev->ev_fd] = i + 1;
299171169Smlaier	}
300171169Smlaier
301171169Smlaier	pfd->revents = 0;
302171169Smlaier	if (ev->ev_events & EV_WRITE) {
303171169Smlaier		pfd->events |= POLLOUT;
304171169Smlaier		pop->event_w_back[i] = ev;
305171169Smlaier	}
306171169Smlaier	if (ev->ev_events & EV_READ) {
307171169Smlaier		pfd->events |= POLLIN;
308171169Smlaier		pop->event_r_back[i] = ev;
309171169Smlaier	}
310171169Smlaier	poll_check_ok(pop);
311171169Smlaier
312171169Smlaier	return (0);
313171169Smlaier}
314171169Smlaier
315171169Smlaier/*
316171169Smlaier * Nothing to be done here.
317171169Smlaier */
318171169Smlaier
319171169Smlaierint
320171169Smlaierpoll_del(void *arg, struct event *ev)
321171169Smlaier{
322171169Smlaier	struct pollop *pop = arg;
323171169Smlaier	struct pollfd *pfd = NULL;
324171169Smlaier	int i;
325171169Smlaier
326171169Smlaier	if (ev->ev_events & EV_SIGNAL)
327171169Smlaier		return (evsignal_del(ev));
328171169Smlaier
329171169Smlaier	if (!(ev->ev_events & (EV_READ|EV_WRITE)))
330171169Smlaier		return (0);
331171169Smlaier
332171169Smlaier	poll_check_ok(pop);
333171169Smlaier	i = pop->idxplus1_by_fd[ev->ev_fd] - 1;
334171169Smlaier	if (i < 0)
335171169Smlaier		return (-1);
336171169Smlaier
337171169Smlaier	/* Do we still want to read or write? */
338171169Smlaier	pfd = &pop->event_set[i];
339171169Smlaier	if (ev->ev_events & EV_READ) {
340171169Smlaier		pfd->events &= ~POLLIN;
341171169Smlaier		pop->event_r_back[i] = NULL;
342171169Smlaier	}
343171169Smlaier	if (ev->ev_events & EV_WRITE) {
344171169Smlaier		pfd->events &= ~POLLOUT;
345171169Smlaier		pop->event_w_back[i] = NULL;
346171169Smlaier	}
347171169Smlaier	poll_check_ok(pop);
348171169Smlaier	if (pfd->events)
349171169Smlaier		/* Another event cares about that fd. */
350171169Smlaier		return (0);
351171169Smlaier
352171169Smlaier	/* Okay, so we aren't interested in that fd anymore. */
353171169Smlaier	pop->idxplus1_by_fd[ev->ev_fd] = 0;
354171169Smlaier
355171169Smlaier	--pop->nfds;
356171169Smlaier	if (i != pop->nfds) {
357171169Smlaier		/*
358171169Smlaier		 * Shift the last pollfd down into the now-unoccupied
359171169Smlaier		 * position.
360171169Smlaier		 */
361171169Smlaier		memcpy(&pop->event_set[i], &pop->event_set[pop->nfds],
362171169Smlaier		       sizeof(struct pollfd));
363171169Smlaier		pop->event_r_back[i] = pop->event_r_back[pop->nfds];
364171169Smlaier		pop->event_w_back[i] = pop->event_w_back[pop->nfds];
365171169Smlaier		pop->idxplus1_by_fd[pop->event_set[i].fd] = i + 1;
366171169Smlaier	}
367171169Smlaier
368171169Smlaier	poll_check_ok(pop);
369171169Smlaier	return (0);
370171169Smlaier}
371171169Smlaier
372171169Smlaiervoid
373171169Smlaierpoll_dealloc(void *arg)
374171169Smlaier{
375171169Smlaier	struct pollop *pop = arg;
376171169Smlaier
377171169Smlaier	if (pop->event_set)
378171169Smlaier		free(pop->event_set);
379171169Smlaier	if (pop->event_r_back)
380171169Smlaier		free(pop->event_r_back);
381171169Smlaier	if (pop->event_w_back)
382171169Smlaier		free(pop->event_w_back);
383171169Smlaier	if (pop->idxplus1_by_fd)
384171169Smlaier		free(pop->idxplus1_by_fd);
385171169Smlaier
386171169Smlaier	memset(pop, 0, sizeof(struct pollop));
387171169Smlaier	free(pop);
388171169Smlaier}
389