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