12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
32b15cb3dSCy Schubert *
42b15cb3dSCy Schubert * Redistribution and use in source and binary forms, with or without
52b15cb3dSCy Schubert * modification, are permitted provided that the following conditions
62b15cb3dSCy Schubert * are met:
72b15cb3dSCy Schubert * 1. Redistributions of source code must retain the above copyright
82b15cb3dSCy Schubert * notice, this list of conditions and the following disclaimer.
92b15cb3dSCy Schubert * 2. Redistributions in binary form must reproduce the above copyright
102b15cb3dSCy Schubert * notice, this list of conditions and the following disclaimer in the
112b15cb3dSCy Schubert * documentation and/or other materials provided with the distribution.
122b15cb3dSCy Schubert * 3. The name of the author may not be used to endorse or promote products
132b15cb3dSCy Schubert * derived from this software without specific prior written permission.
142b15cb3dSCy Schubert *
152b15cb3dSCy Schubert * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
162b15cb3dSCy Schubert * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
172b15cb3dSCy Schubert * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
182b15cb3dSCy Schubert * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
192b15cb3dSCy Schubert * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
202b15cb3dSCy Schubert * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
212b15cb3dSCy Schubert * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
222b15cb3dSCy Schubert * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
232b15cb3dSCy Schubert * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
242b15cb3dSCy Schubert * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
252b15cb3dSCy Schubert */
262b15cb3dSCy Schubert #include "event2/event-config.h"
272b15cb3dSCy Schubert #include "evconfig-private.h"
282b15cb3dSCy Schubert
292b15cb3dSCy Schubert #ifdef _WIN32
302b15cb3dSCy Schubert #include <winsock2.h>
312b15cb3dSCy Schubert #define WIN32_LEAN_AND_MEAN
322b15cb3dSCy Schubert #include <windows.h>
332b15cb3dSCy Schubert #undef WIN32_LEAN_AND_MEAN
342b15cb3dSCy Schubert #endif
352b15cb3dSCy Schubert #include <sys/types.h>
362b15cb3dSCy Schubert #if !defined(_WIN32) && defined(EVENT__HAVE_SYS_TIME_H)
372b15cb3dSCy Schubert #include <sys/time.h>
382b15cb3dSCy Schubert #endif
392b15cb3dSCy Schubert #include <sys/queue.h>
402b15cb3dSCy Schubert #include <stdio.h>
412b15cb3dSCy Schubert #include <stdlib.h>
422b15cb3dSCy Schubert #ifndef _WIN32
432b15cb3dSCy Schubert #include <unistd.h>
442b15cb3dSCy Schubert #endif
452b15cb3dSCy Schubert #include <errno.h>
46*a466cc55SCy Schubert #include <limits.h>
472b15cb3dSCy Schubert #include <signal.h>
482b15cb3dSCy Schubert #include <string.h>
492b15cb3dSCy Schubert #include <time.h>
502b15cb3dSCy Schubert
512b15cb3dSCy Schubert #include "event-internal.h"
522b15cb3dSCy Schubert #include "evmap-internal.h"
532b15cb3dSCy Schubert #include "mm-internal.h"
542b15cb3dSCy Schubert #include "changelist-internal.h"
552b15cb3dSCy Schubert
562b15cb3dSCy Schubert /** An entry for an evmap_io list: notes all the events that want to read or
572b15cb3dSCy Schubert write on a given fd, and the number of each.
582b15cb3dSCy Schubert */
592b15cb3dSCy Schubert struct evmap_io {
602b15cb3dSCy Schubert struct event_dlist events;
612b15cb3dSCy Schubert ev_uint16_t nread;
622b15cb3dSCy Schubert ev_uint16_t nwrite;
632b15cb3dSCy Schubert ev_uint16_t nclose;
642b15cb3dSCy Schubert };
652b15cb3dSCy Schubert
662b15cb3dSCy Schubert /* An entry for an evmap_signal list: notes all the events that want to know
672b15cb3dSCy Schubert when a signal triggers. */
682b15cb3dSCy Schubert struct evmap_signal {
692b15cb3dSCy Schubert struct event_dlist events;
702b15cb3dSCy Schubert };
712b15cb3dSCy Schubert
722b15cb3dSCy Schubert /* On some platforms, fds start at 0 and increment by 1 as they are
732b15cb3dSCy Schubert allocated, and old numbers get used. For these platforms, we
742b15cb3dSCy Schubert implement io maps just like signal maps: as an array of pointers to
752b15cb3dSCy Schubert struct evmap_io. But on other platforms (windows), sockets are not
762b15cb3dSCy Schubert 0-indexed, not necessarily consecutive, and not necessarily reused.
772b15cb3dSCy Schubert There, we use a hashtable to implement evmap_io.
782b15cb3dSCy Schubert */
792b15cb3dSCy Schubert #ifdef EVMAP_USE_HT
802b15cb3dSCy Schubert struct event_map_entry {
812b15cb3dSCy Schubert HT_ENTRY(event_map_entry) map_node;
822b15cb3dSCy Schubert evutil_socket_t fd;
832b15cb3dSCy Schubert union { /* This is a union in case we need to make more things that can
842b15cb3dSCy Schubert be in the hashtable. */
852b15cb3dSCy Schubert struct evmap_io evmap_io;
862b15cb3dSCy Schubert } ent;
872b15cb3dSCy Schubert };
882b15cb3dSCy Schubert
892b15cb3dSCy Schubert /* Helper used by the event_io_map hashtable code; tries to return a good hash
902b15cb3dSCy Schubert * of the fd in e->fd. */
912b15cb3dSCy Schubert static inline unsigned
hashsocket(struct event_map_entry * e)922b15cb3dSCy Schubert hashsocket(struct event_map_entry *e)
932b15cb3dSCy Schubert {
942b15cb3dSCy Schubert /* On win32, in practice, the low 2-3 bits of a SOCKET seem not to
952b15cb3dSCy Schubert * matter. Our hashtable implementation really likes low-order bits,
962b15cb3dSCy Schubert * though, so let's do the rotate-and-add trick. */
972b15cb3dSCy Schubert unsigned h = (unsigned) e->fd;
982b15cb3dSCy Schubert h += (h >> 2) | (h << 30);
992b15cb3dSCy Schubert return h;
1002b15cb3dSCy Schubert }
1012b15cb3dSCy Schubert
1022b15cb3dSCy Schubert /* Helper used by the event_io_map hashtable code; returns true iff e1 and e2
1032b15cb3dSCy Schubert * have the same e->fd. */
1042b15cb3dSCy Schubert static inline int
eqsocket(struct event_map_entry * e1,struct event_map_entry * e2)1052b15cb3dSCy Schubert eqsocket(struct event_map_entry *e1, struct event_map_entry *e2)
1062b15cb3dSCy Schubert {
1072b15cb3dSCy Schubert return e1->fd == e2->fd;
1082b15cb3dSCy Schubert }
1092b15cb3dSCy Schubert
HT_PROTOTYPE(event_io_map,event_map_entry,map_node,hashsocket,eqsocket)1102b15cb3dSCy Schubert HT_PROTOTYPE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket)
1112b15cb3dSCy Schubert HT_GENERATE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket,
1122b15cb3dSCy Schubert 0.5, mm_malloc, mm_realloc, mm_free)
1132b15cb3dSCy Schubert
1142b15cb3dSCy Schubert #define GET_IO_SLOT(x, map, slot, type) \
1152b15cb3dSCy Schubert do { \
1162b15cb3dSCy Schubert struct event_map_entry key_, *ent_; \
1172b15cb3dSCy Schubert key_.fd = slot; \
1182b15cb3dSCy Schubert ent_ = HT_FIND(event_io_map, map, &key_); \
1192b15cb3dSCy Schubert (x) = ent_ ? &ent_->ent.type : NULL; \
1202b15cb3dSCy Schubert } while (0);
1212b15cb3dSCy Schubert
1222b15cb3dSCy Schubert #define GET_IO_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \
1232b15cb3dSCy Schubert do { \
1242b15cb3dSCy Schubert struct event_map_entry key_, *ent_; \
1252b15cb3dSCy Schubert key_.fd = slot; \
1262b15cb3dSCy Schubert HT_FIND_OR_INSERT_(event_io_map, map_node, hashsocket, map, \
1272b15cb3dSCy Schubert event_map_entry, &key_, ptr, \
1282b15cb3dSCy Schubert { \
1292b15cb3dSCy Schubert ent_ = *ptr; \
1302b15cb3dSCy Schubert }, \
1312b15cb3dSCy Schubert { \
1322b15cb3dSCy Schubert ent_ = mm_calloc(1,sizeof(struct event_map_entry)+fdinfo_len); \
1332b15cb3dSCy Schubert if (EVUTIL_UNLIKELY(ent_ == NULL)) \
1342b15cb3dSCy Schubert return (-1); \
1352b15cb3dSCy Schubert ent_->fd = slot; \
1362b15cb3dSCy Schubert (ctor)(&ent_->ent.type); \
1372b15cb3dSCy Schubert HT_FOI_INSERT_(map_node, map, &key_, ent_, ptr) \
1382b15cb3dSCy Schubert }); \
1392b15cb3dSCy Schubert (x) = &ent_->ent.type; \
1402b15cb3dSCy Schubert } while (0)
1412b15cb3dSCy Schubert
1422b15cb3dSCy Schubert void evmap_io_initmap_(struct event_io_map *ctx)
1432b15cb3dSCy Schubert {
1442b15cb3dSCy Schubert HT_INIT(event_io_map, ctx);
1452b15cb3dSCy Schubert }
1462b15cb3dSCy Schubert
evmap_io_clear_(struct event_io_map * ctx)1472b15cb3dSCy Schubert void evmap_io_clear_(struct event_io_map *ctx)
1482b15cb3dSCy Schubert {
1492b15cb3dSCy Schubert struct event_map_entry **ent, **next, *this;
1502b15cb3dSCy Schubert for (ent = HT_START(event_io_map, ctx); ent; ent = next) {
1512b15cb3dSCy Schubert this = *ent;
1522b15cb3dSCy Schubert next = HT_NEXT_RMV(event_io_map, ctx, ent);
1532b15cb3dSCy Schubert mm_free(this);
1542b15cb3dSCy Schubert }
1552b15cb3dSCy Schubert HT_CLEAR(event_io_map, ctx); /* remove all storage held by the ctx. */
1562b15cb3dSCy Schubert }
1572b15cb3dSCy Schubert #endif
1582b15cb3dSCy Schubert
1592b15cb3dSCy Schubert /* Set the variable 'x' to the field in event_map 'map' with fields of type
1602b15cb3dSCy Schubert 'struct type *' corresponding to the fd or signal 'slot'. Set 'x' to NULL
1612b15cb3dSCy Schubert if there are no entries for 'slot'. Does no bounds-checking. */
1622b15cb3dSCy Schubert #define GET_SIGNAL_SLOT(x, map, slot, type) \
1632b15cb3dSCy Schubert (x) = (struct type *)((map)->entries[slot])
1642b15cb3dSCy Schubert /* As GET_SLOT, but construct the entry for 'slot' if it is not present,
1652b15cb3dSCy Schubert by allocating enough memory for a 'struct type', and initializing the new
1662b15cb3dSCy Schubert value by calling the function 'ctor' on it. Makes the function
1672b15cb3dSCy Schubert return -1 on allocation failure.
1682b15cb3dSCy Schubert */
1692b15cb3dSCy Schubert #define GET_SIGNAL_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \
1702b15cb3dSCy Schubert do { \
1712b15cb3dSCy Schubert if ((map)->entries[slot] == NULL) { \
1722b15cb3dSCy Schubert (map)->entries[slot] = \
1732b15cb3dSCy Schubert mm_calloc(1,sizeof(struct type)+fdinfo_len); \
1742b15cb3dSCy Schubert if (EVUTIL_UNLIKELY((map)->entries[slot] == NULL)) \
1752b15cb3dSCy Schubert return (-1); \
1762b15cb3dSCy Schubert (ctor)((struct type *)(map)->entries[slot]); \
1772b15cb3dSCy Schubert } \
1782b15cb3dSCy Schubert (x) = (struct type *)((map)->entries[slot]); \
1792b15cb3dSCy Schubert } while (0)
1802b15cb3dSCy Schubert
1812b15cb3dSCy Schubert /* If we aren't using hashtables, then define the IO_SLOT macros and functions
1822b15cb3dSCy Schubert as thin aliases over the SIGNAL_SLOT versions. */
1832b15cb3dSCy Schubert #ifndef EVMAP_USE_HT
1842b15cb3dSCy Schubert #define GET_IO_SLOT(x,map,slot,type) GET_SIGNAL_SLOT(x,map,slot,type)
1852b15cb3dSCy Schubert #define GET_IO_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len) \
1862b15cb3dSCy Schubert GET_SIGNAL_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)
1872b15cb3dSCy Schubert #define FDINFO_OFFSET sizeof(struct evmap_io)
1882b15cb3dSCy Schubert void
evmap_io_initmap_(struct event_io_map * ctx)1892b15cb3dSCy Schubert evmap_io_initmap_(struct event_io_map* ctx)
1902b15cb3dSCy Schubert {
1912b15cb3dSCy Schubert evmap_signal_initmap_(ctx);
1922b15cb3dSCy Schubert }
1932b15cb3dSCy Schubert void
evmap_io_clear_(struct event_io_map * ctx)1942b15cb3dSCy Schubert evmap_io_clear_(struct event_io_map* ctx)
1952b15cb3dSCy Schubert {
1962b15cb3dSCy Schubert evmap_signal_clear_(ctx);
1972b15cb3dSCy Schubert }
1982b15cb3dSCy Schubert #endif
1992b15cb3dSCy Schubert
2002b15cb3dSCy Schubert
2012b15cb3dSCy Schubert /** Expand 'map' with new entries of width 'msize' until it is big enough
2022b15cb3dSCy Schubert to store a value in 'slot'.
2032b15cb3dSCy Schubert */
2042b15cb3dSCy Schubert static int
evmap_make_space(struct event_signal_map * map,int slot,int msize)2052b15cb3dSCy Schubert evmap_make_space(struct event_signal_map *map, int slot, int msize)
2062b15cb3dSCy Schubert {
2072b15cb3dSCy Schubert if (map->nentries <= slot) {
2082b15cb3dSCy Schubert int nentries = map->nentries ? map->nentries : 32;
2092b15cb3dSCy Schubert void **tmp;
2102b15cb3dSCy Schubert
211*a466cc55SCy Schubert if (slot > INT_MAX / 2)
212*a466cc55SCy Schubert return (-1);
213*a466cc55SCy Schubert
2142b15cb3dSCy Schubert while (nentries <= slot)
2152b15cb3dSCy Schubert nentries <<= 1;
2162b15cb3dSCy Schubert
217*a466cc55SCy Schubert if (nentries > INT_MAX / msize)
218*a466cc55SCy Schubert return (-1);
219*a466cc55SCy Schubert
2202b15cb3dSCy Schubert tmp = (void **)mm_realloc(map->entries, nentries * msize);
2212b15cb3dSCy Schubert if (tmp == NULL)
2222b15cb3dSCy Schubert return (-1);
2232b15cb3dSCy Schubert
2242b15cb3dSCy Schubert memset(&tmp[map->nentries], 0,
2252b15cb3dSCy Schubert (nentries - map->nentries) * msize);
2262b15cb3dSCy Schubert
2272b15cb3dSCy Schubert map->nentries = nentries;
2282b15cb3dSCy Schubert map->entries = tmp;
2292b15cb3dSCy Schubert }
2302b15cb3dSCy Schubert
2312b15cb3dSCy Schubert return (0);
2322b15cb3dSCy Schubert }
2332b15cb3dSCy Schubert
2342b15cb3dSCy Schubert void
evmap_signal_initmap_(struct event_signal_map * ctx)2352b15cb3dSCy Schubert evmap_signal_initmap_(struct event_signal_map *ctx)
2362b15cb3dSCy Schubert {
2372b15cb3dSCy Schubert ctx->nentries = 0;
2382b15cb3dSCy Schubert ctx->entries = NULL;
2392b15cb3dSCy Schubert }
2402b15cb3dSCy Schubert
2412b15cb3dSCy Schubert void
evmap_signal_clear_(struct event_signal_map * ctx)2422b15cb3dSCy Schubert evmap_signal_clear_(struct event_signal_map *ctx)
2432b15cb3dSCy Schubert {
2442b15cb3dSCy Schubert if (ctx->entries != NULL) {
2452b15cb3dSCy Schubert int i;
2462b15cb3dSCy Schubert for (i = 0; i < ctx->nentries; ++i) {
2472b15cb3dSCy Schubert if (ctx->entries[i] != NULL)
2482b15cb3dSCy Schubert mm_free(ctx->entries[i]);
2492b15cb3dSCy Schubert }
2502b15cb3dSCy Schubert mm_free(ctx->entries);
2512b15cb3dSCy Schubert ctx->entries = NULL;
2522b15cb3dSCy Schubert }
2532b15cb3dSCy Schubert ctx->nentries = 0;
2542b15cb3dSCy Schubert }
2552b15cb3dSCy Schubert
2562b15cb3dSCy Schubert
2572b15cb3dSCy Schubert /* code specific to file descriptors */
2582b15cb3dSCy Schubert
2592b15cb3dSCy Schubert /** Constructor for struct evmap_io */
2602b15cb3dSCy Schubert static void
evmap_io_init(struct evmap_io * entry)2612b15cb3dSCy Schubert evmap_io_init(struct evmap_io *entry)
2622b15cb3dSCy Schubert {
2632b15cb3dSCy Schubert LIST_INIT(&entry->events);
2642b15cb3dSCy Schubert entry->nread = 0;
2652b15cb3dSCy Schubert entry->nwrite = 0;
2662b15cb3dSCy Schubert entry->nclose = 0;
2672b15cb3dSCy Schubert }
2682b15cb3dSCy Schubert
2692b15cb3dSCy Schubert
2702b15cb3dSCy Schubert /* return -1 on error, 0 on success if nothing changed in the event backend,
2712b15cb3dSCy Schubert * and 1 on success if something did. */
2722b15cb3dSCy Schubert int
evmap_io_add_(struct event_base * base,evutil_socket_t fd,struct event * ev)2732b15cb3dSCy Schubert evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
2742b15cb3dSCy Schubert {
2752b15cb3dSCy Schubert const struct eventop *evsel = base->evsel;
2762b15cb3dSCy Schubert struct event_io_map *io = &base->io;
2772b15cb3dSCy Schubert struct evmap_io *ctx = NULL;
2782b15cb3dSCy Schubert int nread, nwrite, nclose, retval = 0;
2792b15cb3dSCy Schubert short res = 0, old = 0;
2802b15cb3dSCy Schubert struct event *old_ev;
2812b15cb3dSCy Schubert
2822b15cb3dSCy Schubert EVUTIL_ASSERT(fd == ev->ev_fd);
2832b15cb3dSCy Schubert
2842b15cb3dSCy Schubert if (fd < 0)
2852b15cb3dSCy Schubert return 0;
2862b15cb3dSCy Schubert
2872b15cb3dSCy Schubert #ifndef EVMAP_USE_HT
2882b15cb3dSCy Schubert if (fd >= io->nentries) {
2892b15cb3dSCy Schubert if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1)
2902b15cb3dSCy Schubert return (-1);
2912b15cb3dSCy Schubert }
2922b15cb3dSCy Schubert #endif
2932b15cb3dSCy Schubert GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init,
2942b15cb3dSCy Schubert evsel->fdinfo_len);
2952b15cb3dSCy Schubert
2962b15cb3dSCy Schubert nread = ctx->nread;
2972b15cb3dSCy Schubert nwrite = ctx->nwrite;
2982b15cb3dSCy Schubert nclose = ctx->nclose;
2992b15cb3dSCy Schubert
3002b15cb3dSCy Schubert if (nread)
3012b15cb3dSCy Schubert old |= EV_READ;
3022b15cb3dSCy Schubert if (nwrite)
3032b15cb3dSCy Schubert old |= EV_WRITE;
3042b15cb3dSCy Schubert if (nclose)
3052b15cb3dSCy Schubert old |= EV_CLOSED;
3062b15cb3dSCy Schubert
3072b15cb3dSCy Schubert if (ev->ev_events & EV_READ) {
3082b15cb3dSCy Schubert if (++nread == 1)
3092b15cb3dSCy Schubert res |= EV_READ;
3102b15cb3dSCy Schubert }
3112b15cb3dSCy Schubert if (ev->ev_events & EV_WRITE) {
3122b15cb3dSCy Schubert if (++nwrite == 1)
3132b15cb3dSCy Schubert res |= EV_WRITE;
3142b15cb3dSCy Schubert }
3152b15cb3dSCy Schubert if (ev->ev_events & EV_CLOSED) {
3162b15cb3dSCy Schubert if (++nclose == 1)
3172b15cb3dSCy Schubert res |= EV_CLOSED;
3182b15cb3dSCy Schubert }
3192b15cb3dSCy Schubert if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) {
3202b15cb3dSCy Schubert event_warnx("Too many events reading or writing on fd %d",
3212b15cb3dSCy Schubert (int)fd);
3222b15cb3dSCy Schubert return -1;
3232b15cb3dSCy Schubert }
3242b15cb3dSCy Schubert if (EVENT_DEBUG_MODE_IS_ON() &&
3252b15cb3dSCy Schubert (old_ev = LIST_FIRST(&ctx->events)) &&
3262b15cb3dSCy Schubert (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) {
3272b15cb3dSCy Schubert event_warnx("Tried to mix edge-triggered and non-edge-triggered"
3282b15cb3dSCy Schubert " events on fd %d", (int)fd);
3292b15cb3dSCy Schubert return -1;
3302b15cb3dSCy Schubert }
3312b15cb3dSCy Schubert
3322b15cb3dSCy Schubert if (res) {
3332b15cb3dSCy Schubert void *extra = ((char*)ctx) + sizeof(struct evmap_io);
3342b15cb3dSCy Schubert /* XXX(niels): we cannot mix edge-triggered and
3352b15cb3dSCy Schubert * level-triggered, we should probably assert on
3362b15cb3dSCy Schubert * this. */
3372b15cb3dSCy Schubert if (evsel->add(base, ev->ev_fd,
3382b15cb3dSCy Schubert old, (ev->ev_events & EV_ET) | res, extra) == -1)
3392b15cb3dSCy Schubert return (-1);
3402b15cb3dSCy Schubert retval = 1;
3412b15cb3dSCy Schubert }
3422b15cb3dSCy Schubert
3432b15cb3dSCy Schubert ctx->nread = (ev_uint16_t) nread;
3442b15cb3dSCy Schubert ctx->nwrite = (ev_uint16_t) nwrite;
3452b15cb3dSCy Schubert ctx->nclose = (ev_uint16_t) nclose;
3462b15cb3dSCy Schubert LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next);
3472b15cb3dSCy Schubert
3482b15cb3dSCy Schubert return (retval);
3492b15cb3dSCy Schubert }
3502b15cb3dSCy Schubert
3512b15cb3dSCy Schubert /* return -1 on error, 0 on success if nothing changed in the event backend,
3522b15cb3dSCy Schubert * and 1 on success if something did. */
3532b15cb3dSCy Schubert int
evmap_io_del_(struct event_base * base,evutil_socket_t fd,struct event * ev)3542b15cb3dSCy Schubert evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
3552b15cb3dSCy Schubert {
3562b15cb3dSCy Schubert const struct eventop *evsel = base->evsel;
3572b15cb3dSCy Schubert struct event_io_map *io = &base->io;
3582b15cb3dSCy Schubert struct evmap_io *ctx;
3592b15cb3dSCy Schubert int nread, nwrite, nclose, retval = 0;
3602b15cb3dSCy Schubert short res = 0, old = 0;
3612b15cb3dSCy Schubert
3622b15cb3dSCy Schubert if (fd < 0)
3632b15cb3dSCy Schubert return 0;
3642b15cb3dSCy Schubert
3652b15cb3dSCy Schubert EVUTIL_ASSERT(fd == ev->ev_fd);
3662b15cb3dSCy Schubert
3672b15cb3dSCy Schubert #ifndef EVMAP_USE_HT
3682b15cb3dSCy Schubert if (fd >= io->nentries)
3692b15cb3dSCy Schubert return (-1);
3702b15cb3dSCy Schubert #endif
3712b15cb3dSCy Schubert
3722b15cb3dSCy Schubert GET_IO_SLOT(ctx, io, fd, evmap_io);
3732b15cb3dSCy Schubert
3742b15cb3dSCy Schubert nread = ctx->nread;
3752b15cb3dSCy Schubert nwrite = ctx->nwrite;
3762b15cb3dSCy Schubert nclose = ctx->nclose;
3772b15cb3dSCy Schubert
3782b15cb3dSCy Schubert if (nread)
3792b15cb3dSCy Schubert old |= EV_READ;
3802b15cb3dSCy Schubert if (nwrite)
3812b15cb3dSCy Schubert old |= EV_WRITE;
3822b15cb3dSCy Schubert if (nclose)
3832b15cb3dSCy Schubert old |= EV_CLOSED;
3842b15cb3dSCy Schubert
3852b15cb3dSCy Schubert if (ev->ev_events & EV_READ) {
3862b15cb3dSCy Schubert if (--nread == 0)
3872b15cb3dSCy Schubert res |= EV_READ;
3882b15cb3dSCy Schubert EVUTIL_ASSERT(nread >= 0);
3892b15cb3dSCy Schubert }
3902b15cb3dSCy Schubert if (ev->ev_events & EV_WRITE) {
3912b15cb3dSCy Schubert if (--nwrite == 0)
3922b15cb3dSCy Schubert res |= EV_WRITE;
3932b15cb3dSCy Schubert EVUTIL_ASSERT(nwrite >= 0);
3942b15cb3dSCy Schubert }
3952b15cb3dSCy Schubert if (ev->ev_events & EV_CLOSED) {
3962b15cb3dSCy Schubert if (--nclose == 0)
3972b15cb3dSCy Schubert res |= EV_CLOSED;
3982b15cb3dSCy Schubert EVUTIL_ASSERT(nclose >= 0);
3992b15cb3dSCy Schubert }
4002b15cb3dSCy Schubert
4012b15cb3dSCy Schubert if (res) {
4022b15cb3dSCy Schubert void *extra = ((char*)ctx) + sizeof(struct evmap_io);
403*a466cc55SCy Schubert if (evsel->del(base, ev->ev_fd,
404*a466cc55SCy Schubert old, (ev->ev_events & EV_ET) | res, extra) == -1) {
4052b15cb3dSCy Schubert retval = -1;
4062b15cb3dSCy Schubert } else {
4072b15cb3dSCy Schubert retval = 1;
4082b15cb3dSCy Schubert }
4092b15cb3dSCy Schubert }
4102b15cb3dSCy Schubert
4112b15cb3dSCy Schubert ctx->nread = nread;
4122b15cb3dSCy Schubert ctx->nwrite = nwrite;
4132b15cb3dSCy Schubert ctx->nclose = nclose;
4142b15cb3dSCy Schubert LIST_REMOVE(ev, ev_io_next);
4152b15cb3dSCy Schubert
4162b15cb3dSCy Schubert return (retval);
4172b15cb3dSCy Schubert }
4182b15cb3dSCy Schubert
4192b15cb3dSCy Schubert void
evmap_io_active_(struct event_base * base,evutil_socket_t fd,short events)4202b15cb3dSCy Schubert evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events)
4212b15cb3dSCy Schubert {
4222b15cb3dSCy Schubert struct event_io_map *io = &base->io;
4232b15cb3dSCy Schubert struct evmap_io *ctx;
4242b15cb3dSCy Schubert struct event *ev;
4252b15cb3dSCy Schubert
4262b15cb3dSCy Schubert #ifndef EVMAP_USE_HT
4272b15cb3dSCy Schubert if (fd < 0 || fd >= io->nentries)
4282b15cb3dSCy Schubert return;
4292b15cb3dSCy Schubert #endif
4302b15cb3dSCy Schubert GET_IO_SLOT(ctx, io, fd, evmap_io);
4312b15cb3dSCy Schubert
4322b15cb3dSCy Schubert if (NULL == ctx)
4332b15cb3dSCy Schubert return;
4342b15cb3dSCy Schubert LIST_FOREACH(ev, &ctx->events, ev_io_next) {
435*a466cc55SCy Schubert if (ev->ev_events & (events & ~EV_ET))
4362b15cb3dSCy Schubert event_active_nolock_(ev, ev->ev_events & events, 1);
4372b15cb3dSCy Schubert }
4382b15cb3dSCy Schubert }
4392b15cb3dSCy Schubert
4402b15cb3dSCy Schubert /* code specific to signals */
4412b15cb3dSCy Schubert
4422b15cb3dSCy Schubert static void
evmap_signal_init(struct evmap_signal * entry)4432b15cb3dSCy Schubert evmap_signal_init(struct evmap_signal *entry)
4442b15cb3dSCy Schubert {
4452b15cb3dSCy Schubert LIST_INIT(&entry->events);
4462b15cb3dSCy Schubert }
4472b15cb3dSCy Schubert
4482b15cb3dSCy Schubert
4492b15cb3dSCy Schubert int
evmap_signal_add_(struct event_base * base,int sig,struct event * ev)4502b15cb3dSCy Schubert evmap_signal_add_(struct event_base *base, int sig, struct event *ev)
4512b15cb3dSCy Schubert {
4522b15cb3dSCy Schubert const struct eventop *evsel = base->evsigsel;
4532b15cb3dSCy Schubert struct event_signal_map *map = &base->sigmap;
4542b15cb3dSCy Schubert struct evmap_signal *ctx = NULL;
4552b15cb3dSCy Schubert
456*a466cc55SCy Schubert if (sig < 0 || sig >= NSIG)
457*a466cc55SCy Schubert return (-1);
458*a466cc55SCy Schubert
4592b15cb3dSCy Schubert if (sig >= map->nentries) {
4602b15cb3dSCy Schubert if (evmap_make_space(
4612b15cb3dSCy Schubert map, sig, sizeof(struct evmap_signal *)) == -1)
4622b15cb3dSCy Schubert return (-1);
4632b15cb3dSCy Schubert }
4642b15cb3dSCy Schubert GET_SIGNAL_SLOT_AND_CTOR(ctx, map, sig, evmap_signal, evmap_signal_init,
4652b15cb3dSCy Schubert base->evsigsel->fdinfo_len);
4662b15cb3dSCy Schubert
4672b15cb3dSCy Schubert if (LIST_EMPTY(&ctx->events)) {
4682b15cb3dSCy Schubert if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL)
4692b15cb3dSCy Schubert == -1)
4702b15cb3dSCy Schubert return (-1);
4712b15cb3dSCy Schubert }
4722b15cb3dSCy Schubert
4732b15cb3dSCy Schubert LIST_INSERT_HEAD(&ctx->events, ev, ev_signal_next);
4742b15cb3dSCy Schubert
4752b15cb3dSCy Schubert return (1);
4762b15cb3dSCy Schubert }
4772b15cb3dSCy Schubert
4782b15cb3dSCy Schubert int
evmap_signal_del_(struct event_base * base,int sig,struct event * ev)4792b15cb3dSCy Schubert evmap_signal_del_(struct event_base *base, int sig, struct event *ev)
4802b15cb3dSCy Schubert {
4812b15cb3dSCy Schubert const struct eventop *evsel = base->evsigsel;
4822b15cb3dSCy Schubert struct event_signal_map *map = &base->sigmap;
4832b15cb3dSCy Schubert struct evmap_signal *ctx;
4842b15cb3dSCy Schubert
485*a466cc55SCy Schubert if (sig < 0 || sig >= map->nentries)
4862b15cb3dSCy Schubert return (-1);
4872b15cb3dSCy Schubert
4882b15cb3dSCy Schubert GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
4892b15cb3dSCy Schubert
4902b15cb3dSCy Schubert LIST_REMOVE(ev, ev_signal_next);
4912b15cb3dSCy Schubert
4922b15cb3dSCy Schubert if (LIST_FIRST(&ctx->events) == NULL) {
4932b15cb3dSCy Schubert if (evsel->del(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1)
4942b15cb3dSCy Schubert return (-1);
4952b15cb3dSCy Schubert }
4962b15cb3dSCy Schubert
4972b15cb3dSCy Schubert return (1);
4982b15cb3dSCy Schubert }
4992b15cb3dSCy Schubert
5002b15cb3dSCy Schubert void
evmap_signal_active_(struct event_base * base,evutil_socket_t sig,int ncalls)5012b15cb3dSCy Schubert evmap_signal_active_(struct event_base *base, evutil_socket_t sig, int ncalls)
5022b15cb3dSCy Schubert {
5032b15cb3dSCy Schubert struct event_signal_map *map = &base->sigmap;
5042b15cb3dSCy Schubert struct evmap_signal *ctx;
5052b15cb3dSCy Schubert struct event *ev;
5062b15cb3dSCy Schubert
5072b15cb3dSCy Schubert if (sig < 0 || sig >= map->nentries)
5082b15cb3dSCy Schubert return;
5092b15cb3dSCy Schubert GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
5102b15cb3dSCy Schubert
5112b15cb3dSCy Schubert if (!ctx)
5122b15cb3dSCy Schubert return;
5132b15cb3dSCy Schubert LIST_FOREACH(ev, &ctx->events, ev_signal_next)
5142b15cb3dSCy Schubert event_active_nolock_(ev, EV_SIGNAL, ncalls);
5152b15cb3dSCy Schubert }
5162b15cb3dSCy Schubert
5172b15cb3dSCy Schubert void *
evmap_io_get_fdinfo_(struct event_io_map * map,evutil_socket_t fd)5182b15cb3dSCy Schubert evmap_io_get_fdinfo_(struct event_io_map *map, evutil_socket_t fd)
5192b15cb3dSCy Schubert {
5202b15cb3dSCy Schubert struct evmap_io *ctx;
5212b15cb3dSCy Schubert GET_IO_SLOT(ctx, map, fd, evmap_io);
5222b15cb3dSCy Schubert if (ctx)
5232b15cb3dSCy Schubert return ((char*)ctx) + sizeof(struct evmap_io);
5242b15cb3dSCy Schubert else
5252b15cb3dSCy Schubert return NULL;
5262b15cb3dSCy Schubert }
5272b15cb3dSCy Schubert
5282b15cb3dSCy Schubert /* Callback type for evmap_io_foreach_fd */
5292b15cb3dSCy Schubert typedef int (*evmap_io_foreach_fd_cb)(
5302b15cb3dSCy Schubert struct event_base *, evutil_socket_t, struct evmap_io *, void *);
5312b15cb3dSCy Schubert
5322b15cb3dSCy Schubert /* Multipurpose helper function: Iterate over every file descriptor event_base
5332b15cb3dSCy Schubert * for which we could have EV_READ or EV_WRITE events. For each such fd, call
5342b15cb3dSCy Schubert * fn(base, signum, evmap_io, arg), where fn is the user-provided
5352b15cb3dSCy Schubert * function, base is the event_base, signum is the signal number, evmap_io
5362b15cb3dSCy Schubert * is an evmap_io structure containing a list of events pending on the
5372b15cb3dSCy Schubert * file descriptor, and arg is the user-supplied argument.
5382b15cb3dSCy Schubert *
5392b15cb3dSCy Schubert * If fn returns 0, continue on to the next signal. Otherwise, return the same
5402b15cb3dSCy Schubert * value that fn returned.
5412b15cb3dSCy Schubert *
5422b15cb3dSCy Schubert * Note that there is no guarantee that the file descriptors will be processed
5432b15cb3dSCy Schubert * in any particular order.
5442b15cb3dSCy Schubert */
5452b15cb3dSCy Schubert static int
evmap_io_foreach_fd(struct event_base * base,evmap_io_foreach_fd_cb fn,void * arg)5462b15cb3dSCy Schubert evmap_io_foreach_fd(struct event_base *base,
5472b15cb3dSCy Schubert evmap_io_foreach_fd_cb fn,
5482b15cb3dSCy Schubert void *arg)
5492b15cb3dSCy Schubert {
5502b15cb3dSCy Schubert evutil_socket_t fd;
5512b15cb3dSCy Schubert struct event_io_map *iomap = &base->io;
5522b15cb3dSCy Schubert int r = 0;
5532b15cb3dSCy Schubert #ifdef EVMAP_USE_HT
5542b15cb3dSCy Schubert struct event_map_entry **mapent;
5552b15cb3dSCy Schubert HT_FOREACH(mapent, event_io_map, iomap) {
5562b15cb3dSCy Schubert struct evmap_io *ctx = &(*mapent)->ent.evmap_io;
5572b15cb3dSCy Schubert fd = (*mapent)->fd;
5582b15cb3dSCy Schubert #else
5592b15cb3dSCy Schubert for (fd = 0; fd < iomap->nentries; ++fd) {
5602b15cb3dSCy Schubert struct evmap_io *ctx = iomap->entries[fd];
5612b15cb3dSCy Schubert if (!ctx)
5622b15cb3dSCy Schubert continue;
5632b15cb3dSCy Schubert #endif
5642b15cb3dSCy Schubert if ((r = fn(base, fd, ctx, arg)))
5652b15cb3dSCy Schubert break;
5662b15cb3dSCy Schubert }
5672b15cb3dSCy Schubert return r;
5682b15cb3dSCy Schubert }
5692b15cb3dSCy Schubert
5702b15cb3dSCy Schubert /* Callback type for evmap_signal_foreach_signal */
5712b15cb3dSCy Schubert typedef int (*evmap_signal_foreach_signal_cb)(
5722b15cb3dSCy Schubert struct event_base *, int, struct evmap_signal *, void *);
5732b15cb3dSCy Schubert
5742b15cb3dSCy Schubert /* Multipurpose helper function: Iterate over every signal number in the
5752b15cb3dSCy Schubert * event_base for which we could have signal events. For each such signal,
5762b15cb3dSCy Schubert * call fn(base, signum, evmap_signal, arg), where fn is the user-provided
5772b15cb3dSCy Schubert * function, base is the event_base, signum is the signal number, evmap_signal
5782b15cb3dSCy Schubert * is an evmap_signal structure containing a list of events pending on the
5792b15cb3dSCy Schubert * signal, and arg is the user-supplied argument.
5802b15cb3dSCy Schubert *
5812b15cb3dSCy Schubert * If fn returns 0, continue on to the next signal. Otherwise, return the same
5822b15cb3dSCy Schubert * value that fn returned.
5832b15cb3dSCy Schubert */
5842b15cb3dSCy Schubert static int
5852b15cb3dSCy Schubert evmap_signal_foreach_signal(struct event_base *base,
5862b15cb3dSCy Schubert evmap_signal_foreach_signal_cb fn,
5872b15cb3dSCy Schubert void *arg)
5882b15cb3dSCy Schubert {
5892b15cb3dSCy Schubert struct event_signal_map *sigmap = &base->sigmap;
5902b15cb3dSCy Schubert int r = 0;
5912b15cb3dSCy Schubert int signum;
5922b15cb3dSCy Schubert
5932b15cb3dSCy Schubert for (signum = 0; signum < sigmap->nentries; ++signum) {
5942b15cb3dSCy Schubert struct evmap_signal *ctx = sigmap->entries[signum];
5952b15cb3dSCy Schubert if (!ctx)
5962b15cb3dSCy Schubert continue;
5972b15cb3dSCy Schubert if ((r = fn(base, signum, ctx, arg)))
5982b15cb3dSCy Schubert break;
5992b15cb3dSCy Schubert }
6002b15cb3dSCy Schubert return r;
6012b15cb3dSCy Schubert }
6022b15cb3dSCy Schubert
6032b15cb3dSCy Schubert /* Helper for evmap_reinit_: tell the backend to add every fd for which we have
6042b15cb3dSCy Schubert * pending events, with the appropriate combination of EV_READ, EV_WRITE, and
6052b15cb3dSCy Schubert * EV_ET. */
6062b15cb3dSCy Schubert static int
6072b15cb3dSCy Schubert evmap_io_reinit_iter_fn(struct event_base *base, evutil_socket_t fd,
6082b15cb3dSCy Schubert struct evmap_io *ctx, void *arg)
6092b15cb3dSCy Schubert {
6102b15cb3dSCy Schubert const struct eventop *evsel = base->evsel;
6112b15cb3dSCy Schubert void *extra;
6122b15cb3dSCy Schubert int *result = arg;
6132b15cb3dSCy Schubert short events = 0;
6142b15cb3dSCy Schubert struct event *ev;
6152b15cb3dSCy Schubert EVUTIL_ASSERT(ctx);
6162b15cb3dSCy Schubert
6172b15cb3dSCy Schubert extra = ((char*)ctx) + sizeof(struct evmap_io);
6182b15cb3dSCy Schubert if (ctx->nread)
6192b15cb3dSCy Schubert events |= EV_READ;
6202b15cb3dSCy Schubert if (ctx->nwrite)
6212b15cb3dSCy Schubert events |= EV_WRITE;
6222b15cb3dSCy Schubert if (ctx->nclose)
6232b15cb3dSCy Schubert events |= EV_CLOSED;
6242b15cb3dSCy Schubert if (evsel->fdinfo_len)
6252b15cb3dSCy Schubert memset(extra, 0, evsel->fdinfo_len);
6262b15cb3dSCy Schubert if (events &&
6272b15cb3dSCy Schubert (ev = LIST_FIRST(&ctx->events)) &&
6282b15cb3dSCy Schubert (ev->ev_events & EV_ET))
6292b15cb3dSCy Schubert events |= EV_ET;
6302b15cb3dSCy Schubert if (evsel->add(base, fd, 0, events, extra) == -1)
6312b15cb3dSCy Schubert *result = -1;
6322b15cb3dSCy Schubert
6332b15cb3dSCy Schubert return 0;
6342b15cb3dSCy Schubert }
6352b15cb3dSCy Schubert
6362b15cb3dSCy Schubert /* Helper for evmap_reinit_: tell the backend to add every signal for which we
6372b15cb3dSCy Schubert * have pending events. */
6382b15cb3dSCy Schubert static int
6392b15cb3dSCy Schubert evmap_signal_reinit_iter_fn(struct event_base *base,
6402b15cb3dSCy Schubert int signum, struct evmap_signal *ctx, void *arg)
6412b15cb3dSCy Schubert {
6422b15cb3dSCy Schubert const struct eventop *evsel = base->evsigsel;
6432b15cb3dSCy Schubert int *result = arg;
6442b15cb3dSCy Schubert
6452b15cb3dSCy Schubert if (!LIST_EMPTY(&ctx->events)) {
6462b15cb3dSCy Schubert if (evsel->add(base, signum, 0, EV_SIGNAL, NULL) == -1)
6472b15cb3dSCy Schubert *result = -1;
6482b15cb3dSCy Schubert }
6492b15cb3dSCy Schubert return 0;
6502b15cb3dSCy Schubert }
6512b15cb3dSCy Schubert
6522b15cb3dSCy Schubert int
6532b15cb3dSCy Schubert evmap_reinit_(struct event_base *base)
6542b15cb3dSCy Schubert {
6552b15cb3dSCy Schubert int result = 0;
6562b15cb3dSCy Schubert
6572b15cb3dSCy Schubert evmap_io_foreach_fd(base, evmap_io_reinit_iter_fn, &result);
6582b15cb3dSCy Schubert if (result < 0)
6592b15cb3dSCy Schubert return -1;
6602b15cb3dSCy Schubert evmap_signal_foreach_signal(base, evmap_signal_reinit_iter_fn, &result);
6612b15cb3dSCy Schubert if (result < 0)
6622b15cb3dSCy Schubert return -1;
6632b15cb3dSCy Schubert return 0;
6642b15cb3dSCy Schubert }
6652b15cb3dSCy Schubert
6662b15cb3dSCy Schubert /* Helper for evmap_delete_all_: delete every event in an event_dlist. */
6672b15cb3dSCy Schubert static int
6682b15cb3dSCy Schubert delete_all_in_dlist(struct event_dlist *dlist)
6692b15cb3dSCy Schubert {
6702b15cb3dSCy Schubert struct event *ev;
6712b15cb3dSCy Schubert while ((ev = LIST_FIRST(dlist)))
6722b15cb3dSCy Schubert event_del(ev);
6732b15cb3dSCy Schubert return 0;
6742b15cb3dSCy Schubert }
6752b15cb3dSCy Schubert
6762b15cb3dSCy Schubert /* Helper for evmap_delete_all_: delete every event pending on an fd. */
6772b15cb3dSCy Schubert static int
6782b15cb3dSCy Schubert evmap_io_delete_all_iter_fn(struct event_base *base, evutil_socket_t fd,
6792b15cb3dSCy Schubert struct evmap_io *io_info, void *arg)
6802b15cb3dSCy Schubert {
6812b15cb3dSCy Schubert return delete_all_in_dlist(&io_info->events);
6822b15cb3dSCy Schubert }
6832b15cb3dSCy Schubert
6842b15cb3dSCy Schubert /* Helper for evmap_delete_all_: delete every event pending on a signal. */
6852b15cb3dSCy Schubert static int
6862b15cb3dSCy Schubert evmap_signal_delete_all_iter_fn(struct event_base *base, int signum,
6872b15cb3dSCy Schubert struct evmap_signal *sig_info, void *arg)
6882b15cb3dSCy Schubert {
6892b15cb3dSCy Schubert return delete_all_in_dlist(&sig_info->events);
6902b15cb3dSCy Schubert }
6912b15cb3dSCy Schubert
6922b15cb3dSCy Schubert void
6932b15cb3dSCy Schubert evmap_delete_all_(struct event_base *base)
6942b15cb3dSCy Schubert {
6952b15cb3dSCy Schubert evmap_signal_foreach_signal(base, evmap_signal_delete_all_iter_fn, NULL);
6962b15cb3dSCy Schubert evmap_io_foreach_fd(base, evmap_io_delete_all_iter_fn, NULL);
6972b15cb3dSCy Schubert }
6982b15cb3dSCy Schubert
6992b15cb3dSCy Schubert /** Per-fd structure for use with changelists. It keeps track, for each fd or
7002b15cb3dSCy Schubert * signal using the changelist, of where its entry in the changelist is.
7012b15cb3dSCy Schubert */
7022b15cb3dSCy Schubert struct event_changelist_fdinfo {
7032b15cb3dSCy Schubert int idxplus1; /* this is the index +1, so that memset(0) will make it
7042b15cb3dSCy Schubert * a no-such-element */
7052b15cb3dSCy Schubert };
7062b15cb3dSCy Schubert
7072b15cb3dSCy Schubert void
7082b15cb3dSCy Schubert event_changelist_init_(struct event_changelist *changelist)
7092b15cb3dSCy Schubert {
7102b15cb3dSCy Schubert changelist->changes = NULL;
7112b15cb3dSCy Schubert changelist->changes_size = 0;
7122b15cb3dSCy Schubert changelist->n_changes = 0;
7132b15cb3dSCy Schubert }
7142b15cb3dSCy Schubert
7152b15cb3dSCy Schubert /** Helper: return the changelist_fdinfo corresponding to a given change. */
7162b15cb3dSCy Schubert static inline struct event_changelist_fdinfo *
7172b15cb3dSCy Schubert event_change_get_fdinfo(struct event_base *base,
7182b15cb3dSCy Schubert const struct event_change *change)
7192b15cb3dSCy Schubert {
7202b15cb3dSCy Schubert char *ptr;
7212b15cb3dSCy Schubert if (change->read_change & EV_CHANGE_SIGNAL) {
7222b15cb3dSCy Schubert struct evmap_signal *ctx;
7232b15cb3dSCy Schubert GET_SIGNAL_SLOT(ctx, &base->sigmap, change->fd, evmap_signal);
7242b15cb3dSCy Schubert ptr = ((char*)ctx) + sizeof(struct evmap_signal);
7252b15cb3dSCy Schubert } else {
7262b15cb3dSCy Schubert struct evmap_io *ctx;
7272b15cb3dSCy Schubert GET_IO_SLOT(ctx, &base->io, change->fd, evmap_io);
7282b15cb3dSCy Schubert ptr = ((char*)ctx) + sizeof(struct evmap_io);
7292b15cb3dSCy Schubert }
7302b15cb3dSCy Schubert return (void*)ptr;
7312b15cb3dSCy Schubert }
7322b15cb3dSCy Schubert
7332b15cb3dSCy Schubert /** Callback helper for event_changelist_assert_ok */
7342b15cb3dSCy Schubert static int
7352b15cb3dSCy Schubert event_changelist_assert_ok_foreach_iter_fn(
7362b15cb3dSCy Schubert struct event_base *base,
7372b15cb3dSCy Schubert evutil_socket_t fd, struct evmap_io *io, void *arg)
7382b15cb3dSCy Schubert {
7392b15cb3dSCy Schubert struct event_changelist *changelist = &base->changelist;
7402b15cb3dSCy Schubert struct event_changelist_fdinfo *f;
7412b15cb3dSCy Schubert f = (void*)
7422b15cb3dSCy Schubert ( ((char*)io) + sizeof(struct evmap_io) );
7432b15cb3dSCy Schubert if (f->idxplus1) {
7442b15cb3dSCy Schubert struct event_change *c = &changelist->changes[f->idxplus1 - 1];
7452b15cb3dSCy Schubert EVUTIL_ASSERT(c->fd == fd);
7462b15cb3dSCy Schubert }
7472b15cb3dSCy Schubert return 0;
7482b15cb3dSCy Schubert }
7492b15cb3dSCy Schubert
7502b15cb3dSCy Schubert /** Make sure that the changelist is consistent with the evmap structures. */
7512b15cb3dSCy Schubert static void
7522b15cb3dSCy Schubert event_changelist_assert_ok(struct event_base *base)
7532b15cb3dSCy Schubert {
7542b15cb3dSCy Schubert int i;
7552b15cb3dSCy Schubert struct event_changelist *changelist = &base->changelist;
7562b15cb3dSCy Schubert
7572b15cb3dSCy Schubert EVUTIL_ASSERT(changelist->changes_size >= changelist->n_changes);
7582b15cb3dSCy Schubert for (i = 0; i < changelist->n_changes; ++i) {
7592b15cb3dSCy Schubert struct event_change *c = &changelist->changes[i];
7602b15cb3dSCy Schubert struct event_changelist_fdinfo *f;
7612b15cb3dSCy Schubert EVUTIL_ASSERT(c->fd >= 0);
7622b15cb3dSCy Schubert f = event_change_get_fdinfo(base, c);
7632b15cb3dSCy Schubert EVUTIL_ASSERT(f);
7642b15cb3dSCy Schubert EVUTIL_ASSERT(f->idxplus1 == i + 1);
7652b15cb3dSCy Schubert }
7662b15cb3dSCy Schubert
7672b15cb3dSCy Schubert evmap_io_foreach_fd(base,
7682b15cb3dSCy Schubert event_changelist_assert_ok_foreach_iter_fn,
7692b15cb3dSCy Schubert NULL);
7702b15cb3dSCy Schubert }
7712b15cb3dSCy Schubert
7722b15cb3dSCy Schubert #ifdef DEBUG_CHANGELIST
7732b15cb3dSCy Schubert #define event_changelist_check(base) event_changelist_assert_ok((base))
7742b15cb3dSCy Schubert #else
7752b15cb3dSCy Schubert #define event_changelist_check(base) ((void)0)
7762b15cb3dSCy Schubert #endif
7772b15cb3dSCy Schubert
7782b15cb3dSCy Schubert void
7792b15cb3dSCy Schubert event_changelist_remove_all_(struct event_changelist *changelist,
7802b15cb3dSCy Schubert struct event_base *base)
7812b15cb3dSCy Schubert {
7822b15cb3dSCy Schubert int i;
7832b15cb3dSCy Schubert
7842b15cb3dSCy Schubert event_changelist_check(base);
7852b15cb3dSCy Schubert
7862b15cb3dSCy Schubert for (i = 0; i < changelist->n_changes; ++i) {
7872b15cb3dSCy Schubert struct event_change *ch = &changelist->changes[i];
7882b15cb3dSCy Schubert struct event_changelist_fdinfo *fdinfo =
7892b15cb3dSCy Schubert event_change_get_fdinfo(base, ch);
7902b15cb3dSCy Schubert EVUTIL_ASSERT(fdinfo->idxplus1 == i + 1);
7912b15cb3dSCy Schubert fdinfo->idxplus1 = 0;
7922b15cb3dSCy Schubert }
7932b15cb3dSCy Schubert
7942b15cb3dSCy Schubert changelist->n_changes = 0;
7952b15cb3dSCy Schubert
7962b15cb3dSCy Schubert event_changelist_check(base);
7972b15cb3dSCy Schubert }
7982b15cb3dSCy Schubert
7992b15cb3dSCy Schubert void
8002b15cb3dSCy Schubert event_changelist_freemem_(struct event_changelist *changelist)
8012b15cb3dSCy Schubert {
8022b15cb3dSCy Schubert if (changelist->changes)
8032b15cb3dSCy Schubert mm_free(changelist->changes);
8042b15cb3dSCy Schubert event_changelist_init_(changelist); /* zero it all out. */
8052b15cb3dSCy Schubert }
8062b15cb3dSCy Schubert
8072b15cb3dSCy Schubert /** Increase the size of 'changelist' to hold more changes. */
8082b15cb3dSCy Schubert static int
8092b15cb3dSCy Schubert event_changelist_grow(struct event_changelist *changelist)
8102b15cb3dSCy Schubert {
8112b15cb3dSCy Schubert int new_size;
8122b15cb3dSCy Schubert struct event_change *new_changes;
8132b15cb3dSCy Schubert if (changelist->changes_size < 64)
8142b15cb3dSCy Schubert new_size = 64;
8152b15cb3dSCy Schubert else
8162b15cb3dSCy Schubert new_size = changelist->changes_size * 2;
8172b15cb3dSCy Schubert
8182b15cb3dSCy Schubert new_changes = mm_realloc(changelist->changes,
8192b15cb3dSCy Schubert new_size * sizeof(struct event_change));
8202b15cb3dSCy Schubert
8212b15cb3dSCy Schubert if (EVUTIL_UNLIKELY(new_changes == NULL))
8222b15cb3dSCy Schubert return (-1);
8232b15cb3dSCy Schubert
8242b15cb3dSCy Schubert changelist->changes = new_changes;
8252b15cb3dSCy Schubert changelist->changes_size = new_size;
8262b15cb3dSCy Schubert
8272b15cb3dSCy Schubert return (0);
8282b15cb3dSCy Schubert }
8292b15cb3dSCy Schubert
8302b15cb3dSCy Schubert /** Return a pointer to the changelist entry for the file descriptor or signal
8312b15cb3dSCy Schubert * 'fd', whose fdinfo is 'fdinfo'. If none exists, construct it, setting its
8322b15cb3dSCy Schubert * old_events field to old_events.
8332b15cb3dSCy Schubert */
8342b15cb3dSCy Schubert static struct event_change *
8352b15cb3dSCy Schubert event_changelist_get_or_construct(struct event_changelist *changelist,
8362b15cb3dSCy Schubert evutil_socket_t fd,
8372b15cb3dSCy Schubert short old_events,
8382b15cb3dSCy Schubert struct event_changelist_fdinfo *fdinfo)
8392b15cb3dSCy Schubert {
8402b15cb3dSCy Schubert struct event_change *change;
8412b15cb3dSCy Schubert
8422b15cb3dSCy Schubert if (fdinfo->idxplus1 == 0) {
8432b15cb3dSCy Schubert int idx;
8442b15cb3dSCy Schubert EVUTIL_ASSERT(changelist->n_changes <= changelist->changes_size);
8452b15cb3dSCy Schubert
8462b15cb3dSCy Schubert if (changelist->n_changes == changelist->changes_size) {
8472b15cb3dSCy Schubert if (event_changelist_grow(changelist) < 0)
8482b15cb3dSCy Schubert return NULL;
8492b15cb3dSCy Schubert }
8502b15cb3dSCy Schubert
8512b15cb3dSCy Schubert idx = changelist->n_changes++;
8522b15cb3dSCy Schubert change = &changelist->changes[idx];
8532b15cb3dSCy Schubert fdinfo->idxplus1 = idx + 1;
8542b15cb3dSCy Schubert
8552b15cb3dSCy Schubert memset(change, 0, sizeof(struct event_change));
8562b15cb3dSCy Schubert change->fd = fd;
8572b15cb3dSCy Schubert change->old_events = old_events;
8582b15cb3dSCy Schubert } else {
8592b15cb3dSCy Schubert change = &changelist->changes[fdinfo->idxplus1 - 1];
8602b15cb3dSCy Schubert EVUTIL_ASSERT(change->fd == fd);
8612b15cb3dSCy Schubert }
8622b15cb3dSCy Schubert return change;
8632b15cb3dSCy Schubert }
8642b15cb3dSCy Schubert
8652b15cb3dSCy Schubert int
8662b15cb3dSCy Schubert event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, short events,
8672b15cb3dSCy Schubert void *p)
8682b15cb3dSCy Schubert {
8692b15cb3dSCy Schubert struct event_changelist *changelist = &base->changelist;
8702b15cb3dSCy Schubert struct event_changelist_fdinfo *fdinfo = p;
8712b15cb3dSCy Schubert struct event_change *change;
872*a466cc55SCy Schubert ev_uint8_t evchange = EV_CHANGE_ADD | (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
8732b15cb3dSCy Schubert
8742b15cb3dSCy Schubert event_changelist_check(base);
8752b15cb3dSCy Schubert
8762b15cb3dSCy Schubert change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
8772b15cb3dSCy Schubert if (!change)
8782b15cb3dSCy Schubert return -1;
8792b15cb3dSCy Schubert
8802b15cb3dSCy Schubert /* An add replaces any previous delete, but doesn't result in a no-op,
8812b15cb3dSCy Schubert * since the delete might fail (because the fd had been closed since
8822b15cb3dSCy Schubert * the last add, for instance. */
8832b15cb3dSCy Schubert
884*a466cc55SCy Schubert if (events & (EV_READ|EV_SIGNAL))
885*a466cc55SCy Schubert change->read_change = evchange;
886*a466cc55SCy Schubert if (events & EV_WRITE)
887*a466cc55SCy Schubert change->write_change = evchange;
888*a466cc55SCy Schubert if (events & EV_CLOSED)
889*a466cc55SCy Schubert change->close_change = evchange;
8902b15cb3dSCy Schubert
8912b15cb3dSCy Schubert event_changelist_check(base);
8922b15cb3dSCy Schubert return (0);
8932b15cb3dSCy Schubert }
8942b15cb3dSCy Schubert
8952b15cb3dSCy Schubert int
8962b15cb3dSCy Schubert event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events,
8972b15cb3dSCy Schubert void *p)
8982b15cb3dSCy Schubert {
8992b15cb3dSCy Schubert struct event_changelist *changelist = &base->changelist;
9002b15cb3dSCy Schubert struct event_changelist_fdinfo *fdinfo = p;
9012b15cb3dSCy Schubert struct event_change *change;
902*a466cc55SCy Schubert ev_uint8_t del = EV_CHANGE_DEL | (events & EV_ET);
9032b15cb3dSCy Schubert
9042b15cb3dSCy Schubert event_changelist_check(base);
9052b15cb3dSCy Schubert change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
9062b15cb3dSCy Schubert event_changelist_check(base);
9072b15cb3dSCy Schubert if (!change)
9082b15cb3dSCy Schubert return -1;
9092b15cb3dSCy Schubert
9102b15cb3dSCy Schubert /* A delete on an event set that doesn't contain the event to be
9112b15cb3dSCy Schubert deleted produces a no-op. This effectively emoves any previous
9122b15cb3dSCy Schubert uncommitted add, rather than replacing it: on those platforms where
9132b15cb3dSCy Schubert "add, delete, dispatch" is not the same as "no-op, dispatch", we
9142b15cb3dSCy Schubert want the no-op behavior.
9152b15cb3dSCy Schubert
9162b15cb3dSCy Schubert If we have a no-op item, we could remove it it from the list
9172b15cb3dSCy Schubert entirely, but really there's not much point: skipping the no-op
9182b15cb3dSCy Schubert change when we do the dispatch later is far cheaper than rejuggling
9192b15cb3dSCy Schubert the array now.
9202b15cb3dSCy Schubert
9212b15cb3dSCy Schubert As this stands, it also lets through deletions of events that are
9222b15cb3dSCy Schubert not currently set.
9232b15cb3dSCy Schubert */
9242b15cb3dSCy Schubert
9252b15cb3dSCy Schubert if (events & (EV_READ|EV_SIGNAL)) {
9262b15cb3dSCy Schubert if (!(change->old_events & (EV_READ | EV_SIGNAL)))
9272b15cb3dSCy Schubert change->read_change = 0;
9282b15cb3dSCy Schubert else
929*a466cc55SCy Schubert change->read_change = del;
9302b15cb3dSCy Schubert }
9312b15cb3dSCy Schubert if (events & EV_WRITE) {
9322b15cb3dSCy Schubert if (!(change->old_events & EV_WRITE))
9332b15cb3dSCy Schubert change->write_change = 0;
9342b15cb3dSCy Schubert else
935*a466cc55SCy Schubert change->write_change = del;
9362b15cb3dSCy Schubert }
9372b15cb3dSCy Schubert if (events & EV_CLOSED) {
9382b15cb3dSCy Schubert if (!(change->old_events & EV_CLOSED))
9392b15cb3dSCy Schubert change->close_change = 0;
9402b15cb3dSCy Schubert else
941*a466cc55SCy Schubert change->close_change = del;
9422b15cb3dSCy Schubert }
9432b15cb3dSCy Schubert
9442b15cb3dSCy Schubert event_changelist_check(base);
9452b15cb3dSCy Schubert return (0);
9462b15cb3dSCy Schubert }
9472b15cb3dSCy Schubert
9482b15cb3dSCy Schubert /* Helper for evmap_check_integrity_: verify that all of the events pending on
9492b15cb3dSCy Schubert * given fd are set up correctly, and that the nread and nwrite counts on that
9502b15cb3dSCy Schubert * fd are correct. */
9512b15cb3dSCy Schubert static int
9522b15cb3dSCy Schubert evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd,
9532b15cb3dSCy Schubert struct evmap_io *io_info, void *arg)
9542b15cb3dSCy Schubert {
9552b15cb3dSCy Schubert struct event *ev;
9562b15cb3dSCy Schubert int n_read = 0, n_write = 0, n_close = 0;
9572b15cb3dSCy Schubert
9582b15cb3dSCy Schubert /* First, make sure the list itself isn't corrupt. Otherwise,
9592b15cb3dSCy Schubert * running LIST_FOREACH could be an exciting adventure. */
9602b15cb3dSCy Schubert EVUTIL_ASSERT_LIST_OK(&io_info->events, event, ev_io_next);
9612b15cb3dSCy Schubert
9622b15cb3dSCy Schubert LIST_FOREACH(ev, &io_info->events, ev_io_next) {
9632b15cb3dSCy Schubert EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
9642b15cb3dSCy Schubert EVUTIL_ASSERT(ev->ev_fd == fd);
9652b15cb3dSCy Schubert EVUTIL_ASSERT(!(ev->ev_events & EV_SIGNAL));
9662b15cb3dSCy Schubert EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
9672b15cb3dSCy Schubert if (ev->ev_events & EV_READ)
9682b15cb3dSCy Schubert ++n_read;
9692b15cb3dSCy Schubert if (ev->ev_events & EV_WRITE)
9702b15cb3dSCy Schubert ++n_write;
9712b15cb3dSCy Schubert if (ev->ev_events & EV_CLOSED)
9722b15cb3dSCy Schubert ++n_close;
9732b15cb3dSCy Schubert }
9742b15cb3dSCy Schubert
9752b15cb3dSCy Schubert EVUTIL_ASSERT(n_read == io_info->nread);
9762b15cb3dSCy Schubert EVUTIL_ASSERT(n_write == io_info->nwrite);
9772b15cb3dSCy Schubert EVUTIL_ASSERT(n_close == io_info->nclose);
9782b15cb3dSCy Schubert
9792b15cb3dSCy Schubert return 0;
9802b15cb3dSCy Schubert }
9812b15cb3dSCy Schubert
9822b15cb3dSCy Schubert /* Helper for evmap_check_integrity_: verify that all of the events pending
9832b15cb3dSCy Schubert * on given signal are set up correctly. */
9842b15cb3dSCy Schubert static int
9852b15cb3dSCy Schubert evmap_signal_check_integrity_fn(struct event_base *base,
9862b15cb3dSCy Schubert int signum, struct evmap_signal *sig_info, void *arg)
9872b15cb3dSCy Schubert {
9882b15cb3dSCy Schubert struct event *ev;
9892b15cb3dSCy Schubert /* First, make sure the list itself isn't corrupt. */
9902b15cb3dSCy Schubert EVUTIL_ASSERT_LIST_OK(&sig_info->events, event, ev_signal_next);
9912b15cb3dSCy Schubert
9922b15cb3dSCy Schubert LIST_FOREACH(ev, &sig_info->events, ev_io_next) {
9932b15cb3dSCy Schubert EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
9942b15cb3dSCy Schubert EVUTIL_ASSERT(ev->ev_fd == signum);
9952b15cb3dSCy Schubert EVUTIL_ASSERT((ev->ev_events & EV_SIGNAL));
9962b15cb3dSCy Schubert EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
9972b15cb3dSCy Schubert }
9982b15cb3dSCy Schubert return 0;
9992b15cb3dSCy Schubert }
10002b15cb3dSCy Schubert
10012b15cb3dSCy Schubert void
10022b15cb3dSCy Schubert evmap_check_integrity_(struct event_base *base)
10032b15cb3dSCy Schubert {
10042b15cb3dSCy Schubert evmap_io_foreach_fd(base, evmap_io_check_integrity_fn, NULL);
10052b15cb3dSCy Schubert evmap_signal_foreach_signal(base, evmap_signal_check_integrity_fn, NULL);
10062b15cb3dSCy Schubert
10072b15cb3dSCy Schubert if (base->evsel->add == event_changelist_add_)
10082b15cb3dSCy Schubert event_changelist_assert_ok(base);
10092b15cb3dSCy Schubert }
10102b15cb3dSCy Schubert
10112b15cb3dSCy Schubert /* Helper type for evmap_foreach_event_: Bundles a function to call on every
10122b15cb3dSCy Schubert * event, and the user-provided void* to use as its third argument. */
10132b15cb3dSCy Schubert struct evmap_foreach_event_helper {
10142b15cb3dSCy Schubert event_base_foreach_event_cb fn;
10152b15cb3dSCy Schubert void *arg;
10162b15cb3dSCy Schubert };
10172b15cb3dSCy Schubert
10182b15cb3dSCy Schubert /* Helper for evmap_foreach_event_: calls a provided function on every event
10192b15cb3dSCy Schubert * pending on a given fd. */
10202b15cb3dSCy Schubert static int
10212b15cb3dSCy Schubert evmap_io_foreach_event_fn(struct event_base *base, evutil_socket_t fd,
10222b15cb3dSCy Schubert struct evmap_io *io_info, void *arg)
10232b15cb3dSCy Schubert {
10242b15cb3dSCy Schubert struct evmap_foreach_event_helper *h = arg;
10252b15cb3dSCy Schubert struct event *ev;
10262b15cb3dSCy Schubert int r;
10272b15cb3dSCy Schubert LIST_FOREACH(ev, &io_info->events, ev_io_next) {
10282b15cb3dSCy Schubert if ((r = h->fn(base, ev, h->arg)))
10292b15cb3dSCy Schubert return r;
10302b15cb3dSCy Schubert }
10312b15cb3dSCy Schubert return 0;
10322b15cb3dSCy Schubert }
10332b15cb3dSCy Schubert
10342b15cb3dSCy Schubert /* Helper for evmap_foreach_event_: calls a provided function on every event
10352b15cb3dSCy Schubert * pending on a given signal. */
10362b15cb3dSCy Schubert static int
10372b15cb3dSCy Schubert evmap_signal_foreach_event_fn(struct event_base *base, int signum,
10382b15cb3dSCy Schubert struct evmap_signal *sig_info, void *arg)
10392b15cb3dSCy Schubert {
10402b15cb3dSCy Schubert struct event *ev;
10412b15cb3dSCy Schubert struct evmap_foreach_event_helper *h = arg;
10422b15cb3dSCy Schubert int r;
10432b15cb3dSCy Schubert LIST_FOREACH(ev, &sig_info->events, ev_signal_next) {
10442b15cb3dSCy Schubert if ((r = h->fn(base, ev, h->arg)))
10452b15cb3dSCy Schubert return r;
10462b15cb3dSCy Schubert }
10472b15cb3dSCy Schubert return 0;
10482b15cb3dSCy Schubert }
10492b15cb3dSCy Schubert
10502b15cb3dSCy Schubert int
10512b15cb3dSCy Schubert evmap_foreach_event_(struct event_base *base,
10522b15cb3dSCy Schubert event_base_foreach_event_cb fn, void *arg)
10532b15cb3dSCy Schubert {
10542b15cb3dSCy Schubert struct evmap_foreach_event_helper h;
10552b15cb3dSCy Schubert int r;
10562b15cb3dSCy Schubert h.fn = fn;
10572b15cb3dSCy Schubert h.arg = arg;
10582b15cb3dSCy Schubert if ((r = evmap_io_foreach_fd(base, evmap_io_foreach_event_fn, &h)))
10592b15cb3dSCy Schubert return r;
10602b15cb3dSCy Schubert return evmap_signal_foreach_signal(base, evmap_signal_foreach_event_fn, &h);
10612b15cb3dSCy Schubert }
10622b15cb3dSCy Schubert
1063