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