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