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