xref: /aosp_15_r20/external/cronet/third_party/libevent/devpoll.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker /*
2*6777b538SAndroid Build Coastguard Worker  * Copyright 2000-2004 Niels Provos <[email protected]>
3*6777b538SAndroid Build Coastguard Worker  * All rights reserved.
4*6777b538SAndroid Build Coastguard Worker  *
5*6777b538SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
6*6777b538SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions
7*6777b538SAndroid Build Coastguard Worker  * are met:
8*6777b538SAndroid Build Coastguard Worker  * 1. Redistributions of source code must retain the above copyright
9*6777b538SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer.
10*6777b538SAndroid Build Coastguard Worker  * 2. Redistributions in binary form must reproduce the above copyright
11*6777b538SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer in the
12*6777b538SAndroid Build Coastguard Worker  *    documentation and/or other materials provided with the distribution.
13*6777b538SAndroid Build Coastguard Worker  * 3. The name of the author may not be used to endorse or promote products
14*6777b538SAndroid Build Coastguard Worker  *    derived from this software without specific prior written permission.
15*6777b538SAndroid Build Coastguard Worker  *
16*6777b538SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*6777b538SAndroid Build Coastguard Worker  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*6777b538SAndroid Build Coastguard Worker  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*6777b538SAndroid Build Coastguard Worker  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*6777b538SAndroid Build Coastguard Worker  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*6777b538SAndroid Build Coastguard Worker  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*6777b538SAndroid Build Coastguard Worker  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*6777b538SAndroid Build Coastguard Worker  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*6777b538SAndroid Build Coastguard Worker  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*6777b538SAndroid Build Coastguard Worker  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*6777b538SAndroid Build Coastguard Worker  */
27*6777b538SAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
28*6777b538SAndroid Build Coastguard Worker #include "config.h"
29*6777b538SAndroid Build Coastguard Worker #endif
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker #include <sys/types.h>
32*6777b538SAndroid Build Coastguard Worker #include <sys/resource.h>
33*6777b538SAndroid Build Coastguard Worker #ifdef HAVE_SYS_TIME_H
34*6777b538SAndroid Build Coastguard Worker #include <sys/time.h>
35*6777b538SAndroid Build Coastguard Worker #else
36*6777b538SAndroid Build Coastguard Worker #include <sys/_libevent_time.h>
37*6777b538SAndroid Build Coastguard Worker #endif
38*6777b538SAndroid Build Coastguard Worker #include <sys/queue.h>
39*6777b538SAndroid Build Coastguard Worker #include <sys/devpoll.h>
40*6777b538SAndroid Build Coastguard Worker #include <signal.h>
41*6777b538SAndroid Build Coastguard Worker #include <stdio.h>
42*6777b538SAndroid Build Coastguard Worker #include <stdlib.h>
43*6777b538SAndroid Build Coastguard Worker #include <string.h>
44*6777b538SAndroid Build Coastguard Worker #include <unistd.h>
45*6777b538SAndroid Build Coastguard Worker #include <fcntl.h>
46*6777b538SAndroid Build Coastguard Worker #include <errno.h>
47*6777b538SAndroid Build Coastguard Worker #include <assert.h>
48*6777b538SAndroid Build Coastguard Worker 
49*6777b538SAndroid Build Coastguard Worker #include "event.h"
50*6777b538SAndroid Build Coastguard Worker #include "event-internal.h"
51*6777b538SAndroid Build Coastguard Worker #include "evsignal.h"
52*6777b538SAndroid Build Coastguard Worker #include "log.h"
53*6777b538SAndroid Build Coastguard Worker 
54*6777b538SAndroid Build Coastguard Worker /* due to limitations in the devpoll interface, we need to keep track of
55*6777b538SAndroid Build Coastguard Worker  * all file descriptors outself.
56*6777b538SAndroid Build Coastguard Worker  */
57*6777b538SAndroid Build Coastguard Worker struct evdevpoll {
58*6777b538SAndroid Build Coastguard Worker 	struct event *evread;
59*6777b538SAndroid Build Coastguard Worker 	struct event *evwrite;
60*6777b538SAndroid Build Coastguard Worker };
61*6777b538SAndroid Build Coastguard Worker 
62*6777b538SAndroid Build Coastguard Worker struct devpollop {
63*6777b538SAndroid Build Coastguard Worker 	struct evdevpoll *fds;
64*6777b538SAndroid Build Coastguard Worker 	int nfds;
65*6777b538SAndroid Build Coastguard Worker 	struct pollfd *events;
66*6777b538SAndroid Build Coastguard Worker 	int nevents;
67*6777b538SAndroid Build Coastguard Worker 	int dpfd;
68*6777b538SAndroid Build Coastguard Worker 	struct pollfd *changes;
69*6777b538SAndroid Build Coastguard Worker 	int nchanges;
70*6777b538SAndroid Build Coastguard Worker };
71*6777b538SAndroid Build Coastguard Worker 
72*6777b538SAndroid Build Coastguard Worker static void *devpoll_init	(struct event_base *);
73*6777b538SAndroid Build Coastguard Worker static int devpoll_add	(void *, struct event *);
74*6777b538SAndroid Build Coastguard Worker static int devpoll_del	(void *, struct event *);
75*6777b538SAndroid Build Coastguard Worker static int devpoll_dispatch	(struct event_base *, void *, struct timeval *);
76*6777b538SAndroid Build Coastguard Worker static void devpoll_dealloc	(struct event_base *, void *);
77*6777b538SAndroid Build Coastguard Worker 
78*6777b538SAndroid Build Coastguard Worker const struct eventop devpollops = {
79*6777b538SAndroid Build Coastguard Worker 	"devpoll",
80*6777b538SAndroid Build Coastguard Worker 	devpoll_init,
81*6777b538SAndroid Build Coastguard Worker 	devpoll_add,
82*6777b538SAndroid Build Coastguard Worker 	devpoll_del,
83*6777b538SAndroid Build Coastguard Worker 	devpoll_dispatch,
84*6777b538SAndroid Build Coastguard Worker 	devpoll_dealloc,
85*6777b538SAndroid Build Coastguard Worker 	1 /* need reinit */
86*6777b538SAndroid Build Coastguard Worker };
87*6777b538SAndroid Build Coastguard Worker 
88*6777b538SAndroid Build Coastguard Worker #define NEVENT	32000
89*6777b538SAndroid Build Coastguard Worker 
90*6777b538SAndroid Build Coastguard Worker static int
devpoll_commit(struct devpollop * devpollop)91*6777b538SAndroid Build Coastguard Worker devpoll_commit(struct devpollop *devpollop)
92*6777b538SAndroid Build Coastguard Worker {
93*6777b538SAndroid Build Coastguard Worker 	/*
94*6777b538SAndroid Build Coastguard Worker 	 * Due to a bug in Solaris, we have to use pwrite with an offset of 0.
95*6777b538SAndroid Build Coastguard Worker 	 * Write is limited to 2GB of data, until it will fail.
96*6777b538SAndroid Build Coastguard Worker 	 */
97*6777b538SAndroid Build Coastguard Worker 	if (pwrite(devpollop->dpfd, devpollop->changes,
98*6777b538SAndroid Build Coastguard Worker 		sizeof(struct pollfd) * devpollop->nchanges, 0) == -1)
99*6777b538SAndroid Build Coastguard Worker 		return(-1);
100*6777b538SAndroid Build Coastguard Worker 
101*6777b538SAndroid Build Coastguard Worker 	devpollop->nchanges = 0;
102*6777b538SAndroid Build Coastguard Worker 	return(0);
103*6777b538SAndroid Build Coastguard Worker }
104*6777b538SAndroid Build Coastguard Worker 
105*6777b538SAndroid Build Coastguard Worker static int
devpoll_queue(struct devpollop * devpollop,int fd,int events)106*6777b538SAndroid Build Coastguard Worker devpoll_queue(struct devpollop *devpollop, int fd, int events) {
107*6777b538SAndroid Build Coastguard Worker 	struct pollfd *pfd;
108*6777b538SAndroid Build Coastguard Worker 
109*6777b538SAndroid Build Coastguard Worker 	if (devpollop->nchanges >= devpollop->nevents) {
110*6777b538SAndroid Build Coastguard Worker 		/*
111*6777b538SAndroid Build Coastguard Worker 		 * Change buffer is full, must commit it to /dev/poll before
112*6777b538SAndroid Build Coastguard Worker 		 * adding more
113*6777b538SAndroid Build Coastguard Worker 		 */
114*6777b538SAndroid Build Coastguard Worker 		if (devpoll_commit(devpollop) != 0)
115*6777b538SAndroid Build Coastguard Worker 			return(-1);
116*6777b538SAndroid Build Coastguard Worker 	}
117*6777b538SAndroid Build Coastguard Worker 
118*6777b538SAndroid Build Coastguard Worker 	pfd = &devpollop->changes[devpollop->nchanges++];
119*6777b538SAndroid Build Coastguard Worker 	pfd->fd = fd;
120*6777b538SAndroid Build Coastguard Worker 	pfd->events = events;
121*6777b538SAndroid Build Coastguard Worker 	pfd->revents = 0;
122*6777b538SAndroid Build Coastguard Worker 
123*6777b538SAndroid Build Coastguard Worker 	return(0);
124*6777b538SAndroid Build Coastguard Worker }
125*6777b538SAndroid Build Coastguard Worker 
126*6777b538SAndroid Build Coastguard Worker static void *
devpoll_init(struct event_base * base)127*6777b538SAndroid Build Coastguard Worker devpoll_init(struct event_base *base)
128*6777b538SAndroid Build Coastguard Worker {
129*6777b538SAndroid Build Coastguard Worker 	int dpfd, nfiles = NEVENT;
130*6777b538SAndroid Build Coastguard Worker 	struct rlimit rl;
131*6777b538SAndroid Build Coastguard Worker 	struct devpollop *devpollop;
132*6777b538SAndroid Build Coastguard Worker 
133*6777b538SAndroid Build Coastguard Worker 	/* Disable devpoll when this environment variable is set */
134*6777b538SAndroid Build Coastguard Worker 	if (evutil_getenv("EVENT_NODEVPOLL"))
135*6777b538SAndroid Build Coastguard Worker 		return (NULL);
136*6777b538SAndroid Build Coastguard Worker 
137*6777b538SAndroid Build Coastguard Worker 	if (!(devpollop = calloc(1, sizeof(struct devpollop))))
138*6777b538SAndroid Build Coastguard Worker 		return (NULL);
139*6777b538SAndroid Build Coastguard Worker 
140*6777b538SAndroid Build Coastguard Worker 	if (getrlimit(RLIMIT_NOFILE, &rl) == 0 &&
141*6777b538SAndroid Build Coastguard Worker 	    rl.rlim_cur != RLIM_INFINITY)
142*6777b538SAndroid Build Coastguard Worker 		nfiles = rl.rlim_cur;
143*6777b538SAndroid Build Coastguard Worker 
144*6777b538SAndroid Build Coastguard Worker 	/* Initialize the kernel queue */
145*6777b538SAndroid Build Coastguard Worker 	if ((dpfd = open("/dev/poll", O_RDWR)) == -1) {
146*6777b538SAndroid Build Coastguard Worker                 event_warn("open: /dev/poll");
147*6777b538SAndroid Build Coastguard Worker 		free(devpollop);
148*6777b538SAndroid Build Coastguard Worker 		return (NULL);
149*6777b538SAndroid Build Coastguard Worker 	}
150*6777b538SAndroid Build Coastguard Worker 
151*6777b538SAndroid Build Coastguard Worker 	devpollop->dpfd = dpfd;
152*6777b538SAndroid Build Coastguard Worker 
153*6777b538SAndroid Build Coastguard Worker 	/* Initialize fields */
154*6777b538SAndroid Build Coastguard Worker 	devpollop->events = calloc(nfiles, sizeof(struct pollfd));
155*6777b538SAndroid Build Coastguard Worker 	if (devpollop->events == NULL) {
156*6777b538SAndroid Build Coastguard Worker 		free(devpollop);
157*6777b538SAndroid Build Coastguard Worker 		close(dpfd);
158*6777b538SAndroid Build Coastguard Worker 		return (NULL);
159*6777b538SAndroid Build Coastguard Worker 	}
160*6777b538SAndroid Build Coastguard Worker 	devpollop->nevents = nfiles;
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker 	devpollop->fds = calloc(nfiles, sizeof(struct evdevpoll));
163*6777b538SAndroid Build Coastguard Worker 	if (devpollop->fds == NULL) {
164*6777b538SAndroid Build Coastguard Worker 		free(devpollop->events);
165*6777b538SAndroid Build Coastguard Worker 		free(devpollop);
166*6777b538SAndroid Build Coastguard Worker 		close(dpfd);
167*6777b538SAndroid Build Coastguard Worker 		return (NULL);
168*6777b538SAndroid Build Coastguard Worker 	}
169*6777b538SAndroid Build Coastguard Worker 	devpollop->nfds = nfiles;
170*6777b538SAndroid Build Coastguard Worker 
171*6777b538SAndroid Build Coastguard Worker 	devpollop->changes = calloc(nfiles, sizeof(struct pollfd));
172*6777b538SAndroid Build Coastguard Worker 	if (devpollop->changes == NULL) {
173*6777b538SAndroid Build Coastguard Worker 		free(devpollop->fds);
174*6777b538SAndroid Build Coastguard Worker 		free(devpollop->events);
175*6777b538SAndroid Build Coastguard Worker 		free(devpollop);
176*6777b538SAndroid Build Coastguard Worker 		close(dpfd);
177*6777b538SAndroid Build Coastguard Worker 		return (NULL);
178*6777b538SAndroid Build Coastguard Worker 	}
179*6777b538SAndroid Build Coastguard Worker 
180*6777b538SAndroid Build Coastguard Worker 	evsignal_init(base);
181*6777b538SAndroid Build Coastguard Worker 
182*6777b538SAndroid Build Coastguard Worker 	return (devpollop);
183*6777b538SAndroid Build Coastguard Worker }
184*6777b538SAndroid Build Coastguard Worker 
185*6777b538SAndroid Build Coastguard Worker static int
devpoll_recalc(struct event_base * base,void * arg,int max)186*6777b538SAndroid Build Coastguard Worker devpoll_recalc(struct event_base *base, void *arg, int max)
187*6777b538SAndroid Build Coastguard Worker {
188*6777b538SAndroid Build Coastguard Worker 	struct devpollop *devpollop = arg;
189*6777b538SAndroid Build Coastguard Worker 
190*6777b538SAndroid Build Coastguard Worker 	if (max >= devpollop->nfds) {
191*6777b538SAndroid Build Coastguard Worker 		struct evdevpoll *fds;
192*6777b538SAndroid Build Coastguard Worker 		int nfds;
193*6777b538SAndroid Build Coastguard Worker 
194*6777b538SAndroid Build Coastguard Worker 		nfds = devpollop->nfds;
195*6777b538SAndroid Build Coastguard Worker 		while (nfds <= max)
196*6777b538SAndroid Build Coastguard Worker 			nfds <<= 1;
197*6777b538SAndroid Build Coastguard Worker 
198*6777b538SAndroid Build Coastguard Worker 		fds = realloc(devpollop->fds, nfds * sizeof(struct evdevpoll));
199*6777b538SAndroid Build Coastguard Worker 		if (fds == NULL) {
200*6777b538SAndroid Build Coastguard Worker 			event_warn("realloc");
201*6777b538SAndroid Build Coastguard Worker 			return (-1);
202*6777b538SAndroid Build Coastguard Worker 		}
203*6777b538SAndroid Build Coastguard Worker 		devpollop->fds = fds;
204*6777b538SAndroid Build Coastguard Worker 		memset(fds + devpollop->nfds, 0,
205*6777b538SAndroid Build Coastguard Worker 		    (nfds - devpollop->nfds) * sizeof(struct evdevpoll));
206*6777b538SAndroid Build Coastguard Worker 		devpollop->nfds = nfds;
207*6777b538SAndroid Build Coastguard Worker 	}
208*6777b538SAndroid Build Coastguard Worker 
209*6777b538SAndroid Build Coastguard Worker 	return (0);
210*6777b538SAndroid Build Coastguard Worker }
211*6777b538SAndroid Build Coastguard Worker 
212*6777b538SAndroid Build Coastguard Worker static int
devpoll_dispatch(struct event_base * base,void * arg,struct timeval * tv)213*6777b538SAndroid Build Coastguard Worker devpoll_dispatch(struct event_base *base, void *arg, struct timeval *tv)
214*6777b538SAndroid Build Coastguard Worker {
215*6777b538SAndroid Build Coastguard Worker 	struct devpollop *devpollop = arg;
216*6777b538SAndroid Build Coastguard Worker 	struct pollfd *events = devpollop->events;
217*6777b538SAndroid Build Coastguard Worker 	struct dvpoll dvp;
218*6777b538SAndroid Build Coastguard Worker 	struct evdevpoll *evdp;
219*6777b538SAndroid Build Coastguard Worker 	int i, res, timeout = -1;
220*6777b538SAndroid Build Coastguard Worker 
221*6777b538SAndroid Build Coastguard Worker 	if (devpollop->nchanges)
222*6777b538SAndroid Build Coastguard Worker 		devpoll_commit(devpollop);
223*6777b538SAndroid Build Coastguard Worker 
224*6777b538SAndroid Build Coastguard Worker 	if (tv != NULL)
225*6777b538SAndroid Build Coastguard Worker 		timeout = tv->tv_sec * 1000 + (tv->tv_usec + 999) / 1000;
226*6777b538SAndroid Build Coastguard Worker 
227*6777b538SAndroid Build Coastguard Worker 	dvp.dp_fds = devpollop->events;
228*6777b538SAndroid Build Coastguard Worker 	dvp.dp_nfds = devpollop->nevents;
229*6777b538SAndroid Build Coastguard Worker 	dvp.dp_timeout = timeout;
230*6777b538SAndroid Build Coastguard Worker 
231*6777b538SAndroid Build Coastguard Worker 	res = ioctl(devpollop->dpfd, DP_POLL, &dvp);
232*6777b538SAndroid Build Coastguard Worker 
233*6777b538SAndroid Build Coastguard Worker 	if (res == -1) {
234*6777b538SAndroid Build Coastguard Worker 		if (errno != EINTR) {
235*6777b538SAndroid Build Coastguard Worker 			event_warn("ioctl: DP_POLL");
236*6777b538SAndroid Build Coastguard Worker 			return (-1);
237*6777b538SAndroid Build Coastguard Worker 		}
238*6777b538SAndroid Build Coastguard Worker 
239*6777b538SAndroid Build Coastguard Worker 		evsignal_process(base);
240*6777b538SAndroid Build Coastguard Worker 		return (0);
241*6777b538SAndroid Build Coastguard Worker 	} else if (base->sig.evsignal_caught) {
242*6777b538SAndroid Build Coastguard Worker 		evsignal_process(base);
243*6777b538SAndroid Build Coastguard Worker 	}
244*6777b538SAndroid Build Coastguard Worker 
245*6777b538SAndroid Build Coastguard Worker 	event_debug(("%s: devpoll_wait reports %d", __func__, res));
246*6777b538SAndroid Build Coastguard Worker 
247*6777b538SAndroid Build Coastguard Worker 	for (i = 0; i < res; i++) {
248*6777b538SAndroid Build Coastguard Worker 		int which = 0;
249*6777b538SAndroid Build Coastguard Worker 		int what = events[i].revents;
250*6777b538SAndroid Build Coastguard Worker 		struct event *evread = NULL, *evwrite = NULL;
251*6777b538SAndroid Build Coastguard Worker 
252*6777b538SAndroid Build Coastguard Worker 		assert(events[i].fd < devpollop->nfds);
253*6777b538SAndroid Build Coastguard Worker 		evdp = &devpollop->fds[events[i].fd];
254*6777b538SAndroid Build Coastguard Worker 
255*6777b538SAndroid Build Coastguard Worker                 if (what & POLLHUP)
256*6777b538SAndroid Build Coastguard Worker                         what |= POLLIN | POLLOUT;
257*6777b538SAndroid Build Coastguard Worker                 else if (what & POLLERR)
258*6777b538SAndroid Build Coastguard Worker                         what |= POLLIN | POLLOUT;
259*6777b538SAndroid Build Coastguard Worker 
260*6777b538SAndroid Build Coastguard Worker 		if (what & POLLIN) {
261*6777b538SAndroid Build Coastguard Worker 			evread = evdp->evread;
262*6777b538SAndroid Build Coastguard Worker 			which |= EV_READ;
263*6777b538SAndroid Build Coastguard Worker 		}
264*6777b538SAndroid Build Coastguard Worker 
265*6777b538SAndroid Build Coastguard Worker 		if (what & POLLOUT) {
266*6777b538SAndroid Build Coastguard Worker 			evwrite = evdp->evwrite;
267*6777b538SAndroid Build Coastguard Worker 			which |= EV_WRITE;
268*6777b538SAndroid Build Coastguard Worker 		}
269*6777b538SAndroid Build Coastguard Worker 
270*6777b538SAndroid Build Coastguard Worker 		if (!which)
271*6777b538SAndroid Build Coastguard Worker 			continue;
272*6777b538SAndroid Build Coastguard Worker 
273*6777b538SAndroid Build Coastguard Worker 		if (evread != NULL && !(evread->ev_events & EV_PERSIST))
274*6777b538SAndroid Build Coastguard Worker 			event_del(evread);
275*6777b538SAndroid Build Coastguard Worker 		if (evwrite != NULL && evwrite != evread &&
276*6777b538SAndroid Build Coastguard Worker 		    !(evwrite->ev_events & EV_PERSIST))
277*6777b538SAndroid Build Coastguard Worker 			event_del(evwrite);
278*6777b538SAndroid Build Coastguard Worker 
279*6777b538SAndroid Build Coastguard Worker 		if (evread != NULL)
280*6777b538SAndroid Build Coastguard Worker 			event_active(evread, EV_READ, 1);
281*6777b538SAndroid Build Coastguard Worker 		if (evwrite != NULL)
282*6777b538SAndroid Build Coastguard Worker 			event_active(evwrite, EV_WRITE, 1);
283*6777b538SAndroid Build Coastguard Worker 	}
284*6777b538SAndroid Build Coastguard Worker 
285*6777b538SAndroid Build Coastguard Worker 	return (0);
286*6777b538SAndroid Build Coastguard Worker }
287*6777b538SAndroid Build Coastguard Worker 
288*6777b538SAndroid Build Coastguard Worker 
289*6777b538SAndroid Build Coastguard Worker static int
devpoll_add(void * arg,struct event * ev)290*6777b538SAndroid Build Coastguard Worker devpoll_add(void *arg, struct event *ev)
291*6777b538SAndroid Build Coastguard Worker {
292*6777b538SAndroid Build Coastguard Worker 	struct devpollop *devpollop = arg;
293*6777b538SAndroid Build Coastguard Worker 	struct evdevpoll *evdp;
294*6777b538SAndroid Build Coastguard Worker 	int fd, events;
295*6777b538SAndroid Build Coastguard Worker 
296*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_SIGNAL)
297*6777b538SAndroid Build Coastguard Worker 		return (evsignal_add(ev));
298*6777b538SAndroid Build Coastguard Worker 
299*6777b538SAndroid Build Coastguard Worker 	fd = ev->ev_fd;
300*6777b538SAndroid Build Coastguard Worker 	if (fd >= devpollop->nfds) {
301*6777b538SAndroid Build Coastguard Worker 		/* Extend the file descriptor array as necessary */
302*6777b538SAndroid Build Coastguard Worker 		if (devpoll_recalc(ev->ev_base, devpollop, fd) == -1)
303*6777b538SAndroid Build Coastguard Worker 			return (-1);
304*6777b538SAndroid Build Coastguard Worker 	}
305*6777b538SAndroid Build Coastguard Worker 	evdp = &devpollop->fds[fd];
306*6777b538SAndroid Build Coastguard Worker 
307*6777b538SAndroid Build Coastguard Worker 	/*
308*6777b538SAndroid Build Coastguard Worker 	 * It's not necessary to OR the existing read/write events that we
309*6777b538SAndroid Build Coastguard Worker 	 * are currently interested in with the new event we are adding.
310*6777b538SAndroid Build Coastguard Worker 	 * The /dev/poll driver ORs any new events with the existing events
311*6777b538SAndroid Build Coastguard Worker 	 * that it has cached for the fd.
312*6777b538SAndroid Build Coastguard Worker 	 */
313*6777b538SAndroid Build Coastguard Worker 
314*6777b538SAndroid Build Coastguard Worker 	events = 0;
315*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_READ) {
316*6777b538SAndroid Build Coastguard Worker 		if (evdp->evread && evdp->evread != ev) {
317*6777b538SAndroid Build Coastguard Worker 		   /* There is already a different read event registered */
318*6777b538SAndroid Build Coastguard Worker 		   return(-1);
319*6777b538SAndroid Build Coastguard Worker 		}
320*6777b538SAndroid Build Coastguard Worker 		events |= POLLIN;
321*6777b538SAndroid Build Coastguard Worker 	}
322*6777b538SAndroid Build Coastguard Worker 
323*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_WRITE) {
324*6777b538SAndroid Build Coastguard Worker 		if (evdp->evwrite && evdp->evwrite != ev) {
325*6777b538SAndroid Build Coastguard Worker 		   /* There is already a different write event registered */
326*6777b538SAndroid Build Coastguard Worker 		   return(-1);
327*6777b538SAndroid Build Coastguard Worker 		}
328*6777b538SAndroid Build Coastguard Worker 		events |= POLLOUT;
329*6777b538SAndroid Build Coastguard Worker 	}
330*6777b538SAndroid Build Coastguard Worker 
331*6777b538SAndroid Build Coastguard Worker 	if (devpoll_queue(devpollop, fd, events) != 0)
332*6777b538SAndroid Build Coastguard Worker 		return(-1);
333*6777b538SAndroid Build Coastguard Worker 
334*6777b538SAndroid Build Coastguard Worker 	/* Update events responsible */
335*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_READ)
336*6777b538SAndroid Build Coastguard Worker 		evdp->evread = ev;
337*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_WRITE)
338*6777b538SAndroid Build Coastguard Worker 		evdp->evwrite = ev;
339*6777b538SAndroid Build Coastguard Worker 
340*6777b538SAndroid Build Coastguard Worker 	return (0);
341*6777b538SAndroid Build Coastguard Worker }
342*6777b538SAndroid Build Coastguard Worker 
343*6777b538SAndroid Build Coastguard Worker static int
devpoll_del(void * arg,struct event * ev)344*6777b538SAndroid Build Coastguard Worker devpoll_del(void *arg, struct event *ev)
345*6777b538SAndroid Build Coastguard Worker {
346*6777b538SAndroid Build Coastguard Worker 	struct devpollop *devpollop = arg;
347*6777b538SAndroid Build Coastguard Worker 	struct evdevpoll *evdp;
348*6777b538SAndroid Build Coastguard Worker 	int fd, events;
349*6777b538SAndroid Build Coastguard Worker 	int needwritedelete = 1, needreaddelete = 1;
350*6777b538SAndroid Build Coastguard Worker 
351*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_SIGNAL)
352*6777b538SAndroid Build Coastguard Worker 		return (evsignal_del(ev));
353*6777b538SAndroid Build Coastguard Worker 
354*6777b538SAndroid Build Coastguard Worker 	fd = ev->ev_fd;
355*6777b538SAndroid Build Coastguard Worker 	if (fd >= devpollop->nfds)
356*6777b538SAndroid Build Coastguard Worker 		return (0);
357*6777b538SAndroid Build Coastguard Worker 	evdp = &devpollop->fds[fd];
358*6777b538SAndroid Build Coastguard Worker 
359*6777b538SAndroid Build Coastguard Worker 	events = 0;
360*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_READ)
361*6777b538SAndroid Build Coastguard Worker 		events |= POLLIN;
362*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_WRITE)
363*6777b538SAndroid Build Coastguard Worker 		events |= POLLOUT;
364*6777b538SAndroid Build Coastguard Worker 
365*6777b538SAndroid Build Coastguard Worker 	/*
366*6777b538SAndroid Build Coastguard Worker 	 * The only way to remove an fd from the /dev/poll monitored set is
367*6777b538SAndroid Build Coastguard Worker 	 * to use POLLREMOVE by itself.  This removes ALL events for the fd
368*6777b538SAndroid Build Coastguard Worker 	 * provided so if we care about two events and are only removing one
369*6777b538SAndroid Build Coastguard Worker 	 * we must re-add the other event after POLLREMOVE.
370*6777b538SAndroid Build Coastguard Worker 	 */
371*6777b538SAndroid Build Coastguard Worker 
372*6777b538SAndroid Build Coastguard Worker 	if (devpoll_queue(devpollop, fd, POLLREMOVE) != 0)
373*6777b538SAndroid Build Coastguard Worker 		return(-1);
374*6777b538SAndroid Build Coastguard Worker 
375*6777b538SAndroid Build Coastguard Worker 	if ((events & (POLLIN|POLLOUT)) != (POLLIN|POLLOUT)) {
376*6777b538SAndroid Build Coastguard Worker 		/*
377*6777b538SAndroid Build Coastguard Worker 		 * We're not deleting all events, so we must resubmit the
378*6777b538SAndroid Build Coastguard Worker 		 * event that we are still interested in if one exists.
379*6777b538SAndroid Build Coastguard Worker 		 */
380*6777b538SAndroid Build Coastguard Worker 
381*6777b538SAndroid Build Coastguard Worker 		if ((events & POLLIN) && evdp->evwrite != NULL) {
382*6777b538SAndroid Build Coastguard Worker 			/* Deleting read, still care about write */
383*6777b538SAndroid Build Coastguard Worker 			devpoll_queue(devpollop, fd, POLLOUT);
384*6777b538SAndroid Build Coastguard Worker 			needwritedelete = 0;
385*6777b538SAndroid Build Coastguard Worker 		} else if ((events & POLLOUT) && evdp->evread != NULL) {
386*6777b538SAndroid Build Coastguard Worker 			/* Deleting write, still care about read */
387*6777b538SAndroid Build Coastguard Worker 			devpoll_queue(devpollop, fd, POLLIN);
388*6777b538SAndroid Build Coastguard Worker 			needreaddelete = 0;
389*6777b538SAndroid Build Coastguard Worker 		}
390*6777b538SAndroid Build Coastguard Worker 	}
391*6777b538SAndroid Build Coastguard Worker 
392*6777b538SAndroid Build Coastguard Worker 	if (needreaddelete)
393*6777b538SAndroid Build Coastguard Worker 		evdp->evread = NULL;
394*6777b538SAndroid Build Coastguard Worker 	if (needwritedelete)
395*6777b538SAndroid Build Coastguard Worker 		evdp->evwrite = NULL;
396*6777b538SAndroid Build Coastguard Worker 
397*6777b538SAndroid Build Coastguard Worker 	return (0);
398*6777b538SAndroid Build Coastguard Worker }
399*6777b538SAndroid Build Coastguard Worker 
400*6777b538SAndroid Build Coastguard Worker static void
devpoll_dealloc(struct event_base * base,void * arg)401*6777b538SAndroid Build Coastguard Worker devpoll_dealloc(struct event_base *base, void *arg)
402*6777b538SAndroid Build Coastguard Worker {
403*6777b538SAndroid Build Coastguard Worker 	struct devpollop *devpollop = arg;
404*6777b538SAndroid Build Coastguard Worker 
405*6777b538SAndroid Build Coastguard Worker 	evsignal_dealloc(base);
406*6777b538SAndroid Build Coastguard Worker 	if (devpollop->fds)
407*6777b538SAndroid Build Coastguard Worker 		free(devpollop->fds);
408*6777b538SAndroid Build Coastguard Worker 	if (devpollop->events)
409*6777b538SAndroid Build Coastguard Worker 		free(devpollop->events);
410*6777b538SAndroid Build Coastguard Worker 	if (devpollop->changes)
411*6777b538SAndroid Build Coastguard Worker 		free(devpollop->changes);
412*6777b538SAndroid Build Coastguard Worker 	if (devpollop->dpfd >= 0)
413*6777b538SAndroid Build Coastguard Worker 		close(devpollop->dpfd);
414*6777b538SAndroid Build Coastguard Worker 
415*6777b538SAndroid Build Coastguard Worker 	memset(devpollop, 0, sizeof(struct devpollop));
416*6777b538SAndroid Build Coastguard Worker 	free(devpollop);
417*6777b538SAndroid Build Coastguard Worker }
418