xref: /libevent-2.1.12/evmap.c (revision db2efdf5)
102b2b4d1SNiels Provos /*
2e49e2891SNick Mathewson  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
302b2b4d1SNiels Provos  *
402b2b4d1SNiels Provos  * Redistribution and use in source and binary forms, with or without
502b2b4d1SNiels Provos  * modification, are permitted provided that the following conditions
602b2b4d1SNiels Provos  * are met:
702b2b4d1SNiels Provos  * 1. Redistributions of source code must retain the above copyright
802b2b4d1SNiels Provos  *    notice, this list of conditions and the following disclaimer.
902b2b4d1SNiels Provos  * 2. Redistributions in binary form must reproduce the above copyright
1002b2b4d1SNiels Provos  *    notice, this list of conditions and the following disclaimer in the
1102b2b4d1SNiels Provos  *    documentation and/or other materials provided with the distribution.
1202b2b4d1SNiels Provos  * 3. The name of the author may not be used to endorse or promote products
1302b2b4d1SNiels Provos  *    derived from this software without specific prior written permission.
1402b2b4d1SNiels Provos  *
1502b2b4d1SNiels Provos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1602b2b4d1SNiels Provos  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1702b2b4d1SNiels Provos  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1802b2b4d1SNiels Provos  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1902b2b4d1SNiels Provos  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2002b2b4d1SNiels Provos  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2102b2b4d1SNiels Provos  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2202b2b4d1SNiels Provos  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2302b2b4d1SNiels Provos  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2402b2b4d1SNiels Provos  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2502b2b4d1SNiels Provos  */
26ec347b92SNick Mathewson #include "event2/event-config.h"
270915ca0aSKevin Bowling #include "evconfig-private.h"
2802b2b4d1SNiels Provos 
299f560bfaSNick Mathewson #ifdef _WIN32
305b5b880bSNick Mathewson #include <winsock2.h>
3102b2b4d1SNiels Provos #define WIN32_LEAN_AND_MEAN
3202b2b4d1SNiels Provos #include <windows.h>
3302b2b4d1SNiels Provos #undef WIN32_LEAN_AND_MEAN
3402b2b4d1SNiels Provos #endif
3502b2b4d1SNiels Provos #include <sys/types.h>
3668120d9bSNick Mathewson #if !defined(_WIN32) && defined(EVENT__HAVE_SYS_TIME_H)
3702b2b4d1SNiels Provos #include <sys/time.h>
3802b2b4d1SNiels Provos #endif
3902b2b4d1SNiels Provos #include <sys/queue.h>
4002b2b4d1SNiels Provos #include <stdio.h>
4102b2b4d1SNiels Provos #include <stdlib.h>
429f560bfaSNick Mathewson #ifndef _WIN32
4302b2b4d1SNiels Provos #include <unistd.h>
4402b2b4d1SNiels Provos #endif
4502b2b4d1SNiels Provos #include <errno.h>
4687fa93a8SAzat Khuzhin #include <limits.h>
4702b2b4d1SNiels Provos #include <signal.h>
4802b2b4d1SNiels Provos #include <string.h>
4902b2b4d1SNiels Provos #include <time.h>
5002b2b4d1SNiels Provos 
5102b2b4d1SNiels Provos #include "event-internal.h"
52169321c9SNick Mathewson #include "evmap-internal.h"
5302b2b4d1SNiels Provos #include "mm-internal.h"
5427308aaeSNick Mathewson #include "changelist-internal.h"
5502b2b4d1SNiels Provos 
5655bcd7d2SNick Mathewson /** An entry for an evmap_io list: notes all the events that want to read or
5755bcd7d2SNick Mathewson 	write on a given fd, and the number of each.
5855bcd7d2SNick Mathewson   */
5955bcd7d2SNick Mathewson struct evmap_io {
606494772eSNick Mathewson 	struct event_dlist events;
61819f949fSNick Mathewson 	ev_uint16_t nread;
62819f949fSNick Mathewson 	ev_uint16_t nwrite;
63b1b69ac7SDiego Giagio 	ev_uint16_t nclose;
6455bcd7d2SNick Mathewson };
6555bcd7d2SNick Mathewson 
6655bcd7d2SNick Mathewson /* An entry for an evmap_signal list: notes all the events that want to know
6755bcd7d2SNick Mathewson    when a signal triggers. */
6855bcd7d2SNick Mathewson struct evmap_signal {
696494772eSNick Mathewson 	struct event_dlist events;
7055bcd7d2SNick Mathewson };
7155bcd7d2SNick Mathewson 
7255bcd7d2SNick Mathewson /* On some platforms, fds start at 0 and increment by 1 as they are
7355bcd7d2SNick Mathewson    allocated, and old numbers get used.  For these platforms, we
7455bcd7d2SNick Mathewson    implement io maps just like signal maps: as an array of pointers to
7555bcd7d2SNick Mathewson    struct evmap_io.  But on other platforms (windows), sockets are not
7655bcd7d2SNick Mathewson    0-indexed, not necessarily consecutive, and not necessarily reused.
7755bcd7d2SNick Mathewson    There, we use a hashtable to implement evmap_io.
7855bcd7d2SNick Mathewson */
7955bcd7d2SNick Mathewson #ifdef EVMAP_USE_HT
8055bcd7d2SNick Mathewson struct event_map_entry {
8155bcd7d2SNick Mathewson 	HT_ENTRY(event_map_entry) map_node;
8255bcd7d2SNick Mathewson 	evutil_socket_t fd;
8355bcd7d2SNick Mathewson 	union { /* This is a union in case we need to make more things that can
8455bcd7d2SNick Mathewson 			   be in the hashtable. */
8555bcd7d2SNick Mathewson 		struct evmap_io evmap_io;
8655bcd7d2SNick Mathewson 	} ent;
8755bcd7d2SNick Mathewson };
8855bcd7d2SNick Mathewson 
89c247adc7SNick Mathewson /* Helper used by the event_io_map hashtable code; tries to return a good hash
90c247adc7SNick Mathewson  * of the fd in e->fd. */
9155bcd7d2SNick Mathewson static inline unsigned
hashsocket(struct event_map_entry * e)9255bcd7d2SNick Mathewson hashsocket(struct event_map_entry *e)
9355bcd7d2SNick Mathewson {
9491e3ead8SNick Mathewson 	/* On win32, in practice, the low 2-3 bits of a SOCKET seem not to
9591e3ead8SNick Mathewson 	 * matter.  Our hashtable implementation really likes low-order bits,
9691e3ead8SNick Mathewson 	 * though, so let's do the rotate-and-add trick. */
9791e3ead8SNick Mathewson 	unsigned h = (unsigned) e->fd;
9891e3ead8SNick Mathewson 	h += (h >> 2) | (h << 30);
9991e3ead8SNick Mathewson 	return h;
10055bcd7d2SNick Mathewson }
10155bcd7d2SNick Mathewson 
102c247adc7SNick Mathewson /* Helper used by the event_io_map hashtable code; returns true iff e1 and e2
103c247adc7SNick Mathewson  * have the same e->fd. */
10455bcd7d2SNick Mathewson static inline int
eqsocket(struct event_map_entry * e1,struct event_map_entry * e2)10555bcd7d2SNick Mathewson eqsocket(struct event_map_entry *e1, struct event_map_entry *e2)
10655bcd7d2SNick Mathewson {
10755bcd7d2SNick Mathewson 	return e1->fd == e2->fd;
10855bcd7d2SNick Mathewson }
10955bcd7d2SNick Mathewson 
HT_PROTOTYPE(event_io_map,event_map_entry,map_node,hashsocket,eqsocket)110e56ff65aSNick Mathewson HT_PROTOTYPE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket)
11155bcd7d2SNick Mathewson HT_GENERATE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket,
112e56ff65aSNick Mathewson 			0.5, mm_malloc, mm_realloc, mm_free)
11355bcd7d2SNick Mathewson 
11455bcd7d2SNick Mathewson #define GET_IO_SLOT(x, map, slot, type)					\
11555bcd7d2SNick Mathewson 	do {								\
116946b5841SNick Mathewson 		struct event_map_entry key_, *ent_;			\
117946b5841SNick Mathewson 		key_.fd = slot;						\
118946b5841SNick Mathewson 		ent_ = HT_FIND(event_io_map, map, &key_);		\
119946b5841SNick Mathewson 		(x) = ent_ ? &ent_->ent.type : NULL;			\
12055bcd7d2SNick Mathewson 	} while (0);
12155bcd7d2SNick Mathewson 
122554e1493SNick Mathewson #define GET_IO_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len)	\
12355bcd7d2SNick Mathewson 	do {								\
124946b5841SNick Mathewson 		struct event_map_entry key_, *ent_;			\
125946b5841SNick Mathewson 		key_.fd = slot;						\
126066775e3SNick Mathewson 		HT_FIND_OR_INSERT_(event_io_map, map_node, hashsocket, map, \
127946b5841SNick Mathewson 		    event_map_entry, &key_, ptr,			\
12855bcd7d2SNick Mathewson 		    {							\
129946b5841SNick Mathewson 			    ent_ = *ptr;				\
13055bcd7d2SNick Mathewson 		    },							\
13155bcd7d2SNick Mathewson 		    {							\
132946b5841SNick Mathewson 			    ent_ = mm_calloc(1,sizeof(struct event_map_entry)+fdinfo_len); \
133946b5841SNick Mathewson 			    if (EVUTIL_UNLIKELY(ent_ == NULL))		\
13489d5e09eSNick Mathewson 				    return (-1);			\
135946b5841SNick Mathewson 			    ent_->fd = slot;				\
136946b5841SNick Mathewson 			    (ctor)(&ent_->ent.type);			\
137946b5841SNick Mathewson 			    HT_FOI_INSERT_(map_node, map, &key_, ent_, ptr) \
13855bcd7d2SNick Mathewson 				});					\
139946b5841SNick Mathewson 		(x) = &ent_->ent.type;					\
14055bcd7d2SNick Mathewson 	} while (0)
14155bcd7d2SNick Mathewson 
1428ac3c4c2SNick Mathewson void evmap_io_initmap_(struct event_io_map *ctx)
1436bb2f842SNick Mathewson {
1446bb2f842SNick Mathewson 	HT_INIT(event_io_map, ctx);
1456bb2f842SNick Mathewson }
1466bb2f842SNick Mathewson 
evmap_io_clear_(struct event_io_map * ctx)1478ac3c4c2SNick Mathewson void evmap_io_clear_(struct event_io_map *ctx)
14855bcd7d2SNick Mathewson {
14955bcd7d2SNick Mathewson 	struct event_map_entry **ent, **next, *this;
15055bcd7d2SNick Mathewson 	for (ent = HT_START(event_io_map, ctx); ent; ent = next) {
15155bcd7d2SNick Mathewson 		this = *ent;
15255bcd7d2SNick Mathewson 		next = HT_NEXT_RMV(event_io_map, ctx, ent);
15355bcd7d2SNick Mathewson 		mm_free(this);
15455bcd7d2SNick Mathewson 	}
155b4f89f00SNick Mathewson 	HT_CLEAR(event_io_map, ctx); /* remove all storage held by the ctx. */
15655bcd7d2SNick Mathewson }
15755bcd7d2SNick Mathewson #endif
15855bcd7d2SNick Mathewson 
1598f5777e6SNick Mathewson /* Set the variable 'x' to the field in event_map 'map' with fields of type
1608f5777e6SNick Mathewson    'struct type *' corresponding to the fd or signal 'slot'.  Set 'x' to NULL
1618f5777e6SNick Mathewson    if there are no entries for 'slot'.  Does no bounds-checking. */
16255bcd7d2SNick Mathewson #define GET_SIGNAL_SLOT(x, map, slot, type)			\
163172b6575SNiels Provos 	(x) = (struct type *)((map)->entries[slot])
1648f5777e6SNick Mathewson /* As GET_SLOT, but construct the entry for 'slot' if it is not present,
1658f5777e6SNick Mathewson    by allocating enough memory for a 'struct type', and initializing the new
16689d5e09eSNick Mathewson    value by calling the function 'ctor' on it.  Makes the function
16789d5e09eSNick Mathewson    return -1 on allocation failure.
1688f5777e6SNick Mathewson  */
169554e1493SNick Mathewson #define GET_SIGNAL_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len)	\
170172b6575SNiels Provos 	do {								\
171172b6575SNiels Provos 		if ((map)->entries[slot] == NULL) {			\
17264a37e61SNick Mathewson 			(map)->entries[slot] =				\
17364a37e61SNick Mathewson 			    mm_calloc(1,sizeof(struct type)+fdinfo_len); \
17489d5e09eSNick Mathewson 			if (EVUTIL_UNLIKELY((map)->entries[slot] == NULL)) \
17589d5e09eSNick Mathewson 				return (-1);				\
176172b6575SNiels Provos 			(ctor)((struct type *)(map)->entries[slot]);	\
177172b6575SNiels Provos 		}							\
178172b6575SNiels Provos 		(x) = (struct type *)((map)->entries[slot]);		\
17955bcd7d2SNick Mathewson 	} while (0)
18055bcd7d2SNick Mathewson 
18155bcd7d2SNick Mathewson /* If we aren't using hashtables, then define the IO_SLOT macros and functions
18255bcd7d2SNick Mathewson    as thin aliases over the SIGNAL_SLOT versions. */
18355bcd7d2SNick Mathewson #ifndef EVMAP_USE_HT
18455bcd7d2SNick Mathewson #define GET_IO_SLOT(x,map,slot,type) GET_SIGNAL_SLOT(x,map,slot,type)
185554e1493SNick Mathewson #define GET_IO_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)	\
186554e1493SNick Mathewson 	GET_SIGNAL_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)
187554e1493SNick Mathewson #define FDINFO_OFFSET sizeof(struct evmap_io)
18855bcd7d2SNick Mathewson void
evmap_io_initmap_(struct event_io_map * ctx)1898ac3c4c2SNick Mathewson evmap_io_initmap_(struct event_io_map* ctx)
1906bb2f842SNick Mathewson {
1918ac3c4c2SNick Mathewson 	evmap_signal_initmap_(ctx);
1926bb2f842SNick Mathewson }
1936bb2f842SNick Mathewson void
evmap_io_clear_(struct event_io_map * ctx)1948ac3c4c2SNick Mathewson evmap_io_clear_(struct event_io_map* ctx)
19555bcd7d2SNick Mathewson {
1968ac3c4c2SNick Mathewson 	evmap_signal_clear_(ctx);
19755bcd7d2SNick Mathewson }
19855bcd7d2SNick Mathewson #endif
19955bcd7d2SNick Mathewson 
20002b2b4d1SNiels Provos 
2018f5777e6SNick Mathewson /** Expand 'map' with new entries of width 'msize' until it is big enough
2028f5777e6SNick Mathewson 	to store a value in 'slot'.
2038f5777e6SNick Mathewson  */
204b55ca7deSNiels Provos static int
evmap_make_space(struct event_signal_map * map,int slot,int msize)20555bcd7d2SNick Mathewson evmap_make_space(struct event_signal_map *map, int slot, int msize)
20602b2b4d1SNiels Provos {
20702b2b4d1SNiels Provos 	if (map->nentries <= slot) {
20802b2b4d1SNiels Provos 		int nentries = map->nentries ? map->nentries : 32;
20930cba6d0SNiels Provos 		void **tmp;
21002b2b4d1SNiels Provos 
21187fa93a8SAzat Khuzhin 		if (slot > INT_MAX / 2)
21287fa93a8SAzat Khuzhin 			return (-1);
21387fa93a8SAzat Khuzhin 
21402b2b4d1SNiels Provos 		while (nentries <= slot)
21502b2b4d1SNiels Provos 			nentries <<= 1;
21602b2b4d1SNiels Provos 
21787fa93a8SAzat Khuzhin 		if (nentries > INT_MAX / msize)
21887fa93a8SAzat Khuzhin 			return (-1);
21987fa93a8SAzat Khuzhin 
22030cba6d0SNiels Provos 		tmp = (void **)mm_realloc(map->entries, nentries * msize);
22102b2b4d1SNiels Provos 		if (tmp == NULL)
222b55ca7deSNiels Provos 			return (-1);
22302b2b4d1SNiels Provos 
224172b6575SNiels Provos 		memset(&tmp[map->nentries], 0,
225ad7f1b4aSNick Mathewson 		    (nentries - map->nentries) * msize);
22602b2b4d1SNiels Provos 
22702b2b4d1SNiels Provos 		map->nentries = nentries;
22802b2b4d1SNiels Provos 		map->entries = tmp;
22902b2b4d1SNiels Provos 	}
23002b2b4d1SNiels Provos 
231b55ca7deSNiels Provos 	return (0);
23202b2b4d1SNiels Provos }
23302b2b4d1SNiels Provos 
23402b2b4d1SNiels Provos void
evmap_signal_initmap_(struct event_signal_map * ctx)2358ac3c4c2SNick Mathewson evmap_signal_initmap_(struct event_signal_map *ctx)
2366bb2f842SNick Mathewson {
2376bb2f842SNick Mathewson 	ctx->nentries = 0;
2386bb2f842SNick Mathewson 	ctx->entries = NULL;
2396bb2f842SNick Mathewson }
2406bb2f842SNick Mathewson 
2416bb2f842SNick Mathewson void
evmap_signal_clear_(struct event_signal_map * ctx)2428ac3c4c2SNick Mathewson evmap_signal_clear_(struct event_signal_map *ctx)
24302b2b4d1SNiels Provos {
24402b2b4d1SNiels Provos 	if (ctx->entries != NULL) {
24530cba6d0SNiels Provos 		int i;
246172b6575SNiels Provos 		for (i = 0; i < ctx->nentries; ++i) {
247172b6575SNiels Provos 			if (ctx->entries[i] != NULL)
24830cba6d0SNiels Provos 				mm_free(ctx->entries[i]);
249172b6575SNiels Provos 		}
25002b2b4d1SNiels Provos 		mm_free(ctx->entries);
25102b2b4d1SNiels Provos 		ctx->entries = NULL;
25202b2b4d1SNiels Provos 	}
2530e779906SNiels Provos 	ctx->nentries = 0;
25402b2b4d1SNiels Provos }
25502b2b4d1SNiels Provos 
25602b2b4d1SNiels Provos 
25755bcd7d2SNick Mathewson /* code specific to file descriptors */
25802b2b4d1SNiels Provos 
2598f5777e6SNick Mathewson /** Constructor for struct evmap_io */
26002b2b4d1SNiels Provos static void
evmap_io_init(struct evmap_io * entry)2618f5777e6SNick Mathewson evmap_io_init(struct evmap_io *entry)
26202b2b4d1SNiels Provos {
2636494772eSNick Mathewson 	LIST_INIT(&entry->events);
26402b2b4d1SNiels Provos 	entry->nread = 0;
26502b2b4d1SNiels Provos 	entry->nwrite = 0;
266b1b69ac7SDiego Giagio 	entry->nclose = 0;
26702b2b4d1SNiels Provos }
26802b2b4d1SNiels Provos 
26902b2b4d1SNiels Provos 
270ba8a1771SNick Mathewson /* return -1 on error, 0 on success if nothing changed in the event backend,
271ba8a1771SNick Mathewson  * and 1 on success if something did. */
27202b2b4d1SNiels Provos int
evmap_io_add_(struct event_base * base,evutil_socket_t fd,struct event * ev)2738ac3c4c2SNick Mathewson evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
27402b2b4d1SNiels Provos {
27502b2b4d1SNiels Provos 	const struct eventop *evsel = base->evsel;
27655bcd7d2SNick Mathewson 	struct event_io_map *io = &base->io;
27702b2b4d1SNiels Provos 	struct evmap_io *ctx = NULL;
278b1b69ac7SDiego Giagio 	int nread, nwrite, nclose, retval = 0;
27902b2b4d1SNiels Provos 	short res = 0, old = 0;
280cb670740SNick Mathewson 	struct event *old_ev;
28102b2b4d1SNiels Provos 
282c247adc7SNick Mathewson 	EVUTIL_ASSERT(fd == ev->ev_fd);
2838f5777e6SNick Mathewson 
284c2ead9f1SNick Mathewson 	if (fd < 0)
285c2ead9f1SNick Mathewson 		return 0;
286c2ead9f1SNick Mathewson 
28755bcd7d2SNick Mathewson #ifndef EVMAP_USE_HT
28802b2b4d1SNiels Provos 	if (fd >= io->nentries) {
289ad7f1b4aSNick Mathewson 		if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1)
29002b2b4d1SNiels Provos 			return (-1);
29102b2b4d1SNiels Provos 	}
29255bcd7d2SNick Mathewson #endif
293554e1493SNick Mathewson 	GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init,
294554e1493SNick Mathewson 						 evsel->fdinfo_len);
29502b2b4d1SNiels Provos 
29602b2b4d1SNiels Provos 	nread = ctx->nread;
29702b2b4d1SNiels Provos 	nwrite = ctx->nwrite;
298b1b69ac7SDiego Giagio 	nclose = ctx->nclose;
29902b2b4d1SNiels Provos 
30002b2b4d1SNiels Provos 	if (nread)
30102b2b4d1SNiels Provos 		old |= EV_READ;
30202b2b4d1SNiels Provos 	if (nwrite)
30302b2b4d1SNiels Provos 		old |= EV_WRITE;
304b1b69ac7SDiego Giagio 	if (nclose)
305b1b69ac7SDiego Giagio 		old |= EV_CLOSED;
30602b2b4d1SNiels Provos 
30702b2b4d1SNiels Provos 	if (ev->ev_events & EV_READ) {
30802b2b4d1SNiels Provos 		if (++nread == 1)
30902b2b4d1SNiels Provos 			res |= EV_READ;
31002b2b4d1SNiels Provos 	}
31102b2b4d1SNiels Provos 	if (ev->ev_events & EV_WRITE) {
31202b2b4d1SNiels Provos 		if (++nwrite == 1)
31302b2b4d1SNiels Provos 			res |= EV_WRITE;
31402b2b4d1SNiels Provos 	}
315b1b69ac7SDiego Giagio 	if (ev->ev_events & EV_CLOSED) {
316b1b69ac7SDiego Giagio 		if (++nclose == 1)
317b1b69ac7SDiego Giagio 			res |= EV_CLOSED;
318b1b69ac7SDiego Giagio 	}
319b1b69ac7SDiego Giagio 	if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) {
320819f949fSNick Mathewson 		event_warnx("Too many events reading or writing on fd %d",
321819f949fSNick Mathewson 		    (int)fd);
322819f949fSNick Mathewson 		return -1;
323819f949fSNick Mathewson 	}
324cb670740SNick Mathewson 	if (EVENT_DEBUG_MODE_IS_ON() &&
3255683e2b1SNick Mathewson 	    (old_ev = LIST_FIRST(&ctx->events)) &&
326cb670740SNick Mathewson 	    (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) {
327cb670740SNick Mathewson 		event_warnx("Tried to mix edge-triggered and non-edge-triggered"
328cb670740SNick Mathewson 		    " events on fd %d", (int)fd);
329cb670740SNick Mathewson 		return -1;
330cb670740SNick Mathewson 	}
33102b2b4d1SNiels Provos 
33202b2b4d1SNiels Provos 	if (res) {
333554e1493SNick Mathewson 		void *extra = ((char*)ctx) + sizeof(struct evmap_io);
33402b2b4d1SNiels Provos 		/* XXX(niels): we cannot mix edge-triggered and
33502b2b4d1SNiels Provos 		 * level-triggered, we should probably assert on
33602b2b4d1SNiels Provos 		 * this. */
33702b2b4d1SNiels Provos 		if (evsel->add(base, ev->ev_fd,
338554e1493SNick Mathewson 			old, (ev->ev_events & EV_ET) | res, extra) == -1)
33902b2b4d1SNiels Provos 			return (-1);
340ba8a1771SNick Mathewson 		retval = 1;
34102b2b4d1SNiels Provos 	}
34202b2b4d1SNiels Provos 
343819f949fSNick Mathewson 	ctx->nread = (ev_uint16_t) nread;
344819f949fSNick Mathewson 	ctx->nwrite = (ev_uint16_t) nwrite;
345b1b69ac7SDiego Giagio 	ctx->nclose = (ev_uint16_t) nclose;
3466494772eSNick Mathewson 	LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next);
34702b2b4d1SNiels Provos 
348ba8a1771SNick Mathewson 	return (retval);
34902b2b4d1SNiels Provos }
35002b2b4d1SNiels Provos 
351ba8a1771SNick Mathewson /* return -1 on error, 0 on success if nothing changed in the event backend,
352ba8a1771SNick Mathewson  * and 1 on success if something did. */
35302b2b4d1SNiels Provos int
evmap_io_del_(struct event_base * base,evutil_socket_t fd,struct event * ev)3548ac3c4c2SNick Mathewson evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
35502b2b4d1SNiels Provos {
35602b2b4d1SNiels Provos 	const struct eventop *evsel = base->evsel;
35755bcd7d2SNick Mathewson 	struct event_io_map *io = &base->io;
35802b2b4d1SNiels Provos 	struct evmap_io *ctx;
359b1b69ac7SDiego Giagio 	int nread, nwrite, nclose, retval = 0;
36002b2b4d1SNiels Provos 	short res = 0, old = 0;
36102b2b4d1SNiels Provos 
362c2ead9f1SNick Mathewson 	if (fd < 0)
363c2ead9f1SNick Mathewson 		return 0;
364c2ead9f1SNick Mathewson 
365c247adc7SNick Mathewson 	EVUTIL_ASSERT(fd == ev->ev_fd);
3668f5777e6SNick Mathewson 
36755bcd7d2SNick Mathewson #ifndef EVMAP_USE_HT
36802b2b4d1SNiels Provos 	if (fd >= io->nentries)
36902b2b4d1SNiels Provos 		return (-1);
37055bcd7d2SNick Mathewson #endif
37102b2b4d1SNiels Provos 
37255bcd7d2SNick Mathewson 	GET_IO_SLOT(ctx, io, fd, evmap_io);
37302b2b4d1SNiels Provos 
37402b2b4d1SNiels Provos 	nread = ctx->nread;
37502b2b4d1SNiels Provos 	nwrite = ctx->nwrite;
376b1b69ac7SDiego Giagio 	nclose = ctx->nclose;
37702b2b4d1SNiels Provos 
37802b2b4d1SNiels Provos 	if (nread)
37902b2b4d1SNiels Provos 		old |= EV_READ;
38002b2b4d1SNiels Provos 	if (nwrite)
38102b2b4d1SNiels Provos 		old |= EV_WRITE;
382b1b69ac7SDiego Giagio 	if (nclose)
383b1b69ac7SDiego Giagio 		old |= EV_CLOSED;
38402b2b4d1SNiels Provos 
38502b2b4d1SNiels Provos 	if (ev->ev_events & EV_READ) {
38602b2b4d1SNiels Provos 		if (--nread == 0)
38702b2b4d1SNiels Provos 			res |= EV_READ;
3882e36dbe1SNick Mathewson 		EVUTIL_ASSERT(nread >= 0);
38902b2b4d1SNiels Provos 	}
39002b2b4d1SNiels Provos 	if (ev->ev_events & EV_WRITE) {
39102b2b4d1SNiels Provos 		if (--nwrite == 0)
39202b2b4d1SNiels Provos 			res |= EV_WRITE;
3932e36dbe1SNick Mathewson 		EVUTIL_ASSERT(nwrite >= 0);
39402b2b4d1SNiels Provos 	}
395b1b69ac7SDiego Giagio 	if (ev->ev_events & EV_CLOSED) {
396b1b69ac7SDiego Giagio 		if (--nclose == 0)
397b1b69ac7SDiego Giagio 			res |= EV_CLOSED;
398b1b69ac7SDiego Giagio 		EVUTIL_ASSERT(nclose >= 0);
399b1b69ac7SDiego Giagio 	}
40002b2b4d1SNiels Provos 
40102b2b4d1SNiels Provos 	if (res) {
402554e1493SNick Mathewson 		void *extra = ((char*)ctx) + sizeof(struct evmap_io);
403ca4b6404SAzat Khuzhin 		if (evsel->del(base, ev->ev_fd,
404ca4b6404SAzat Khuzhin 			old, (ev->ev_events & EV_ET) | res, extra) == -1) {
4059b5a527fSMaxime Henrion 			retval = -1;
4069b5a527fSMaxime Henrion 		} else {
407ba8a1771SNick Mathewson 			retval = 1;
40802b2b4d1SNiels Provos 		}
4099b5a527fSMaxime Henrion 	}
41002b2b4d1SNiels Provos 
41102b2b4d1SNiels Provos 	ctx->nread = nread;
41202b2b4d1SNiels Provos 	ctx->nwrite = nwrite;
413b1b69ac7SDiego Giagio 	ctx->nclose = nclose;
4146494772eSNick Mathewson 	LIST_REMOVE(ev, ev_io_next);
41502b2b4d1SNiels Provos 
416ba8a1771SNick Mathewson 	return (retval);
41702b2b4d1SNiels Provos }
41802b2b4d1SNiels Provos 
41902b2b4d1SNiels Provos void
evmap_io_active_(struct event_base * base,evutil_socket_t fd,short events)4208ac3c4c2SNick Mathewson evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events)
42102b2b4d1SNiels Provos {
42255bcd7d2SNick Mathewson 	struct event_io_map *io = &base->io;
42302b2b4d1SNiels Provos 	struct evmap_io *ctx;
42402b2b4d1SNiels Provos 	struct event *ev;
42502b2b4d1SNiels Provos 
42655bcd7d2SNick Mathewson #ifndef EVMAP_USE_HT
427974c60e1SNick Mathewson 	if (fd < 0 || fd >= io->nentries)
428974c60e1SNick Mathewson 		return;
42955bcd7d2SNick Mathewson #endif
43055bcd7d2SNick Mathewson 	GET_IO_SLOT(ctx, io, fd, evmap_io);
43102b2b4d1SNiels Provos 
432974c60e1SNick Mathewson 	if (NULL == ctx)
433974c60e1SNick Mathewson 		return;
4346494772eSNick Mathewson 	LIST_FOREACH(ev, &ctx->events, ev_io_next) {
435*db2efdf5SAzat Khuzhin 		if (ev->ev_events & (events & ~EV_ET))
4368ac3c4c2SNick Mathewson 			event_active_nolock_(ev, ev->ev_events & events, 1);
43702b2b4d1SNiels Provos 	}
43802b2b4d1SNiels Provos }
43902b2b4d1SNiels Provos 
44002b2b4d1SNiels Provos /* code specific to signals */
44102b2b4d1SNiels Provos 
44202b2b4d1SNiels Provos static void
evmap_signal_init(struct evmap_signal * entry)4438f5777e6SNick Mathewson evmap_signal_init(struct evmap_signal *entry)
44402b2b4d1SNiels Provos {
4456494772eSNick Mathewson 	LIST_INIT(&entry->events);
44602b2b4d1SNiels Provos }
44702b2b4d1SNiels Provos 
44802b2b4d1SNiels Provos 
44902b2b4d1SNiels Provos int
evmap_signal_add_(struct event_base * base,int sig,struct event * ev)4508ac3c4c2SNick Mathewson evmap_signal_add_(struct event_base *base, int sig, struct event *ev)
45102b2b4d1SNiels Provos {
45202b2b4d1SNiels Provos 	const struct eventop *evsel = base->evsigsel;
45355bcd7d2SNick Mathewson 	struct event_signal_map *map = &base->sigmap;
45402b2b4d1SNiels Provos 	struct evmap_signal *ctx = NULL;
45502b2b4d1SNiels Provos 
45687fa93a8SAzat Khuzhin 	if (sig < 0 || sig >= NSIG)
45787fa93a8SAzat Khuzhin 		return (-1);
45887fa93a8SAzat Khuzhin 
45902b2b4d1SNiels Provos 	if (sig >= map->nentries) {
460b55ca7deSNiels Provos 		if (evmap_make_space(
461ad7f1b4aSNick Mathewson 			map, sig, sizeof(struct evmap_signal *)) == -1)
46202b2b4d1SNiels Provos 			return (-1);
46302b2b4d1SNiels Provos 	}
46427308aaeSNick Mathewson 	GET_SIGNAL_SLOT_AND_CTOR(ctx, map, sig, evmap_signal, evmap_signal_init,
46527308aaeSNick Mathewson 	    base->evsigsel->fdinfo_len);
46602b2b4d1SNiels Provos 
4676494772eSNick Mathewson 	if (LIST_EMPTY(&ctx->events)) {
468f6b26949SNick Mathewson 		if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL)
469f6b26949SNick Mathewson 		    == -1)
47002b2b4d1SNiels Provos 			return (-1);
47102b2b4d1SNiels Provos 	}
47202b2b4d1SNiels Provos 
4736494772eSNick Mathewson 	LIST_INSERT_HEAD(&ctx->events, ev, ev_signal_next);
47402b2b4d1SNiels Provos 
475ba8a1771SNick Mathewson 	return (1);
47602b2b4d1SNiels Provos }
47702b2b4d1SNiels Provos 
47802b2b4d1SNiels Provos int
evmap_signal_del_(struct event_base * base,int sig,struct event * ev)4798ac3c4c2SNick Mathewson evmap_signal_del_(struct event_base *base, int sig, struct event *ev)
48002b2b4d1SNiels Provos {
48102b2b4d1SNiels Provos 	const struct eventop *evsel = base->evsigsel;
48255bcd7d2SNick Mathewson 	struct event_signal_map *map = &base->sigmap;
48302b2b4d1SNiels Provos 	struct evmap_signal *ctx;
48402b2b4d1SNiels Provos 
48587fa93a8SAzat Khuzhin 	if (sig < 0 || sig >= map->nentries)
48602b2b4d1SNiels Provos 		return (-1);
48702b2b4d1SNiels Provos 
48855bcd7d2SNick Mathewson 	GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
48902b2b4d1SNiels Provos 
4906494772eSNick Mathewson 	LIST_REMOVE(ev, ev_signal_next);
4916494772eSNick Mathewson 
4926494772eSNick Mathewson 	if (LIST_FIRST(&ctx->events) == NULL) {
493f6b26949SNick Mathewson 		if (evsel->del(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1)
49402b2b4d1SNiels Provos 			return (-1);
49502b2b4d1SNiels Provos 	}
49602b2b4d1SNiels Provos 
497ba8a1771SNick Mathewson 	return (1);
49802b2b4d1SNiels Provos }
49902b2b4d1SNiels Provos 
50002b2b4d1SNiels Provos void
evmap_signal_active_(struct event_base * base,evutil_socket_t sig,int ncalls)5018ac3c4c2SNick Mathewson evmap_signal_active_(struct event_base *base, evutil_socket_t sig, int ncalls)
50202b2b4d1SNiels Provos {
50355bcd7d2SNick Mathewson 	struct event_signal_map *map = &base->sigmap;
50402b2b4d1SNiels Provos 	struct evmap_signal *ctx;
50502b2b4d1SNiels Provos 	struct event *ev;
50602b2b4d1SNiels Provos 
507974c60e1SNick Mathewson 	if (sig < 0 || sig >= map->nentries)
508974c60e1SNick Mathewson 		return;
50955bcd7d2SNick Mathewson 	GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
51002b2b4d1SNiels Provos 
511974c60e1SNick Mathewson 	if (!ctx)
512974c60e1SNick Mathewson 		return;
5136494772eSNick Mathewson 	LIST_FOREACH(ev, &ctx->events, ev_signal_next)
5148ac3c4c2SNick Mathewson 		event_active_nolock_(ev, EV_SIGNAL, ncalls);
51502b2b4d1SNiels Provos }
516554e1493SNick Mathewson 
517554e1493SNick Mathewson void *
evmap_io_get_fdinfo_(struct event_io_map * map,evutil_socket_t fd)5188ac3c4c2SNick Mathewson evmap_io_get_fdinfo_(struct event_io_map *map, evutil_socket_t fd)
519554e1493SNick Mathewson {
520554e1493SNick Mathewson 	struct evmap_io *ctx;
521554e1493SNick Mathewson 	GET_IO_SLOT(ctx, map, fd, evmap_io);
522554e1493SNick Mathewson 	if (ctx)
523554e1493SNick Mathewson 		return ((char*)ctx) + sizeof(struct evmap_io);
524554e1493SNick Mathewson 	else
525554e1493SNick Mathewson 		return NULL;
526554e1493SNick Mathewson }
52727308aaeSNick Mathewson 
528c89b4e63SNick Mathewson /* Callback type for evmap_io_foreach_fd */
529c89b4e63SNick Mathewson typedef int (*evmap_io_foreach_fd_cb)(
530c89b4e63SNick Mathewson 	struct event_base *, evutil_socket_t, struct evmap_io *, void *);
531272033efSNick Mathewson 
532c89b4e63SNick Mathewson /* Multipurpose helper function: Iterate over every file descriptor event_base
533c89b4e63SNick Mathewson  * for which we could have EV_READ or EV_WRITE events.  For each such fd, call
534c89b4e63SNick Mathewson  * fn(base, signum, evmap_io, arg), where fn is the user-provided
535c89b4e63SNick Mathewson  * function, base is the event_base, signum is the signal number, evmap_io
536c89b4e63SNick Mathewson  * is an evmap_io structure containing a list of events pending on the
537c89b4e63SNick Mathewson  * file descriptor, and arg is the user-supplied argument.
538c89b4e63SNick Mathewson  *
539c89b4e63SNick Mathewson  * If fn returns 0, continue on to the next signal. Otherwise, return the same
540c89b4e63SNick Mathewson  * value that fn returned.
541c89b4e63SNick Mathewson  *
542c89b4e63SNick Mathewson  * Note that there is no guarantee that the file descriptors will be processed
543c89b4e63SNick Mathewson  * in any particular order.
544c89b4e63SNick Mathewson  */
545c89b4e63SNick Mathewson static int
evmap_io_foreach_fd(struct event_base * base,evmap_io_foreach_fd_cb fn,void * arg)546c89b4e63SNick Mathewson evmap_io_foreach_fd(struct event_base *base,
547c89b4e63SNick Mathewson     evmap_io_foreach_fd_cb fn,
548c89b4e63SNick Mathewson     void *arg)
549c89b4e63SNick Mathewson {
550c89b4e63SNick Mathewson 	evutil_socket_t fd;
551c89b4e63SNick Mathewson 	struct event_io_map *iomap = &base->io;
552c89b4e63SNick Mathewson 	int r = 0;
553272033efSNick Mathewson #ifdef EVMAP_USE_HT
554272033efSNick Mathewson 	struct event_map_entry **mapent;
555066775e3SNick Mathewson 	HT_FOREACH(mapent, event_io_map, iomap) {
556272033efSNick Mathewson 		struct evmap_io *ctx = &(*mapent)->ent.evmap_io;
557c89b4e63SNick Mathewson 		fd = (*mapent)->fd;
558272033efSNick Mathewson #else
559c89b4e63SNick Mathewson 	for (fd = 0; fd < iomap->nentries; ++fd) {
560c89b4e63SNick Mathewson 		struct evmap_io *ctx = iomap->entries[fd];
561272033efSNick Mathewson 		if (!ctx)
562272033efSNick Mathewson 			continue;
563272033efSNick Mathewson #endif
564c89b4e63SNick Mathewson 		if ((r = fn(base, fd, ctx, arg)))
565c89b4e63SNick Mathewson 			break;
566c89b4e63SNick Mathewson 	}
567c89b4e63SNick Mathewson 	return r;
568c89b4e63SNick Mathewson }
569c89b4e63SNick Mathewson 
570c89b4e63SNick Mathewson /* Callback type for evmap_signal_foreach_signal */
571c89b4e63SNick Mathewson typedef int (*evmap_signal_foreach_signal_cb)(
572c89b4e63SNick Mathewson 	struct event_base *, int, struct evmap_signal *, void *);
573c89b4e63SNick Mathewson 
574c89b4e63SNick Mathewson /* Multipurpose helper function: Iterate over every signal number in the
575c89b4e63SNick Mathewson  * event_base for which we could have signal events.  For each such signal,
576c89b4e63SNick Mathewson  * call fn(base, signum, evmap_signal, arg), where fn is the user-provided
577c89b4e63SNick Mathewson  * function, base is the event_base, signum is the signal number, evmap_signal
578c89b4e63SNick Mathewson  * is an evmap_signal structure containing a list of events pending on the
579c89b4e63SNick Mathewson  * signal, and arg is the user-supplied argument.
580c89b4e63SNick Mathewson  *
581c89b4e63SNick Mathewson  * If fn returns 0, continue on to the next signal. Otherwise, return the same
582c89b4e63SNick Mathewson  * value that fn returned.
583c89b4e63SNick Mathewson  */
584c89b4e63SNick Mathewson static int
585c89b4e63SNick Mathewson evmap_signal_foreach_signal(struct event_base *base,
586c89b4e63SNick Mathewson     evmap_signal_foreach_signal_cb fn,
587c89b4e63SNick Mathewson     void *arg)
588c89b4e63SNick Mathewson {
589c89b4e63SNick Mathewson 	struct event_signal_map *sigmap = &base->sigmap;
590c89b4e63SNick Mathewson 	int r = 0;
591c89b4e63SNick Mathewson 	int signum;
592c89b4e63SNick Mathewson 
593c89b4e63SNick Mathewson 	for (signum = 0; signum < sigmap->nentries; ++signum) {
594c89b4e63SNick Mathewson 		struct evmap_signal *ctx = sigmap->entries[signum];
595c89b4e63SNick Mathewson 		if (!ctx)
596c89b4e63SNick Mathewson 			continue;
597c89b4e63SNick Mathewson 		if ((r = fn(base, signum, ctx, arg)))
598c89b4e63SNick Mathewson 			break;
599c89b4e63SNick Mathewson 	}
600c89b4e63SNick Mathewson 	return r;
601c89b4e63SNick Mathewson }
602c89b4e63SNick Mathewson 
6038ac3c4c2SNick Mathewson /* Helper for evmap_reinit_: tell the backend to add every fd for which we have
604c89b4e63SNick Mathewson  * pending events, with the appropriate combination of EV_READ, EV_WRITE, and
605c89b4e63SNick Mathewson  * EV_ET. */
606c89b4e63SNick Mathewson static int
607c89b4e63SNick Mathewson evmap_io_reinit_iter_fn(struct event_base *base, evutil_socket_t fd,
608c89b4e63SNick Mathewson     struct evmap_io *ctx, void *arg)
609c89b4e63SNick Mathewson {
610c89b4e63SNick Mathewson 	const struct eventop *evsel = base->evsel;
611c89b4e63SNick Mathewson 	void *extra;
612c89b4e63SNick Mathewson 	int *result = arg;
613c89b4e63SNick Mathewson 	short events = 0;
614c89b4e63SNick Mathewson 	struct event *ev;
615c89b4e63SNick Mathewson 	EVUTIL_ASSERT(ctx);
616c89b4e63SNick Mathewson 
617272033efSNick Mathewson 	extra = ((char*)ctx) + sizeof(struct evmap_io);
618272033efSNick Mathewson 	if (ctx->nread)
619272033efSNick Mathewson 		events |= EV_READ;
620ebfd8a89Smaksqwe 	if (ctx->nwrite)
621272033efSNick Mathewson 		events |= EV_WRITE;
622b1b69ac7SDiego Giagio 	if (ctx->nclose)
623b1b69ac7SDiego Giagio 		events |= EV_CLOSED;
624272033efSNick Mathewson 	if (evsel->fdinfo_len)
625272033efSNick Mathewson 		memset(extra, 0, evsel->fdinfo_len);
626c89b4e63SNick Mathewson 	if (events &&
627c89b4e63SNick Mathewson 	    (ev = LIST_FIRST(&ctx->events)) &&
628c89b4e63SNick Mathewson 	    (ev->ev_events & EV_ET))
629272033efSNick Mathewson 		events |= EV_ET;
630c89b4e63SNick Mathewson 	if (evsel->add(base, fd, 0, events, extra) == -1)
631c89b4e63SNick Mathewson 		*result = -1;
632c89b4e63SNick Mathewson 
633c89b4e63SNick Mathewson 	return 0;
634272033efSNick Mathewson }
635272033efSNick Mathewson 
6368ac3c4c2SNick Mathewson /* Helper for evmap_reinit_: tell the backend to add every signal for which we
637c89b4e63SNick Mathewson  * have pending events.  */
638c89b4e63SNick Mathewson static int
639c89b4e63SNick Mathewson evmap_signal_reinit_iter_fn(struct event_base *base,
640c89b4e63SNick Mathewson     int signum, struct evmap_signal *ctx, void *arg)
641272033efSNick Mathewson {
642272033efSNick Mathewson 	const struct eventop *evsel = base->evsigsel;
643c89b4e63SNick Mathewson 	int *result = arg;
644272033efSNick Mathewson 
645272033efSNick Mathewson 	if (!LIST_EMPTY(&ctx->events)) {
646c89b4e63SNick Mathewson 		if (evsel->add(base, signum, 0, EV_SIGNAL, NULL) == -1)
647c89b4e63SNick Mathewson 			*result = -1;
648272033efSNick Mathewson 	}
649604569bfSNick Mathewson 	return 0;
650272033efSNick Mathewson }
651272033efSNick Mathewson 
652272033efSNick Mathewson int
6538ac3c4c2SNick Mathewson evmap_reinit_(struct event_base *base)
654272033efSNick Mathewson {
655c89b4e63SNick Mathewson 	int result = 0;
656272033efSNick Mathewson 
657c89b4e63SNick Mathewson 	evmap_io_foreach_fd(base, evmap_io_reinit_iter_fn, &result);
658c89b4e63SNick Mathewson 	if (result < 0)
659c89b4e63SNick Mathewson 		return -1;
660c89b4e63SNick Mathewson 	evmap_signal_foreach_signal(base, evmap_signal_reinit_iter_fn, &result);
661c89b4e63SNick Mathewson 	if (result < 0)
662c89b4e63SNick Mathewson 		return -1;
663604569bfSNick Mathewson 	return 0;
664272033efSNick Mathewson }
665604569bfSNick Mathewson 
6668ac3c4c2SNick Mathewson /* Helper for evmap_delete_all_: delete every event in an event_dlist. */
667c89b4e63SNick Mathewson static int
668c89b4e63SNick Mathewson delete_all_in_dlist(struct event_dlist *dlist)
669c89b4e63SNick Mathewson {
670c89b4e63SNick Mathewson 	struct event *ev;
671c89b4e63SNick Mathewson 	while ((ev = LIST_FIRST(dlist)))
672c89b4e63SNick Mathewson 		event_del(ev);
673c89b4e63SNick Mathewson 	return 0;
674272033efSNick Mathewson }
675c89b4e63SNick Mathewson 
6768ac3c4c2SNick Mathewson /* Helper for evmap_delete_all_: delete every event pending on an fd. */
677c89b4e63SNick Mathewson static int
678c89b4e63SNick Mathewson evmap_io_delete_all_iter_fn(struct event_base *base, evutil_socket_t fd,
679c89b4e63SNick Mathewson     struct evmap_io *io_info, void *arg)
680c89b4e63SNick Mathewson {
681c89b4e63SNick Mathewson 	return delete_all_in_dlist(&io_info->events);
682c89b4e63SNick Mathewson }
683c89b4e63SNick Mathewson 
6848ac3c4c2SNick Mathewson /* Helper for evmap_delete_all_: delete every event pending on a signal. */
685c89b4e63SNick Mathewson static int
686c89b4e63SNick Mathewson evmap_signal_delete_all_iter_fn(struct event_base *base, int signum,
687c89b4e63SNick Mathewson     struct evmap_signal *sig_info, void *arg)
688c89b4e63SNick Mathewson {
689c89b4e63SNick Mathewson 	return delete_all_in_dlist(&sig_info->events);
690c89b4e63SNick Mathewson }
691c89b4e63SNick Mathewson 
692c89b4e63SNick Mathewson void
6938ac3c4c2SNick Mathewson evmap_delete_all_(struct event_base *base)
694c89b4e63SNick Mathewson {
695c89b4e63SNick Mathewson 	evmap_signal_foreach_signal(base, evmap_signal_delete_all_iter_fn, NULL);
696c89b4e63SNick Mathewson 	evmap_io_foreach_fd(base, evmap_io_delete_all_iter_fn, NULL);
697272033efSNick Mathewson }
698272033efSNick Mathewson 
69927308aaeSNick Mathewson /** Per-fd structure for use with changelists.  It keeps track, for each fd or
70027308aaeSNick Mathewson  * signal using the changelist, of where its entry in the changelist is.
70127308aaeSNick Mathewson  */
70227308aaeSNick Mathewson struct event_changelist_fdinfo {
70327308aaeSNick Mathewson 	int idxplus1; /* this is the index +1, so that memset(0) will make it
70427308aaeSNick Mathewson 		       * a no-such-element */
70527308aaeSNick Mathewson };
70627308aaeSNick Mathewson 
70727308aaeSNick Mathewson void
7088ac3c4c2SNick Mathewson event_changelist_init_(struct event_changelist *changelist)
70927308aaeSNick Mathewson {
71027308aaeSNick Mathewson 	changelist->changes = NULL;
71127308aaeSNick Mathewson 	changelist->changes_size = 0;
71227308aaeSNick Mathewson 	changelist->n_changes = 0;
71327308aaeSNick Mathewson }
71427308aaeSNick Mathewson 
71527308aaeSNick Mathewson /** Helper: return the changelist_fdinfo corresponding to a given change. */
71627308aaeSNick Mathewson static inline struct event_changelist_fdinfo *
71727308aaeSNick Mathewson event_change_get_fdinfo(struct event_base *base,
71827308aaeSNick Mathewson     const struct event_change *change)
71927308aaeSNick Mathewson {
72027308aaeSNick Mathewson 	char *ptr;
72127308aaeSNick Mathewson 	if (change->read_change & EV_CHANGE_SIGNAL) {
72227308aaeSNick Mathewson 		struct evmap_signal *ctx;
72327308aaeSNick Mathewson 		GET_SIGNAL_SLOT(ctx, &base->sigmap, change->fd, evmap_signal);
72427308aaeSNick Mathewson 		ptr = ((char*)ctx) + sizeof(struct evmap_signal);
72527308aaeSNick Mathewson 	} else {
72627308aaeSNick Mathewson 		struct evmap_io *ctx;
72727308aaeSNick Mathewson 		GET_IO_SLOT(ctx, &base->io, change->fd, evmap_io);
72827308aaeSNick Mathewson 		ptr = ((char*)ctx) + sizeof(struct evmap_io);
72927308aaeSNick Mathewson 	}
73027308aaeSNick Mathewson 	return (void*)ptr;
73127308aaeSNick Mathewson }
73227308aaeSNick Mathewson 
733066775e3SNick Mathewson /** Callback helper for event_changelist_assert_ok */
734066775e3SNick Mathewson static int
735066775e3SNick Mathewson event_changelist_assert_ok_foreach_iter_fn(
736066775e3SNick Mathewson 	struct event_base *base,
737066775e3SNick Mathewson 	evutil_socket_t fd, struct evmap_io *io, void *arg)
738066775e3SNick Mathewson {
739066775e3SNick Mathewson 	struct event_changelist *changelist = &base->changelist;
740066775e3SNick Mathewson 	struct event_changelist_fdinfo *f;
741066775e3SNick Mathewson 	f = (void*)
742066775e3SNick Mathewson 	    ( ((char*)io) + sizeof(struct evmap_io) );
743066775e3SNick Mathewson 	if (f->idxplus1) {
744066775e3SNick Mathewson 		struct event_change *c = &changelist->changes[f->idxplus1 - 1];
745066775e3SNick Mathewson 		EVUTIL_ASSERT(c->fd == fd);
746066775e3SNick Mathewson 	}
747066775e3SNick Mathewson 	return 0;
748066775e3SNick Mathewson }
749066775e3SNick Mathewson 
75027308aaeSNick Mathewson /** Make sure that the changelist is consistent with the evmap structures. */
75127308aaeSNick Mathewson static void
75239b3f38dSNick Mathewson event_changelist_assert_ok(struct event_base *base)
75327308aaeSNick Mathewson {
75427308aaeSNick Mathewson 	int i;
75527308aaeSNick Mathewson 	struct event_changelist *changelist = &base->changelist;
75627308aaeSNick Mathewson 
75727308aaeSNick Mathewson 	EVUTIL_ASSERT(changelist->changes_size >= changelist->n_changes);
75827308aaeSNick Mathewson 	for (i = 0; i < changelist->n_changes; ++i) {
75927308aaeSNick Mathewson 		struct event_change *c = &changelist->changes[i];
76027308aaeSNick Mathewson 		struct event_changelist_fdinfo *f;
76127308aaeSNick Mathewson 		EVUTIL_ASSERT(c->fd >= 0);
76227308aaeSNick Mathewson 		f = event_change_get_fdinfo(base, c);
76327308aaeSNick Mathewson 		EVUTIL_ASSERT(f);
76427308aaeSNick Mathewson 		EVUTIL_ASSERT(f->idxplus1 == i + 1);
76527308aaeSNick Mathewson 	}
76627308aaeSNick Mathewson 
767066775e3SNick Mathewson 	evmap_io_foreach_fd(base,
768066775e3SNick Mathewson 	    event_changelist_assert_ok_foreach_iter_fn,
769066775e3SNick Mathewson 	    NULL);
77027308aaeSNick Mathewson }
77139b3f38dSNick Mathewson 
77239b3f38dSNick Mathewson #ifdef DEBUG_CHANGELIST
77339b3f38dSNick Mathewson #define event_changelist_check(base)  event_changelist_assert_ok((base))
77427308aaeSNick Mathewson #else
77527308aaeSNick Mathewson #define event_changelist_check(base)  ((void)0)
77627308aaeSNick Mathewson #endif
77727308aaeSNick Mathewson 
77827308aaeSNick Mathewson void
7798ac3c4c2SNick Mathewson event_changelist_remove_all_(struct event_changelist *changelist,
78027308aaeSNick Mathewson     struct event_base *base)
78127308aaeSNick Mathewson {
78227308aaeSNick Mathewson 	int i;
78327308aaeSNick Mathewson 
78427308aaeSNick Mathewson 	event_changelist_check(base);
78527308aaeSNick Mathewson 
78627308aaeSNick Mathewson 	for (i = 0; i < changelist->n_changes; ++i) {
78727308aaeSNick Mathewson 		struct event_change *ch = &changelist->changes[i];
78827308aaeSNick Mathewson 		struct event_changelist_fdinfo *fdinfo =
78927308aaeSNick Mathewson 		    event_change_get_fdinfo(base, ch);
79027308aaeSNick Mathewson 		EVUTIL_ASSERT(fdinfo->idxplus1 == i + 1);
79127308aaeSNick Mathewson 		fdinfo->idxplus1 = 0;
79227308aaeSNick Mathewson 	}
79327308aaeSNick Mathewson 
79427308aaeSNick Mathewson 	changelist->n_changes = 0;
79527308aaeSNick Mathewson 
79627308aaeSNick Mathewson 	event_changelist_check(base);
79727308aaeSNick Mathewson }
79827308aaeSNick Mathewson 
79927308aaeSNick Mathewson void
8008ac3c4c2SNick Mathewson event_changelist_freemem_(struct event_changelist *changelist)
80127308aaeSNick Mathewson {
80227308aaeSNick Mathewson 	if (changelist->changes)
80327308aaeSNick Mathewson 		mm_free(changelist->changes);
8048ac3c4c2SNick Mathewson 	event_changelist_init_(changelist); /* zero it all out. */
80527308aaeSNick Mathewson }
80627308aaeSNick Mathewson 
80727308aaeSNick Mathewson /** Increase the size of 'changelist' to hold more changes. */
80827308aaeSNick Mathewson static int
80927308aaeSNick Mathewson event_changelist_grow(struct event_changelist *changelist)
81027308aaeSNick Mathewson {
81127308aaeSNick Mathewson 	int new_size;
81227308aaeSNick Mathewson 	struct event_change *new_changes;
81327308aaeSNick Mathewson 	if (changelist->changes_size < 64)
81427308aaeSNick Mathewson 		new_size = 64;
81527308aaeSNick Mathewson 	else
81627308aaeSNick Mathewson 		new_size = changelist->changes_size * 2;
81727308aaeSNick Mathewson 
81827308aaeSNick Mathewson 	new_changes = mm_realloc(changelist->changes,
81927308aaeSNick Mathewson 	    new_size * sizeof(struct event_change));
82027308aaeSNick Mathewson 
82127308aaeSNick Mathewson 	if (EVUTIL_UNLIKELY(new_changes == NULL))
82227308aaeSNick Mathewson 		return (-1);
82327308aaeSNick Mathewson 
82427308aaeSNick Mathewson 	changelist->changes = new_changes;
82527308aaeSNick Mathewson 	changelist->changes_size = new_size;
82627308aaeSNick Mathewson 
82727308aaeSNick Mathewson 	return (0);
82827308aaeSNick Mathewson }
82927308aaeSNick Mathewson 
83027308aaeSNick Mathewson /** Return a pointer to the changelist entry for the file descriptor or signal
83127308aaeSNick Mathewson  * 'fd', whose fdinfo is 'fdinfo'.  If none exists, construct it, setting its
83227308aaeSNick Mathewson  * old_events field to old_events.
83327308aaeSNick Mathewson  */
83427308aaeSNick Mathewson static struct event_change *
83527308aaeSNick Mathewson event_changelist_get_or_construct(struct event_changelist *changelist,
83627308aaeSNick Mathewson     evutil_socket_t fd,
83727308aaeSNick Mathewson     short old_events,
83827308aaeSNick Mathewson     struct event_changelist_fdinfo *fdinfo)
83927308aaeSNick Mathewson {
84027308aaeSNick Mathewson 	struct event_change *change;
84127308aaeSNick Mathewson 
84227308aaeSNick Mathewson 	if (fdinfo->idxplus1 == 0) {
84327308aaeSNick Mathewson 		int idx;
84427308aaeSNick Mathewson 		EVUTIL_ASSERT(changelist->n_changes <= changelist->changes_size);
84527308aaeSNick Mathewson 
84627308aaeSNick Mathewson 		if (changelist->n_changes == changelist->changes_size) {
84727308aaeSNick Mathewson 			if (event_changelist_grow(changelist) < 0)
84827308aaeSNick Mathewson 				return NULL;
84927308aaeSNick Mathewson 		}
85027308aaeSNick Mathewson 
85127308aaeSNick Mathewson 		idx = changelist->n_changes++;
85227308aaeSNick Mathewson 		change = &changelist->changes[idx];
85327308aaeSNick Mathewson 		fdinfo->idxplus1 = idx + 1;
85427308aaeSNick Mathewson 
85527308aaeSNick Mathewson 		memset(change, 0, sizeof(struct event_change));
85627308aaeSNick Mathewson 		change->fd = fd;
85727308aaeSNick Mathewson 		change->old_events = old_events;
85827308aaeSNick Mathewson 	} else {
85927308aaeSNick Mathewson 		change = &changelist->changes[fdinfo->idxplus1 - 1];
86027308aaeSNick Mathewson 		EVUTIL_ASSERT(change->fd == fd);
86127308aaeSNick Mathewson 	}
86227308aaeSNick Mathewson 	return change;
86327308aaeSNick Mathewson }
86427308aaeSNick Mathewson 
86527308aaeSNick Mathewson int
8668ac3c4c2SNick Mathewson event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, short events,
86727308aaeSNick Mathewson     void *p)
86827308aaeSNick Mathewson {
86927308aaeSNick Mathewson 	struct event_changelist *changelist = &base->changelist;
87027308aaeSNick Mathewson 	struct event_changelist_fdinfo *fdinfo = p;
87127308aaeSNick Mathewson 	struct event_change *change;
872048bee0aSAzat Khuzhin 	ev_uint8_t evchange = EV_CHANGE_ADD | (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
87327308aaeSNick Mathewson 
87427308aaeSNick Mathewson 	event_changelist_check(base);
87527308aaeSNick Mathewson 
87627308aaeSNick Mathewson 	change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
87727308aaeSNick Mathewson 	if (!change)
87827308aaeSNick Mathewson 		return -1;
87927308aaeSNick Mathewson 
88027308aaeSNick Mathewson 	/* An add replaces any previous delete, but doesn't result in a no-op,
88127308aaeSNick Mathewson 	 * since the delete might fail (because the fd had been closed since
88227308aaeSNick Mathewson 	 * the last add, for instance. */
88327308aaeSNick Mathewson 
884ca4b6404SAzat Khuzhin 	if (events & (EV_READ|EV_SIGNAL))
885ca4b6404SAzat Khuzhin 		change->read_change = evchange;
886ca4b6404SAzat Khuzhin 	if (events & EV_WRITE)
887ca4b6404SAzat Khuzhin 		change->write_change = evchange;
888ca4b6404SAzat Khuzhin 	if (events & EV_CLOSED)
889ca4b6404SAzat Khuzhin 		change->close_change = evchange;
89027308aaeSNick Mathewson 
89127308aaeSNick Mathewson 	event_changelist_check(base);
89227308aaeSNick Mathewson 	return (0);
89327308aaeSNick Mathewson }
89427308aaeSNick Mathewson 
89527308aaeSNick Mathewson int
8968ac3c4c2SNick Mathewson event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events,
89727308aaeSNick Mathewson     void *p)
89827308aaeSNick Mathewson {
89927308aaeSNick Mathewson 	struct event_changelist *changelist = &base->changelist;
90027308aaeSNick Mathewson 	struct event_changelist_fdinfo *fdinfo = p;
90127308aaeSNick Mathewson 	struct event_change *change;
902048bee0aSAzat Khuzhin 	ev_uint8_t del = EV_CHANGE_DEL | (events & EV_ET);
90327308aaeSNick Mathewson 
90427308aaeSNick Mathewson 	event_changelist_check(base);
90527308aaeSNick Mathewson 	change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
90627308aaeSNick Mathewson 	event_changelist_check(base);
90727308aaeSNick Mathewson 	if (!change)
90827308aaeSNick Mathewson 		return -1;
90927308aaeSNick Mathewson 
91004ba27ebSMike Smellie 	/* A delete on an event set that doesn't contain the event to be
91104ba27ebSMike Smellie 	   deleted produces a no-op.  This effectively emoves any previous
91204ba27ebSMike Smellie 	   uncommitted add, rather than replacing it: on those platforms where
91304ba27ebSMike Smellie 	   "add, delete, dispatch" is not the same as "no-op, dispatch", we
91404ba27ebSMike Smellie 	   want the no-op behavior.
915cf249e7dSMike Smellie 
916c247adc7SNick Mathewson 	   If we have a no-op item, we could remove it it from the list
917c247adc7SNick Mathewson 	   entirely, but really there's not much point: skipping the no-op
918c247adc7SNick Mathewson 	   change when we do the dispatch later is far cheaper than rejuggling
919c247adc7SNick Mathewson 	   the array now.
920cf249e7dSMike Smellie 
921cf249e7dSMike Smellie 	   As this stands, it also lets through deletions of events that are
922cf249e7dSMike Smellie 	   not currently set.
92327308aaeSNick Mathewson 	 */
92427308aaeSNick Mathewson 
92527308aaeSNick Mathewson 	if (events & (EV_READ|EV_SIGNAL)) {
92604ba27ebSMike Smellie 		if (!(change->old_events & (EV_READ | EV_SIGNAL)))
92727308aaeSNick Mathewson 			change->read_change = 0;
92827308aaeSNick Mathewson 		else
929ca4b6404SAzat Khuzhin 			change->read_change = del;
93027308aaeSNick Mathewson 	}
93127308aaeSNick Mathewson 	if (events & EV_WRITE) {
93204ba27ebSMike Smellie 		if (!(change->old_events & EV_WRITE))
93327308aaeSNick Mathewson 			change->write_change = 0;
93427308aaeSNick Mathewson 		else
935ca4b6404SAzat Khuzhin 			change->write_change = del;
93627308aaeSNick Mathewson 	}
937b1b69ac7SDiego Giagio 	if (events & EV_CLOSED) {
938b1b69ac7SDiego Giagio 		if (!(change->old_events & EV_CLOSED))
939b1b69ac7SDiego Giagio 			change->close_change = 0;
940b1b69ac7SDiego Giagio 		else
941ca4b6404SAzat Khuzhin 			change->close_change = del;
942b1b69ac7SDiego Giagio 	}
94327308aaeSNick Mathewson 
94427308aaeSNick Mathewson 	event_changelist_check(base);
94527308aaeSNick Mathewson 	return (0);
94627308aaeSNick Mathewson }
94727308aaeSNick Mathewson 
9488ac3c4c2SNick Mathewson /* Helper for evmap_check_integrity_: verify that all of the events pending on
949c89b4e63SNick Mathewson  * given fd are set up correctly, and that the nread and nwrite counts on that
950c89b4e63SNick Mathewson  * fd are correct. */
951c89b4e63SNick Mathewson static int
952c89b4e63SNick Mathewson evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd,
953c89b4e63SNick Mathewson     struct evmap_io *io_info, void *arg)
954c89b4e63SNick Mathewson {
955c89b4e63SNick Mathewson 	struct event *ev;
956b1b69ac7SDiego Giagio 	int n_read = 0, n_write = 0, n_close = 0;
957c89b4e63SNick Mathewson 
958c89b4e63SNick Mathewson 	/* First, make sure the list itself isn't corrupt. Otherwise,
959c89b4e63SNick Mathewson 	 * running LIST_FOREACH could be an exciting adventure. */
960c89b4e63SNick Mathewson 	EVUTIL_ASSERT_LIST_OK(&io_info->events, event, ev_io_next);
961c89b4e63SNick Mathewson 
962c89b4e63SNick Mathewson 	LIST_FOREACH(ev, &io_info->events, ev_io_next) {
963c89b4e63SNick Mathewson 		EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
964c89b4e63SNick Mathewson 		EVUTIL_ASSERT(ev->ev_fd == fd);
965c89b4e63SNick Mathewson 		EVUTIL_ASSERT(!(ev->ev_events & EV_SIGNAL));
966b1b69ac7SDiego Giagio 		EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
967c89b4e63SNick Mathewson 		if (ev->ev_events & EV_READ)
968c89b4e63SNick Mathewson 			++n_read;
969c89b4e63SNick Mathewson 		if (ev->ev_events & EV_WRITE)
970c89b4e63SNick Mathewson 			++n_write;
971b1b69ac7SDiego Giagio 		if (ev->ev_events & EV_CLOSED)
972b1b69ac7SDiego Giagio 			++n_close;
973c89b4e63SNick Mathewson 	}
974c89b4e63SNick Mathewson 
975c89b4e63SNick Mathewson 	EVUTIL_ASSERT(n_read == io_info->nread);
976c89b4e63SNick Mathewson 	EVUTIL_ASSERT(n_write == io_info->nwrite);
977b1b69ac7SDiego Giagio 	EVUTIL_ASSERT(n_close == io_info->nclose);
978c89b4e63SNick Mathewson 
979c89b4e63SNick Mathewson 	return 0;
980c89b4e63SNick Mathewson }
981c89b4e63SNick Mathewson 
9828ac3c4c2SNick Mathewson /* Helper for evmap_check_integrity_: verify that all of the events pending
983c89b4e63SNick Mathewson  * on given signal are set up correctly. */
984c89b4e63SNick Mathewson static int
985c89b4e63SNick Mathewson evmap_signal_check_integrity_fn(struct event_base *base,
986c89b4e63SNick Mathewson     int signum, struct evmap_signal *sig_info, void *arg)
987c89b4e63SNick Mathewson {
988c89b4e63SNick Mathewson 	struct event *ev;
989c89b4e63SNick Mathewson 	/* First, make sure the list itself isn't corrupt. */
990c89b4e63SNick Mathewson 	EVUTIL_ASSERT_LIST_OK(&sig_info->events, event, ev_signal_next);
991c89b4e63SNick Mathewson 
992c89b4e63SNick Mathewson 	LIST_FOREACH(ev, &sig_info->events, ev_io_next) {
993c89b4e63SNick Mathewson 		EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
994c89b4e63SNick Mathewson 		EVUTIL_ASSERT(ev->ev_fd == signum);
995c89b4e63SNick Mathewson 		EVUTIL_ASSERT((ev->ev_events & EV_SIGNAL));
996b1b69ac7SDiego Giagio 		EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
997c89b4e63SNick Mathewson 	}
998c89b4e63SNick Mathewson 	return 0;
999c89b4e63SNick Mathewson }
1000c89b4e63SNick Mathewson 
100127737d55SNick Mathewson void
10028ac3c4c2SNick Mathewson evmap_check_integrity_(struct event_base *base)
100327737d55SNick Mathewson {
1004c89b4e63SNick Mathewson 	evmap_io_foreach_fd(base, evmap_io_check_integrity_fn, NULL);
1005c89b4e63SNick Mathewson 	evmap_signal_foreach_signal(base, evmap_signal_check_integrity_fn, NULL);
100639b3f38dSNick Mathewson 
10078ac3c4c2SNick Mathewson 	if (base->evsel->add == event_changelist_add_)
100839b3f38dSNick Mathewson 		event_changelist_assert_ok(base);
100927737d55SNick Mathewson }
1010c89b4e63SNick Mathewson 
10118ac3c4c2SNick Mathewson /* Helper type for evmap_foreach_event_: Bundles a function to call on every
1012c89b4e63SNick Mathewson  * event, and the user-provided void* to use as its third argument. */
1013c89b4e63SNick Mathewson struct evmap_foreach_event_helper {
1014232055efSNick Mathewson 	event_base_foreach_event_cb fn;
1015c89b4e63SNick Mathewson 	void *arg;
1016c89b4e63SNick Mathewson };
1017c89b4e63SNick Mathewson 
10188ac3c4c2SNick Mathewson /* Helper for evmap_foreach_event_: calls a provided function on every event
1019c89b4e63SNick Mathewson  * pending on a given fd.  */
1020c89b4e63SNick Mathewson static int
1021c89b4e63SNick Mathewson evmap_io_foreach_event_fn(struct event_base *base, evutil_socket_t fd,
1022c89b4e63SNick Mathewson     struct evmap_io *io_info, void *arg)
1023c89b4e63SNick Mathewson {
1024c89b4e63SNick Mathewson 	struct evmap_foreach_event_helper *h = arg;
1025c89b4e63SNick Mathewson 	struct event *ev;
1026c89b4e63SNick Mathewson 	int r;
1027c89b4e63SNick Mathewson 	LIST_FOREACH(ev, &io_info->events, ev_io_next) {
1028c89b4e63SNick Mathewson 		if ((r = h->fn(base, ev, h->arg)))
1029c89b4e63SNick Mathewson 			return r;
1030c89b4e63SNick Mathewson 	}
1031c89b4e63SNick Mathewson 	return 0;
1032c89b4e63SNick Mathewson }
1033c89b4e63SNick Mathewson 
10348ac3c4c2SNick Mathewson /* Helper for evmap_foreach_event_: calls a provided function on every event
1035c89b4e63SNick Mathewson  * pending on a given signal.  */
1036c89b4e63SNick Mathewson static int
1037c89b4e63SNick Mathewson evmap_signal_foreach_event_fn(struct event_base *base, int signum,
1038c89b4e63SNick Mathewson     struct evmap_signal *sig_info, void *arg)
1039c89b4e63SNick Mathewson {
1040c89b4e63SNick Mathewson 	struct event *ev;
1041c89b4e63SNick Mathewson 	struct evmap_foreach_event_helper *h = arg;
1042c89b4e63SNick Mathewson 	int r;
1043c89b4e63SNick Mathewson 	LIST_FOREACH(ev, &sig_info->events, ev_signal_next) {
1044c89b4e63SNick Mathewson 		if ((r = h->fn(base, ev, h->arg)))
1045c89b4e63SNick Mathewson 			return r;
1046c89b4e63SNick Mathewson 	}
1047c89b4e63SNick Mathewson 	return 0;
1048c89b4e63SNick Mathewson }
1049c89b4e63SNick Mathewson 
1050c89b4e63SNick Mathewson int
10518ac3c4c2SNick Mathewson evmap_foreach_event_(struct event_base *base,
1052232055efSNick Mathewson     event_base_foreach_event_cb fn, void *arg)
1053c89b4e63SNick Mathewson {
1054c89b4e63SNick Mathewson 	struct evmap_foreach_event_helper h;
1055c89b4e63SNick Mathewson 	int r;
1056c89b4e63SNick Mathewson 	h.fn = fn;
1057c89b4e63SNick Mathewson 	h.arg = arg;
1058c89b4e63SNick Mathewson 	if ((r = evmap_io_foreach_fd(base, evmap_io_foreach_event_fn, &h)))
1059c89b4e63SNick Mathewson 		return r;
1060c89b4e63SNick Mathewson 	return evmap_signal_foreach_signal(base, evmap_signal_foreach_event_fn, &h);
1061c89b4e63SNick Mathewson }
1062c89b4e63SNick Mathewson 
1063