xref: /freebsd/contrib/ntp/sntp/libevent/evmap.c (revision f4b37ed0f8b307b1f3f0f630ca725d68f1dff30d)
1 /*
2  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. The name of the author may not be used to endorse or promote products
13  *    derived from this software without specific prior written permission.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 #include "event2/event-config.h"
27 #include "evconfig-private.h"
28 
29 #ifdef _WIN32
30 #include <winsock2.h>
31 #define WIN32_LEAN_AND_MEAN
32 #include <windows.h>
33 #undef WIN32_LEAN_AND_MEAN
34 #endif
35 #include <sys/types.h>
36 #if !defined(_WIN32) && defined(EVENT__HAVE_SYS_TIME_H)
37 #include <sys/time.h>
38 #endif
39 #include <sys/queue.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #ifndef _WIN32
43 #include <unistd.h>
44 #endif
45 #include <errno.h>
46 #include <signal.h>
47 #include <string.h>
48 #include <time.h>
49 
50 #include "event-internal.h"
51 #include "evmap-internal.h"
52 #include "mm-internal.h"
53 #include "changelist-internal.h"
54 
55 /** An entry for an evmap_io list: notes all the events that want to read or
56 	write on a given fd, and the number of each.
57   */
58 struct evmap_io {
59 	struct event_dlist events;
60 	ev_uint16_t nread;
61 	ev_uint16_t nwrite;
62 	ev_uint16_t nclose;
63 };
64 
65 /* An entry for an evmap_signal list: notes all the events that want to know
66    when a signal triggers. */
67 struct evmap_signal {
68 	struct event_dlist events;
69 };
70 
71 /* On some platforms, fds start at 0 and increment by 1 as they are
72    allocated, and old numbers get used.  For these platforms, we
73    implement io maps just like signal maps: as an array of pointers to
74    struct evmap_io.  But on other platforms (windows), sockets are not
75    0-indexed, not necessarily consecutive, and not necessarily reused.
76    There, we use a hashtable to implement evmap_io.
77 */
78 #ifdef EVMAP_USE_HT
79 struct event_map_entry {
80 	HT_ENTRY(event_map_entry) map_node;
81 	evutil_socket_t fd;
82 	union { /* This is a union in case we need to make more things that can
83 			   be in the hashtable. */
84 		struct evmap_io evmap_io;
85 	} ent;
86 };
87 
88 /* Helper used by the event_io_map hashtable code; tries to return a good hash
89  * of the fd in e->fd. */
90 static inline unsigned
91 hashsocket(struct event_map_entry *e)
92 {
93 	/* On win32, in practice, the low 2-3 bits of a SOCKET seem not to
94 	 * matter.  Our hashtable implementation really likes low-order bits,
95 	 * though, so let's do the rotate-and-add trick. */
96 	unsigned h = (unsigned) e->fd;
97 	h += (h >> 2) | (h << 30);
98 	return h;
99 }
100 
101 /* Helper used by the event_io_map hashtable code; returns true iff e1 and e2
102  * have the same e->fd. */
103 static inline int
104 eqsocket(struct event_map_entry *e1, struct event_map_entry *e2)
105 {
106 	return e1->fd == e2->fd;
107 }
108 
109 HT_PROTOTYPE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket)
110 HT_GENERATE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket,
111 			0.5, mm_malloc, mm_realloc, mm_free)
112 
113 #define GET_IO_SLOT(x, map, slot, type)					\
114 	do {								\
115 		struct event_map_entry key_, *ent_;			\
116 		key_.fd = slot;						\
117 		ent_ = HT_FIND(event_io_map, map, &key_);		\
118 		(x) = ent_ ? &ent_->ent.type : NULL;			\
119 	} while (0);
120 
121 #define GET_IO_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len)	\
122 	do {								\
123 		struct event_map_entry key_, *ent_;			\
124 		key_.fd = slot;						\
125 		HT_FIND_OR_INSERT_(event_io_map, map_node, hashsocket, map, \
126 		    event_map_entry, &key_, ptr,			\
127 		    {							\
128 			    ent_ = *ptr;				\
129 		    },							\
130 		    {							\
131 			    ent_ = mm_calloc(1,sizeof(struct event_map_entry)+fdinfo_len); \
132 			    if (EVUTIL_UNLIKELY(ent_ == NULL))		\
133 				    return (-1);			\
134 			    ent_->fd = slot;				\
135 			    (ctor)(&ent_->ent.type);			\
136 			    HT_FOI_INSERT_(map_node, map, &key_, ent_, ptr) \
137 				});					\
138 		(x) = &ent_->ent.type;					\
139 	} while (0)
140 
141 void evmap_io_initmap_(struct event_io_map *ctx)
142 {
143 	HT_INIT(event_io_map, ctx);
144 }
145 
146 void evmap_io_clear_(struct event_io_map *ctx)
147 {
148 	struct event_map_entry **ent, **next, *this;
149 	for (ent = HT_START(event_io_map, ctx); ent; ent = next) {
150 		this = *ent;
151 		next = HT_NEXT_RMV(event_io_map, ctx, ent);
152 		mm_free(this);
153 	}
154 	HT_CLEAR(event_io_map, ctx); /* remove all storage held by the ctx. */
155 }
156 #endif
157 
158 /* Set the variable 'x' to the field in event_map 'map' with fields of type
159    'struct type *' corresponding to the fd or signal 'slot'.  Set 'x' to NULL
160    if there are no entries for 'slot'.  Does no bounds-checking. */
161 #define GET_SIGNAL_SLOT(x, map, slot, type)			\
162 	(x) = (struct type *)((map)->entries[slot])
163 /* As GET_SLOT, but construct the entry for 'slot' if it is not present,
164    by allocating enough memory for a 'struct type', and initializing the new
165    value by calling the function 'ctor' on it.  Makes the function
166    return -1 on allocation failure.
167  */
168 #define GET_SIGNAL_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len)	\
169 	do {								\
170 		if ((map)->entries[slot] == NULL) {			\
171 			(map)->entries[slot] =				\
172 			    mm_calloc(1,sizeof(struct type)+fdinfo_len); \
173 			if (EVUTIL_UNLIKELY((map)->entries[slot] == NULL)) \
174 				return (-1);				\
175 			(ctor)((struct type *)(map)->entries[slot]);	\
176 		}							\
177 		(x) = (struct type *)((map)->entries[slot]);		\
178 	} while (0)
179 
180 /* If we aren't using hashtables, then define the IO_SLOT macros and functions
181    as thin aliases over the SIGNAL_SLOT versions. */
182 #ifndef EVMAP_USE_HT
183 #define GET_IO_SLOT(x,map,slot,type) GET_SIGNAL_SLOT(x,map,slot,type)
184 #define GET_IO_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)	\
185 	GET_SIGNAL_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)
186 #define FDINFO_OFFSET sizeof(struct evmap_io)
187 void
188 evmap_io_initmap_(struct event_io_map* ctx)
189 {
190 	evmap_signal_initmap_(ctx);
191 }
192 void
193 evmap_io_clear_(struct event_io_map* ctx)
194 {
195 	evmap_signal_clear_(ctx);
196 }
197 #endif
198 
199 
200 /** Expand 'map' with new entries of width 'msize' until it is big enough
201 	to store a value in 'slot'.
202  */
203 static int
204 evmap_make_space(struct event_signal_map *map, int slot, int msize)
205 {
206 	if (map->nentries <= slot) {
207 		int nentries = map->nentries ? map->nentries : 32;
208 		void **tmp;
209 
210 		while (nentries <= slot)
211 			nentries <<= 1;
212 
213 		tmp = (void **)mm_realloc(map->entries, nentries * msize);
214 		if (tmp == NULL)
215 			return (-1);
216 
217 		memset(&tmp[map->nentries], 0,
218 		    (nentries - map->nentries) * msize);
219 
220 		map->nentries = nentries;
221 		map->entries = tmp;
222 	}
223 
224 	return (0);
225 }
226 
227 void
228 evmap_signal_initmap_(struct event_signal_map *ctx)
229 {
230 	ctx->nentries = 0;
231 	ctx->entries = NULL;
232 }
233 
234 void
235 evmap_signal_clear_(struct event_signal_map *ctx)
236 {
237 	if (ctx->entries != NULL) {
238 		int i;
239 		for (i = 0; i < ctx->nentries; ++i) {
240 			if (ctx->entries[i] != NULL)
241 				mm_free(ctx->entries[i]);
242 		}
243 		mm_free(ctx->entries);
244 		ctx->entries = NULL;
245 	}
246 	ctx->nentries = 0;
247 }
248 
249 
250 /* code specific to file descriptors */
251 
252 /** Constructor for struct evmap_io */
253 static void
254 evmap_io_init(struct evmap_io *entry)
255 {
256 	LIST_INIT(&entry->events);
257 	entry->nread = 0;
258 	entry->nwrite = 0;
259 	entry->nclose = 0;
260 }
261 
262 
263 /* return -1 on error, 0 on success if nothing changed in the event backend,
264  * and 1 on success if something did. */
265 int
266 evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
267 {
268 	const struct eventop *evsel = base->evsel;
269 	struct event_io_map *io = &base->io;
270 	struct evmap_io *ctx = NULL;
271 	int nread, nwrite, nclose, retval = 0;
272 	short res = 0, old = 0;
273 	struct event *old_ev;
274 
275 	EVUTIL_ASSERT(fd == ev->ev_fd);
276 
277 	if (fd < 0)
278 		return 0;
279 
280 #ifndef EVMAP_USE_HT
281 	if (fd >= io->nentries) {
282 		if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1)
283 			return (-1);
284 	}
285 #endif
286 	GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init,
287 						 evsel->fdinfo_len);
288 
289 	nread = ctx->nread;
290 	nwrite = ctx->nwrite;
291 	nclose = ctx->nclose;
292 
293 	if (nread)
294 		old |= EV_READ;
295 	if (nwrite)
296 		old |= EV_WRITE;
297 	if (nclose)
298 		old |= EV_CLOSED;
299 
300 	if (ev->ev_events & EV_READ) {
301 		if (++nread == 1)
302 			res |= EV_READ;
303 	}
304 	if (ev->ev_events & EV_WRITE) {
305 		if (++nwrite == 1)
306 			res |= EV_WRITE;
307 	}
308 	if (ev->ev_events & EV_CLOSED) {
309 		if (++nclose == 1)
310 			res |= EV_CLOSED;
311 	}
312 	if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) {
313 		event_warnx("Too many events reading or writing on fd %d",
314 		    (int)fd);
315 		return -1;
316 	}
317 	if (EVENT_DEBUG_MODE_IS_ON() &&
318 	    (old_ev = LIST_FIRST(&ctx->events)) &&
319 	    (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) {
320 		event_warnx("Tried to mix edge-triggered and non-edge-triggered"
321 		    " events on fd %d", (int)fd);
322 		return -1;
323 	}
324 
325 	if (res) {
326 		void *extra = ((char*)ctx) + sizeof(struct evmap_io);
327 		/* XXX(niels): we cannot mix edge-triggered and
328 		 * level-triggered, we should probably assert on
329 		 * this. */
330 		if (evsel->add(base, ev->ev_fd,
331 			old, (ev->ev_events & EV_ET) | res, extra) == -1)
332 			return (-1);
333 		retval = 1;
334 	}
335 
336 	ctx->nread = (ev_uint16_t) nread;
337 	ctx->nwrite = (ev_uint16_t) nwrite;
338 	ctx->nclose = (ev_uint16_t) nclose;
339 	LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next);
340 
341 	return (retval);
342 }
343 
344 /* return -1 on error, 0 on success if nothing changed in the event backend,
345  * and 1 on success if something did. */
346 int
347 evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
348 {
349 	const struct eventop *evsel = base->evsel;
350 	struct event_io_map *io = &base->io;
351 	struct evmap_io *ctx;
352 	int nread, nwrite, nclose, retval = 0;
353 	short res = 0, old = 0;
354 
355 	if (fd < 0)
356 		return 0;
357 
358 	EVUTIL_ASSERT(fd == ev->ev_fd);
359 
360 #ifndef EVMAP_USE_HT
361 	if (fd >= io->nentries)
362 		return (-1);
363 #endif
364 
365 	GET_IO_SLOT(ctx, io, fd, evmap_io);
366 
367 	nread = ctx->nread;
368 	nwrite = ctx->nwrite;
369 	nclose = ctx->nclose;
370 
371 	if (nread)
372 		old |= EV_READ;
373 	if (nwrite)
374 		old |= EV_WRITE;
375 	if (nclose)
376 		old |= EV_CLOSED;
377 
378 	if (ev->ev_events & EV_READ) {
379 		if (--nread == 0)
380 			res |= EV_READ;
381 		EVUTIL_ASSERT(nread >= 0);
382 	}
383 	if (ev->ev_events & EV_WRITE) {
384 		if (--nwrite == 0)
385 			res |= EV_WRITE;
386 		EVUTIL_ASSERT(nwrite >= 0);
387 	}
388 	if (ev->ev_events & EV_CLOSED) {
389 		if (--nclose == 0)
390 			res |= EV_CLOSED;
391 		EVUTIL_ASSERT(nclose >= 0);
392 	}
393 
394 	if (res) {
395 		void *extra = ((char*)ctx) + sizeof(struct evmap_io);
396 		if (evsel->del(base, ev->ev_fd, old, res, extra) == -1) {
397 			retval = -1;
398 		} else {
399 			retval = 1;
400 		}
401 	}
402 
403 	ctx->nread = nread;
404 	ctx->nwrite = nwrite;
405 	ctx->nclose = nclose;
406 	LIST_REMOVE(ev, ev_io_next);
407 
408 	return (retval);
409 }
410 
411 void
412 evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events)
413 {
414 	struct event_io_map *io = &base->io;
415 	struct evmap_io *ctx;
416 	struct event *ev;
417 
418 #ifndef EVMAP_USE_HT
419 	if (fd < 0 || fd >= io->nentries)
420 		return;
421 #endif
422 	GET_IO_SLOT(ctx, io, fd, evmap_io);
423 
424 	if (NULL == ctx)
425 		return;
426 	LIST_FOREACH(ev, &ctx->events, ev_io_next) {
427 		if (ev->ev_events & events)
428 			event_active_nolock_(ev, ev->ev_events & events, 1);
429 	}
430 }
431 
432 /* code specific to signals */
433 
434 static void
435 evmap_signal_init(struct evmap_signal *entry)
436 {
437 	LIST_INIT(&entry->events);
438 }
439 
440 
441 int
442 evmap_signal_add_(struct event_base *base, int sig, struct event *ev)
443 {
444 	const struct eventop *evsel = base->evsigsel;
445 	struct event_signal_map *map = &base->sigmap;
446 	struct evmap_signal *ctx = NULL;
447 
448 	if (sig >= map->nentries) {
449 		if (evmap_make_space(
450 			map, sig, sizeof(struct evmap_signal *)) == -1)
451 			return (-1);
452 	}
453 	GET_SIGNAL_SLOT_AND_CTOR(ctx, map, sig, evmap_signal, evmap_signal_init,
454 	    base->evsigsel->fdinfo_len);
455 
456 	if (LIST_EMPTY(&ctx->events)) {
457 		if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL)
458 		    == -1)
459 			return (-1);
460 	}
461 
462 	LIST_INSERT_HEAD(&ctx->events, ev, ev_signal_next);
463 
464 	return (1);
465 }
466 
467 int
468 evmap_signal_del_(struct event_base *base, int sig, struct event *ev)
469 {
470 	const struct eventop *evsel = base->evsigsel;
471 	struct event_signal_map *map = &base->sigmap;
472 	struct evmap_signal *ctx;
473 
474 	if (sig >= map->nentries)
475 		return (-1);
476 
477 	GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
478 
479 	LIST_REMOVE(ev, ev_signal_next);
480 
481 	if (LIST_FIRST(&ctx->events) == NULL) {
482 		if (evsel->del(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1)
483 			return (-1);
484 	}
485 
486 	return (1);
487 }
488 
489 void
490 evmap_signal_active_(struct event_base *base, evutil_socket_t sig, int ncalls)
491 {
492 	struct event_signal_map *map = &base->sigmap;
493 	struct evmap_signal *ctx;
494 	struct event *ev;
495 
496 	if (sig < 0 || sig >= map->nentries)
497 		return;
498 	GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
499 
500 	if (!ctx)
501 		return;
502 	LIST_FOREACH(ev, &ctx->events, ev_signal_next)
503 		event_active_nolock_(ev, EV_SIGNAL, ncalls);
504 }
505 
506 void *
507 evmap_io_get_fdinfo_(struct event_io_map *map, evutil_socket_t fd)
508 {
509 	struct evmap_io *ctx;
510 	GET_IO_SLOT(ctx, map, fd, evmap_io);
511 	if (ctx)
512 		return ((char*)ctx) + sizeof(struct evmap_io);
513 	else
514 		return NULL;
515 }
516 
517 /* Callback type for evmap_io_foreach_fd */
518 typedef int (*evmap_io_foreach_fd_cb)(
519 	struct event_base *, evutil_socket_t, struct evmap_io *, void *);
520 
521 /* Multipurpose helper function: Iterate over every file descriptor event_base
522  * for which we could have EV_READ or EV_WRITE events.  For each such fd, call
523  * fn(base, signum, evmap_io, arg), where fn is the user-provided
524  * function, base is the event_base, signum is the signal number, evmap_io
525  * is an evmap_io structure containing a list of events pending on the
526  * file descriptor, and arg is the user-supplied argument.
527  *
528  * If fn returns 0, continue on to the next signal. Otherwise, return the same
529  * value that fn returned.
530  *
531  * Note that there is no guarantee that the file descriptors will be processed
532  * in any particular order.
533  */
534 static int
535 evmap_io_foreach_fd(struct event_base *base,
536     evmap_io_foreach_fd_cb fn,
537     void *arg)
538 {
539 	evutil_socket_t fd;
540 	struct event_io_map *iomap = &base->io;
541 	int r = 0;
542 #ifdef EVMAP_USE_HT
543 	struct event_map_entry **mapent;
544 	HT_FOREACH(mapent, event_io_map, iomap) {
545 		struct evmap_io *ctx = &(*mapent)->ent.evmap_io;
546 		fd = (*mapent)->fd;
547 #else
548 	for (fd = 0; fd < iomap->nentries; ++fd) {
549 		struct evmap_io *ctx = iomap->entries[fd];
550 		if (!ctx)
551 			continue;
552 #endif
553 		if ((r = fn(base, fd, ctx, arg)))
554 			break;
555 	}
556 	return r;
557 }
558 
559 /* Callback type for evmap_signal_foreach_signal */
560 typedef int (*evmap_signal_foreach_signal_cb)(
561 	struct event_base *, int, struct evmap_signal *, void *);
562 
563 /* Multipurpose helper function: Iterate over every signal number in the
564  * event_base for which we could have signal events.  For each such signal,
565  * call fn(base, signum, evmap_signal, arg), where fn is the user-provided
566  * function, base is the event_base, signum is the signal number, evmap_signal
567  * is an evmap_signal structure containing a list of events pending on the
568  * signal, and arg is the user-supplied argument.
569  *
570  * If fn returns 0, continue on to the next signal. Otherwise, return the same
571  * value that fn returned.
572  */
573 static int
574 evmap_signal_foreach_signal(struct event_base *base,
575     evmap_signal_foreach_signal_cb fn,
576     void *arg)
577 {
578 	struct event_signal_map *sigmap = &base->sigmap;
579 	int r = 0;
580 	int signum;
581 
582 	for (signum = 0; signum < sigmap->nentries; ++signum) {
583 		struct evmap_signal *ctx = sigmap->entries[signum];
584 		if (!ctx)
585 			continue;
586 		if ((r = fn(base, signum, ctx, arg)))
587 			break;
588 	}
589 	return r;
590 }
591 
592 /* Helper for evmap_reinit_: tell the backend to add every fd for which we have
593  * pending events, with the appropriate combination of EV_READ, EV_WRITE, and
594  * EV_ET. */
595 static int
596 evmap_io_reinit_iter_fn(struct event_base *base, evutil_socket_t fd,
597     struct evmap_io *ctx, void *arg)
598 {
599 	const struct eventop *evsel = base->evsel;
600 	void *extra;
601 	int *result = arg;
602 	short events = 0;
603 	struct event *ev;
604 	EVUTIL_ASSERT(ctx);
605 
606 	extra = ((char*)ctx) + sizeof(struct evmap_io);
607 	if (ctx->nread)
608 		events |= EV_READ;
609 	if (ctx->nwrite)
610 		events |= EV_WRITE;
611 	if (ctx->nclose)
612 		events |= EV_CLOSED;
613 	if (evsel->fdinfo_len)
614 		memset(extra, 0, evsel->fdinfo_len);
615 	if (events &&
616 	    (ev = LIST_FIRST(&ctx->events)) &&
617 	    (ev->ev_events & EV_ET))
618 		events |= EV_ET;
619 	if (evsel->add(base, fd, 0, events, extra) == -1)
620 		*result = -1;
621 
622 	return 0;
623 }
624 
625 /* Helper for evmap_reinit_: tell the backend to add every signal for which we
626  * have pending events.  */
627 static int
628 evmap_signal_reinit_iter_fn(struct event_base *base,
629     int signum, struct evmap_signal *ctx, void *arg)
630 {
631 	const struct eventop *evsel = base->evsigsel;
632 	int *result = arg;
633 
634 	if (!LIST_EMPTY(&ctx->events)) {
635 		if (evsel->add(base, signum, 0, EV_SIGNAL, NULL) == -1)
636 			*result = -1;
637 	}
638 	return 0;
639 }
640 
641 int
642 evmap_reinit_(struct event_base *base)
643 {
644 	int result = 0;
645 
646 	evmap_io_foreach_fd(base, evmap_io_reinit_iter_fn, &result);
647 	if (result < 0)
648 		return -1;
649 	evmap_signal_foreach_signal(base, evmap_signal_reinit_iter_fn, &result);
650 	if (result < 0)
651 		return -1;
652 	return 0;
653 }
654 
655 /* Helper for evmap_delete_all_: delete every event in an event_dlist. */
656 static int
657 delete_all_in_dlist(struct event_dlist *dlist)
658 {
659 	struct event *ev;
660 	while ((ev = LIST_FIRST(dlist)))
661 		event_del(ev);
662 	return 0;
663 }
664 
665 /* Helper for evmap_delete_all_: delete every event pending on an fd. */
666 static int
667 evmap_io_delete_all_iter_fn(struct event_base *base, evutil_socket_t fd,
668     struct evmap_io *io_info, void *arg)
669 {
670 	return delete_all_in_dlist(&io_info->events);
671 }
672 
673 /* Helper for evmap_delete_all_: delete every event pending on a signal. */
674 static int
675 evmap_signal_delete_all_iter_fn(struct event_base *base, int signum,
676     struct evmap_signal *sig_info, void *arg)
677 {
678 	return delete_all_in_dlist(&sig_info->events);
679 }
680 
681 void
682 evmap_delete_all_(struct event_base *base)
683 {
684 	evmap_signal_foreach_signal(base, evmap_signal_delete_all_iter_fn, NULL);
685 	evmap_io_foreach_fd(base, evmap_io_delete_all_iter_fn, NULL);
686 }
687 
688 /** Per-fd structure for use with changelists.  It keeps track, for each fd or
689  * signal using the changelist, of where its entry in the changelist is.
690  */
691 struct event_changelist_fdinfo {
692 	int idxplus1; /* this is the index +1, so that memset(0) will make it
693 		       * a no-such-element */
694 };
695 
696 void
697 event_changelist_init_(struct event_changelist *changelist)
698 {
699 	changelist->changes = NULL;
700 	changelist->changes_size = 0;
701 	changelist->n_changes = 0;
702 }
703 
704 /** Helper: return the changelist_fdinfo corresponding to a given change. */
705 static inline struct event_changelist_fdinfo *
706 event_change_get_fdinfo(struct event_base *base,
707     const struct event_change *change)
708 {
709 	char *ptr;
710 	if (change->read_change & EV_CHANGE_SIGNAL) {
711 		struct evmap_signal *ctx;
712 		GET_SIGNAL_SLOT(ctx, &base->sigmap, change->fd, evmap_signal);
713 		ptr = ((char*)ctx) + sizeof(struct evmap_signal);
714 	} else {
715 		struct evmap_io *ctx;
716 		GET_IO_SLOT(ctx, &base->io, change->fd, evmap_io);
717 		ptr = ((char*)ctx) + sizeof(struct evmap_io);
718 	}
719 	return (void*)ptr;
720 }
721 
722 /** Callback helper for event_changelist_assert_ok */
723 static int
724 event_changelist_assert_ok_foreach_iter_fn(
725 	struct event_base *base,
726 	evutil_socket_t fd, struct evmap_io *io, void *arg)
727 {
728 	struct event_changelist *changelist = &base->changelist;
729 	struct event_changelist_fdinfo *f;
730 	f = (void*)
731 	    ( ((char*)io) + sizeof(struct evmap_io) );
732 	if (f->idxplus1) {
733 		struct event_change *c = &changelist->changes[f->idxplus1 - 1];
734 		EVUTIL_ASSERT(c->fd == fd);
735 	}
736 	return 0;
737 }
738 
739 /** Make sure that the changelist is consistent with the evmap structures. */
740 static void
741 event_changelist_assert_ok(struct event_base *base)
742 {
743 	int i;
744 	struct event_changelist *changelist = &base->changelist;
745 
746 	EVUTIL_ASSERT(changelist->changes_size >= changelist->n_changes);
747 	for (i = 0; i < changelist->n_changes; ++i) {
748 		struct event_change *c = &changelist->changes[i];
749 		struct event_changelist_fdinfo *f;
750 		EVUTIL_ASSERT(c->fd >= 0);
751 		f = event_change_get_fdinfo(base, c);
752 		EVUTIL_ASSERT(f);
753 		EVUTIL_ASSERT(f->idxplus1 == i + 1);
754 	}
755 
756 	evmap_io_foreach_fd(base,
757 	    event_changelist_assert_ok_foreach_iter_fn,
758 	    NULL);
759 }
760 
761 #ifdef DEBUG_CHANGELIST
762 #define event_changelist_check(base)  event_changelist_assert_ok((base))
763 #else
764 #define event_changelist_check(base)  ((void)0)
765 #endif
766 
767 void
768 event_changelist_remove_all_(struct event_changelist *changelist,
769     struct event_base *base)
770 {
771 	int i;
772 
773 	event_changelist_check(base);
774 
775 	for (i = 0; i < changelist->n_changes; ++i) {
776 		struct event_change *ch = &changelist->changes[i];
777 		struct event_changelist_fdinfo *fdinfo =
778 		    event_change_get_fdinfo(base, ch);
779 		EVUTIL_ASSERT(fdinfo->idxplus1 == i + 1);
780 		fdinfo->idxplus1 = 0;
781 	}
782 
783 	changelist->n_changes = 0;
784 
785 	event_changelist_check(base);
786 }
787 
788 void
789 event_changelist_freemem_(struct event_changelist *changelist)
790 {
791 	if (changelist->changes)
792 		mm_free(changelist->changes);
793 	event_changelist_init_(changelist); /* zero it all out. */
794 }
795 
796 /** Increase the size of 'changelist' to hold more changes. */
797 static int
798 event_changelist_grow(struct event_changelist *changelist)
799 {
800 	int new_size;
801 	struct event_change *new_changes;
802 	if (changelist->changes_size < 64)
803 		new_size = 64;
804 	else
805 		new_size = changelist->changes_size * 2;
806 
807 	new_changes = mm_realloc(changelist->changes,
808 	    new_size * sizeof(struct event_change));
809 
810 	if (EVUTIL_UNLIKELY(new_changes == NULL))
811 		return (-1);
812 
813 	changelist->changes = new_changes;
814 	changelist->changes_size = new_size;
815 
816 	return (0);
817 }
818 
819 /** Return a pointer to the changelist entry for the file descriptor or signal
820  * 'fd', whose fdinfo is 'fdinfo'.  If none exists, construct it, setting its
821  * old_events field to old_events.
822  */
823 static struct event_change *
824 event_changelist_get_or_construct(struct event_changelist *changelist,
825     evutil_socket_t fd,
826     short old_events,
827     struct event_changelist_fdinfo *fdinfo)
828 {
829 	struct event_change *change;
830 
831 	if (fdinfo->idxplus1 == 0) {
832 		int idx;
833 		EVUTIL_ASSERT(changelist->n_changes <= changelist->changes_size);
834 
835 		if (changelist->n_changes == changelist->changes_size) {
836 			if (event_changelist_grow(changelist) < 0)
837 				return NULL;
838 		}
839 
840 		idx = changelist->n_changes++;
841 		change = &changelist->changes[idx];
842 		fdinfo->idxplus1 = idx + 1;
843 
844 		memset(change, 0, sizeof(struct event_change));
845 		change->fd = fd;
846 		change->old_events = old_events;
847 	} else {
848 		change = &changelist->changes[fdinfo->idxplus1 - 1];
849 		EVUTIL_ASSERT(change->fd == fd);
850 	}
851 	return change;
852 }
853 
854 int
855 event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, short events,
856     void *p)
857 {
858 	struct event_changelist *changelist = &base->changelist;
859 	struct event_changelist_fdinfo *fdinfo = p;
860 	struct event_change *change;
861 
862 	event_changelist_check(base);
863 
864 	change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
865 	if (!change)
866 		return -1;
867 
868 	/* An add replaces any previous delete, but doesn't result in a no-op,
869 	 * since the delete might fail (because the fd had been closed since
870 	 * the last add, for instance. */
871 
872 	if (events & (EV_READ|EV_SIGNAL)) {
873 		change->read_change = EV_CHANGE_ADD |
874 		    (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
875 	}
876 	if (events & EV_WRITE) {
877 		change->write_change = EV_CHANGE_ADD |
878 		    (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
879 	}
880 	if (events & EV_CLOSED) {
881 		change->close_change = EV_CHANGE_ADD |
882 		    (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
883 	}
884 
885 	event_changelist_check(base);
886 	return (0);
887 }
888 
889 int
890 event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events,
891     void *p)
892 {
893 	struct event_changelist *changelist = &base->changelist;
894 	struct event_changelist_fdinfo *fdinfo = p;
895 	struct event_change *change;
896 
897 	event_changelist_check(base);
898 	change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
899 	event_changelist_check(base);
900 	if (!change)
901 		return -1;
902 
903 	/* A delete on an event set that doesn't contain the event to be
904 	   deleted produces a no-op.  This effectively emoves any previous
905 	   uncommitted add, rather than replacing it: on those platforms where
906 	   "add, delete, dispatch" is not the same as "no-op, dispatch", we
907 	   want the no-op behavior.
908 
909 	   If we have a no-op item, we could remove it it from the list
910 	   entirely, but really there's not much point: skipping the no-op
911 	   change when we do the dispatch later is far cheaper than rejuggling
912 	   the array now.
913 
914 	   As this stands, it also lets through deletions of events that are
915 	   not currently set.
916 	 */
917 
918 	if (events & (EV_READ|EV_SIGNAL)) {
919 		if (!(change->old_events & (EV_READ | EV_SIGNAL)))
920 			change->read_change = 0;
921 		else
922 			change->read_change = EV_CHANGE_DEL;
923 	}
924 	if (events & EV_WRITE) {
925 		if (!(change->old_events & EV_WRITE))
926 			change->write_change = 0;
927 		else
928 			change->write_change = EV_CHANGE_DEL;
929 	}
930 	if (events & EV_CLOSED) {
931 		if (!(change->old_events & EV_CLOSED))
932 			change->close_change = 0;
933 		else
934 			change->close_change = EV_CHANGE_DEL;
935 	}
936 
937 	event_changelist_check(base);
938 	return (0);
939 }
940 
941 /* Helper for evmap_check_integrity_: verify that all of the events pending on
942  * given fd are set up correctly, and that the nread and nwrite counts on that
943  * fd are correct. */
944 static int
945 evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd,
946     struct evmap_io *io_info, void *arg)
947 {
948 	struct event *ev;
949 	int n_read = 0, n_write = 0, n_close = 0;
950 
951 	/* First, make sure the list itself isn't corrupt. Otherwise,
952 	 * running LIST_FOREACH could be an exciting adventure. */
953 	EVUTIL_ASSERT_LIST_OK(&io_info->events, event, ev_io_next);
954 
955 	LIST_FOREACH(ev, &io_info->events, ev_io_next) {
956 		EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
957 		EVUTIL_ASSERT(ev->ev_fd == fd);
958 		EVUTIL_ASSERT(!(ev->ev_events & EV_SIGNAL));
959 		EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
960 		if (ev->ev_events & EV_READ)
961 			++n_read;
962 		if (ev->ev_events & EV_WRITE)
963 			++n_write;
964 		if (ev->ev_events & EV_CLOSED)
965 			++n_close;
966 	}
967 
968 	EVUTIL_ASSERT(n_read == io_info->nread);
969 	EVUTIL_ASSERT(n_write == io_info->nwrite);
970 	EVUTIL_ASSERT(n_close == io_info->nclose);
971 
972 	return 0;
973 }
974 
975 /* Helper for evmap_check_integrity_: verify that all of the events pending
976  * on given signal are set up correctly. */
977 static int
978 evmap_signal_check_integrity_fn(struct event_base *base,
979     int signum, struct evmap_signal *sig_info, void *arg)
980 {
981 	struct event *ev;
982 	/* First, make sure the list itself isn't corrupt. */
983 	EVUTIL_ASSERT_LIST_OK(&sig_info->events, event, ev_signal_next);
984 
985 	LIST_FOREACH(ev, &sig_info->events, ev_io_next) {
986 		EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
987 		EVUTIL_ASSERT(ev->ev_fd == signum);
988 		EVUTIL_ASSERT((ev->ev_events & EV_SIGNAL));
989 		EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
990 	}
991 	return 0;
992 }
993 
994 void
995 evmap_check_integrity_(struct event_base *base)
996 {
997 	evmap_io_foreach_fd(base, evmap_io_check_integrity_fn, NULL);
998 	evmap_signal_foreach_signal(base, evmap_signal_check_integrity_fn, NULL);
999 
1000 	if (base->evsel->add == event_changelist_add_)
1001 		event_changelist_assert_ok(base);
1002 }
1003 
1004 /* Helper type for evmap_foreach_event_: Bundles a function to call on every
1005  * event, and the user-provided void* to use as its third argument. */
1006 struct evmap_foreach_event_helper {
1007 	event_base_foreach_event_cb fn;
1008 	void *arg;
1009 };
1010 
1011 /* Helper for evmap_foreach_event_: calls a provided function on every event
1012  * pending on a given fd.  */
1013 static int
1014 evmap_io_foreach_event_fn(struct event_base *base, evutil_socket_t fd,
1015     struct evmap_io *io_info, void *arg)
1016 {
1017 	struct evmap_foreach_event_helper *h = arg;
1018 	struct event *ev;
1019 	int r;
1020 	LIST_FOREACH(ev, &io_info->events, ev_io_next) {
1021 		if ((r = h->fn(base, ev, h->arg)))
1022 			return r;
1023 	}
1024 	return 0;
1025 }
1026 
1027 /* Helper for evmap_foreach_event_: calls a provided function on every event
1028  * pending on a given signal.  */
1029 static int
1030 evmap_signal_foreach_event_fn(struct event_base *base, int signum,
1031     struct evmap_signal *sig_info, void *arg)
1032 {
1033 	struct event *ev;
1034 	struct evmap_foreach_event_helper *h = arg;
1035 	int r;
1036 	LIST_FOREACH(ev, &sig_info->events, ev_signal_next) {
1037 		if ((r = h->fn(base, ev, h->arg)))
1038 			return r;
1039 	}
1040 	return 0;
1041 }
1042 
1043 int
1044 evmap_foreach_event_(struct event_base *base,
1045     event_base_foreach_event_cb fn, void *arg)
1046 {
1047 	struct evmap_foreach_event_helper h;
1048 	int r;
1049 	h.fn = fn;
1050 	h.arg = arg;
1051 	if ((r = evmap_io_foreach_fd(base, evmap_io_foreach_event_fn, &h)))
1052 		return r;
1053 	return evmap_signal_foreach_signal(base, evmap_signal_foreach_event_fn, &h);
1054 }
1055 
1056