xref: /netbsd-src/external/bsd/libevent/dist/evport.c (revision 805a1ce9000bc0ec0951bf35f7e52b85cafb37e2)
1*805a1ce9Schristos /*	$NetBSD: evport.c,v 1.1.1.2 2017/01/31 21:14:53 christos Exp $	*/
26ecf6635Schristos /*
36ecf6635Schristos  * Submitted by David Pacheco (dp.spambait@gmail.com)
46ecf6635Schristos  *
56ecf6635Schristos  * Copyright 2006-2007 Niels Provos
66ecf6635Schristos  * Copyright 2007-2012 Niels Provos and Nick Mathewson
76ecf6635Schristos  *
86ecf6635Schristos  * Redistribution and use in source and binary forms, with or without
96ecf6635Schristos  * modification, are permitted provided that the following conditions
106ecf6635Schristos  * are met:
116ecf6635Schristos  * 1. Redistributions of source code must retain the above copyright
126ecf6635Schristos  *    notice, this list of conditions and the following disclaimer.
136ecf6635Schristos  * 2. Redistributions in binary form must reproduce the above copyright
146ecf6635Schristos  *    notice, this list of conditions and the following disclaimer in the
156ecf6635Schristos  *    documentation and/or other materials provided with the distribution.
166ecf6635Schristos  * 3. The name of the author may not be used to endorse or promote products
176ecf6635Schristos  *    derived from this software without specific prior written permission.
186ecf6635Schristos  *
196ecf6635Schristos  * THIS SOFTWARE IS PROVIDED BY SUN MICROSYSTEMS, INC. ``AS IS'' AND ANY
206ecf6635Schristos  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
216ecf6635Schristos  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
226ecf6635Schristos  * DISCLAIMED. IN NO EVENT SHALL SUN MICROSYSTEMS, INC. BE LIABLE FOR ANY
236ecf6635Schristos  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
246ecf6635Schristos  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
256ecf6635Schristos  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
266ecf6635Schristos  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
276ecf6635Schristos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
286ecf6635Schristos  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
296ecf6635Schristos  */
306ecf6635Schristos 
316ecf6635Schristos /*
326ecf6635Schristos  * Copyright (c) 2007 Sun Microsystems. All rights reserved.
336ecf6635Schristos  * Use is subject to license terms.
346ecf6635Schristos  */
356ecf6635Schristos 
366ecf6635Schristos /*
376ecf6635Schristos  * evport.c: event backend using Solaris 10 event ports. See port_create(3C).
386ecf6635Schristos  * This implementation is loosely modeled after the one used for select(2) (in
396ecf6635Schristos  * select.c).
406ecf6635Schristos  *
416ecf6635Schristos  * The outstanding events are tracked in a data structure called evport_data.
426ecf6635Schristos  * Each entry in the ed_fds array corresponds to a file descriptor, and contains
436ecf6635Schristos  * pointers to the read and write events that correspond to that fd. (That is,
446ecf6635Schristos  * when the file is readable, the "read" event should handle it, etc.)
456ecf6635Schristos  *
466ecf6635Schristos  * evport_add and evport_del update this data structure. evport_dispatch uses it
476ecf6635Schristos  * to determine where to callback when an event occurs (which it gets from
486ecf6635Schristos  * port_getn).
496ecf6635Schristos  *
506ecf6635Schristos  * Helper functions are used: grow() grows the file descriptor array as
516ecf6635Schristos  * necessary when large fd's come in. reassociate() takes care of maintaining
526ecf6635Schristos  * the proper file-descriptor/event-port associations.
536ecf6635Schristos  *
546ecf6635Schristos  * As in the select(2) implementation, signals are handled by evsignal.
556ecf6635Schristos  */
566ecf6635Schristos 
576ecf6635Schristos #include "event2/event-config.h"
586ecf6635Schristos #include <sys/cdefs.h>
59*805a1ce9Schristos __RCSID("$NetBSD: evport.c,v 1.1.1.2 2017/01/31 21:14:53 christos Exp $");
60*805a1ce9Schristos #include "evconfig-private.h"
61*805a1ce9Schristos 
62*805a1ce9Schristos #ifdef EVENT__HAVE_EVENT_PORTS
636ecf6635Schristos 
646ecf6635Schristos #include <sys/time.h>
656ecf6635Schristos #include <sys/queue.h>
666ecf6635Schristos #include <errno.h>
676ecf6635Schristos #include <poll.h>
686ecf6635Schristos #include <port.h>
696ecf6635Schristos #include <signal.h>
706ecf6635Schristos #include <stdio.h>
716ecf6635Schristos #include <stdlib.h>
726ecf6635Schristos #include <string.h>
736ecf6635Schristos #include <time.h>
746ecf6635Schristos #include <unistd.h>
756ecf6635Schristos 
766ecf6635Schristos #include "event2/thread.h"
776ecf6635Schristos 
786ecf6635Schristos #include "evthread-internal.h"
796ecf6635Schristos #include "event-internal.h"
806ecf6635Schristos #include "log-internal.h"
816ecf6635Schristos #include "evsignal-internal.h"
826ecf6635Schristos #include "evmap-internal.h"
836ecf6635Schristos 
84*805a1ce9Schristos #define INITIAL_EVENTS_PER_GETN 8
85*805a1ce9Schristos #define MAX_EVENTS_PER_GETN 4096
866ecf6635Schristos 
876ecf6635Schristos /*
886ecf6635Schristos  * Per-file-descriptor information about what events we're subscribed to. These
896ecf6635Schristos  * fields are NULL if no event is subscribed to either of them.
906ecf6635Schristos  */
916ecf6635Schristos 
926ecf6635Schristos struct fd_info {
93*805a1ce9Schristos 	/* combinations of EV_READ and EV_WRITE */
94*805a1ce9Schristos 	short fdi_what;
95*805a1ce9Schristos 	/* Index of this fd within ed_pending, plus 1.  Zero if this fd is
96*805a1ce9Schristos 	 * not in ed_pending.  (The +1 is a hack so that memset(0) will set
97*805a1ce9Schristos 	 * it to a nil index. */
98*805a1ce9Schristos 	int pending_idx_plus_1;
996ecf6635Schristos };
1006ecf6635Schristos 
1016ecf6635Schristos #define FDI_HAS_READ(fdi)  ((fdi)->fdi_what & EV_READ)
1026ecf6635Schristos #define FDI_HAS_WRITE(fdi) ((fdi)->fdi_what & EV_WRITE)
1036ecf6635Schristos #define FDI_HAS_EVENTS(fdi) (FDI_HAS_READ(fdi) || FDI_HAS_WRITE(fdi))
1046ecf6635Schristos #define FDI_TO_SYSEVENTS(fdi) (FDI_HAS_READ(fdi) ? POLLIN : 0) | \
1056ecf6635Schristos     (FDI_HAS_WRITE(fdi) ? POLLOUT : 0)
1066ecf6635Schristos 
1076ecf6635Schristos struct evport_data {
1086ecf6635Schristos 	int		ed_port;	/* event port for system events  */
109*805a1ce9Schristos 	/* How many elements of ed_pending should we look at? */
110*805a1ce9Schristos 	int ed_npending;
111*805a1ce9Schristos 	/* How many elements are allocated in ed_pending and pevtlist? */
112*805a1ce9Schristos 	int ed_maxevents;
1136ecf6635Schristos 	/* fdi's that we need to reassoc */
114*805a1ce9Schristos 	int *ed_pending;
115*805a1ce9Schristos 	/* storage space for incoming events. */
116*805a1ce9Schristos 	port_event_t *ed_pevtlist;
117*805a1ce9Schristos 
1186ecf6635Schristos };
1196ecf6635Schristos 
1206ecf6635Schristos static void*	evport_init(struct event_base *);
1216ecf6635Schristos static int evport_add(struct event_base *, int fd, short old, short events, void *);
1226ecf6635Schristos static int evport_del(struct event_base *, int fd, short old, short events, void *);
1236ecf6635Schristos static int	evport_dispatch(struct event_base *, struct timeval *);
1246ecf6635Schristos static void	evport_dealloc(struct event_base *);
125*805a1ce9Schristos static int	grow(struct evport_data *, int min_events);
1266ecf6635Schristos 
1276ecf6635Schristos const struct eventop evportops = {
1286ecf6635Schristos 	"evport",
1296ecf6635Schristos 	evport_init,
1306ecf6635Schristos 	evport_add,
1316ecf6635Schristos 	evport_del,
1326ecf6635Schristos 	evport_dispatch,
1336ecf6635Schristos 	evport_dealloc,
1346ecf6635Schristos 	1, /* need reinit */
1356ecf6635Schristos 	0, /* features */
136*805a1ce9Schristos 	sizeof(struct fd_info), /* fdinfo length */
1376ecf6635Schristos };
1386ecf6635Schristos 
1396ecf6635Schristos /*
1406ecf6635Schristos  * Initialize the event port implementation.
1416ecf6635Schristos  */
1426ecf6635Schristos 
1436ecf6635Schristos static void*
evport_init(struct event_base * base)1446ecf6635Schristos evport_init(struct event_base *base)
1456ecf6635Schristos {
1466ecf6635Schristos 	struct evport_data *evpd;
1476ecf6635Schristos 
1486ecf6635Schristos 	if (!(evpd = mm_calloc(1, sizeof(struct evport_data))))
1496ecf6635Schristos 		return (NULL);
1506ecf6635Schristos 
1516ecf6635Schristos 	if ((evpd->ed_port = port_create()) == -1) {
1526ecf6635Schristos 		mm_free(evpd);
1536ecf6635Schristos 		return (NULL);
1546ecf6635Schristos 	}
1556ecf6635Schristos 
156*805a1ce9Schristos 	if (grow(evpd, INITIAL_EVENTS_PER_GETN) < 0) {
1576ecf6635Schristos 		close(evpd->ed_port);
1586ecf6635Schristos 		mm_free(evpd);
159*805a1ce9Schristos 		return NULL;
1606ecf6635Schristos 	}
1616ecf6635Schristos 
162*805a1ce9Schristos 	evpd->ed_npending = 0;
163*805a1ce9Schristos 
164*805a1ce9Schristos 	evsig_init_(base);
1656ecf6635Schristos 
1666ecf6635Schristos 	return (evpd);
1676ecf6635Schristos }
1686ecf6635Schristos 
169*805a1ce9Schristos static int
grow(struct evport_data * data,int min_events)170*805a1ce9Schristos grow(struct evport_data *data, int min_events)
171*805a1ce9Schristos {
172*805a1ce9Schristos 	int newsize;
173*805a1ce9Schristos 	int *new_pending;
174*805a1ce9Schristos 	port_event_t *new_pevtlist;
175*805a1ce9Schristos 	if (data->ed_maxevents) {
176*805a1ce9Schristos 		newsize = data->ed_maxevents;
177*805a1ce9Schristos 		do {
178*805a1ce9Schristos 			newsize *= 2;
179*805a1ce9Schristos 		} while (newsize < min_events);
180*805a1ce9Schristos 	} else {
181*805a1ce9Schristos 		newsize = min_events;
182*805a1ce9Schristos 	}
183*805a1ce9Schristos 
184*805a1ce9Schristos 	new_pending = mm_realloc(data->ed_pending, sizeof(int)*newsize);
185*805a1ce9Schristos 	if (new_pending == NULL)
186*805a1ce9Schristos 		return -1;
187*805a1ce9Schristos 	data->ed_pending = new_pending;
188*805a1ce9Schristos 	new_pevtlist = mm_realloc(data->ed_pevtlist, sizeof(port_event_t)*newsize);
189*805a1ce9Schristos 	if (new_pevtlist == NULL)
190*805a1ce9Schristos 		return -1;
191*805a1ce9Schristos 	data->ed_pevtlist = new_pevtlist;
192*805a1ce9Schristos 
193*805a1ce9Schristos 	data->ed_maxevents = newsize;
194*805a1ce9Schristos 	return 0;
195*805a1ce9Schristos }
196*805a1ce9Schristos 
1976ecf6635Schristos #ifdef CHECK_INVARIANTS
1986ecf6635Schristos /*
1996ecf6635Schristos  * Checks some basic properties about the evport_data structure. Because it
2006ecf6635Schristos  * checks all file descriptors, this function can be expensive when the maximum
2016ecf6635Schristos  * file descriptor ever used is rather large.
2026ecf6635Schristos  */
2036ecf6635Schristos 
2046ecf6635Schristos static void
check_evportop(struct evport_data * evpd)2056ecf6635Schristos check_evportop(struct evport_data *evpd)
2066ecf6635Schristos {
2076ecf6635Schristos 	EVUTIL_ASSERT(evpd);
2086ecf6635Schristos 	EVUTIL_ASSERT(evpd->ed_port > 0);
2096ecf6635Schristos }
2106ecf6635Schristos 
2116ecf6635Schristos /*
2126ecf6635Schristos  * Verifies very basic integrity of a given port_event.
2136ecf6635Schristos  */
2146ecf6635Schristos static void
check_event(port_event_t * pevt)2156ecf6635Schristos check_event(port_event_t* pevt)
2166ecf6635Schristos {
2176ecf6635Schristos 	/*
2186ecf6635Schristos 	 * We've only registered for PORT_SOURCE_FD events. The only
2196ecf6635Schristos 	 * other thing we can legitimately receive is PORT_SOURCE_ALERT,
2206ecf6635Schristos 	 * but since we're not using port_alert either, we can assume
2216ecf6635Schristos 	 * PORT_SOURCE_FD.
2226ecf6635Schristos 	 */
2236ecf6635Schristos 	EVUTIL_ASSERT(pevt->portev_source == PORT_SOURCE_FD);
2246ecf6635Schristos }
2256ecf6635Schristos 
2266ecf6635Schristos #else
2276ecf6635Schristos #define check_evportop(epop)
2286ecf6635Schristos #define check_event(pevt)
2296ecf6635Schristos #endif /* CHECK_INVARIANTS */
2306ecf6635Schristos 
2316ecf6635Schristos /*
2326ecf6635Schristos  * (Re)associates the given file descriptor with the event port. The OS events
2336ecf6635Schristos  * are specified (implicitly) from the fd_info struct.
2346ecf6635Schristos  */
2356ecf6635Schristos static int
reassociate(struct evport_data * epdp,struct fd_info * fdip,int fd)2366ecf6635Schristos reassociate(struct evport_data *epdp, struct fd_info *fdip, int fd)
2376ecf6635Schristos {
2386ecf6635Schristos 	int sysevents = FDI_TO_SYSEVENTS(fdip);
2396ecf6635Schristos 
2406ecf6635Schristos 	if (sysevents != 0) {
2416ecf6635Schristos 		if (port_associate(epdp->ed_port, PORT_SOURCE_FD,
242*805a1ce9Schristos 				   fd, sysevents, fdip) == -1) {
2436ecf6635Schristos 			event_warn("port_associate");
2446ecf6635Schristos 			return (-1);
2456ecf6635Schristos 		}
2466ecf6635Schristos 	}
2476ecf6635Schristos 
2486ecf6635Schristos 	check_evportop(epdp);
2496ecf6635Schristos 
2506ecf6635Schristos 	return (0);
2516ecf6635Schristos }
2526ecf6635Schristos 
2536ecf6635Schristos /*
2546ecf6635Schristos  * Main event loop - polls port_getn for some number of events, and processes
2556ecf6635Schristos  * them.
2566ecf6635Schristos  */
2576ecf6635Schristos 
2586ecf6635Schristos static int
evport_dispatch(struct event_base * base,struct timeval * tv)2596ecf6635Schristos evport_dispatch(struct event_base *base, struct timeval *tv)
2606ecf6635Schristos {
2616ecf6635Schristos 	int i, res;
2626ecf6635Schristos 	struct evport_data *epdp = base->evbase;
263*805a1ce9Schristos 	port_event_t *pevtlist = epdp->ed_pevtlist;
2646ecf6635Schristos 
2656ecf6635Schristos 	/*
2666ecf6635Schristos 	 * port_getn will block until it has at least nevents events. It will
2676ecf6635Schristos 	 * also return how many it's given us (which may be more than we asked
268*805a1ce9Schristos 	 * for, as long as it's less than our maximum (ed_maxevents)) in
2696ecf6635Schristos 	 * nevents.
2706ecf6635Schristos 	 */
2716ecf6635Schristos 	int nevents = 1;
2726ecf6635Schristos 
2736ecf6635Schristos 	/*
2746ecf6635Schristos 	 * We have to convert a struct timeval to a struct timespec
2756ecf6635Schristos 	 * (only difference is nanoseconds vs. microseconds). If no time-based
2766ecf6635Schristos 	 * events are active, we should wait for I/O (and tv == NULL).
2776ecf6635Schristos 	 */
2786ecf6635Schristos 	struct timespec ts;
2796ecf6635Schristos 	struct timespec *ts_p = NULL;
2806ecf6635Schristos 	if (tv != NULL) {
2816ecf6635Schristos 		ts.tv_sec = tv->tv_sec;
2826ecf6635Schristos 		ts.tv_nsec = tv->tv_usec * 1000;
2836ecf6635Schristos 		ts_p = &ts;
2846ecf6635Schristos 	}
2856ecf6635Schristos 
2866ecf6635Schristos 	/*
2876ecf6635Schristos 	 * Before doing anything else, we need to reassociate the events we hit
2886ecf6635Schristos 	 * last time which need reassociation. See comment at the end of the
2896ecf6635Schristos 	 * loop below.
2906ecf6635Schristos 	 */
291*805a1ce9Schristos 	for (i = 0; i < epdp->ed_npending; ++i) {
2926ecf6635Schristos 		struct fd_info *fdi = NULL;
293*805a1ce9Schristos 		const int fd = epdp->ed_pending[i];
294*805a1ce9Schristos 		if (fd != -1) {
295*805a1ce9Schristos 			/* We might have cleared out this event; we need
296*805a1ce9Schristos 			 * to be sure that it's still set. */
297*805a1ce9Schristos 			fdi = evmap_io_get_fdinfo_(&base->io, fd);
2986ecf6635Schristos 		}
2996ecf6635Schristos 
3006ecf6635Schristos 		if (fdi != NULL && FDI_HAS_EVENTS(fdi)) {
3016ecf6635Schristos 			reassociate(epdp, fdi, fd);
302*805a1ce9Schristos 			/* epdp->ed_pending[i] = -1; */
303*805a1ce9Schristos 			fdi->pending_idx_plus_1 = 0;
3046ecf6635Schristos 		}
3056ecf6635Schristos 	}
3066ecf6635Schristos 
3076ecf6635Schristos 	EVBASE_RELEASE_LOCK(base, th_base_lock);
3086ecf6635Schristos 
309*805a1ce9Schristos 	res = port_getn(epdp->ed_port, pevtlist, epdp->ed_maxevents,
3106ecf6635Schristos 	    (unsigned int *) &nevents, ts_p);
3116ecf6635Schristos 
3126ecf6635Schristos 	EVBASE_ACQUIRE_LOCK(base, th_base_lock);
3136ecf6635Schristos 
3146ecf6635Schristos 	if (res == -1) {
3156ecf6635Schristos 		if (errno == EINTR || errno == EAGAIN) {
3166ecf6635Schristos 			return (0);
3176ecf6635Schristos 		} else if (errno == ETIME) {
3186ecf6635Schristos 			if (nevents == 0)
3196ecf6635Schristos 				return (0);
3206ecf6635Schristos 		} else {
3216ecf6635Schristos 			event_warn("port_getn");
3226ecf6635Schristos 			return (-1);
3236ecf6635Schristos 		}
3246ecf6635Schristos 	}
3256ecf6635Schristos 
3266ecf6635Schristos 	event_debug(("%s: port_getn reports %d events", __func__, nevents));
3276ecf6635Schristos 
3286ecf6635Schristos 	for (i = 0; i < nevents; ++i) {
3296ecf6635Schristos 		port_event_t *pevt = &pevtlist[i];
3306ecf6635Schristos 		int fd = (int) pevt->portev_object;
331*805a1ce9Schristos 		struct fd_info *fdi = pevt->portev_user;
332*805a1ce9Schristos 		/*EVUTIL_ASSERT(evmap_io_get_fdinfo_(&base->io, fd) == fdi);*/
3336ecf6635Schristos 
3346ecf6635Schristos 		check_evportop(epdp);
3356ecf6635Schristos 		check_event(pevt);
3366ecf6635Schristos 		epdp->ed_pending[i] = fd;
337*805a1ce9Schristos 		fdi->pending_idx_plus_1 = i + 1;
3386ecf6635Schristos 
3396ecf6635Schristos 		/*
3406ecf6635Schristos 		 * Figure out what kind of event it was
3416ecf6635Schristos 		 * (because we have to pass this to the callback)
3426ecf6635Schristos 		 */
3436ecf6635Schristos 		res = 0;
3446ecf6635Schristos 		if (pevt->portev_events & (POLLERR|POLLHUP)) {
3456ecf6635Schristos 			res = EV_READ | EV_WRITE;
3466ecf6635Schristos 		} else {
3476ecf6635Schristos 			if (pevt->portev_events & POLLIN)
3486ecf6635Schristos 				res |= EV_READ;
3496ecf6635Schristos 			if (pevt->portev_events & POLLOUT)
3506ecf6635Schristos 				res |= EV_WRITE;
3516ecf6635Schristos 		}
3526ecf6635Schristos 
3536ecf6635Schristos 		/*
3546ecf6635Schristos 		 * Check for the error situations or a hangup situation
3556ecf6635Schristos 		 */
3566ecf6635Schristos 		if (pevt->portev_events & (POLLERR|POLLHUP|POLLNVAL))
3576ecf6635Schristos 			res |= EV_READ|EV_WRITE;
3586ecf6635Schristos 
359*805a1ce9Schristos 		evmap_io_active_(base, fd, res);
3606ecf6635Schristos 	} /* end of all events gotten */
361*805a1ce9Schristos 	epdp->ed_npending = nevents;
362*805a1ce9Schristos 
363*805a1ce9Schristos 	if (nevents == epdp->ed_maxevents &&
364*805a1ce9Schristos 	    epdp->ed_maxevents < MAX_EVENTS_PER_GETN) {
365*805a1ce9Schristos 		/* we used all the space this time.  We should be ready
366*805a1ce9Schristos 		 * for more events next time around. */
367*805a1ce9Schristos 		grow(epdp, epdp->ed_maxevents * 2);
368*805a1ce9Schristos 	}
3696ecf6635Schristos 
3706ecf6635Schristos 	check_evportop(epdp);
3716ecf6635Schristos 
3726ecf6635Schristos 	return (0);
3736ecf6635Schristos }
3746ecf6635Schristos 
3756ecf6635Schristos 
3766ecf6635Schristos /*
3776ecf6635Schristos  * Adds the given event (so that you will be notified when it happens via
3786ecf6635Schristos  * the callback function).
3796ecf6635Schristos  */
3806ecf6635Schristos 
3816ecf6635Schristos static int
evport_add(struct event_base * base,int fd,short old,short events,void * p)3826ecf6635Schristos evport_add(struct event_base *base, int fd, short old, short events, void *p)
3836ecf6635Schristos {
3846ecf6635Schristos 	struct evport_data *evpd = base->evbase;
385*805a1ce9Schristos 	struct fd_info *fdi = p;
3866ecf6635Schristos 
3876ecf6635Schristos 	check_evportop(evpd);
3886ecf6635Schristos 
3896ecf6635Schristos 	fdi->fdi_what |= events;
3906ecf6635Schristos 
3916ecf6635Schristos 	return reassociate(evpd, fdi, fd);
3926ecf6635Schristos }
3936ecf6635Schristos 
3946ecf6635Schristos /*
3956ecf6635Schristos  * Removes the given event from the list of events to wait for.
3966ecf6635Schristos  */
3976ecf6635Schristos 
3986ecf6635Schristos static int
evport_del(struct event_base * base,int fd,short old,short events,void * p)3996ecf6635Schristos evport_del(struct event_base *base, int fd, short old, short events, void *p)
4006ecf6635Schristos {
4016ecf6635Schristos 	struct evport_data *evpd = base->evbase;
402*805a1ce9Schristos 	struct fd_info *fdi = p;
403*805a1ce9Schristos 	int associated = ! fdi->pending_idx_plus_1;
4046ecf6635Schristos 
4056ecf6635Schristos 	check_evportop(evpd);
4066ecf6635Schristos 
407*805a1ce9Schristos 	fdi->fdi_what &= ~(events &(EV_READ|EV_WRITE));
4086ecf6635Schristos 
4096ecf6635Schristos 	if (associated) {
4106ecf6635Schristos 		if (!FDI_HAS_EVENTS(fdi) &&
4116ecf6635Schristos 		    port_dissociate(evpd->ed_port, PORT_SOURCE_FD, fd) == -1) {
4126ecf6635Schristos 			/*
4136ecf6635Schristos 			 * Ignore EBADFD error the fd could have been closed
4146ecf6635Schristos 			 * before event_del() was called.
4156ecf6635Schristos 			 */
4166ecf6635Schristos 			if (errno != EBADFD) {
4176ecf6635Schristos 				event_warn("port_dissociate");
4186ecf6635Schristos 				return (-1);
4196ecf6635Schristos 			}
4206ecf6635Schristos 		} else {
4216ecf6635Schristos 			if (FDI_HAS_EVENTS(fdi)) {
4226ecf6635Schristos 				return (reassociate(evpd, fdi, fd));
4236ecf6635Schristos 			}
4246ecf6635Schristos 		}
4256ecf6635Schristos 	} else {
4266ecf6635Schristos 		if ((fdi->fdi_what & (EV_READ|EV_WRITE)) == 0) {
427*805a1ce9Schristos 			const int i = fdi->pending_idx_plus_1 - 1;
428*805a1ce9Schristos 			EVUTIL_ASSERT(evpd->ed_pending[i] == fd);
4296ecf6635Schristos 			evpd->ed_pending[i] = -1;
430*805a1ce9Schristos 			fdi->pending_idx_plus_1 = 0;
4316ecf6635Schristos 		}
4326ecf6635Schristos 	}
4336ecf6635Schristos 	return 0;
4346ecf6635Schristos }
4356ecf6635Schristos 
4366ecf6635Schristos 
4376ecf6635Schristos static void
evport_dealloc(struct event_base * base)4386ecf6635Schristos evport_dealloc(struct event_base *base)
4396ecf6635Schristos {
4406ecf6635Schristos 	struct evport_data *evpd = base->evbase;
4416ecf6635Schristos 
442*805a1ce9Schristos 	evsig_dealloc_(base);
4436ecf6635Schristos 
4446ecf6635Schristos 	close(evpd->ed_port);
4456ecf6635Schristos 
446*805a1ce9Schristos 	if (evpd->ed_pending)
447*805a1ce9Schristos 		mm_free(evpd->ed_pending);
448*805a1ce9Schristos 	if (evpd->ed_pevtlist)
449*805a1ce9Schristos 		mm_free(evpd->ed_pevtlist);
450*805a1ce9Schristos 
4516ecf6635Schristos 	mm_free(evpd);
4526ecf6635Schristos }
453*805a1ce9Schristos 
454*805a1ce9Schristos #endif /* EVENT__HAVE_EVENT_PORTS */
455