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