xref: /aosp_15_r20/external/cronet/third_party/libevent/evport.c (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker /*
2*6777b538SAndroid Build Coastguard Worker  * Submitted by David Pacheco ([email protected])
3*6777b538SAndroid Build Coastguard Worker  *
4*6777b538SAndroid Build Coastguard Worker  * Redistribution and use in source and binary forms, with or without
5*6777b538SAndroid Build Coastguard Worker  * modification, are permitted provided that the following conditions
6*6777b538SAndroid Build Coastguard Worker  * are met:
7*6777b538SAndroid Build Coastguard Worker  * 1. Redistributions of source code must retain the above copyright
8*6777b538SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer.
9*6777b538SAndroid Build Coastguard Worker  * 2. Redistributions in binary form must reproduce the above copyright
10*6777b538SAndroid Build Coastguard Worker  *    notice, this list of conditions and the following disclaimer in the
11*6777b538SAndroid Build Coastguard Worker  *    documentation and/or other materials provided with the distribution.
12*6777b538SAndroid Build Coastguard Worker  * 3. The name of the author may not be used to endorse or promote products
13*6777b538SAndroid Build Coastguard Worker  *    derived from this software without specific prior written permission.
14*6777b538SAndroid Build Coastguard Worker  *
15*6777b538SAndroid Build Coastguard Worker  * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``AS IS'' AND ANY
16*6777b538SAndroid Build Coastguard Worker  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17*6777b538SAndroid Build Coastguard Worker  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18*6777b538SAndroid Build Coastguard Worker  * DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
19*6777b538SAndroid Build Coastguard Worker  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20*6777b538SAndroid Build Coastguard Worker  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21*6777b538SAndroid Build Coastguard Worker  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22*6777b538SAndroid Build Coastguard Worker  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23*6777b538SAndroid Build Coastguard Worker  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24*6777b538SAndroid Build Coastguard Worker  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*6777b538SAndroid Build Coastguard Worker  */
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker /*
28*6777b538SAndroid Build Coastguard Worker  * Copyright (c) 2007 Sun Microsystems. All rights reserved.
29*6777b538SAndroid Build Coastguard Worker  * Use is subject to license terms.
30*6777b538SAndroid Build Coastguard Worker  */
31*6777b538SAndroid Build Coastguard Worker 
32*6777b538SAndroid Build Coastguard Worker /*
33*6777b538SAndroid Build Coastguard Worker  * evport.c: event backend using Solaris 10 event ports. See port_create(3C).
34*6777b538SAndroid Build Coastguard Worker  * This implementation is loosely modeled after the one used for select(2) (in
35*6777b538SAndroid Build Coastguard Worker  * select.c).
36*6777b538SAndroid Build Coastguard Worker  *
37*6777b538SAndroid Build Coastguard Worker  * The outstanding events are tracked in a data structure called evport_data.
38*6777b538SAndroid Build Coastguard Worker  * Each entry in the ed_fds array corresponds to a file descriptor, and contains
39*6777b538SAndroid Build Coastguard Worker  * pointers to the read and write events that correspond to that fd. (That is,
40*6777b538SAndroid Build Coastguard Worker  * when the file is readable, the "read" event should handle it, etc.)
41*6777b538SAndroid Build Coastguard Worker  *
42*6777b538SAndroid Build Coastguard Worker  * evport_add and evport_del update this data structure. evport_dispatch uses it
43*6777b538SAndroid Build Coastguard Worker  * to determine where to callback when an event occurs (which it gets from
44*6777b538SAndroid Build Coastguard Worker  * port_getn).
45*6777b538SAndroid Build Coastguard Worker  *
46*6777b538SAndroid Build Coastguard Worker  * Helper functions are used: grow() grows the file descriptor array as
47*6777b538SAndroid Build Coastguard Worker  * necessary when large fd's come in. reassociate() takes care of maintaining
48*6777b538SAndroid Build Coastguard Worker  * the proper file-descriptor/event-port associations.
49*6777b538SAndroid Build Coastguard Worker  *
50*6777b538SAndroid Build Coastguard Worker  * As in the select(2) implementation, signals are handled by evsignal.
51*6777b538SAndroid Build Coastguard Worker  */
52*6777b538SAndroid Build Coastguard Worker 
53*6777b538SAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
54*6777b538SAndroid Build Coastguard Worker #include "config.h"
55*6777b538SAndroid Build Coastguard Worker #endif
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker #include <sys/time.h>
58*6777b538SAndroid Build Coastguard Worker #include <assert.h>
59*6777b538SAndroid Build Coastguard Worker #include <sys/queue.h>
60*6777b538SAndroid Build Coastguard Worker #include <errno.h>
61*6777b538SAndroid Build Coastguard Worker #include <poll.h>
62*6777b538SAndroid Build Coastguard Worker #include <port.h>
63*6777b538SAndroid Build Coastguard Worker #include <signal.h>
64*6777b538SAndroid Build Coastguard Worker #include <stdio.h>
65*6777b538SAndroid Build Coastguard Worker #include <stdlib.h>
66*6777b538SAndroid Build Coastguard Worker #include <string.h>
67*6777b538SAndroid Build Coastguard Worker #include <time.h>
68*6777b538SAndroid Build Coastguard Worker #include <unistd.h>
69*6777b538SAndroid Build Coastguard Worker #ifdef CHECK_INVARIANTS
70*6777b538SAndroid Build Coastguard Worker #include <assert.h>
71*6777b538SAndroid Build Coastguard Worker #endif
72*6777b538SAndroid Build Coastguard Worker 
73*6777b538SAndroid Build Coastguard Worker #include "event.h"
74*6777b538SAndroid Build Coastguard Worker #include "event-internal.h"
75*6777b538SAndroid Build Coastguard Worker #include "log.h"
76*6777b538SAndroid Build Coastguard Worker #include "evsignal.h"
77*6777b538SAndroid Build Coastguard Worker 
78*6777b538SAndroid Build Coastguard Worker 
79*6777b538SAndroid Build Coastguard Worker /*
80*6777b538SAndroid Build Coastguard Worker  * Default value for ed_nevents, which is the maximum file descriptor number we
81*6777b538SAndroid Build Coastguard Worker  * can handle. If an event comes in for a file descriptor F > nevents, we will
82*6777b538SAndroid Build Coastguard Worker  * grow the array of file descriptors, doubling its size.
83*6777b538SAndroid Build Coastguard Worker  */
84*6777b538SAndroid Build Coastguard Worker #define DEFAULT_NFDS	16
85*6777b538SAndroid Build Coastguard Worker 
86*6777b538SAndroid Build Coastguard Worker 
87*6777b538SAndroid Build Coastguard Worker /*
88*6777b538SAndroid Build Coastguard Worker  * EVENTS_PER_GETN is the maximum number of events to retrieve from port_getn on
89*6777b538SAndroid Build Coastguard Worker  * any particular call. You can speed things up by increasing this, but it will
90*6777b538SAndroid Build Coastguard Worker  * (obviously) require more memory.
91*6777b538SAndroid Build Coastguard Worker  */
92*6777b538SAndroid Build Coastguard Worker #define EVENTS_PER_GETN 8
93*6777b538SAndroid Build Coastguard Worker 
94*6777b538SAndroid Build Coastguard Worker /*
95*6777b538SAndroid Build Coastguard Worker  * Per-file-descriptor information about what events we're subscribed to. These
96*6777b538SAndroid Build Coastguard Worker  * fields are NULL if no event is subscribed to either of them.
97*6777b538SAndroid Build Coastguard Worker  */
98*6777b538SAndroid Build Coastguard Worker 
99*6777b538SAndroid Build Coastguard Worker struct fd_info {
100*6777b538SAndroid Build Coastguard Worker 	struct event* fdi_revt; /* the event responsible for the "read"  */
101*6777b538SAndroid Build Coastguard Worker 	struct event* fdi_wevt; /* the event responsible for the "write" */
102*6777b538SAndroid Build Coastguard Worker };
103*6777b538SAndroid Build Coastguard Worker 
104*6777b538SAndroid Build Coastguard Worker #define FDI_HAS_READ(fdi)  ((fdi)->fdi_revt != NULL)
105*6777b538SAndroid Build Coastguard Worker #define FDI_HAS_WRITE(fdi) ((fdi)->fdi_wevt != NULL)
106*6777b538SAndroid Build Coastguard Worker #define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi))
107*6777b538SAndroid Build Coastguard Worker #define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \
108*6777b538SAndroid Build Coastguard Worker     (FDI_HAS_WRITE(fdi) ? POLLOUT : 0)
109*6777b538SAndroid Build Coastguard Worker 
110*6777b538SAndroid Build Coastguard Worker struct evport_data {
111*6777b538SAndroid Build Coastguard Worker 	int 		ed_port;	/* event port for system events  */
112*6777b538SAndroid Build Coastguard Worker 	int		ed_nevents;	/* number of allocated fdi's 	 */
113*6777b538SAndroid Build Coastguard Worker 	struct fd_info *ed_fds;		/* allocated fdi table 		 */
114*6777b538SAndroid Build Coastguard Worker 	/* fdi's that we need to reassoc */
115*6777b538SAndroid Build Coastguard Worker 	int ed_pending[EVENTS_PER_GETN]; /* fd's with pending events */
116*6777b538SAndroid Build Coastguard Worker };
117*6777b538SAndroid Build Coastguard Worker 
118*6777b538SAndroid Build Coastguard Worker static void*	evport_init	(struct event_base *);
119*6777b538SAndroid Build Coastguard Worker static int 	evport_add	(void *, struct event *);
120*6777b538SAndroid Build Coastguard Worker static int 	evport_del	(void *, struct event *);
121*6777b538SAndroid Build Coastguard Worker static int 	evport_dispatch	(struct event_base *, void *, struct timeval *);
122*6777b538SAndroid Build Coastguard Worker static void	evport_dealloc	(struct event_base *, void *);
123*6777b538SAndroid Build Coastguard Worker 
124*6777b538SAndroid Build Coastguard Worker const struct eventop evportops = {
125*6777b538SAndroid Build Coastguard Worker 	"evport",
126*6777b538SAndroid Build Coastguard Worker 	evport_init,
127*6777b538SAndroid Build Coastguard Worker 	evport_add,
128*6777b538SAndroid Build Coastguard Worker 	evport_del,
129*6777b538SAndroid Build Coastguard Worker 	evport_dispatch,
130*6777b538SAndroid Build Coastguard Worker 	evport_dealloc,
131*6777b538SAndroid Build Coastguard Worker 	1 /* need reinit */
132*6777b538SAndroid Build Coastguard Worker };
133*6777b538SAndroid Build Coastguard Worker 
134*6777b538SAndroid Build Coastguard Worker /*
135*6777b538SAndroid Build Coastguard Worker  * Initialize the event port implementation.
136*6777b538SAndroid Build Coastguard Worker  */
137*6777b538SAndroid Build Coastguard Worker 
138*6777b538SAndroid Build Coastguard Worker static void*
evport_init(struct event_base * base)139*6777b538SAndroid Build Coastguard Worker evport_init(struct event_base *base)
140*6777b538SAndroid Build Coastguard Worker {
141*6777b538SAndroid Build Coastguard Worker 	struct evport_data *evpd;
142*6777b538SAndroid Build Coastguard Worker 	int i;
143*6777b538SAndroid Build Coastguard Worker 	/*
144*6777b538SAndroid Build Coastguard Worker 	 * Disable event ports when this environment variable is set
145*6777b538SAndroid Build Coastguard Worker 	 */
146*6777b538SAndroid Build Coastguard Worker 	if (evutil_getenv("EVENT_NOEVPORT"))
147*6777b538SAndroid Build Coastguard Worker 		return (NULL);
148*6777b538SAndroid Build Coastguard Worker 
149*6777b538SAndroid Build Coastguard Worker 	if (!(evpd = calloc(1, sizeof(struct evport_data))))
150*6777b538SAndroid Build Coastguard Worker 		return (NULL);
151*6777b538SAndroid Build Coastguard Worker 
152*6777b538SAndroid Build Coastguard Worker 	if ((evpd->ed_port = port_create()) == -1) {
153*6777b538SAndroid Build Coastguard Worker 		free(evpd);
154*6777b538SAndroid Build Coastguard Worker 		return (NULL);
155*6777b538SAndroid Build Coastguard Worker 	}
156*6777b538SAndroid Build Coastguard Worker 
157*6777b538SAndroid Build Coastguard Worker 	/*
158*6777b538SAndroid Build Coastguard Worker 	 * Initialize file descriptor structure
159*6777b538SAndroid Build Coastguard Worker 	 */
160*6777b538SAndroid Build Coastguard Worker 	evpd->ed_fds = calloc(DEFAULT_NFDS, sizeof(struct fd_info));
161*6777b538SAndroid Build Coastguard Worker 	if (evpd->ed_fds == NULL) {
162*6777b538SAndroid Build Coastguard Worker 		close(evpd->ed_port);
163*6777b538SAndroid Build Coastguard Worker 		free(evpd);
164*6777b538SAndroid Build Coastguard Worker 		return (NULL);
165*6777b538SAndroid Build Coastguard Worker 	}
166*6777b538SAndroid Build Coastguard Worker 	evpd->ed_nevents = DEFAULT_NFDS;
167*6777b538SAndroid Build Coastguard Worker 	for (i = 0; i < EVENTS_PER_GETN; i++)
168*6777b538SAndroid Build Coastguard Worker 		evpd->ed_pending[i] = -1;
169*6777b538SAndroid Build Coastguard Worker 
170*6777b538SAndroid Build Coastguard Worker 	evsignal_init(base);
171*6777b538SAndroid Build Coastguard Worker 
172*6777b538SAndroid Build Coastguard Worker 	return (evpd);
173*6777b538SAndroid Build Coastguard Worker }
174*6777b538SAndroid Build Coastguard Worker 
175*6777b538SAndroid Build Coastguard Worker #ifdef CHECK_INVARIANTS
176*6777b538SAndroid Build Coastguard Worker /*
177*6777b538SAndroid Build Coastguard Worker  * Checks some basic properties about the evport_data structure. Because it
178*6777b538SAndroid Build Coastguard Worker  * checks all file descriptors, this function can be expensive when the maximum
179*6777b538SAndroid Build Coastguard Worker  * file descriptor ever used is rather large.
180*6777b538SAndroid Build Coastguard Worker  */
181*6777b538SAndroid Build Coastguard Worker 
182*6777b538SAndroid Build Coastguard Worker static void
check_evportop(struct evport_data * evpd)183*6777b538SAndroid Build Coastguard Worker check_evportop(struct evport_data *evpd)
184*6777b538SAndroid Build Coastguard Worker {
185*6777b538SAndroid Build Coastguard Worker 	assert(evpd);
186*6777b538SAndroid Build Coastguard Worker 	assert(evpd->ed_nevents > 0);
187*6777b538SAndroid Build Coastguard Worker 	assert(evpd->ed_port > 0);
188*6777b538SAndroid Build Coastguard Worker 	assert(evpd->ed_fds > 0);
189*6777b538SAndroid Build Coastguard Worker 
190*6777b538SAndroid Build Coastguard Worker 	/*
191*6777b538SAndroid Build Coastguard Worker 	 * Verify the integrity of the fd_info struct as well as the events to
192*6777b538SAndroid Build Coastguard Worker 	 * which it points (at least, that they're valid references and correct
193*6777b538SAndroid Build Coastguard Worker 	 * for their position in the structure).
194*6777b538SAndroid Build Coastguard Worker 	 */
195*6777b538SAndroid Build Coastguard Worker 	int i;
196*6777b538SAndroid Build Coastguard Worker 	for (i = 0; i < evpd->ed_nevents; ++i) {
197*6777b538SAndroid Build Coastguard Worker 		struct event 	*ev;
198*6777b538SAndroid Build Coastguard Worker 		struct fd_info 	*fdi;
199*6777b538SAndroid Build Coastguard Worker 
200*6777b538SAndroid Build Coastguard Worker 		fdi = &evpd->ed_fds[i];
201*6777b538SAndroid Build Coastguard Worker 		if ((ev = fdi->fdi_revt) != NULL) {
202*6777b538SAndroid Build Coastguard Worker 			assert(ev->ev_fd == i);
203*6777b538SAndroid Build Coastguard Worker 		}
204*6777b538SAndroid Build Coastguard Worker 		if ((ev = fdi->fdi_wevt) != NULL) {
205*6777b538SAndroid Build Coastguard Worker 			assert(ev->ev_fd == i);
206*6777b538SAndroid Build Coastguard Worker 		}
207*6777b538SAndroid Build Coastguard Worker 	}
208*6777b538SAndroid Build Coastguard Worker }
209*6777b538SAndroid Build Coastguard Worker 
210*6777b538SAndroid Build Coastguard Worker /*
211*6777b538SAndroid Build Coastguard Worker  * Verifies very basic integrity of a given port_event.
212*6777b538SAndroid Build Coastguard Worker  */
213*6777b538SAndroid Build Coastguard Worker static void
check_event(port_event_t * pevt)214*6777b538SAndroid Build Coastguard Worker check_event(port_event_t* pevt)
215*6777b538SAndroid Build Coastguard Worker {
216*6777b538SAndroid Build Coastguard Worker 	/*
217*6777b538SAndroid Build Coastguard Worker 	 * We've only registered for PORT_SOURCE_FD events. The only
218*6777b538SAndroid Build Coastguard Worker 	 * other thing we can legitimately receive is PORT_SOURCE_ALERT,
219*6777b538SAndroid Build Coastguard Worker 	 * but since we're not using port_alert either, we can assume
220*6777b538SAndroid Build Coastguard Worker 	 * PORT_SOURCE_FD.
221*6777b538SAndroid Build Coastguard Worker 	 */
222*6777b538SAndroid Build Coastguard Worker 	assert(pevt->portev_source == PORT_SOURCE_FD);
223*6777b538SAndroid Build Coastguard Worker 	assert(pevt->portev_user == NULL);
224*6777b538SAndroid Build Coastguard Worker }
225*6777b538SAndroid Build Coastguard Worker 
226*6777b538SAndroid Build Coastguard Worker #else
227*6777b538SAndroid Build Coastguard Worker #define check_evportop(epop)
228*6777b538SAndroid Build Coastguard Worker #define check_event(pevt)
229*6777b538SAndroid Build Coastguard Worker #endif /* CHECK_INVARIANTS */
230*6777b538SAndroid Build Coastguard Worker 
231*6777b538SAndroid Build Coastguard Worker /*
232*6777b538SAndroid Build Coastguard Worker  * Doubles the size of the allocated file descriptor array.
233*6777b538SAndroid Build Coastguard Worker  */
234*6777b538SAndroid Build Coastguard Worker static int
grow(struct evport_data * epdp,int factor)235*6777b538SAndroid Build Coastguard Worker grow(struct evport_data *epdp, int factor)
236*6777b538SAndroid Build Coastguard Worker {
237*6777b538SAndroid Build Coastguard Worker 	struct fd_info *tmp;
238*6777b538SAndroid Build Coastguard Worker 	int oldsize = epdp->ed_nevents;
239*6777b538SAndroid Build Coastguard Worker 	int newsize = factor * oldsize;
240*6777b538SAndroid Build Coastguard Worker 	assert(factor > 1);
241*6777b538SAndroid Build Coastguard Worker 
242*6777b538SAndroid Build Coastguard Worker 	check_evportop(epdp);
243*6777b538SAndroid Build Coastguard Worker 
244*6777b538SAndroid Build Coastguard Worker 	tmp = realloc(epdp->ed_fds, sizeof(struct fd_info) * newsize);
245*6777b538SAndroid Build Coastguard Worker 	if (NULL == tmp)
246*6777b538SAndroid Build Coastguard Worker 		return -1;
247*6777b538SAndroid Build Coastguard Worker 	epdp->ed_fds = tmp;
248*6777b538SAndroid Build Coastguard Worker 	memset((char*) (epdp->ed_fds + oldsize), 0,
249*6777b538SAndroid Build Coastguard Worker 	    (newsize - oldsize)*sizeof(struct fd_info));
250*6777b538SAndroid Build Coastguard Worker 	epdp->ed_nevents = newsize;
251*6777b538SAndroid Build Coastguard Worker 
252*6777b538SAndroid Build Coastguard Worker 	check_evportop(epdp);
253*6777b538SAndroid Build Coastguard Worker 
254*6777b538SAndroid Build Coastguard Worker 	return 0;
255*6777b538SAndroid Build Coastguard Worker }
256*6777b538SAndroid Build Coastguard Worker 
257*6777b538SAndroid Build Coastguard Worker 
258*6777b538SAndroid Build Coastguard Worker /*
259*6777b538SAndroid Build Coastguard Worker  * (Re)associates the given file descriptor with the event port. The OS events
260*6777b538SAndroid Build Coastguard Worker  * are specified (implicitly) from the fd_info struct.
261*6777b538SAndroid Build Coastguard Worker  */
262*6777b538SAndroid Build Coastguard Worker static int
reassociate(struct evport_data * epdp,struct fd_info * fdip,int fd)263*6777b538SAndroid Build Coastguard Worker reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd)
264*6777b538SAndroid Build Coastguard Worker {
265*6777b538SAndroid Build Coastguard Worker 	int sysevents = FDI_TO_SYSEVENTS(fdip);
266*6777b538SAndroid Build Coastguard Worker 
267*6777b538SAndroid Build Coastguard Worker 	if (sysevents != 0) {
268*6777b538SAndroid Build Coastguard Worker 		if (port_associate(epdp->ed_port, PORT_SOURCE_FD,
269*6777b538SAndroid Build Coastguard Worker 				   fd, sysevents, NULL) == -1) {
270*6777b538SAndroid Build Coastguard Worker 			event_warn("port_associate");
271*6777b538SAndroid Build Coastguard Worker 			return (-1);
272*6777b538SAndroid Build Coastguard Worker 		}
273*6777b538SAndroid Build Coastguard Worker 	}
274*6777b538SAndroid Build Coastguard Worker 
275*6777b538SAndroid Build Coastguard Worker 	check_evportop(epdp);
276*6777b538SAndroid Build Coastguard Worker 
277*6777b538SAndroid Build Coastguard Worker 	return (0);
278*6777b538SAndroid Build Coastguard Worker }
279*6777b538SAndroid Build Coastguard Worker 
280*6777b538SAndroid Build Coastguard Worker /*
281*6777b538SAndroid Build Coastguard Worker  * Main event loop - polls port_getn for some number of events, and processes
282*6777b538SAndroid Build Coastguard Worker  * them.
283*6777b538SAndroid Build Coastguard Worker  */
284*6777b538SAndroid Build Coastguard Worker 
285*6777b538SAndroid Build Coastguard Worker static int
evport_dispatch(struct event_base * base,void * arg,struct timeval * tv)286*6777b538SAndroid Build Coastguard Worker evport_dispatch(struct event_base *base, void *arg, struct timeval *tv)
287*6777b538SAndroid Build Coastguard Worker {
288*6777b538SAndroid Build Coastguard Worker 	int i, res;
289*6777b538SAndroid Build Coastguard Worker 	struct evport_data *epdp = arg;
290*6777b538SAndroid Build Coastguard Worker 	port_event_t pevtlist[EVENTS_PER_GETN];
291*6777b538SAndroid Build Coastguard Worker 
292*6777b538SAndroid Build Coastguard Worker 	/*
293*6777b538SAndroid Build Coastguard Worker 	 * port_getn will block until it has at least nevents events. It will
294*6777b538SAndroid Build Coastguard Worker 	 * also return how many it's given us (which may be more than we asked
295*6777b538SAndroid Build Coastguard Worker 	 * for, as long as it's less than our maximum (EVENTS_PER_GETN)) in
296*6777b538SAndroid Build Coastguard Worker 	 * nevents.
297*6777b538SAndroid Build Coastguard Worker 	 */
298*6777b538SAndroid Build Coastguard Worker 	int nevents = 1;
299*6777b538SAndroid Build Coastguard Worker 
300*6777b538SAndroid Build Coastguard Worker 	/*
301*6777b538SAndroid Build Coastguard Worker 	 * We have to convert a struct timeval to a struct timespec
302*6777b538SAndroid Build Coastguard Worker 	 * (only difference is nanoseconds vs. microseconds). If no time-based
303*6777b538SAndroid Build Coastguard Worker 	 * events are active, we should wait for I/O (and tv == NULL).
304*6777b538SAndroid Build Coastguard Worker 	 */
305*6777b538SAndroid Build Coastguard Worker 	struct timespec ts;
306*6777b538SAndroid Build Coastguard Worker 	struct timespec *ts_p = NULL;
307*6777b538SAndroid Build Coastguard Worker 	if (tv != NULL) {
308*6777b538SAndroid Build Coastguard Worker 		ts.tv_sec = tv->tv_sec;
309*6777b538SAndroid Build Coastguard Worker 		ts.tv_nsec = tv->tv_usec * 1000;
310*6777b538SAndroid Build Coastguard Worker 		ts_p = &ts;
311*6777b538SAndroid Build Coastguard Worker 	}
312*6777b538SAndroid Build Coastguard Worker 
313*6777b538SAndroid Build Coastguard Worker 	/*
314*6777b538SAndroid Build Coastguard Worker 	 * Before doing anything else, we need to reassociate the events we hit
315*6777b538SAndroid Build Coastguard Worker 	 * last time which need reassociation. See comment at the end of the
316*6777b538SAndroid Build Coastguard Worker 	 * loop below.
317*6777b538SAndroid Build Coastguard Worker 	 */
318*6777b538SAndroid Build Coastguard Worker 	for (i = 0; i < EVENTS_PER_GETN; ++i) {
319*6777b538SAndroid Build Coastguard Worker 		struct fd_info *fdi = NULL;
320*6777b538SAndroid Build Coastguard Worker 		if (epdp->ed_pending[i] != -1) {
321*6777b538SAndroid Build Coastguard Worker 			fdi = &(epdp->ed_fds[epdp->ed_pending[i]]);
322*6777b538SAndroid Build Coastguard Worker 		}
323*6777b538SAndroid Build Coastguard Worker 
324*6777b538SAndroid Build Coastguard Worker 		if (fdi != NULL && FDI_HAS_EVENTS(fdi)) {
325*6777b538SAndroid Build Coastguard Worker 			int fd = FDI_HAS_READ(fdi) ? fdi->fdi_revt->ev_fd :
326*6777b538SAndroid Build Coastguard Worker 			    fdi->fdi_wevt->ev_fd;
327*6777b538SAndroid Build Coastguard Worker 			reassociate(epdp, fdi, fd);
328*6777b538SAndroid Build Coastguard Worker 			epdp->ed_pending[i] = -1;
329*6777b538SAndroid Build Coastguard Worker 		}
330*6777b538SAndroid Build Coastguard Worker 	}
331*6777b538SAndroid Build Coastguard Worker 
332*6777b538SAndroid Build Coastguard Worker 	if ((res = port_getn(epdp->ed_port, pevtlist, EVENTS_PER_GETN,
333*6777b538SAndroid Build Coastguard Worker 		    (unsigned int *) &nevents, ts_p)) == -1) {
334*6777b538SAndroid Build Coastguard Worker 		if (errno == EINTR || errno == EAGAIN) {
335*6777b538SAndroid Build Coastguard Worker 			evsignal_process(base);
336*6777b538SAndroid Build Coastguard Worker 			return (0);
337*6777b538SAndroid Build Coastguard Worker 		} else if (errno == ETIME) {
338*6777b538SAndroid Build Coastguard Worker 			if (nevents == 0)
339*6777b538SAndroid Build Coastguard Worker 				return (0);
340*6777b538SAndroid Build Coastguard Worker 		} else {
341*6777b538SAndroid Build Coastguard Worker 			event_warn("port_getn");
342*6777b538SAndroid Build Coastguard Worker 			return (-1);
343*6777b538SAndroid Build Coastguard Worker 		}
344*6777b538SAndroid Build Coastguard Worker 	} else if (base->sig.evsignal_caught) {
345*6777b538SAndroid Build Coastguard Worker 		evsignal_process(base);
346*6777b538SAndroid Build Coastguard Worker 	}
347*6777b538SAndroid Build Coastguard Worker 
348*6777b538SAndroid Build Coastguard Worker 	event_debug(("%s: port_getn reports %d events", __func__, nevents));
349*6777b538SAndroid Build Coastguard Worker 
350*6777b538SAndroid Build Coastguard Worker 	for (i = 0; i < nevents; ++i) {
351*6777b538SAndroid Build Coastguard Worker 		struct event *ev;
352*6777b538SAndroid Build Coastguard Worker 		struct fd_info *fdi;
353*6777b538SAndroid Build Coastguard Worker 		port_event_t *pevt = &pevtlist[i];
354*6777b538SAndroid Build Coastguard Worker 		int fd = (int) pevt->portev_object;
355*6777b538SAndroid Build Coastguard Worker 
356*6777b538SAndroid Build Coastguard Worker 		check_evportop(epdp);
357*6777b538SAndroid Build Coastguard Worker 		check_event(pevt);
358*6777b538SAndroid Build Coastguard Worker 		epdp->ed_pending[i] = fd;
359*6777b538SAndroid Build Coastguard Worker 
360*6777b538SAndroid Build Coastguard Worker 		/*
361*6777b538SAndroid Build Coastguard Worker 		 * Figure out what kind of event it was
362*6777b538SAndroid Build Coastguard Worker 		 * (because we have to pass this to the callback)
363*6777b538SAndroid Build Coastguard Worker 		 */
364*6777b538SAndroid Build Coastguard Worker 		res = 0;
365*6777b538SAndroid Build Coastguard Worker 		if (pevt->portev_events & POLLIN)
366*6777b538SAndroid Build Coastguard Worker 			res |= EV_READ;
367*6777b538SAndroid Build Coastguard Worker 		if (pevt->portev_events & POLLOUT)
368*6777b538SAndroid Build Coastguard Worker 			res |= EV_WRITE;
369*6777b538SAndroid Build Coastguard Worker 
370*6777b538SAndroid Build Coastguard Worker 		/*
371*6777b538SAndroid Build Coastguard Worker 		 * Check for the error situations or a hangup situation
372*6777b538SAndroid Build Coastguard Worker 		 */
373*6777b538SAndroid Build Coastguard Worker 		if (pevt->portev_events & (POLLERR|POLLHUP|POLLNVAL))
374*6777b538SAndroid Build Coastguard Worker 			res |= EV_READ|EV_WRITE;
375*6777b538SAndroid Build Coastguard Worker 
376*6777b538SAndroid Build Coastguard Worker 		assert(epdp->ed_nevents > fd);
377*6777b538SAndroid Build Coastguard Worker 		fdi = &(epdp->ed_fds[fd]);
378*6777b538SAndroid Build Coastguard Worker 
379*6777b538SAndroid Build Coastguard Worker 		/*
380*6777b538SAndroid Build Coastguard Worker 		 * We now check for each of the possible events (READ
381*6777b538SAndroid Build Coastguard Worker 		 * or WRITE).  Then, we activate the event (which will
382*6777b538SAndroid Build Coastguard Worker 		 * cause its callback to be executed).
383*6777b538SAndroid Build Coastguard Worker 		 */
384*6777b538SAndroid Build Coastguard Worker 
385*6777b538SAndroid Build Coastguard Worker 		if ((res & EV_READ) && ((ev = fdi->fdi_revt) != NULL)) {
386*6777b538SAndroid Build Coastguard Worker 			event_active(ev, res, 1);
387*6777b538SAndroid Build Coastguard Worker 		}
388*6777b538SAndroid Build Coastguard Worker 
389*6777b538SAndroid Build Coastguard Worker 		if ((res & EV_WRITE) && ((ev = fdi->fdi_wevt) != NULL)) {
390*6777b538SAndroid Build Coastguard Worker 			event_active(ev, res, 1);
391*6777b538SAndroid Build Coastguard Worker 		}
392*6777b538SAndroid Build Coastguard Worker 	} /* end of all events gotten */
393*6777b538SAndroid Build Coastguard Worker 
394*6777b538SAndroid Build Coastguard Worker 	check_evportop(epdp);
395*6777b538SAndroid Build Coastguard Worker 
396*6777b538SAndroid Build Coastguard Worker 	return (0);
397*6777b538SAndroid Build Coastguard Worker }
398*6777b538SAndroid Build Coastguard Worker 
399*6777b538SAndroid Build Coastguard Worker 
400*6777b538SAndroid Build Coastguard Worker /*
401*6777b538SAndroid Build Coastguard Worker  * Adds the given event (so that you will be notified when it happens via
402*6777b538SAndroid Build Coastguard Worker  * the callback function).
403*6777b538SAndroid Build Coastguard Worker  */
404*6777b538SAndroid Build Coastguard Worker 
405*6777b538SAndroid Build Coastguard Worker static int
evport_add(void * arg,struct event * ev)406*6777b538SAndroid Build Coastguard Worker evport_add(void *arg, struct event *ev)
407*6777b538SAndroid Build Coastguard Worker {
408*6777b538SAndroid Build Coastguard Worker 	struct evport_data *evpd = arg;
409*6777b538SAndroid Build Coastguard Worker 	struct fd_info *fdi;
410*6777b538SAndroid Build Coastguard Worker 	int factor;
411*6777b538SAndroid Build Coastguard Worker 
412*6777b538SAndroid Build Coastguard Worker 	check_evportop(evpd);
413*6777b538SAndroid Build Coastguard Worker 
414*6777b538SAndroid Build Coastguard Worker 	/*
415*6777b538SAndroid Build Coastguard Worker 	 * Delegate, if it's not ours to handle.
416*6777b538SAndroid Build Coastguard Worker 	 */
417*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_SIGNAL)
418*6777b538SAndroid Build Coastguard Worker 		return (evsignal_add(ev));
419*6777b538SAndroid Build Coastguard Worker 
420*6777b538SAndroid Build Coastguard Worker 	/*
421*6777b538SAndroid Build Coastguard Worker 	 * If necessary, grow the file descriptor info table
422*6777b538SAndroid Build Coastguard Worker 	 */
423*6777b538SAndroid Build Coastguard Worker 
424*6777b538SAndroid Build Coastguard Worker 	factor = 1;
425*6777b538SAndroid Build Coastguard Worker 	while (ev->ev_fd >= factor * evpd->ed_nevents)
426*6777b538SAndroid Build Coastguard Worker 		factor *= 2;
427*6777b538SAndroid Build Coastguard Worker 
428*6777b538SAndroid Build Coastguard Worker 	if (factor > 1) {
429*6777b538SAndroid Build Coastguard Worker 		if (-1 == grow(evpd, factor)) {
430*6777b538SAndroid Build Coastguard Worker 			return (-1);
431*6777b538SAndroid Build Coastguard Worker 		}
432*6777b538SAndroid Build Coastguard Worker 	}
433*6777b538SAndroid Build Coastguard Worker 
434*6777b538SAndroid Build Coastguard Worker 	fdi = &evpd->ed_fds[ev->ev_fd];
435*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_READ)
436*6777b538SAndroid Build Coastguard Worker 		fdi->fdi_revt = ev;
437*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_WRITE)
438*6777b538SAndroid Build Coastguard Worker 		fdi->fdi_wevt = ev;
439*6777b538SAndroid Build Coastguard Worker 
440*6777b538SAndroid Build Coastguard Worker 	return reassociate(evpd, fdi, ev->ev_fd);
441*6777b538SAndroid Build Coastguard Worker }
442*6777b538SAndroid Build Coastguard Worker 
443*6777b538SAndroid Build Coastguard Worker /*
444*6777b538SAndroid Build Coastguard Worker  * Removes the given event from the list of events to wait for.
445*6777b538SAndroid Build Coastguard Worker  */
446*6777b538SAndroid Build Coastguard Worker 
447*6777b538SAndroid Build Coastguard Worker static int
evport_del(void * arg,struct event * ev)448*6777b538SAndroid Build Coastguard Worker evport_del(void *arg, struct event *ev)
449*6777b538SAndroid Build Coastguard Worker {
450*6777b538SAndroid Build Coastguard Worker 	struct evport_data *evpd = arg;
451*6777b538SAndroid Build Coastguard Worker 	struct fd_info *fdi;
452*6777b538SAndroid Build Coastguard Worker 	int i;
453*6777b538SAndroid Build Coastguard Worker 	int associated = 1;
454*6777b538SAndroid Build Coastguard Worker 
455*6777b538SAndroid Build Coastguard Worker 	check_evportop(evpd);
456*6777b538SAndroid Build Coastguard Worker 
457*6777b538SAndroid Build Coastguard Worker 	/*
458*6777b538SAndroid Build Coastguard Worker 	 * Delegate, if it's not ours to handle
459*6777b538SAndroid Build Coastguard Worker 	 */
460*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_SIGNAL) {
461*6777b538SAndroid Build Coastguard Worker 		return (evsignal_del(ev));
462*6777b538SAndroid Build Coastguard Worker 	}
463*6777b538SAndroid Build Coastguard Worker 
464*6777b538SAndroid Build Coastguard Worker 	if (evpd->ed_nevents < ev->ev_fd) {
465*6777b538SAndroid Build Coastguard Worker 		return (-1);
466*6777b538SAndroid Build Coastguard Worker 	}
467*6777b538SAndroid Build Coastguard Worker 
468*6777b538SAndroid Build Coastguard Worker 	for (i = 0; i < EVENTS_PER_GETN; ++i) {
469*6777b538SAndroid Build Coastguard Worker 		if (evpd->ed_pending[i] == ev->ev_fd) {
470*6777b538SAndroid Build Coastguard Worker 			associated = 0;
471*6777b538SAndroid Build Coastguard Worker 			break;
472*6777b538SAndroid Build Coastguard Worker 		}
473*6777b538SAndroid Build Coastguard Worker 	}
474*6777b538SAndroid Build Coastguard Worker 
475*6777b538SAndroid Build Coastguard Worker 	fdi = &evpd->ed_fds[ev->ev_fd];
476*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_READ)
477*6777b538SAndroid Build Coastguard Worker 		fdi->fdi_revt = NULL;
478*6777b538SAndroid Build Coastguard Worker 	if (ev->ev_events & EV_WRITE)
479*6777b538SAndroid Build Coastguard Worker 		fdi->fdi_wevt = NULL;
480*6777b538SAndroid Build Coastguard Worker 
481*6777b538SAndroid Build Coastguard Worker 	if (associated) {
482*6777b538SAndroid Build Coastguard Worker 		if (!FDI_HAS_EVENTS(fdi) &&
483*6777b538SAndroid Build Coastguard Worker 		    port_dissociate(evpd->ed_port, PORT_SOURCE_FD,
484*6777b538SAndroid Build Coastguard Worker 		    ev->ev_fd) == -1) {
485*6777b538SAndroid Build Coastguard Worker 			/*
486*6777b538SAndroid Build Coastguard Worker 			 * Ignre EBADFD error the fd could have been closed
487*6777b538SAndroid Build Coastguard Worker 			 * before event_del() was called.
488*6777b538SAndroid Build Coastguard Worker 			 */
489*6777b538SAndroid Build Coastguard Worker 			if (errno != EBADFD) {
490*6777b538SAndroid Build Coastguard Worker 				event_warn("port_dissociate");
491*6777b538SAndroid Build Coastguard Worker 				return (-1);
492*6777b538SAndroid Build Coastguard Worker 			}
493*6777b538SAndroid Build Coastguard Worker 		} else {
494*6777b538SAndroid Build Coastguard Worker 			if (FDI_HAS_EVENTS(fdi)) {
495*6777b538SAndroid Build Coastguard Worker 				return (reassociate(evpd, fdi, ev->ev_fd));
496*6777b538SAndroid Build Coastguard Worker 			}
497*6777b538SAndroid Build Coastguard Worker 		}
498*6777b538SAndroid Build Coastguard Worker 	} else {
499*6777b538SAndroid Build Coastguard Worker 		if (fdi->fdi_revt == NULL && fdi->fdi_wevt == NULL) {
500*6777b538SAndroid Build Coastguard Worker 			evpd->ed_pending[i] = -1;
501*6777b538SAndroid Build Coastguard Worker 		}
502*6777b538SAndroid Build Coastguard Worker 	}
503*6777b538SAndroid Build Coastguard Worker 	return 0;
504*6777b538SAndroid Build Coastguard Worker }
505*6777b538SAndroid Build Coastguard Worker 
506*6777b538SAndroid Build Coastguard Worker 
507*6777b538SAndroid Build Coastguard Worker static void
evport_dealloc(struct event_base * base,void * arg)508*6777b538SAndroid Build Coastguard Worker evport_dealloc(struct event_base *base, void *arg)
509*6777b538SAndroid Build Coastguard Worker {
510*6777b538SAndroid Build Coastguard Worker 	struct evport_data *evpd = arg;
511*6777b538SAndroid Build Coastguard Worker 
512*6777b538SAndroid Build Coastguard Worker 	evsignal_dealloc(base);
513*6777b538SAndroid Build Coastguard Worker 
514*6777b538SAndroid Build Coastguard Worker 	close(evpd->ed_port);
515*6777b538SAndroid Build Coastguard Worker 
516*6777b538SAndroid Build Coastguard Worker 	if (evpd->ed_fds)
517*6777b538SAndroid Build Coastguard Worker 		free(evpd->ed_fds);
518*6777b538SAndroid Build Coastguard Worker 	free(evpd);
519*6777b538SAndroid Build Coastguard Worker }
520