xref: /freebsd/contrib/ntp/sntp/libevent/evmap.c (revision a466cc55373fc3cf86837f09da729535b57e69a1)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
32b15cb3dSCy Schubert  *
42b15cb3dSCy Schubert  * Redistribution and use in source and binary forms, with or without
52b15cb3dSCy Schubert  * modification, are permitted provided that the following conditions
62b15cb3dSCy Schubert  * are met:
72b15cb3dSCy Schubert  * 1. Redistributions of source code must retain the above copyright
82b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer.
92b15cb3dSCy Schubert  * 2. Redistributions in binary form must reproduce the above copyright
102b15cb3dSCy Schubert  *    notice, this list of conditions and the following disclaimer in the
112b15cb3dSCy Schubert  *    documentation and/or other materials provided with the distribution.
122b15cb3dSCy Schubert  * 3. The name of the author may not be used to endorse or promote products
132b15cb3dSCy Schubert  *    derived from this software without specific prior written permission.
142b15cb3dSCy Schubert  *
152b15cb3dSCy Schubert  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
162b15cb3dSCy Schubert  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
172b15cb3dSCy Schubert  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
182b15cb3dSCy Schubert  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
192b15cb3dSCy Schubert  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
202b15cb3dSCy Schubert  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
212b15cb3dSCy Schubert  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
222b15cb3dSCy Schubert  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
232b15cb3dSCy Schubert  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
242b15cb3dSCy Schubert  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
252b15cb3dSCy Schubert  */
262b15cb3dSCy Schubert #include "event2/event-config.h"
272b15cb3dSCy Schubert #include "evconfig-private.h"
282b15cb3dSCy Schubert 
292b15cb3dSCy Schubert #ifdef _WIN32
302b15cb3dSCy Schubert #include <winsock2.h>
312b15cb3dSCy Schubert #define WIN32_LEAN_AND_MEAN
322b15cb3dSCy Schubert #include <windows.h>
332b15cb3dSCy Schubert #undef WIN32_LEAN_AND_MEAN
342b15cb3dSCy Schubert #endif
352b15cb3dSCy Schubert #include <sys/types.h>
362b15cb3dSCy Schubert #if !defined(_WIN32) && defined(EVENT__HAVE_SYS_TIME_H)
372b15cb3dSCy Schubert #include <sys/time.h>
382b15cb3dSCy Schubert #endif
392b15cb3dSCy Schubert #include <sys/queue.h>
402b15cb3dSCy Schubert #include <stdio.h>
412b15cb3dSCy Schubert #include <stdlib.h>
422b15cb3dSCy Schubert #ifndef _WIN32
432b15cb3dSCy Schubert #include <unistd.h>
442b15cb3dSCy Schubert #endif
452b15cb3dSCy Schubert #include <errno.h>
46*a466cc55SCy Schubert #include <limits.h>
472b15cb3dSCy Schubert #include <signal.h>
482b15cb3dSCy Schubert #include <string.h>
492b15cb3dSCy Schubert #include <time.h>
502b15cb3dSCy Schubert 
512b15cb3dSCy Schubert #include "event-internal.h"
522b15cb3dSCy Schubert #include "evmap-internal.h"
532b15cb3dSCy Schubert #include "mm-internal.h"
542b15cb3dSCy Schubert #include "changelist-internal.h"
552b15cb3dSCy Schubert 
562b15cb3dSCy Schubert /** An entry for an evmap_io list: notes all the events that want to read or
572b15cb3dSCy Schubert 	write on a given fd, and the number of each.
582b15cb3dSCy Schubert   */
592b15cb3dSCy Schubert struct evmap_io {
602b15cb3dSCy Schubert 	struct event_dlist events;
612b15cb3dSCy Schubert 	ev_uint16_t nread;
622b15cb3dSCy Schubert 	ev_uint16_t nwrite;
632b15cb3dSCy Schubert 	ev_uint16_t nclose;
642b15cb3dSCy Schubert };
652b15cb3dSCy Schubert 
662b15cb3dSCy Schubert /* An entry for an evmap_signal list: notes all the events that want to know
672b15cb3dSCy Schubert    when a signal triggers. */
682b15cb3dSCy Schubert struct evmap_signal {
692b15cb3dSCy Schubert 	struct event_dlist events;
702b15cb3dSCy Schubert };
712b15cb3dSCy Schubert 
722b15cb3dSCy Schubert /* On some platforms, fds start at 0 and increment by 1 as they are
732b15cb3dSCy Schubert    allocated, and old numbers get used.  For these platforms, we
742b15cb3dSCy Schubert    implement io maps just like signal maps: as an array of pointers to
752b15cb3dSCy Schubert    struct evmap_io.  But on other platforms (windows), sockets are not
762b15cb3dSCy Schubert    0-indexed, not necessarily consecutive, and not necessarily reused.
772b15cb3dSCy Schubert    There, we use a hashtable to implement evmap_io.
782b15cb3dSCy Schubert */
792b15cb3dSCy Schubert #ifdef EVMAP_USE_HT
802b15cb3dSCy Schubert struct event_map_entry {
812b15cb3dSCy Schubert 	HT_ENTRY(event_map_entry) map_node;
822b15cb3dSCy Schubert 	evutil_socket_t fd;
832b15cb3dSCy Schubert 	union { /* This is a union in case we need to make more things that can
842b15cb3dSCy Schubert 			   be in the hashtable. */
852b15cb3dSCy Schubert 		struct evmap_io evmap_io;
862b15cb3dSCy Schubert 	} ent;
872b15cb3dSCy Schubert };
882b15cb3dSCy Schubert 
892b15cb3dSCy Schubert /* Helper used by the event_io_map hashtable code; tries to return a good hash
902b15cb3dSCy Schubert  * of the fd in e->fd. */
912b15cb3dSCy Schubert static inline unsigned
hashsocket(struct event_map_entry * e)922b15cb3dSCy Schubert hashsocket(struct event_map_entry *e)
932b15cb3dSCy Schubert {
942b15cb3dSCy Schubert 	/* On win32, in practice, the low 2-3 bits of a SOCKET seem not to
952b15cb3dSCy Schubert 	 * matter.  Our hashtable implementation really likes low-order bits,
962b15cb3dSCy Schubert 	 * though, so let's do the rotate-and-add trick. */
972b15cb3dSCy Schubert 	unsigned h = (unsigned) e->fd;
982b15cb3dSCy Schubert 	h += (h >> 2) | (h << 30);
992b15cb3dSCy Schubert 	return h;
1002b15cb3dSCy Schubert }
1012b15cb3dSCy Schubert 
1022b15cb3dSCy Schubert /* Helper used by the event_io_map hashtable code; returns true iff e1 and e2
1032b15cb3dSCy Schubert  * have the same e->fd. */
1042b15cb3dSCy Schubert static inline int
eqsocket(struct event_map_entry * e1,struct event_map_entry * e2)1052b15cb3dSCy Schubert eqsocket(struct event_map_entry *e1, struct event_map_entry *e2)
1062b15cb3dSCy Schubert {
1072b15cb3dSCy Schubert 	return e1->fd == e2->fd;
1082b15cb3dSCy Schubert }
1092b15cb3dSCy Schubert 
HT_PROTOTYPE(event_io_map,event_map_entry,map_node,hashsocket,eqsocket)1102b15cb3dSCy Schubert HT_PROTOTYPE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket)
1112b15cb3dSCy Schubert HT_GENERATE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket,
1122b15cb3dSCy Schubert 			0.5, mm_malloc, mm_realloc, mm_free)
1132b15cb3dSCy Schubert 
1142b15cb3dSCy Schubert #define GET_IO_SLOT(x, map, slot, type)					\
1152b15cb3dSCy Schubert 	do {								\
1162b15cb3dSCy Schubert 		struct event_map_entry key_, *ent_;			\
1172b15cb3dSCy Schubert 		key_.fd = slot;						\
1182b15cb3dSCy Schubert 		ent_ = HT_FIND(event_io_map, map, &key_);		\
1192b15cb3dSCy Schubert 		(x) = ent_ ? &ent_->ent.type : NULL;			\
1202b15cb3dSCy Schubert 	} while (0);
1212b15cb3dSCy Schubert 
1222b15cb3dSCy Schubert #define GET_IO_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len)	\
1232b15cb3dSCy Schubert 	do {								\
1242b15cb3dSCy Schubert 		struct event_map_entry key_, *ent_;			\
1252b15cb3dSCy Schubert 		key_.fd = slot;						\
1262b15cb3dSCy Schubert 		HT_FIND_OR_INSERT_(event_io_map, map_node, hashsocket, map, \
1272b15cb3dSCy Schubert 		    event_map_entry, &key_, ptr,			\
1282b15cb3dSCy Schubert 		    {							\
1292b15cb3dSCy Schubert 			    ent_ = *ptr;				\
1302b15cb3dSCy Schubert 		    },							\
1312b15cb3dSCy Schubert 		    {							\
1322b15cb3dSCy Schubert 			    ent_ = mm_calloc(1,sizeof(struct event_map_entry)+fdinfo_len); \
1332b15cb3dSCy Schubert 			    if (EVUTIL_UNLIKELY(ent_ == NULL))		\
1342b15cb3dSCy Schubert 				    return (-1);			\
1352b15cb3dSCy Schubert 			    ent_->fd = slot;				\
1362b15cb3dSCy Schubert 			    (ctor)(&ent_->ent.type);			\
1372b15cb3dSCy Schubert 			    HT_FOI_INSERT_(map_node, map, &key_, ent_, ptr) \
1382b15cb3dSCy Schubert 				});					\
1392b15cb3dSCy Schubert 		(x) = &ent_->ent.type;					\
1402b15cb3dSCy Schubert 	} while (0)
1412b15cb3dSCy Schubert 
1422b15cb3dSCy Schubert void evmap_io_initmap_(struct event_io_map *ctx)
1432b15cb3dSCy Schubert {
1442b15cb3dSCy Schubert 	HT_INIT(event_io_map, ctx);
1452b15cb3dSCy Schubert }
1462b15cb3dSCy Schubert 
evmap_io_clear_(struct event_io_map * ctx)1472b15cb3dSCy Schubert void evmap_io_clear_(struct event_io_map *ctx)
1482b15cb3dSCy Schubert {
1492b15cb3dSCy Schubert 	struct event_map_entry **ent, **next, *this;
1502b15cb3dSCy Schubert 	for (ent = HT_START(event_io_map, ctx); ent; ent = next) {
1512b15cb3dSCy Schubert 		this = *ent;
1522b15cb3dSCy Schubert 		next = HT_NEXT_RMV(event_io_map, ctx, ent);
1532b15cb3dSCy Schubert 		mm_free(this);
1542b15cb3dSCy Schubert 	}
1552b15cb3dSCy Schubert 	HT_CLEAR(event_io_map, ctx); /* remove all storage held by the ctx. */
1562b15cb3dSCy Schubert }
1572b15cb3dSCy Schubert #endif
1582b15cb3dSCy Schubert 
1592b15cb3dSCy Schubert /* Set the variable 'x' to the field in event_map 'map' with fields of type
1602b15cb3dSCy Schubert    'struct type *' corresponding to the fd or signal 'slot'.  Set 'x' to NULL
1612b15cb3dSCy Schubert    if there are no entries for 'slot'.  Does no bounds-checking. */
1622b15cb3dSCy Schubert #define GET_SIGNAL_SLOT(x, map, slot, type)			\
1632b15cb3dSCy Schubert 	(x) = (struct type *)((map)->entries[slot])
1642b15cb3dSCy Schubert /* As GET_SLOT, but construct the entry for 'slot' if it is not present,
1652b15cb3dSCy Schubert    by allocating enough memory for a 'struct type', and initializing the new
1662b15cb3dSCy Schubert    value by calling the function 'ctor' on it.  Makes the function
1672b15cb3dSCy Schubert    return -1 on allocation failure.
1682b15cb3dSCy Schubert  */
1692b15cb3dSCy Schubert #define GET_SIGNAL_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len)	\
1702b15cb3dSCy Schubert 	do {								\
1712b15cb3dSCy Schubert 		if ((map)->entries[slot] == NULL) {			\
1722b15cb3dSCy Schubert 			(map)->entries[slot] =				\
1732b15cb3dSCy Schubert 			    mm_calloc(1,sizeof(struct type)+fdinfo_len); \
1742b15cb3dSCy Schubert 			if (EVUTIL_UNLIKELY((map)->entries[slot] == NULL)) \
1752b15cb3dSCy Schubert 				return (-1);				\
1762b15cb3dSCy Schubert 			(ctor)((struct type *)(map)->entries[slot]);	\
1772b15cb3dSCy Schubert 		}							\
1782b15cb3dSCy Schubert 		(x) = (struct type *)((map)->entries[slot]);		\
1792b15cb3dSCy Schubert 	} while (0)
1802b15cb3dSCy Schubert 
1812b15cb3dSCy Schubert /* If we aren't using hashtables, then define the IO_SLOT macros and functions
1822b15cb3dSCy Schubert    as thin aliases over the SIGNAL_SLOT versions. */
1832b15cb3dSCy Schubert #ifndef EVMAP_USE_HT
1842b15cb3dSCy Schubert #define GET_IO_SLOT(x,map,slot,type) GET_SIGNAL_SLOT(x,map,slot,type)
1852b15cb3dSCy Schubert #define GET_IO_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)	\
1862b15cb3dSCy Schubert 	GET_SIGNAL_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)
1872b15cb3dSCy Schubert #define FDINFO_OFFSET sizeof(struct evmap_io)
1882b15cb3dSCy Schubert void
evmap_io_initmap_(struct event_io_map * ctx)1892b15cb3dSCy Schubert evmap_io_initmap_(struct event_io_map* ctx)
1902b15cb3dSCy Schubert {
1912b15cb3dSCy Schubert 	evmap_signal_initmap_(ctx);
1922b15cb3dSCy Schubert }
1932b15cb3dSCy Schubert void
evmap_io_clear_(struct event_io_map * ctx)1942b15cb3dSCy Schubert evmap_io_clear_(struct event_io_map* ctx)
1952b15cb3dSCy Schubert {
1962b15cb3dSCy Schubert 	evmap_signal_clear_(ctx);
1972b15cb3dSCy Schubert }
1982b15cb3dSCy Schubert #endif
1992b15cb3dSCy Schubert 
2002b15cb3dSCy Schubert 
2012b15cb3dSCy Schubert /** Expand 'map' with new entries of width 'msize' until it is big enough
2022b15cb3dSCy Schubert 	to store a value in 'slot'.
2032b15cb3dSCy Schubert  */
2042b15cb3dSCy Schubert static int
evmap_make_space(struct event_signal_map * map,int slot,int msize)2052b15cb3dSCy Schubert evmap_make_space(struct event_signal_map *map, int slot, int msize)
2062b15cb3dSCy Schubert {
2072b15cb3dSCy Schubert 	if (map->nentries <= slot) {
2082b15cb3dSCy Schubert 		int nentries = map->nentries ? map->nentries : 32;
2092b15cb3dSCy Schubert 		void **tmp;
2102b15cb3dSCy Schubert 
211*a466cc55SCy Schubert 		if (slot > INT_MAX / 2)
212*a466cc55SCy Schubert 			return (-1);
213*a466cc55SCy Schubert 
2142b15cb3dSCy Schubert 		while (nentries <= slot)
2152b15cb3dSCy Schubert 			nentries <<= 1;
2162b15cb3dSCy Schubert 
217*a466cc55SCy Schubert 		if (nentries > INT_MAX / msize)
218*a466cc55SCy Schubert 			return (-1);
219*a466cc55SCy Schubert 
2202b15cb3dSCy Schubert 		tmp = (void **)mm_realloc(map->entries, nentries * msize);
2212b15cb3dSCy Schubert 		if (tmp == NULL)
2222b15cb3dSCy Schubert 			return (-1);
2232b15cb3dSCy Schubert 
2242b15cb3dSCy Schubert 		memset(&tmp[map->nentries], 0,
2252b15cb3dSCy Schubert 		    (nentries - map->nentries) * msize);
2262b15cb3dSCy Schubert 
2272b15cb3dSCy Schubert 		map->nentries = nentries;
2282b15cb3dSCy Schubert 		map->entries = tmp;
2292b15cb3dSCy Schubert 	}
2302b15cb3dSCy Schubert 
2312b15cb3dSCy Schubert 	return (0);
2322b15cb3dSCy Schubert }
2332b15cb3dSCy Schubert 
2342b15cb3dSCy Schubert void
evmap_signal_initmap_(struct event_signal_map * ctx)2352b15cb3dSCy Schubert evmap_signal_initmap_(struct event_signal_map *ctx)
2362b15cb3dSCy Schubert {
2372b15cb3dSCy Schubert 	ctx->nentries = 0;
2382b15cb3dSCy Schubert 	ctx->entries = NULL;
2392b15cb3dSCy Schubert }
2402b15cb3dSCy Schubert 
2412b15cb3dSCy Schubert void
evmap_signal_clear_(struct event_signal_map * ctx)2422b15cb3dSCy Schubert evmap_signal_clear_(struct event_signal_map *ctx)
2432b15cb3dSCy Schubert {
2442b15cb3dSCy Schubert 	if (ctx->entries != NULL) {
2452b15cb3dSCy Schubert 		int i;
2462b15cb3dSCy Schubert 		for (i = 0; i < ctx->nentries; ++i) {
2472b15cb3dSCy Schubert 			if (ctx->entries[i] != NULL)
2482b15cb3dSCy Schubert 				mm_free(ctx->entries[i]);
2492b15cb3dSCy Schubert 		}
2502b15cb3dSCy Schubert 		mm_free(ctx->entries);
2512b15cb3dSCy Schubert 		ctx->entries = NULL;
2522b15cb3dSCy Schubert 	}
2532b15cb3dSCy Schubert 	ctx->nentries = 0;
2542b15cb3dSCy Schubert }
2552b15cb3dSCy Schubert 
2562b15cb3dSCy Schubert 
2572b15cb3dSCy Schubert /* code specific to file descriptors */
2582b15cb3dSCy Schubert 
2592b15cb3dSCy Schubert /** Constructor for struct evmap_io */
2602b15cb3dSCy Schubert static void
evmap_io_init(struct evmap_io * entry)2612b15cb3dSCy Schubert evmap_io_init(struct evmap_io *entry)
2622b15cb3dSCy Schubert {
2632b15cb3dSCy Schubert 	LIST_INIT(&entry->events);
2642b15cb3dSCy Schubert 	entry->nread = 0;
2652b15cb3dSCy Schubert 	entry->nwrite = 0;
2662b15cb3dSCy Schubert 	entry->nclose = 0;
2672b15cb3dSCy Schubert }
2682b15cb3dSCy Schubert 
2692b15cb3dSCy Schubert 
2702b15cb3dSCy Schubert /* return -1 on error, 0 on success if nothing changed in the event backend,
2712b15cb3dSCy Schubert  * and 1 on success if something did. */
2722b15cb3dSCy Schubert int
evmap_io_add_(struct event_base * base,evutil_socket_t fd,struct event * ev)2732b15cb3dSCy Schubert evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
2742b15cb3dSCy Schubert {
2752b15cb3dSCy Schubert 	const struct eventop *evsel = base->evsel;
2762b15cb3dSCy Schubert 	struct event_io_map *io = &base->io;
2772b15cb3dSCy Schubert 	struct evmap_io *ctx = NULL;
2782b15cb3dSCy Schubert 	int nread, nwrite, nclose, retval = 0;
2792b15cb3dSCy Schubert 	short res = 0, old = 0;
2802b15cb3dSCy Schubert 	struct event *old_ev;
2812b15cb3dSCy Schubert 
2822b15cb3dSCy Schubert 	EVUTIL_ASSERT(fd == ev->ev_fd);
2832b15cb3dSCy Schubert 
2842b15cb3dSCy Schubert 	if (fd < 0)
2852b15cb3dSCy Schubert 		return 0;
2862b15cb3dSCy Schubert 
2872b15cb3dSCy Schubert #ifndef EVMAP_USE_HT
2882b15cb3dSCy Schubert 	if (fd >= io->nentries) {
2892b15cb3dSCy Schubert 		if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1)
2902b15cb3dSCy Schubert 			return (-1);
2912b15cb3dSCy Schubert 	}
2922b15cb3dSCy Schubert #endif
2932b15cb3dSCy Schubert 	GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init,
2942b15cb3dSCy Schubert 						 evsel->fdinfo_len);
2952b15cb3dSCy Schubert 
2962b15cb3dSCy Schubert 	nread = ctx->nread;
2972b15cb3dSCy Schubert 	nwrite = ctx->nwrite;
2982b15cb3dSCy Schubert 	nclose = ctx->nclose;
2992b15cb3dSCy Schubert 
3002b15cb3dSCy Schubert 	if (nread)
3012b15cb3dSCy Schubert 		old |= EV_READ;
3022b15cb3dSCy Schubert 	if (nwrite)
3032b15cb3dSCy Schubert 		old |= EV_WRITE;
3042b15cb3dSCy Schubert 	if (nclose)
3052b15cb3dSCy Schubert 		old |= EV_CLOSED;
3062b15cb3dSCy Schubert 
3072b15cb3dSCy Schubert 	if (ev->ev_events & EV_READ) {
3082b15cb3dSCy Schubert 		if (++nread == 1)
3092b15cb3dSCy Schubert 			res |= EV_READ;
3102b15cb3dSCy Schubert 	}
3112b15cb3dSCy Schubert 	if (ev->ev_events & EV_WRITE) {
3122b15cb3dSCy Schubert 		if (++nwrite == 1)
3132b15cb3dSCy Schubert 			res |= EV_WRITE;
3142b15cb3dSCy Schubert 	}
3152b15cb3dSCy Schubert 	if (ev->ev_events & EV_CLOSED) {
3162b15cb3dSCy Schubert 		if (++nclose == 1)
3172b15cb3dSCy Schubert 			res |= EV_CLOSED;
3182b15cb3dSCy Schubert 	}
3192b15cb3dSCy Schubert 	if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) {
3202b15cb3dSCy Schubert 		event_warnx("Too many events reading or writing on fd %d",
3212b15cb3dSCy Schubert 		    (int)fd);
3222b15cb3dSCy Schubert 		return -1;
3232b15cb3dSCy Schubert 	}
3242b15cb3dSCy Schubert 	if (EVENT_DEBUG_MODE_IS_ON() &&
3252b15cb3dSCy Schubert 	    (old_ev = LIST_FIRST(&ctx->events)) &&
3262b15cb3dSCy Schubert 	    (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) {
3272b15cb3dSCy Schubert 		event_warnx("Tried to mix edge-triggered and non-edge-triggered"
3282b15cb3dSCy Schubert 		    " events on fd %d", (int)fd);
3292b15cb3dSCy Schubert 		return -1;
3302b15cb3dSCy Schubert 	}
3312b15cb3dSCy Schubert 
3322b15cb3dSCy Schubert 	if (res) {
3332b15cb3dSCy Schubert 		void *extra = ((char*)ctx) + sizeof(struct evmap_io);
3342b15cb3dSCy Schubert 		/* XXX(niels): we cannot mix edge-triggered and
3352b15cb3dSCy Schubert 		 * level-triggered, we should probably assert on
3362b15cb3dSCy Schubert 		 * this. */
3372b15cb3dSCy Schubert 		if (evsel->add(base, ev->ev_fd,
3382b15cb3dSCy Schubert 			old, (ev->ev_events & EV_ET) | res, extra) == -1)
3392b15cb3dSCy Schubert 			return (-1);
3402b15cb3dSCy Schubert 		retval = 1;
3412b15cb3dSCy Schubert 	}
3422b15cb3dSCy Schubert 
3432b15cb3dSCy Schubert 	ctx->nread = (ev_uint16_t) nread;
3442b15cb3dSCy Schubert 	ctx->nwrite = (ev_uint16_t) nwrite;
3452b15cb3dSCy Schubert 	ctx->nclose = (ev_uint16_t) nclose;
3462b15cb3dSCy Schubert 	LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next);
3472b15cb3dSCy Schubert 
3482b15cb3dSCy Schubert 	return (retval);
3492b15cb3dSCy Schubert }
3502b15cb3dSCy Schubert 
3512b15cb3dSCy Schubert /* return -1 on error, 0 on success if nothing changed in the event backend,
3522b15cb3dSCy Schubert  * and 1 on success if something did. */
3532b15cb3dSCy Schubert int
evmap_io_del_(struct event_base * base,evutil_socket_t fd,struct event * ev)3542b15cb3dSCy Schubert evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
3552b15cb3dSCy Schubert {
3562b15cb3dSCy Schubert 	const struct eventop *evsel = base->evsel;
3572b15cb3dSCy Schubert 	struct event_io_map *io = &base->io;
3582b15cb3dSCy Schubert 	struct evmap_io *ctx;
3592b15cb3dSCy Schubert 	int nread, nwrite, nclose, retval = 0;
3602b15cb3dSCy Schubert 	short res = 0, old = 0;
3612b15cb3dSCy Schubert 
3622b15cb3dSCy Schubert 	if (fd < 0)
3632b15cb3dSCy Schubert 		return 0;
3642b15cb3dSCy Schubert 
3652b15cb3dSCy Schubert 	EVUTIL_ASSERT(fd == ev->ev_fd);
3662b15cb3dSCy Schubert 
3672b15cb3dSCy Schubert #ifndef EVMAP_USE_HT
3682b15cb3dSCy Schubert 	if (fd >= io->nentries)
3692b15cb3dSCy Schubert 		return (-1);
3702b15cb3dSCy Schubert #endif
3712b15cb3dSCy Schubert 
3722b15cb3dSCy Schubert 	GET_IO_SLOT(ctx, io, fd, evmap_io);
3732b15cb3dSCy Schubert 
3742b15cb3dSCy Schubert 	nread = ctx->nread;
3752b15cb3dSCy Schubert 	nwrite = ctx->nwrite;
3762b15cb3dSCy Schubert 	nclose = ctx->nclose;
3772b15cb3dSCy Schubert 
3782b15cb3dSCy Schubert 	if (nread)
3792b15cb3dSCy Schubert 		old |= EV_READ;
3802b15cb3dSCy Schubert 	if (nwrite)
3812b15cb3dSCy Schubert 		old |= EV_WRITE;
3822b15cb3dSCy Schubert 	if (nclose)
3832b15cb3dSCy Schubert 		old |= EV_CLOSED;
3842b15cb3dSCy Schubert 
3852b15cb3dSCy Schubert 	if (ev->ev_events & EV_READ) {
3862b15cb3dSCy Schubert 		if (--nread == 0)
3872b15cb3dSCy Schubert 			res |= EV_READ;
3882b15cb3dSCy Schubert 		EVUTIL_ASSERT(nread >= 0);
3892b15cb3dSCy Schubert 	}
3902b15cb3dSCy Schubert 	if (ev->ev_events & EV_WRITE) {
3912b15cb3dSCy Schubert 		if (--nwrite == 0)
3922b15cb3dSCy Schubert 			res |= EV_WRITE;
3932b15cb3dSCy Schubert 		EVUTIL_ASSERT(nwrite >= 0);
3942b15cb3dSCy Schubert 	}
3952b15cb3dSCy Schubert 	if (ev->ev_events & EV_CLOSED) {
3962b15cb3dSCy Schubert 		if (--nclose == 0)
3972b15cb3dSCy Schubert 			res |= EV_CLOSED;
3982b15cb3dSCy Schubert 		EVUTIL_ASSERT(nclose >= 0);
3992b15cb3dSCy Schubert 	}
4002b15cb3dSCy Schubert 
4012b15cb3dSCy Schubert 	if (res) {
4022b15cb3dSCy Schubert 		void *extra = ((char*)ctx) + sizeof(struct evmap_io);
403*a466cc55SCy Schubert 		if (evsel->del(base, ev->ev_fd,
404*a466cc55SCy Schubert 			old, (ev->ev_events & EV_ET) | res, extra) == -1) {
4052b15cb3dSCy Schubert 			retval = -1;
4062b15cb3dSCy Schubert 		} else {
4072b15cb3dSCy Schubert 			retval = 1;
4082b15cb3dSCy Schubert 		}
4092b15cb3dSCy Schubert 	}
4102b15cb3dSCy Schubert 
4112b15cb3dSCy Schubert 	ctx->nread = nread;
4122b15cb3dSCy Schubert 	ctx->nwrite = nwrite;
4132b15cb3dSCy Schubert 	ctx->nclose = nclose;
4142b15cb3dSCy Schubert 	LIST_REMOVE(ev, ev_io_next);
4152b15cb3dSCy Schubert 
4162b15cb3dSCy Schubert 	return (retval);
4172b15cb3dSCy Schubert }
4182b15cb3dSCy Schubert 
4192b15cb3dSCy Schubert void
evmap_io_active_(struct event_base * base,evutil_socket_t fd,short events)4202b15cb3dSCy Schubert evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events)
4212b15cb3dSCy Schubert {
4222b15cb3dSCy Schubert 	struct event_io_map *io = &base->io;
4232b15cb3dSCy Schubert 	struct evmap_io *ctx;
4242b15cb3dSCy Schubert 	struct event *ev;
4252b15cb3dSCy Schubert 
4262b15cb3dSCy Schubert #ifndef EVMAP_USE_HT
4272b15cb3dSCy Schubert 	if (fd < 0 || fd >= io->nentries)
4282b15cb3dSCy Schubert 		return;
4292b15cb3dSCy Schubert #endif
4302b15cb3dSCy Schubert 	GET_IO_SLOT(ctx, io, fd, evmap_io);
4312b15cb3dSCy Schubert 
4322b15cb3dSCy Schubert 	if (NULL == ctx)
4332b15cb3dSCy Schubert 		return;
4342b15cb3dSCy Schubert 	LIST_FOREACH(ev, &ctx->events, ev_io_next) {
435*a466cc55SCy Schubert 		if (ev->ev_events & (events & ~EV_ET))
4362b15cb3dSCy Schubert 			event_active_nolock_(ev, ev->ev_events & events, 1);
4372b15cb3dSCy Schubert 	}
4382b15cb3dSCy Schubert }
4392b15cb3dSCy Schubert 
4402b15cb3dSCy Schubert /* code specific to signals */
4412b15cb3dSCy Schubert 
4422b15cb3dSCy Schubert static void
evmap_signal_init(struct evmap_signal * entry)4432b15cb3dSCy Schubert evmap_signal_init(struct evmap_signal *entry)
4442b15cb3dSCy Schubert {
4452b15cb3dSCy Schubert 	LIST_INIT(&entry->events);
4462b15cb3dSCy Schubert }
4472b15cb3dSCy Schubert 
4482b15cb3dSCy Schubert 
4492b15cb3dSCy Schubert int
evmap_signal_add_(struct event_base * base,int sig,struct event * ev)4502b15cb3dSCy Schubert evmap_signal_add_(struct event_base *base, int sig, struct event *ev)
4512b15cb3dSCy Schubert {
4522b15cb3dSCy Schubert 	const struct eventop *evsel = base->evsigsel;
4532b15cb3dSCy Schubert 	struct event_signal_map *map = &base->sigmap;
4542b15cb3dSCy Schubert 	struct evmap_signal *ctx = NULL;
4552b15cb3dSCy Schubert 
456*a466cc55SCy Schubert 	if (sig < 0 || sig >= NSIG)
457*a466cc55SCy Schubert 		return (-1);
458*a466cc55SCy Schubert 
4592b15cb3dSCy Schubert 	if (sig >= map->nentries) {
4602b15cb3dSCy Schubert 		if (evmap_make_space(
4612b15cb3dSCy Schubert 			map, sig, sizeof(struct evmap_signal *)) == -1)
4622b15cb3dSCy Schubert 			return (-1);
4632b15cb3dSCy Schubert 	}
4642b15cb3dSCy Schubert 	GET_SIGNAL_SLOT_AND_CTOR(ctx, map, sig, evmap_signal, evmap_signal_init,
4652b15cb3dSCy Schubert 	    base->evsigsel->fdinfo_len);
4662b15cb3dSCy Schubert 
4672b15cb3dSCy Schubert 	if (LIST_EMPTY(&ctx->events)) {
4682b15cb3dSCy Schubert 		if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL)
4692b15cb3dSCy Schubert 		    == -1)
4702b15cb3dSCy Schubert 			return (-1);
4712b15cb3dSCy Schubert 	}
4722b15cb3dSCy Schubert 
4732b15cb3dSCy Schubert 	LIST_INSERT_HEAD(&ctx->events, ev, ev_signal_next);
4742b15cb3dSCy Schubert 
4752b15cb3dSCy Schubert 	return (1);
4762b15cb3dSCy Schubert }
4772b15cb3dSCy Schubert 
4782b15cb3dSCy Schubert int
evmap_signal_del_(struct event_base * base,int sig,struct event * ev)4792b15cb3dSCy Schubert evmap_signal_del_(struct event_base *base, int sig, struct event *ev)
4802b15cb3dSCy Schubert {
4812b15cb3dSCy Schubert 	const struct eventop *evsel = base->evsigsel;
4822b15cb3dSCy Schubert 	struct event_signal_map *map = &base->sigmap;
4832b15cb3dSCy Schubert 	struct evmap_signal *ctx;
4842b15cb3dSCy Schubert 
485*a466cc55SCy Schubert 	if (sig < 0 || sig >= map->nentries)
4862b15cb3dSCy Schubert 		return (-1);
4872b15cb3dSCy Schubert 
4882b15cb3dSCy Schubert 	GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
4892b15cb3dSCy Schubert 
4902b15cb3dSCy Schubert 	LIST_REMOVE(ev, ev_signal_next);
4912b15cb3dSCy Schubert 
4922b15cb3dSCy Schubert 	if (LIST_FIRST(&ctx->events) == NULL) {
4932b15cb3dSCy Schubert 		if (evsel->del(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1)
4942b15cb3dSCy Schubert 			return (-1);
4952b15cb3dSCy Schubert 	}
4962b15cb3dSCy Schubert 
4972b15cb3dSCy Schubert 	return (1);
4982b15cb3dSCy Schubert }
4992b15cb3dSCy Schubert 
5002b15cb3dSCy Schubert void
evmap_signal_active_(struct event_base * base,evutil_socket_t sig,int ncalls)5012b15cb3dSCy Schubert evmap_signal_active_(struct event_base *base, evutil_socket_t sig, int ncalls)
5022b15cb3dSCy Schubert {
5032b15cb3dSCy Schubert 	struct event_signal_map *map = &base->sigmap;
5042b15cb3dSCy Schubert 	struct evmap_signal *ctx;
5052b15cb3dSCy Schubert 	struct event *ev;
5062b15cb3dSCy Schubert 
5072b15cb3dSCy Schubert 	if (sig < 0 || sig >= map->nentries)
5082b15cb3dSCy Schubert 		return;
5092b15cb3dSCy Schubert 	GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
5102b15cb3dSCy Schubert 
5112b15cb3dSCy Schubert 	if (!ctx)
5122b15cb3dSCy Schubert 		return;
5132b15cb3dSCy Schubert 	LIST_FOREACH(ev, &ctx->events, ev_signal_next)
5142b15cb3dSCy Schubert 		event_active_nolock_(ev, EV_SIGNAL, ncalls);
5152b15cb3dSCy Schubert }
5162b15cb3dSCy Schubert 
5172b15cb3dSCy Schubert void *
evmap_io_get_fdinfo_(struct event_io_map * map,evutil_socket_t fd)5182b15cb3dSCy Schubert evmap_io_get_fdinfo_(struct event_io_map *map, evutil_socket_t fd)
5192b15cb3dSCy Schubert {
5202b15cb3dSCy Schubert 	struct evmap_io *ctx;
5212b15cb3dSCy Schubert 	GET_IO_SLOT(ctx, map, fd, evmap_io);
5222b15cb3dSCy Schubert 	if (ctx)
5232b15cb3dSCy Schubert 		return ((char*)ctx) + sizeof(struct evmap_io);
5242b15cb3dSCy Schubert 	else
5252b15cb3dSCy Schubert 		return NULL;
5262b15cb3dSCy Schubert }
5272b15cb3dSCy Schubert 
5282b15cb3dSCy Schubert /* Callback type for evmap_io_foreach_fd */
5292b15cb3dSCy Schubert typedef int (*evmap_io_foreach_fd_cb)(
5302b15cb3dSCy Schubert 	struct event_base *, evutil_socket_t, struct evmap_io *, void *);
5312b15cb3dSCy Schubert 
5322b15cb3dSCy Schubert /* Multipurpose helper function: Iterate over every file descriptor event_base
5332b15cb3dSCy Schubert  * for which we could have EV_READ or EV_WRITE events.  For each such fd, call
5342b15cb3dSCy Schubert  * fn(base, signum, evmap_io, arg), where fn is the user-provided
5352b15cb3dSCy Schubert  * function, base is the event_base, signum is the signal number, evmap_io
5362b15cb3dSCy Schubert  * is an evmap_io structure containing a list of events pending on the
5372b15cb3dSCy Schubert  * file descriptor, and arg is the user-supplied argument.
5382b15cb3dSCy Schubert  *
5392b15cb3dSCy Schubert  * If fn returns 0, continue on to the next signal. Otherwise, return the same
5402b15cb3dSCy Schubert  * value that fn returned.
5412b15cb3dSCy Schubert  *
5422b15cb3dSCy Schubert  * Note that there is no guarantee that the file descriptors will be processed
5432b15cb3dSCy Schubert  * in any particular order.
5442b15cb3dSCy Schubert  */
5452b15cb3dSCy Schubert static int
evmap_io_foreach_fd(struct event_base * base,evmap_io_foreach_fd_cb fn,void * arg)5462b15cb3dSCy Schubert evmap_io_foreach_fd(struct event_base *base,
5472b15cb3dSCy Schubert     evmap_io_foreach_fd_cb fn,
5482b15cb3dSCy Schubert     void *arg)
5492b15cb3dSCy Schubert {
5502b15cb3dSCy Schubert 	evutil_socket_t fd;
5512b15cb3dSCy Schubert 	struct event_io_map *iomap = &base->io;
5522b15cb3dSCy Schubert 	int r = 0;
5532b15cb3dSCy Schubert #ifdef EVMAP_USE_HT
5542b15cb3dSCy Schubert 	struct event_map_entry **mapent;
5552b15cb3dSCy Schubert 	HT_FOREACH(mapent, event_io_map, iomap) {
5562b15cb3dSCy Schubert 		struct evmap_io *ctx = &(*mapent)->ent.evmap_io;
5572b15cb3dSCy Schubert 		fd = (*mapent)->fd;
5582b15cb3dSCy Schubert #else
5592b15cb3dSCy Schubert 	for (fd = 0; fd < iomap->nentries; ++fd) {
5602b15cb3dSCy Schubert 		struct evmap_io *ctx = iomap->entries[fd];
5612b15cb3dSCy Schubert 		if (!ctx)
5622b15cb3dSCy Schubert 			continue;
5632b15cb3dSCy Schubert #endif
5642b15cb3dSCy Schubert 		if ((r = fn(base, fd, ctx, arg)))
5652b15cb3dSCy Schubert 			break;
5662b15cb3dSCy Schubert 	}
5672b15cb3dSCy Schubert 	return r;
5682b15cb3dSCy Schubert }
5692b15cb3dSCy Schubert 
5702b15cb3dSCy Schubert /* Callback type for evmap_signal_foreach_signal */
5712b15cb3dSCy Schubert typedef int (*evmap_signal_foreach_signal_cb)(
5722b15cb3dSCy Schubert 	struct event_base *, int, struct evmap_signal *, void *);
5732b15cb3dSCy Schubert 
5742b15cb3dSCy Schubert /* Multipurpose helper function: Iterate over every signal number in the
5752b15cb3dSCy Schubert  * event_base for which we could have signal events.  For each such signal,
5762b15cb3dSCy Schubert  * call fn(base, signum, evmap_signal, arg), where fn is the user-provided
5772b15cb3dSCy Schubert  * function, base is the event_base, signum is the signal number, evmap_signal
5782b15cb3dSCy Schubert  * is an evmap_signal structure containing a list of events pending on the
5792b15cb3dSCy Schubert  * signal, and arg is the user-supplied argument.
5802b15cb3dSCy Schubert  *
5812b15cb3dSCy Schubert  * If fn returns 0, continue on to the next signal. Otherwise, return the same
5822b15cb3dSCy Schubert  * value that fn returned.
5832b15cb3dSCy Schubert  */
5842b15cb3dSCy Schubert static int
5852b15cb3dSCy Schubert evmap_signal_foreach_signal(struct event_base *base,
5862b15cb3dSCy Schubert     evmap_signal_foreach_signal_cb fn,
5872b15cb3dSCy Schubert     void *arg)
5882b15cb3dSCy Schubert {
5892b15cb3dSCy Schubert 	struct event_signal_map *sigmap = &base->sigmap;
5902b15cb3dSCy Schubert 	int r = 0;
5912b15cb3dSCy Schubert 	int signum;
5922b15cb3dSCy Schubert 
5932b15cb3dSCy Schubert 	for (signum = 0; signum < sigmap->nentries; ++signum) {
5942b15cb3dSCy Schubert 		struct evmap_signal *ctx = sigmap->entries[signum];
5952b15cb3dSCy Schubert 		if (!ctx)
5962b15cb3dSCy Schubert 			continue;
5972b15cb3dSCy Schubert 		if ((r = fn(base, signum, ctx, arg)))
5982b15cb3dSCy Schubert 			break;
5992b15cb3dSCy Schubert 	}
6002b15cb3dSCy Schubert 	return r;
6012b15cb3dSCy Schubert }
6022b15cb3dSCy Schubert 
6032b15cb3dSCy Schubert /* Helper for evmap_reinit_: tell the backend to add every fd for which we have
6042b15cb3dSCy Schubert  * pending events, with the appropriate combination of EV_READ, EV_WRITE, and
6052b15cb3dSCy Schubert  * EV_ET. */
6062b15cb3dSCy Schubert static int
6072b15cb3dSCy Schubert evmap_io_reinit_iter_fn(struct event_base *base, evutil_socket_t fd,
6082b15cb3dSCy Schubert     struct evmap_io *ctx, void *arg)
6092b15cb3dSCy Schubert {
6102b15cb3dSCy Schubert 	const struct eventop *evsel = base->evsel;
6112b15cb3dSCy Schubert 	void *extra;
6122b15cb3dSCy Schubert 	int *result = arg;
6132b15cb3dSCy Schubert 	short events = 0;
6142b15cb3dSCy Schubert 	struct event *ev;
6152b15cb3dSCy Schubert 	EVUTIL_ASSERT(ctx);
6162b15cb3dSCy Schubert 
6172b15cb3dSCy Schubert 	extra = ((char*)ctx) + sizeof(struct evmap_io);
6182b15cb3dSCy Schubert 	if (ctx->nread)
6192b15cb3dSCy Schubert 		events |= EV_READ;
6202b15cb3dSCy Schubert 	if (ctx->nwrite)
6212b15cb3dSCy Schubert 		events |= EV_WRITE;
6222b15cb3dSCy Schubert 	if (ctx->nclose)
6232b15cb3dSCy Schubert 		events |= EV_CLOSED;
6242b15cb3dSCy Schubert 	if (evsel->fdinfo_len)
6252b15cb3dSCy Schubert 		memset(extra, 0, evsel->fdinfo_len);
6262b15cb3dSCy Schubert 	if (events &&
6272b15cb3dSCy Schubert 	    (ev = LIST_FIRST(&ctx->events)) &&
6282b15cb3dSCy Schubert 	    (ev->ev_events & EV_ET))
6292b15cb3dSCy Schubert 		events |= EV_ET;
6302b15cb3dSCy Schubert 	if (evsel->add(base, fd, 0, events, extra) == -1)
6312b15cb3dSCy Schubert 		*result = -1;
6322b15cb3dSCy Schubert 
6332b15cb3dSCy Schubert 	return 0;
6342b15cb3dSCy Schubert }
6352b15cb3dSCy Schubert 
6362b15cb3dSCy Schubert /* Helper for evmap_reinit_: tell the backend to add every signal for which we
6372b15cb3dSCy Schubert  * have pending events.  */
6382b15cb3dSCy Schubert static int
6392b15cb3dSCy Schubert evmap_signal_reinit_iter_fn(struct event_base *base,
6402b15cb3dSCy Schubert     int signum, struct evmap_signal *ctx, void *arg)
6412b15cb3dSCy Schubert {
6422b15cb3dSCy Schubert 	const struct eventop *evsel = base->evsigsel;
6432b15cb3dSCy Schubert 	int *result = arg;
6442b15cb3dSCy Schubert 
6452b15cb3dSCy Schubert 	if (!LIST_EMPTY(&ctx->events)) {
6462b15cb3dSCy Schubert 		if (evsel->add(base, signum, 0, EV_SIGNAL, NULL) == -1)
6472b15cb3dSCy Schubert 			*result = -1;
6482b15cb3dSCy Schubert 	}
6492b15cb3dSCy Schubert 	return 0;
6502b15cb3dSCy Schubert }
6512b15cb3dSCy Schubert 
6522b15cb3dSCy Schubert int
6532b15cb3dSCy Schubert evmap_reinit_(struct event_base *base)
6542b15cb3dSCy Schubert {
6552b15cb3dSCy Schubert 	int result = 0;
6562b15cb3dSCy Schubert 
6572b15cb3dSCy Schubert 	evmap_io_foreach_fd(base, evmap_io_reinit_iter_fn, &result);
6582b15cb3dSCy Schubert 	if (result < 0)
6592b15cb3dSCy Schubert 		return -1;
6602b15cb3dSCy Schubert 	evmap_signal_foreach_signal(base, evmap_signal_reinit_iter_fn, &result);
6612b15cb3dSCy Schubert 	if (result < 0)
6622b15cb3dSCy Schubert 		return -1;
6632b15cb3dSCy Schubert 	return 0;
6642b15cb3dSCy Schubert }
6652b15cb3dSCy Schubert 
6662b15cb3dSCy Schubert /* Helper for evmap_delete_all_: delete every event in an event_dlist. */
6672b15cb3dSCy Schubert static int
6682b15cb3dSCy Schubert delete_all_in_dlist(struct event_dlist *dlist)
6692b15cb3dSCy Schubert {
6702b15cb3dSCy Schubert 	struct event *ev;
6712b15cb3dSCy Schubert 	while ((ev = LIST_FIRST(dlist)))
6722b15cb3dSCy Schubert 		event_del(ev);
6732b15cb3dSCy Schubert 	return 0;
6742b15cb3dSCy Schubert }
6752b15cb3dSCy Schubert 
6762b15cb3dSCy Schubert /* Helper for evmap_delete_all_: delete every event pending on an fd. */
6772b15cb3dSCy Schubert static int
6782b15cb3dSCy Schubert evmap_io_delete_all_iter_fn(struct event_base *base, evutil_socket_t fd,
6792b15cb3dSCy Schubert     struct evmap_io *io_info, void *arg)
6802b15cb3dSCy Schubert {
6812b15cb3dSCy Schubert 	return delete_all_in_dlist(&io_info->events);
6822b15cb3dSCy Schubert }
6832b15cb3dSCy Schubert 
6842b15cb3dSCy Schubert /* Helper for evmap_delete_all_: delete every event pending on a signal. */
6852b15cb3dSCy Schubert static int
6862b15cb3dSCy Schubert evmap_signal_delete_all_iter_fn(struct event_base *base, int signum,
6872b15cb3dSCy Schubert     struct evmap_signal *sig_info, void *arg)
6882b15cb3dSCy Schubert {
6892b15cb3dSCy Schubert 	return delete_all_in_dlist(&sig_info->events);
6902b15cb3dSCy Schubert }
6912b15cb3dSCy Schubert 
6922b15cb3dSCy Schubert void
6932b15cb3dSCy Schubert evmap_delete_all_(struct event_base *base)
6942b15cb3dSCy Schubert {
6952b15cb3dSCy Schubert 	evmap_signal_foreach_signal(base, evmap_signal_delete_all_iter_fn, NULL);
6962b15cb3dSCy Schubert 	evmap_io_foreach_fd(base, evmap_io_delete_all_iter_fn, NULL);
6972b15cb3dSCy Schubert }
6982b15cb3dSCy Schubert 
6992b15cb3dSCy Schubert /** Per-fd structure for use with changelists.  It keeps track, for each fd or
7002b15cb3dSCy Schubert  * signal using the changelist, of where its entry in the changelist is.
7012b15cb3dSCy Schubert  */
7022b15cb3dSCy Schubert struct event_changelist_fdinfo {
7032b15cb3dSCy Schubert 	int idxplus1; /* this is the index +1, so that memset(0) will make it
7042b15cb3dSCy Schubert 		       * a no-such-element */
7052b15cb3dSCy Schubert };
7062b15cb3dSCy Schubert 
7072b15cb3dSCy Schubert void
7082b15cb3dSCy Schubert event_changelist_init_(struct event_changelist *changelist)
7092b15cb3dSCy Schubert {
7102b15cb3dSCy Schubert 	changelist->changes = NULL;
7112b15cb3dSCy Schubert 	changelist->changes_size = 0;
7122b15cb3dSCy Schubert 	changelist->n_changes = 0;
7132b15cb3dSCy Schubert }
7142b15cb3dSCy Schubert 
7152b15cb3dSCy Schubert /** Helper: return the changelist_fdinfo corresponding to a given change. */
7162b15cb3dSCy Schubert static inline struct event_changelist_fdinfo *
7172b15cb3dSCy Schubert event_change_get_fdinfo(struct event_base *base,
7182b15cb3dSCy Schubert     const struct event_change *change)
7192b15cb3dSCy Schubert {
7202b15cb3dSCy Schubert 	char *ptr;
7212b15cb3dSCy Schubert 	if (change->read_change & EV_CHANGE_SIGNAL) {
7222b15cb3dSCy Schubert 		struct evmap_signal *ctx;
7232b15cb3dSCy Schubert 		GET_SIGNAL_SLOT(ctx, &base->sigmap, change->fd, evmap_signal);
7242b15cb3dSCy Schubert 		ptr = ((char*)ctx) + sizeof(struct evmap_signal);
7252b15cb3dSCy Schubert 	} else {
7262b15cb3dSCy Schubert 		struct evmap_io *ctx;
7272b15cb3dSCy Schubert 		GET_IO_SLOT(ctx, &base->io, change->fd, evmap_io);
7282b15cb3dSCy Schubert 		ptr = ((char*)ctx) + sizeof(struct evmap_io);
7292b15cb3dSCy Schubert 	}
7302b15cb3dSCy Schubert 	return (void*)ptr;
7312b15cb3dSCy Schubert }
7322b15cb3dSCy Schubert 
7332b15cb3dSCy Schubert /** Callback helper for event_changelist_assert_ok */
7342b15cb3dSCy Schubert static int
7352b15cb3dSCy Schubert event_changelist_assert_ok_foreach_iter_fn(
7362b15cb3dSCy Schubert 	struct event_base *base,
7372b15cb3dSCy Schubert 	evutil_socket_t fd, struct evmap_io *io, void *arg)
7382b15cb3dSCy Schubert {
7392b15cb3dSCy Schubert 	struct event_changelist *changelist = &base->changelist;
7402b15cb3dSCy Schubert 	struct event_changelist_fdinfo *f;
7412b15cb3dSCy Schubert 	f = (void*)
7422b15cb3dSCy Schubert 	    ( ((char*)io) + sizeof(struct evmap_io) );
7432b15cb3dSCy Schubert 	if (f->idxplus1) {
7442b15cb3dSCy Schubert 		struct event_change *c = &changelist->changes[f->idxplus1 - 1];
7452b15cb3dSCy Schubert 		EVUTIL_ASSERT(c->fd == fd);
7462b15cb3dSCy Schubert 	}
7472b15cb3dSCy Schubert 	return 0;
7482b15cb3dSCy Schubert }
7492b15cb3dSCy Schubert 
7502b15cb3dSCy Schubert /** Make sure that the changelist is consistent with the evmap structures. */
7512b15cb3dSCy Schubert static void
7522b15cb3dSCy Schubert event_changelist_assert_ok(struct event_base *base)
7532b15cb3dSCy Schubert {
7542b15cb3dSCy Schubert 	int i;
7552b15cb3dSCy Schubert 	struct event_changelist *changelist = &base->changelist;
7562b15cb3dSCy Schubert 
7572b15cb3dSCy Schubert 	EVUTIL_ASSERT(changelist->changes_size >= changelist->n_changes);
7582b15cb3dSCy Schubert 	for (i = 0; i < changelist->n_changes; ++i) {
7592b15cb3dSCy Schubert 		struct event_change *c = &changelist->changes[i];
7602b15cb3dSCy Schubert 		struct event_changelist_fdinfo *f;
7612b15cb3dSCy Schubert 		EVUTIL_ASSERT(c->fd >= 0);
7622b15cb3dSCy Schubert 		f = event_change_get_fdinfo(base, c);
7632b15cb3dSCy Schubert 		EVUTIL_ASSERT(f);
7642b15cb3dSCy Schubert 		EVUTIL_ASSERT(f->idxplus1 == i + 1);
7652b15cb3dSCy Schubert 	}
7662b15cb3dSCy Schubert 
7672b15cb3dSCy Schubert 	evmap_io_foreach_fd(base,
7682b15cb3dSCy Schubert 	    event_changelist_assert_ok_foreach_iter_fn,
7692b15cb3dSCy Schubert 	    NULL);
7702b15cb3dSCy Schubert }
7712b15cb3dSCy Schubert 
7722b15cb3dSCy Schubert #ifdef DEBUG_CHANGELIST
7732b15cb3dSCy Schubert #define event_changelist_check(base)  event_changelist_assert_ok((base))
7742b15cb3dSCy Schubert #else
7752b15cb3dSCy Schubert #define event_changelist_check(base)  ((void)0)
7762b15cb3dSCy Schubert #endif
7772b15cb3dSCy Schubert 
7782b15cb3dSCy Schubert void
7792b15cb3dSCy Schubert event_changelist_remove_all_(struct event_changelist *changelist,
7802b15cb3dSCy Schubert     struct event_base *base)
7812b15cb3dSCy Schubert {
7822b15cb3dSCy Schubert 	int i;
7832b15cb3dSCy Schubert 
7842b15cb3dSCy Schubert 	event_changelist_check(base);
7852b15cb3dSCy Schubert 
7862b15cb3dSCy Schubert 	for (i = 0; i < changelist->n_changes; ++i) {
7872b15cb3dSCy Schubert 		struct event_change *ch = &changelist->changes[i];
7882b15cb3dSCy Schubert 		struct event_changelist_fdinfo *fdinfo =
7892b15cb3dSCy Schubert 		    event_change_get_fdinfo(base, ch);
7902b15cb3dSCy Schubert 		EVUTIL_ASSERT(fdinfo->idxplus1 == i + 1);
7912b15cb3dSCy Schubert 		fdinfo->idxplus1 = 0;
7922b15cb3dSCy Schubert 	}
7932b15cb3dSCy Schubert 
7942b15cb3dSCy Schubert 	changelist->n_changes = 0;
7952b15cb3dSCy Schubert 
7962b15cb3dSCy Schubert 	event_changelist_check(base);
7972b15cb3dSCy Schubert }
7982b15cb3dSCy Schubert 
7992b15cb3dSCy Schubert void
8002b15cb3dSCy Schubert event_changelist_freemem_(struct event_changelist *changelist)
8012b15cb3dSCy Schubert {
8022b15cb3dSCy Schubert 	if (changelist->changes)
8032b15cb3dSCy Schubert 		mm_free(changelist->changes);
8042b15cb3dSCy Schubert 	event_changelist_init_(changelist); /* zero it all out. */
8052b15cb3dSCy Schubert }
8062b15cb3dSCy Schubert 
8072b15cb3dSCy Schubert /** Increase the size of 'changelist' to hold more changes. */
8082b15cb3dSCy Schubert static int
8092b15cb3dSCy Schubert event_changelist_grow(struct event_changelist *changelist)
8102b15cb3dSCy Schubert {
8112b15cb3dSCy Schubert 	int new_size;
8122b15cb3dSCy Schubert 	struct event_change *new_changes;
8132b15cb3dSCy Schubert 	if (changelist->changes_size < 64)
8142b15cb3dSCy Schubert 		new_size = 64;
8152b15cb3dSCy Schubert 	else
8162b15cb3dSCy Schubert 		new_size = changelist->changes_size * 2;
8172b15cb3dSCy Schubert 
8182b15cb3dSCy Schubert 	new_changes = mm_realloc(changelist->changes,
8192b15cb3dSCy Schubert 	    new_size * sizeof(struct event_change));
8202b15cb3dSCy Schubert 
8212b15cb3dSCy Schubert 	if (EVUTIL_UNLIKELY(new_changes == NULL))
8222b15cb3dSCy Schubert 		return (-1);
8232b15cb3dSCy Schubert 
8242b15cb3dSCy Schubert 	changelist->changes = new_changes;
8252b15cb3dSCy Schubert 	changelist->changes_size = new_size;
8262b15cb3dSCy Schubert 
8272b15cb3dSCy Schubert 	return (0);
8282b15cb3dSCy Schubert }
8292b15cb3dSCy Schubert 
8302b15cb3dSCy Schubert /** Return a pointer to the changelist entry for the file descriptor or signal
8312b15cb3dSCy Schubert  * 'fd', whose fdinfo is 'fdinfo'.  If none exists, construct it, setting its
8322b15cb3dSCy Schubert  * old_events field to old_events.
8332b15cb3dSCy Schubert  */
8342b15cb3dSCy Schubert static struct event_change *
8352b15cb3dSCy Schubert event_changelist_get_or_construct(struct event_changelist *changelist,
8362b15cb3dSCy Schubert     evutil_socket_t fd,
8372b15cb3dSCy Schubert     short old_events,
8382b15cb3dSCy Schubert     struct event_changelist_fdinfo *fdinfo)
8392b15cb3dSCy Schubert {
8402b15cb3dSCy Schubert 	struct event_change *change;
8412b15cb3dSCy Schubert 
8422b15cb3dSCy Schubert 	if (fdinfo->idxplus1 == 0) {
8432b15cb3dSCy Schubert 		int idx;
8442b15cb3dSCy Schubert 		EVUTIL_ASSERT(changelist->n_changes <= changelist->changes_size);
8452b15cb3dSCy Schubert 
8462b15cb3dSCy Schubert 		if (changelist->n_changes == changelist->changes_size) {
8472b15cb3dSCy Schubert 			if (event_changelist_grow(changelist) < 0)
8482b15cb3dSCy Schubert 				return NULL;
8492b15cb3dSCy Schubert 		}
8502b15cb3dSCy Schubert 
8512b15cb3dSCy Schubert 		idx = changelist->n_changes++;
8522b15cb3dSCy Schubert 		change = &changelist->changes[idx];
8532b15cb3dSCy Schubert 		fdinfo->idxplus1 = idx + 1;
8542b15cb3dSCy Schubert 
8552b15cb3dSCy Schubert 		memset(change, 0, sizeof(struct event_change));
8562b15cb3dSCy Schubert 		change->fd = fd;
8572b15cb3dSCy Schubert 		change->old_events = old_events;
8582b15cb3dSCy Schubert 	} else {
8592b15cb3dSCy Schubert 		change = &changelist->changes[fdinfo->idxplus1 - 1];
8602b15cb3dSCy Schubert 		EVUTIL_ASSERT(change->fd == fd);
8612b15cb3dSCy Schubert 	}
8622b15cb3dSCy Schubert 	return change;
8632b15cb3dSCy Schubert }
8642b15cb3dSCy Schubert 
8652b15cb3dSCy Schubert int
8662b15cb3dSCy Schubert event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, short events,
8672b15cb3dSCy Schubert     void *p)
8682b15cb3dSCy Schubert {
8692b15cb3dSCy Schubert 	struct event_changelist *changelist = &base->changelist;
8702b15cb3dSCy Schubert 	struct event_changelist_fdinfo *fdinfo = p;
8712b15cb3dSCy Schubert 	struct event_change *change;
872*a466cc55SCy Schubert 	ev_uint8_t evchange = EV_CHANGE_ADD | (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
8732b15cb3dSCy Schubert 
8742b15cb3dSCy Schubert 	event_changelist_check(base);
8752b15cb3dSCy Schubert 
8762b15cb3dSCy Schubert 	change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
8772b15cb3dSCy Schubert 	if (!change)
8782b15cb3dSCy Schubert 		return -1;
8792b15cb3dSCy Schubert 
8802b15cb3dSCy Schubert 	/* An add replaces any previous delete, but doesn't result in a no-op,
8812b15cb3dSCy Schubert 	 * since the delete might fail (because the fd had been closed since
8822b15cb3dSCy Schubert 	 * the last add, for instance. */
8832b15cb3dSCy Schubert 
884*a466cc55SCy Schubert 	if (events & (EV_READ|EV_SIGNAL))
885*a466cc55SCy Schubert 		change->read_change = evchange;
886*a466cc55SCy Schubert 	if (events & EV_WRITE)
887*a466cc55SCy Schubert 		change->write_change = evchange;
888*a466cc55SCy Schubert 	if (events & EV_CLOSED)
889*a466cc55SCy Schubert 		change->close_change = evchange;
8902b15cb3dSCy Schubert 
8912b15cb3dSCy Schubert 	event_changelist_check(base);
8922b15cb3dSCy Schubert 	return (0);
8932b15cb3dSCy Schubert }
8942b15cb3dSCy Schubert 
8952b15cb3dSCy Schubert int
8962b15cb3dSCy Schubert event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events,
8972b15cb3dSCy Schubert     void *p)
8982b15cb3dSCy Schubert {
8992b15cb3dSCy Schubert 	struct event_changelist *changelist = &base->changelist;
9002b15cb3dSCy Schubert 	struct event_changelist_fdinfo *fdinfo = p;
9012b15cb3dSCy Schubert 	struct event_change *change;
902*a466cc55SCy Schubert 	ev_uint8_t del = EV_CHANGE_DEL | (events & EV_ET);
9032b15cb3dSCy Schubert 
9042b15cb3dSCy Schubert 	event_changelist_check(base);
9052b15cb3dSCy Schubert 	change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
9062b15cb3dSCy Schubert 	event_changelist_check(base);
9072b15cb3dSCy Schubert 	if (!change)
9082b15cb3dSCy Schubert 		return -1;
9092b15cb3dSCy Schubert 
9102b15cb3dSCy Schubert 	/* A delete on an event set that doesn't contain the event to be
9112b15cb3dSCy Schubert 	   deleted produces a no-op.  This effectively emoves any previous
9122b15cb3dSCy Schubert 	   uncommitted add, rather than replacing it: on those platforms where
9132b15cb3dSCy Schubert 	   "add, delete, dispatch" is not the same as "no-op, dispatch", we
9142b15cb3dSCy Schubert 	   want the no-op behavior.
9152b15cb3dSCy Schubert 
9162b15cb3dSCy Schubert 	   If we have a no-op item, we could remove it it from the list
9172b15cb3dSCy Schubert 	   entirely, but really there's not much point: skipping the no-op
9182b15cb3dSCy Schubert 	   change when we do the dispatch later is far cheaper than rejuggling
9192b15cb3dSCy Schubert 	   the array now.
9202b15cb3dSCy Schubert 
9212b15cb3dSCy Schubert 	   As this stands, it also lets through deletions of events that are
9222b15cb3dSCy Schubert 	   not currently set.
9232b15cb3dSCy Schubert 	 */
9242b15cb3dSCy Schubert 
9252b15cb3dSCy Schubert 	if (events & (EV_READ|EV_SIGNAL)) {
9262b15cb3dSCy Schubert 		if (!(change->old_events & (EV_READ | EV_SIGNAL)))
9272b15cb3dSCy Schubert 			change->read_change = 0;
9282b15cb3dSCy Schubert 		else
929*a466cc55SCy Schubert 			change->read_change = del;
9302b15cb3dSCy Schubert 	}
9312b15cb3dSCy Schubert 	if (events & EV_WRITE) {
9322b15cb3dSCy Schubert 		if (!(change->old_events & EV_WRITE))
9332b15cb3dSCy Schubert 			change->write_change = 0;
9342b15cb3dSCy Schubert 		else
935*a466cc55SCy Schubert 			change->write_change = del;
9362b15cb3dSCy Schubert 	}
9372b15cb3dSCy Schubert 	if (events & EV_CLOSED) {
9382b15cb3dSCy Schubert 		if (!(change->old_events & EV_CLOSED))
9392b15cb3dSCy Schubert 			change->close_change = 0;
9402b15cb3dSCy Schubert 		else
941*a466cc55SCy Schubert 			change->close_change = del;
9422b15cb3dSCy Schubert 	}
9432b15cb3dSCy Schubert 
9442b15cb3dSCy Schubert 	event_changelist_check(base);
9452b15cb3dSCy Schubert 	return (0);
9462b15cb3dSCy Schubert }
9472b15cb3dSCy Schubert 
9482b15cb3dSCy Schubert /* Helper for evmap_check_integrity_: verify that all of the events pending on
9492b15cb3dSCy Schubert  * given fd are set up correctly, and that the nread and nwrite counts on that
9502b15cb3dSCy Schubert  * fd are correct. */
9512b15cb3dSCy Schubert static int
9522b15cb3dSCy Schubert evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd,
9532b15cb3dSCy Schubert     struct evmap_io *io_info, void *arg)
9542b15cb3dSCy Schubert {
9552b15cb3dSCy Schubert 	struct event *ev;
9562b15cb3dSCy Schubert 	int n_read = 0, n_write = 0, n_close = 0;
9572b15cb3dSCy Schubert 
9582b15cb3dSCy Schubert 	/* First, make sure the list itself isn't corrupt. Otherwise,
9592b15cb3dSCy Schubert 	 * running LIST_FOREACH could be an exciting adventure. */
9602b15cb3dSCy Schubert 	EVUTIL_ASSERT_LIST_OK(&io_info->events, event, ev_io_next);
9612b15cb3dSCy Schubert 
9622b15cb3dSCy Schubert 	LIST_FOREACH(ev, &io_info->events, ev_io_next) {
9632b15cb3dSCy Schubert 		EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
9642b15cb3dSCy Schubert 		EVUTIL_ASSERT(ev->ev_fd == fd);
9652b15cb3dSCy Schubert 		EVUTIL_ASSERT(!(ev->ev_events & EV_SIGNAL));
9662b15cb3dSCy Schubert 		EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
9672b15cb3dSCy Schubert 		if (ev->ev_events & EV_READ)
9682b15cb3dSCy Schubert 			++n_read;
9692b15cb3dSCy Schubert 		if (ev->ev_events & EV_WRITE)
9702b15cb3dSCy Schubert 			++n_write;
9712b15cb3dSCy Schubert 		if (ev->ev_events & EV_CLOSED)
9722b15cb3dSCy Schubert 			++n_close;
9732b15cb3dSCy Schubert 	}
9742b15cb3dSCy Schubert 
9752b15cb3dSCy Schubert 	EVUTIL_ASSERT(n_read == io_info->nread);
9762b15cb3dSCy Schubert 	EVUTIL_ASSERT(n_write == io_info->nwrite);
9772b15cb3dSCy Schubert 	EVUTIL_ASSERT(n_close == io_info->nclose);
9782b15cb3dSCy Schubert 
9792b15cb3dSCy Schubert 	return 0;
9802b15cb3dSCy Schubert }
9812b15cb3dSCy Schubert 
9822b15cb3dSCy Schubert /* Helper for evmap_check_integrity_: verify that all of the events pending
9832b15cb3dSCy Schubert  * on given signal are set up correctly. */
9842b15cb3dSCy Schubert static int
9852b15cb3dSCy Schubert evmap_signal_check_integrity_fn(struct event_base *base,
9862b15cb3dSCy Schubert     int signum, struct evmap_signal *sig_info, void *arg)
9872b15cb3dSCy Schubert {
9882b15cb3dSCy Schubert 	struct event *ev;
9892b15cb3dSCy Schubert 	/* First, make sure the list itself isn't corrupt. */
9902b15cb3dSCy Schubert 	EVUTIL_ASSERT_LIST_OK(&sig_info->events, event, ev_signal_next);
9912b15cb3dSCy Schubert 
9922b15cb3dSCy Schubert 	LIST_FOREACH(ev, &sig_info->events, ev_io_next) {
9932b15cb3dSCy Schubert 		EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
9942b15cb3dSCy Schubert 		EVUTIL_ASSERT(ev->ev_fd == signum);
9952b15cb3dSCy Schubert 		EVUTIL_ASSERT((ev->ev_events & EV_SIGNAL));
9962b15cb3dSCy Schubert 		EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
9972b15cb3dSCy Schubert 	}
9982b15cb3dSCy Schubert 	return 0;
9992b15cb3dSCy Schubert }
10002b15cb3dSCy Schubert 
10012b15cb3dSCy Schubert void
10022b15cb3dSCy Schubert evmap_check_integrity_(struct event_base *base)
10032b15cb3dSCy Schubert {
10042b15cb3dSCy Schubert 	evmap_io_foreach_fd(base, evmap_io_check_integrity_fn, NULL);
10052b15cb3dSCy Schubert 	evmap_signal_foreach_signal(base, evmap_signal_check_integrity_fn, NULL);
10062b15cb3dSCy Schubert 
10072b15cb3dSCy Schubert 	if (base->evsel->add == event_changelist_add_)
10082b15cb3dSCy Schubert 		event_changelist_assert_ok(base);
10092b15cb3dSCy Schubert }
10102b15cb3dSCy Schubert 
10112b15cb3dSCy Schubert /* Helper type for evmap_foreach_event_: Bundles a function to call on every
10122b15cb3dSCy Schubert  * event, and the user-provided void* to use as its third argument. */
10132b15cb3dSCy Schubert struct evmap_foreach_event_helper {
10142b15cb3dSCy Schubert 	event_base_foreach_event_cb fn;
10152b15cb3dSCy Schubert 	void *arg;
10162b15cb3dSCy Schubert };
10172b15cb3dSCy Schubert 
10182b15cb3dSCy Schubert /* Helper for evmap_foreach_event_: calls a provided function on every event
10192b15cb3dSCy Schubert  * pending on a given fd.  */
10202b15cb3dSCy Schubert static int
10212b15cb3dSCy Schubert evmap_io_foreach_event_fn(struct event_base *base, evutil_socket_t fd,
10222b15cb3dSCy Schubert     struct evmap_io *io_info, void *arg)
10232b15cb3dSCy Schubert {
10242b15cb3dSCy Schubert 	struct evmap_foreach_event_helper *h = arg;
10252b15cb3dSCy Schubert 	struct event *ev;
10262b15cb3dSCy Schubert 	int r;
10272b15cb3dSCy Schubert 	LIST_FOREACH(ev, &io_info->events, ev_io_next) {
10282b15cb3dSCy Schubert 		if ((r = h->fn(base, ev, h->arg)))
10292b15cb3dSCy Schubert 			return r;
10302b15cb3dSCy Schubert 	}
10312b15cb3dSCy Schubert 	return 0;
10322b15cb3dSCy Schubert }
10332b15cb3dSCy Schubert 
10342b15cb3dSCy Schubert /* Helper for evmap_foreach_event_: calls a provided function on every event
10352b15cb3dSCy Schubert  * pending on a given signal.  */
10362b15cb3dSCy Schubert static int
10372b15cb3dSCy Schubert evmap_signal_foreach_event_fn(struct event_base *base, int signum,
10382b15cb3dSCy Schubert     struct evmap_signal *sig_info, void *arg)
10392b15cb3dSCy Schubert {
10402b15cb3dSCy Schubert 	struct event *ev;
10412b15cb3dSCy Schubert 	struct evmap_foreach_event_helper *h = arg;
10422b15cb3dSCy Schubert 	int r;
10432b15cb3dSCy Schubert 	LIST_FOREACH(ev, &sig_info->events, ev_signal_next) {
10442b15cb3dSCy Schubert 		if ((r = h->fn(base, ev, h->arg)))
10452b15cb3dSCy Schubert 			return r;
10462b15cb3dSCy Schubert 	}
10472b15cb3dSCy Schubert 	return 0;
10482b15cb3dSCy Schubert }
10492b15cb3dSCy Schubert 
10502b15cb3dSCy Schubert int
10512b15cb3dSCy Schubert evmap_foreach_event_(struct event_base *base,
10522b15cb3dSCy Schubert     event_base_foreach_event_cb fn, void *arg)
10532b15cb3dSCy Schubert {
10542b15cb3dSCy Schubert 	struct evmap_foreach_event_helper h;
10552b15cb3dSCy Schubert 	int r;
10562b15cb3dSCy Schubert 	h.fn = fn;
10572b15cb3dSCy Schubert 	h.arg = arg;
10582b15cb3dSCy Schubert 	if ((r = evmap_io_foreach_fd(base, evmap_io_foreach_event_fn, &h)))
10592b15cb3dSCy Schubert 		return r;
10602b15cb3dSCy Schubert 	return evmap_signal_foreach_signal(base, evmap_signal_foreach_event_fn, &h);
10612b15cb3dSCy Schubert }
10622b15cb3dSCy Schubert 
1063