102b2b4d1SNiels Provos /*
2e49e2891SNick Mathewson * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
302b2b4d1SNiels Provos *
402b2b4d1SNiels Provos * Redistribution and use in source and binary forms, with or without
502b2b4d1SNiels Provos * modification, are permitted provided that the following conditions
602b2b4d1SNiels Provos * are met:
702b2b4d1SNiels Provos * 1. Redistributions of source code must retain the above copyright
802b2b4d1SNiels Provos * notice, this list of conditions and the following disclaimer.
902b2b4d1SNiels Provos * 2. Redistributions in binary form must reproduce the above copyright
1002b2b4d1SNiels Provos * notice, this list of conditions and the following disclaimer in the
1102b2b4d1SNiels Provos * documentation and/or other materials provided with the distribution.
1202b2b4d1SNiels Provos * 3. The name of the author may not be used to endorse or promote products
1302b2b4d1SNiels Provos * derived from this software without specific prior written permission.
1402b2b4d1SNiels Provos *
1502b2b4d1SNiels Provos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
1602b2b4d1SNiels Provos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
1702b2b4d1SNiels Provos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
1802b2b4d1SNiels Provos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
1902b2b4d1SNiels Provos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2002b2b4d1SNiels Provos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2102b2b4d1SNiels Provos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
2202b2b4d1SNiels Provos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
2302b2b4d1SNiels Provos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
2402b2b4d1SNiels Provos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
2502b2b4d1SNiels Provos */
26ec347b92SNick Mathewson #include "event2/event-config.h"
270915ca0aSKevin Bowling #include "evconfig-private.h"
2802b2b4d1SNiels Provos
299f560bfaSNick Mathewson #ifdef _WIN32
305b5b880bSNick Mathewson #include <winsock2.h>
3102b2b4d1SNiels Provos #define WIN32_LEAN_AND_MEAN
3202b2b4d1SNiels Provos #include <windows.h>
3302b2b4d1SNiels Provos #undef WIN32_LEAN_AND_MEAN
3402b2b4d1SNiels Provos #endif
3502b2b4d1SNiels Provos #include <sys/types.h>
3668120d9bSNick Mathewson #if !defined(_WIN32) && defined(EVENT__HAVE_SYS_TIME_H)
3702b2b4d1SNiels Provos #include <sys/time.h>
3802b2b4d1SNiels Provos #endif
3902b2b4d1SNiels Provos #include <sys/queue.h>
4002b2b4d1SNiels Provos #include <stdio.h>
4102b2b4d1SNiels Provos #include <stdlib.h>
429f560bfaSNick Mathewson #ifndef _WIN32
4302b2b4d1SNiels Provos #include <unistd.h>
4402b2b4d1SNiels Provos #endif
4502b2b4d1SNiels Provos #include <errno.h>
4687fa93a8SAzat Khuzhin #include <limits.h>
4702b2b4d1SNiels Provos #include <signal.h>
4802b2b4d1SNiels Provos #include <string.h>
4902b2b4d1SNiels Provos #include <time.h>
5002b2b4d1SNiels Provos
5102b2b4d1SNiels Provos #include "event-internal.h"
52169321c9SNick Mathewson #include "evmap-internal.h"
5302b2b4d1SNiels Provos #include "mm-internal.h"
5427308aaeSNick Mathewson #include "changelist-internal.h"
5502b2b4d1SNiels Provos
5655bcd7d2SNick Mathewson /** An entry for an evmap_io list: notes all the events that want to read or
5755bcd7d2SNick Mathewson write on a given fd, and the number of each.
5855bcd7d2SNick Mathewson */
5955bcd7d2SNick Mathewson struct evmap_io {
606494772eSNick Mathewson struct event_dlist events;
61819f949fSNick Mathewson ev_uint16_t nread;
62819f949fSNick Mathewson ev_uint16_t nwrite;
63b1b69ac7SDiego Giagio ev_uint16_t nclose;
6455bcd7d2SNick Mathewson };
6555bcd7d2SNick Mathewson
6655bcd7d2SNick Mathewson /* An entry for an evmap_signal list: notes all the events that want to know
6755bcd7d2SNick Mathewson when a signal triggers. */
6855bcd7d2SNick Mathewson struct evmap_signal {
696494772eSNick Mathewson struct event_dlist events;
7055bcd7d2SNick Mathewson };
7155bcd7d2SNick Mathewson
7255bcd7d2SNick Mathewson /* On some platforms, fds start at 0 and increment by 1 as they are
7355bcd7d2SNick Mathewson allocated, and old numbers get used. For these platforms, we
7455bcd7d2SNick Mathewson implement io maps just like signal maps: as an array of pointers to
7555bcd7d2SNick Mathewson struct evmap_io. But on other platforms (windows), sockets are not
7655bcd7d2SNick Mathewson 0-indexed, not necessarily consecutive, and not necessarily reused.
7755bcd7d2SNick Mathewson There, we use a hashtable to implement evmap_io.
7855bcd7d2SNick Mathewson */
7955bcd7d2SNick Mathewson #ifdef EVMAP_USE_HT
8055bcd7d2SNick Mathewson struct event_map_entry {
8155bcd7d2SNick Mathewson HT_ENTRY(event_map_entry) map_node;
8255bcd7d2SNick Mathewson evutil_socket_t fd;
8355bcd7d2SNick Mathewson union { /* This is a union in case we need to make more things that can
8455bcd7d2SNick Mathewson be in the hashtable. */
8555bcd7d2SNick Mathewson struct evmap_io evmap_io;
8655bcd7d2SNick Mathewson } ent;
8755bcd7d2SNick Mathewson };
8855bcd7d2SNick Mathewson
89c247adc7SNick Mathewson /* Helper used by the event_io_map hashtable code; tries to return a good hash
90c247adc7SNick Mathewson * of the fd in e->fd. */
9155bcd7d2SNick Mathewson static inline unsigned
hashsocket(struct event_map_entry * e)9255bcd7d2SNick Mathewson hashsocket(struct event_map_entry *e)
9355bcd7d2SNick Mathewson {
9491e3ead8SNick Mathewson /* On win32, in practice, the low 2-3 bits of a SOCKET seem not to
9591e3ead8SNick Mathewson * matter. Our hashtable implementation really likes low-order bits,
9691e3ead8SNick Mathewson * though, so let's do the rotate-and-add trick. */
9791e3ead8SNick Mathewson unsigned h = (unsigned) e->fd;
9891e3ead8SNick Mathewson h += (h >> 2) | (h << 30);
9991e3ead8SNick Mathewson return h;
10055bcd7d2SNick Mathewson }
10155bcd7d2SNick Mathewson
102c247adc7SNick Mathewson /* Helper used by the event_io_map hashtable code; returns true iff e1 and e2
103c247adc7SNick Mathewson * have the same e->fd. */
10455bcd7d2SNick Mathewson static inline int
eqsocket(struct event_map_entry * e1,struct event_map_entry * e2)10555bcd7d2SNick Mathewson eqsocket(struct event_map_entry *e1, struct event_map_entry *e2)
10655bcd7d2SNick Mathewson {
10755bcd7d2SNick Mathewson return e1->fd == e2->fd;
10855bcd7d2SNick Mathewson }
10955bcd7d2SNick Mathewson
HT_PROTOTYPE(event_io_map,event_map_entry,map_node,hashsocket,eqsocket)110e56ff65aSNick Mathewson HT_PROTOTYPE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket)
11155bcd7d2SNick Mathewson HT_GENERATE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket,
112e56ff65aSNick Mathewson 0.5, mm_malloc, mm_realloc, mm_free)
11355bcd7d2SNick Mathewson
11455bcd7d2SNick Mathewson #define GET_IO_SLOT(x, map, slot, type) \
11555bcd7d2SNick Mathewson do { \
116946b5841SNick Mathewson struct event_map_entry key_, *ent_; \
117946b5841SNick Mathewson key_.fd = slot; \
118946b5841SNick Mathewson ent_ = HT_FIND(event_io_map, map, &key_); \
119946b5841SNick Mathewson (x) = ent_ ? &ent_->ent.type : NULL; \
12055bcd7d2SNick Mathewson } while (0);
12155bcd7d2SNick Mathewson
122554e1493SNick Mathewson #define GET_IO_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \
12355bcd7d2SNick Mathewson do { \
124946b5841SNick Mathewson struct event_map_entry key_, *ent_; \
125946b5841SNick Mathewson key_.fd = slot; \
126066775e3SNick Mathewson HT_FIND_OR_INSERT_(event_io_map, map_node, hashsocket, map, \
127946b5841SNick Mathewson event_map_entry, &key_, ptr, \
12855bcd7d2SNick Mathewson { \
129946b5841SNick Mathewson ent_ = *ptr; \
13055bcd7d2SNick Mathewson }, \
13155bcd7d2SNick Mathewson { \
132946b5841SNick Mathewson ent_ = mm_calloc(1,sizeof(struct event_map_entry)+fdinfo_len); \
133946b5841SNick Mathewson if (EVUTIL_UNLIKELY(ent_ == NULL)) \
13489d5e09eSNick Mathewson return (-1); \
135946b5841SNick Mathewson ent_->fd = slot; \
136946b5841SNick Mathewson (ctor)(&ent_->ent.type); \
137946b5841SNick Mathewson HT_FOI_INSERT_(map_node, map, &key_, ent_, ptr) \
13855bcd7d2SNick Mathewson }); \
139946b5841SNick Mathewson (x) = &ent_->ent.type; \
14055bcd7d2SNick Mathewson } while (0)
14155bcd7d2SNick Mathewson
1428ac3c4c2SNick Mathewson void evmap_io_initmap_(struct event_io_map *ctx)
1436bb2f842SNick Mathewson {
1446bb2f842SNick Mathewson HT_INIT(event_io_map, ctx);
1456bb2f842SNick Mathewson }
1466bb2f842SNick Mathewson
evmap_io_clear_(struct event_io_map * ctx)1478ac3c4c2SNick Mathewson void evmap_io_clear_(struct event_io_map *ctx)
14855bcd7d2SNick Mathewson {
14955bcd7d2SNick Mathewson struct event_map_entry **ent, **next, *this;
15055bcd7d2SNick Mathewson for (ent = HT_START(event_io_map, ctx); ent; ent = next) {
15155bcd7d2SNick Mathewson this = *ent;
15255bcd7d2SNick Mathewson next = HT_NEXT_RMV(event_io_map, ctx, ent);
15355bcd7d2SNick Mathewson mm_free(this);
15455bcd7d2SNick Mathewson }
155b4f89f00SNick Mathewson HT_CLEAR(event_io_map, ctx); /* remove all storage held by the ctx. */
15655bcd7d2SNick Mathewson }
15755bcd7d2SNick Mathewson #endif
15855bcd7d2SNick Mathewson
1598f5777e6SNick Mathewson /* Set the variable 'x' to the field in event_map 'map' with fields of type
1608f5777e6SNick Mathewson 'struct type *' corresponding to the fd or signal 'slot'. Set 'x' to NULL
1618f5777e6SNick Mathewson if there are no entries for 'slot'. Does no bounds-checking. */
16255bcd7d2SNick Mathewson #define GET_SIGNAL_SLOT(x, map, slot, type) \
163172b6575SNiels Provos (x) = (struct type *)((map)->entries[slot])
1648f5777e6SNick Mathewson /* As GET_SLOT, but construct the entry for 'slot' if it is not present,
1658f5777e6SNick Mathewson by allocating enough memory for a 'struct type', and initializing the new
16689d5e09eSNick Mathewson value by calling the function 'ctor' on it. Makes the function
16789d5e09eSNick Mathewson return -1 on allocation failure.
1688f5777e6SNick Mathewson */
169554e1493SNick Mathewson #define GET_SIGNAL_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \
170172b6575SNiels Provos do { \
171172b6575SNiels Provos if ((map)->entries[slot] == NULL) { \
17264a37e61SNick Mathewson (map)->entries[slot] = \
17364a37e61SNick Mathewson mm_calloc(1,sizeof(struct type)+fdinfo_len); \
17489d5e09eSNick Mathewson if (EVUTIL_UNLIKELY((map)->entries[slot] == NULL)) \
17589d5e09eSNick Mathewson return (-1); \
176172b6575SNiels Provos (ctor)((struct type *)(map)->entries[slot]); \
177172b6575SNiels Provos } \
178172b6575SNiels Provos (x) = (struct type *)((map)->entries[slot]); \
17955bcd7d2SNick Mathewson } while (0)
18055bcd7d2SNick Mathewson
18155bcd7d2SNick Mathewson /* If we aren't using hashtables, then define the IO_SLOT macros and functions
18255bcd7d2SNick Mathewson as thin aliases over the SIGNAL_SLOT versions. */
18355bcd7d2SNick Mathewson #ifndef EVMAP_USE_HT
18455bcd7d2SNick Mathewson #define GET_IO_SLOT(x,map,slot,type) GET_SIGNAL_SLOT(x,map,slot,type)
185554e1493SNick Mathewson #define GET_IO_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len) \
186554e1493SNick Mathewson GET_SIGNAL_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)
187554e1493SNick Mathewson #define FDINFO_OFFSET sizeof(struct evmap_io)
18855bcd7d2SNick Mathewson void
evmap_io_initmap_(struct event_io_map * ctx)1898ac3c4c2SNick Mathewson evmap_io_initmap_(struct event_io_map* ctx)
1906bb2f842SNick Mathewson {
1918ac3c4c2SNick Mathewson evmap_signal_initmap_(ctx);
1926bb2f842SNick Mathewson }
1936bb2f842SNick Mathewson void
evmap_io_clear_(struct event_io_map * ctx)1948ac3c4c2SNick Mathewson evmap_io_clear_(struct event_io_map* ctx)
19555bcd7d2SNick Mathewson {
1968ac3c4c2SNick Mathewson evmap_signal_clear_(ctx);
19755bcd7d2SNick Mathewson }
19855bcd7d2SNick Mathewson #endif
19955bcd7d2SNick Mathewson
20002b2b4d1SNiels Provos
2018f5777e6SNick Mathewson /** Expand 'map' with new entries of width 'msize' until it is big enough
2028f5777e6SNick Mathewson to store a value in 'slot'.
2038f5777e6SNick Mathewson */
204b55ca7deSNiels Provos static int
evmap_make_space(struct event_signal_map * map,int slot,int msize)20555bcd7d2SNick Mathewson evmap_make_space(struct event_signal_map *map, int slot, int msize)
20602b2b4d1SNiels Provos {
20702b2b4d1SNiels Provos if (map->nentries <= slot) {
20802b2b4d1SNiels Provos int nentries = map->nentries ? map->nentries : 32;
20930cba6d0SNiels Provos void **tmp;
21002b2b4d1SNiels Provos
21187fa93a8SAzat Khuzhin if (slot > INT_MAX / 2)
21287fa93a8SAzat Khuzhin return (-1);
21387fa93a8SAzat Khuzhin
21402b2b4d1SNiels Provos while (nentries <= slot)
21502b2b4d1SNiels Provos nentries <<= 1;
21602b2b4d1SNiels Provos
21787fa93a8SAzat Khuzhin if (nentries > INT_MAX / msize)
21887fa93a8SAzat Khuzhin return (-1);
21987fa93a8SAzat Khuzhin
22030cba6d0SNiels Provos tmp = (void **)mm_realloc(map->entries, nentries * msize);
22102b2b4d1SNiels Provos if (tmp == NULL)
222b55ca7deSNiels Provos return (-1);
22302b2b4d1SNiels Provos
224172b6575SNiels Provos memset(&tmp[map->nentries], 0,
225ad7f1b4aSNick Mathewson (nentries - map->nentries) * msize);
22602b2b4d1SNiels Provos
22702b2b4d1SNiels Provos map->nentries = nentries;
22802b2b4d1SNiels Provos map->entries = tmp;
22902b2b4d1SNiels Provos }
23002b2b4d1SNiels Provos
231b55ca7deSNiels Provos return (0);
23202b2b4d1SNiels Provos }
23302b2b4d1SNiels Provos
23402b2b4d1SNiels Provos void
evmap_signal_initmap_(struct event_signal_map * ctx)2358ac3c4c2SNick Mathewson evmap_signal_initmap_(struct event_signal_map *ctx)
2366bb2f842SNick Mathewson {
2376bb2f842SNick Mathewson ctx->nentries = 0;
2386bb2f842SNick Mathewson ctx->entries = NULL;
2396bb2f842SNick Mathewson }
2406bb2f842SNick Mathewson
2416bb2f842SNick Mathewson void
evmap_signal_clear_(struct event_signal_map * ctx)2428ac3c4c2SNick Mathewson evmap_signal_clear_(struct event_signal_map *ctx)
24302b2b4d1SNiels Provos {
24402b2b4d1SNiels Provos if (ctx->entries != NULL) {
24530cba6d0SNiels Provos int i;
246172b6575SNiels Provos for (i = 0; i < ctx->nentries; ++i) {
247172b6575SNiels Provos if (ctx->entries[i] != NULL)
24830cba6d0SNiels Provos mm_free(ctx->entries[i]);
249172b6575SNiels Provos }
25002b2b4d1SNiels Provos mm_free(ctx->entries);
25102b2b4d1SNiels Provos ctx->entries = NULL;
25202b2b4d1SNiels Provos }
2530e779906SNiels Provos ctx->nentries = 0;
25402b2b4d1SNiels Provos }
25502b2b4d1SNiels Provos
25602b2b4d1SNiels Provos
25755bcd7d2SNick Mathewson /* code specific to file descriptors */
25802b2b4d1SNiels Provos
2598f5777e6SNick Mathewson /** Constructor for struct evmap_io */
26002b2b4d1SNiels Provos static void
evmap_io_init(struct evmap_io * entry)2618f5777e6SNick Mathewson evmap_io_init(struct evmap_io *entry)
26202b2b4d1SNiels Provos {
2636494772eSNick Mathewson LIST_INIT(&entry->events);
26402b2b4d1SNiels Provos entry->nread = 0;
26502b2b4d1SNiels Provos entry->nwrite = 0;
266b1b69ac7SDiego Giagio entry->nclose = 0;
26702b2b4d1SNiels Provos }
26802b2b4d1SNiels Provos
26902b2b4d1SNiels Provos
270ba8a1771SNick Mathewson /* return -1 on error, 0 on success if nothing changed in the event backend,
271ba8a1771SNick Mathewson * and 1 on success if something did. */
27202b2b4d1SNiels Provos int
evmap_io_add_(struct event_base * base,evutil_socket_t fd,struct event * ev)2738ac3c4c2SNick Mathewson evmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev)
27402b2b4d1SNiels Provos {
27502b2b4d1SNiels Provos const struct eventop *evsel = base->evsel;
27655bcd7d2SNick Mathewson struct event_io_map *io = &base->io;
27702b2b4d1SNiels Provos struct evmap_io *ctx = NULL;
278b1b69ac7SDiego Giagio int nread, nwrite, nclose, retval = 0;
27902b2b4d1SNiels Provos short res = 0, old = 0;
280cb670740SNick Mathewson struct event *old_ev;
28102b2b4d1SNiels Provos
282c247adc7SNick Mathewson EVUTIL_ASSERT(fd == ev->ev_fd);
2838f5777e6SNick Mathewson
284c2ead9f1SNick Mathewson if (fd < 0)
285c2ead9f1SNick Mathewson return 0;
286c2ead9f1SNick Mathewson
28755bcd7d2SNick Mathewson #ifndef EVMAP_USE_HT
28802b2b4d1SNiels Provos if (fd >= io->nentries) {
289ad7f1b4aSNick Mathewson if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1)
29002b2b4d1SNiels Provos return (-1);
29102b2b4d1SNiels Provos }
29255bcd7d2SNick Mathewson #endif
293554e1493SNick Mathewson GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init,
294554e1493SNick Mathewson evsel->fdinfo_len);
29502b2b4d1SNiels Provos
29602b2b4d1SNiels Provos nread = ctx->nread;
29702b2b4d1SNiels Provos nwrite = ctx->nwrite;
298b1b69ac7SDiego Giagio nclose = ctx->nclose;
29902b2b4d1SNiels Provos
30002b2b4d1SNiels Provos if (nread)
30102b2b4d1SNiels Provos old |= EV_READ;
30202b2b4d1SNiels Provos if (nwrite)
30302b2b4d1SNiels Provos old |= EV_WRITE;
304b1b69ac7SDiego Giagio if (nclose)
305b1b69ac7SDiego Giagio old |= EV_CLOSED;
30602b2b4d1SNiels Provos
30702b2b4d1SNiels Provos if (ev->ev_events & EV_READ) {
30802b2b4d1SNiels Provos if (++nread == 1)
30902b2b4d1SNiels Provos res |= EV_READ;
31002b2b4d1SNiels Provos }
31102b2b4d1SNiels Provos if (ev->ev_events & EV_WRITE) {
31202b2b4d1SNiels Provos if (++nwrite == 1)
31302b2b4d1SNiels Provos res |= EV_WRITE;
31402b2b4d1SNiels Provos }
315b1b69ac7SDiego Giagio if (ev->ev_events & EV_CLOSED) {
316b1b69ac7SDiego Giagio if (++nclose == 1)
317b1b69ac7SDiego Giagio res |= EV_CLOSED;
318b1b69ac7SDiego Giagio }
319b1b69ac7SDiego Giagio if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) {
320819f949fSNick Mathewson event_warnx("Too many events reading or writing on fd %d",
321819f949fSNick Mathewson (int)fd);
322819f949fSNick Mathewson return -1;
323819f949fSNick Mathewson }
324cb670740SNick Mathewson if (EVENT_DEBUG_MODE_IS_ON() &&
3255683e2b1SNick Mathewson (old_ev = LIST_FIRST(&ctx->events)) &&
326cb670740SNick Mathewson (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) {
327cb670740SNick Mathewson event_warnx("Tried to mix edge-triggered and non-edge-triggered"
328cb670740SNick Mathewson " events on fd %d", (int)fd);
329cb670740SNick Mathewson return -1;
330cb670740SNick Mathewson }
33102b2b4d1SNiels Provos
33202b2b4d1SNiels Provos if (res) {
333554e1493SNick Mathewson void *extra = ((char*)ctx) + sizeof(struct evmap_io);
33402b2b4d1SNiels Provos /* XXX(niels): we cannot mix edge-triggered and
33502b2b4d1SNiels Provos * level-triggered, we should probably assert on
33602b2b4d1SNiels Provos * this. */
33702b2b4d1SNiels Provos if (evsel->add(base, ev->ev_fd,
338554e1493SNick Mathewson old, (ev->ev_events & EV_ET) | res, extra) == -1)
33902b2b4d1SNiels Provos return (-1);
340ba8a1771SNick Mathewson retval = 1;
34102b2b4d1SNiels Provos }
34202b2b4d1SNiels Provos
343819f949fSNick Mathewson ctx->nread = (ev_uint16_t) nread;
344819f949fSNick Mathewson ctx->nwrite = (ev_uint16_t) nwrite;
345b1b69ac7SDiego Giagio ctx->nclose = (ev_uint16_t) nclose;
3466494772eSNick Mathewson LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next);
34702b2b4d1SNiels Provos
348ba8a1771SNick Mathewson return (retval);
34902b2b4d1SNiels Provos }
35002b2b4d1SNiels Provos
351ba8a1771SNick Mathewson /* return -1 on error, 0 on success if nothing changed in the event backend,
352ba8a1771SNick Mathewson * and 1 on success if something did. */
35302b2b4d1SNiels Provos int
evmap_io_del_(struct event_base * base,evutil_socket_t fd,struct event * ev)3548ac3c4c2SNick Mathewson evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
35502b2b4d1SNiels Provos {
35602b2b4d1SNiels Provos const struct eventop *evsel = base->evsel;
35755bcd7d2SNick Mathewson struct event_io_map *io = &base->io;
35802b2b4d1SNiels Provos struct evmap_io *ctx;
359b1b69ac7SDiego Giagio int nread, nwrite, nclose, retval = 0;
36002b2b4d1SNiels Provos short res = 0, old = 0;
36102b2b4d1SNiels Provos
362c2ead9f1SNick Mathewson if (fd < 0)
363c2ead9f1SNick Mathewson return 0;
364c2ead9f1SNick Mathewson
365c247adc7SNick Mathewson EVUTIL_ASSERT(fd == ev->ev_fd);
3668f5777e6SNick Mathewson
36755bcd7d2SNick Mathewson #ifndef EVMAP_USE_HT
36802b2b4d1SNiels Provos if (fd >= io->nentries)
36902b2b4d1SNiels Provos return (-1);
37055bcd7d2SNick Mathewson #endif
37102b2b4d1SNiels Provos
37255bcd7d2SNick Mathewson GET_IO_SLOT(ctx, io, fd, evmap_io);
37302b2b4d1SNiels Provos
37402b2b4d1SNiels Provos nread = ctx->nread;
37502b2b4d1SNiels Provos nwrite = ctx->nwrite;
376b1b69ac7SDiego Giagio nclose = ctx->nclose;
37702b2b4d1SNiels Provos
37802b2b4d1SNiels Provos if (nread)
37902b2b4d1SNiels Provos old |= EV_READ;
38002b2b4d1SNiels Provos if (nwrite)
38102b2b4d1SNiels Provos old |= EV_WRITE;
382b1b69ac7SDiego Giagio if (nclose)
383b1b69ac7SDiego Giagio old |= EV_CLOSED;
38402b2b4d1SNiels Provos
38502b2b4d1SNiels Provos if (ev->ev_events & EV_READ) {
38602b2b4d1SNiels Provos if (--nread == 0)
38702b2b4d1SNiels Provos res |= EV_READ;
3882e36dbe1SNick Mathewson EVUTIL_ASSERT(nread >= 0);
38902b2b4d1SNiels Provos }
39002b2b4d1SNiels Provos if (ev->ev_events & EV_WRITE) {
39102b2b4d1SNiels Provos if (--nwrite == 0)
39202b2b4d1SNiels Provos res |= EV_WRITE;
3932e36dbe1SNick Mathewson EVUTIL_ASSERT(nwrite >= 0);
39402b2b4d1SNiels Provos }
395b1b69ac7SDiego Giagio if (ev->ev_events & EV_CLOSED) {
396b1b69ac7SDiego Giagio if (--nclose == 0)
397b1b69ac7SDiego Giagio res |= EV_CLOSED;
398b1b69ac7SDiego Giagio EVUTIL_ASSERT(nclose >= 0);
399b1b69ac7SDiego Giagio }
40002b2b4d1SNiels Provos
40102b2b4d1SNiels Provos if (res) {
402554e1493SNick Mathewson void *extra = ((char*)ctx) + sizeof(struct evmap_io);
403ca4b6404SAzat Khuzhin if (evsel->del(base, ev->ev_fd,
404ca4b6404SAzat Khuzhin old, (ev->ev_events & EV_ET) | res, extra) == -1) {
4059b5a527fSMaxime Henrion retval = -1;
4069b5a527fSMaxime Henrion } else {
407ba8a1771SNick Mathewson retval = 1;
40802b2b4d1SNiels Provos }
4099b5a527fSMaxime Henrion }
41002b2b4d1SNiels Provos
41102b2b4d1SNiels Provos ctx->nread = nread;
41202b2b4d1SNiels Provos ctx->nwrite = nwrite;
413b1b69ac7SDiego Giagio ctx->nclose = nclose;
4146494772eSNick Mathewson LIST_REMOVE(ev, ev_io_next);
41502b2b4d1SNiels Provos
416ba8a1771SNick Mathewson return (retval);
41702b2b4d1SNiels Provos }
41802b2b4d1SNiels Provos
41902b2b4d1SNiels Provos void
evmap_io_active_(struct event_base * base,evutil_socket_t fd,short events)4208ac3c4c2SNick Mathewson evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events)
42102b2b4d1SNiels Provos {
42255bcd7d2SNick Mathewson struct event_io_map *io = &base->io;
42302b2b4d1SNiels Provos struct evmap_io *ctx;
42402b2b4d1SNiels Provos struct event *ev;
42502b2b4d1SNiels Provos
42655bcd7d2SNick Mathewson #ifndef EVMAP_USE_HT
427974c60e1SNick Mathewson if (fd < 0 || fd >= io->nentries)
428974c60e1SNick Mathewson return;
42955bcd7d2SNick Mathewson #endif
43055bcd7d2SNick Mathewson GET_IO_SLOT(ctx, io, fd, evmap_io);
43102b2b4d1SNiels Provos
432974c60e1SNick Mathewson if (NULL == ctx)
433974c60e1SNick Mathewson return;
4346494772eSNick Mathewson LIST_FOREACH(ev, &ctx->events, ev_io_next) {
435*db2efdf5SAzat Khuzhin if (ev->ev_events & (events & ~EV_ET))
4368ac3c4c2SNick Mathewson event_active_nolock_(ev, ev->ev_events & events, 1);
43702b2b4d1SNiels Provos }
43802b2b4d1SNiels Provos }
43902b2b4d1SNiels Provos
44002b2b4d1SNiels Provos /* code specific to signals */
44102b2b4d1SNiels Provos
44202b2b4d1SNiels Provos static void
evmap_signal_init(struct evmap_signal * entry)4438f5777e6SNick Mathewson evmap_signal_init(struct evmap_signal *entry)
44402b2b4d1SNiels Provos {
4456494772eSNick Mathewson LIST_INIT(&entry->events);
44602b2b4d1SNiels Provos }
44702b2b4d1SNiels Provos
44802b2b4d1SNiels Provos
44902b2b4d1SNiels Provos int
evmap_signal_add_(struct event_base * base,int sig,struct event * ev)4508ac3c4c2SNick Mathewson evmap_signal_add_(struct event_base *base, int sig, struct event *ev)
45102b2b4d1SNiels Provos {
45202b2b4d1SNiels Provos const struct eventop *evsel = base->evsigsel;
45355bcd7d2SNick Mathewson struct event_signal_map *map = &base->sigmap;
45402b2b4d1SNiels Provos struct evmap_signal *ctx = NULL;
45502b2b4d1SNiels Provos
45687fa93a8SAzat Khuzhin if (sig < 0 || sig >= NSIG)
45787fa93a8SAzat Khuzhin return (-1);
45887fa93a8SAzat Khuzhin
45902b2b4d1SNiels Provos if (sig >= map->nentries) {
460b55ca7deSNiels Provos if (evmap_make_space(
461ad7f1b4aSNick Mathewson map, sig, sizeof(struct evmap_signal *)) == -1)
46202b2b4d1SNiels Provos return (-1);
46302b2b4d1SNiels Provos }
46427308aaeSNick Mathewson GET_SIGNAL_SLOT_AND_CTOR(ctx, map, sig, evmap_signal, evmap_signal_init,
46527308aaeSNick Mathewson base->evsigsel->fdinfo_len);
46602b2b4d1SNiels Provos
4676494772eSNick Mathewson if (LIST_EMPTY(&ctx->events)) {
468f6b26949SNick Mathewson if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL)
469f6b26949SNick Mathewson == -1)
47002b2b4d1SNiels Provos return (-1);
47102b2b4d1SNiels Provos }
47202b2b4d1SNiels Provos
4736494772eSNick Mathewson LIST_INSERT_HEAD(&ctx->events, ev, ev_signal_next);
47402b2b4d1SNiels Provos
475ba8a1771SNick Mathewson return (1);
47602b2b4d1SNiels Provos }
47702b2b4d1SNiels Provos
47802b2b4d1SNiels Provos int
evmap_signal_del_(struct event_base * base,int sig,struct event * ev)4798ac3c4c2SNick Mathewson evmap_signal_del_(struct event_base *base, int sig, struct event *ev)
48002b2b4d1SNiels Provos {
48102b2b4d1SNiels Provos const struct eventop *evsel = base->evsigsel;
48255bcd7d2SNick Mathewson struct event_signal_map *map = &base->sigmap;
48302b2b4d1SNiels Provos struct evmap_signal *ctx;
48402b2b4d1SNiels Provos
48587fa93a8SAzat Khuzhin if (sig < 0 || sig >= map->nentries)
48602b2b4d1SNiels Provos return (-1);
48702b2b4d1SNiels Provos
48855bcd7d2SNick Mathewson GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
48902b2b4d1SNiels Provos
4906494772eSNick Mathewson LIST_REMOVE(ev, ev_signal_next);
4916494772eSNick Mathewson
4926494772eSNick Mathewson if (LIST_FIRST(&ctx->events) == NULL) {
493f6b26949SNick Mathewson if (evsel->del(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1)
49402b2b4d1SNiels Provos return (-1);
49502b2b4d1SNiels Provos }
49602b2b4d1SNiels Provos
497ba8a1771SNick Mathewson return (1);
49802b2b4d1SNiels Provos }
49902b2b4d1SNiels Provos
50002b2b4d1SNiels Provos void
evmap_signal_active_(struct event_base * base,evutil_socket_t sig,int ncalls)5018ac3c4c2SNick Mathewson evmap_signal_active_(struct event_base *base, evutil_socket_t sig, int ncalls)
50202b2b4d1SNiels Provos {
50355bcd7d2SNick Mathewson struct event_signal_map *map = &base->sigmap;
50402b2b4d1SNiels Provos struct evmap_signal *ctx;
50502b2b4d1SNiels Provos struct event *ev;
50602b2b4d1SNiels Provos
507974c60e1SNick Mathewson if (sig < 0 || sig >= map->nentries)
508974c60e1SNick Mathewson return;
50955bcd7d2SNick Mathewson GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
51002b2b4d1SNiels Provos
511974c60e1SNick Mathewson if (!ctx)
512974c60e1SNick Mathewson return;
5136494772eSNick Mathewson LIST_FOREACH(ev, &ctx->events, ev_signal_next)
5148ac3c4c2SNick Mathewson event_active_nolock_(ev, EV_SIGNAL, ncalls);
51502b2b4d1SNiels Provos }
516554e1493SNick Mathewson
517554e1493SNick Mathewson void *
evmap_io_get_fdinfo_(struct event_io_map * map,evutil_socket_t fd)5188ac3c4c2SNick Mathewson evmap_io_get_fdinfo_(struct event_io_map *map, evutil_socket_t fd)
519554e1493SNick Mathewson {
520554e1493SNick Mathewson struct evmap_io *ctx;
521554e1493SNick Mathewson GET_IO_SLOT(ctx, map, fd, evmap_io);
522554e1493SNick Mathewson if (ctx)
523554e1493SNick Mathewson return ((char*)ctx) + sizeof(struct evmap_io);
524554e1493SNick Mathewson else
525554e1493SNick Mathewson return NULL;
526554e1493SNick Mathewson }
52727308aaeSNick Mathewson
528c89b4e63SNick Mathewson /* Callback type for evmap_io_foreach_fd */
529c89b4e63SNick Mathewson typedef int (*evmap_io_foreach_fd_cb)(
530c89b4e63SNick Mathewson struct event_base *, evutil_socket_t, struct evmap_io *, void *);
531272033efSNick Mathewson
532c89b4e63SNick Mathewson /* Multipurpose helper function: Iterate over every file descriptor event_base
533c89b4e63SNick Mathewson * for which we could have EV_READ or EV_WRITE events. For each such fd, call
534c89b4e63SNick Mathewson * fn(base, signum, evmap_io, arg), where fn is the user-provided
535c89b4e63SNick Mathewson * function, base is the event_base, signum is the signal number, evmap_io
536c89b4e63SNick Mathewson * is an evmap_io structure containing a list of events pending on the
537c89b4e63SNick Mathewson * file descriptor, and arg is the user-supplied argument.
538c89b4e63SNick Mathewson *
539c89b4e63SNick Mathewson * If fn returns 0, continue on to the next signal. Otherwise, return the same
540c89b4e63SNick Mathewson * value that fn returned.
541c89b4e63SNick Mathewson *
542c89b4e63SNick Mathewson * Note that there is no guarantee that the file descriptors will be processed
543c89b4e63SNick Mathewson * in any particular order.
544c89b4e63SNick Mathewson */
545c89b4e63SNick Mathewson static int
evmap_io_foreach_fd(struct event_base * base,evmap_io_foreach_fd_cb fn,void * arg)546c89b4e63SNick Mathewson evmap_io_foreach_fd(struct event_base *base,
547c89b4e63SNick Mathewson evmap_io_foreach_fd_cb fn,
548c89b4e63SNick Mathewson void *arg)
549c89b4e63SNick Mathewson {
550c89b4e63SNick Mathewson evutil_socket_t fd;
551c89b4e63SNick Mathewson struct event_io_map *iomap = &base->io;
552c89b4e63SNick Mathewson int r = 0;
553272033efSNick Mathewson #ifdef EVMAP_USE_HT
554272033efSNick Mathewson struct event_map_entry **mapent;
555066775e3SNick Mathewson HT_FOREACH(mapent, event_io_map, iomap) {
556272033efSNick Mathewson struct evmap_io *ctx = &(*mapent)->ent.evmap_io;
557c89b4e63SNick Mathewson fd = (*mapent)->fd;
558272033efSNick Mathewson #else
559c89b4e63SNick Mathewson for (fd = 0; fd < iomap->nentries; ++fd) {
560c89b4e63SNick Mathewson struct evmap_io *ctx = iomap->entries[fd];
561272033efSNick Mathewson if (!ctx)
562272033efSNick Mathewson continue;
563272033efSNick Mathewson #endif
564c89b4e63SNick Mathewson if ((r = fn(base, fd, ctx, arg)))
565c89b4e63SNick Mathewson break;
566c89b4e63SNick Mathewson }
567c89b4e63SNick Mathewson return r;
568c89b4e63SNick Mathewson }
569c89b4e63SNick Mathewson
570c89b4e63SNick Mathewson /* Callback type for evmap_signal_foreach_signal */
571c89b4e63SNick Mathewson typedef int (*evmap_signal_foreach_signal_cb)(
572c89b4e63SNick Mathewson struct event_base *, int, struct evmap_signal *, void *);
573c89b4e63SNick Mathewson
574c89b4e63SNick Mathewson /* Multipurpose helper function: Iterate over every signal number in the
575c89b4e63SNick Mathewson * event_base for which we could have signal events. For each such signal,
576c89b4e63SNick Mathewson * call fn(base, signum, evmap_signal, arg), where fn is the user-provided
577c89b4e63SNick Mathewson * function, base is the event_base, signum is the signal number, evmap_signal
578c89b4e63SNick Mathewson * is an evmap_signal structure containing a list of events pending on the
579c89b4e63SNick Mathewson * signal, and arg is the user-supplied argument.
580c89b4e63SNick Mathewson *
581c89b4e63SNick Mathewson * If fn returns 0, continue on to the next signal. Otherwise, return the same
582c89b4e63SNick Mathewson * value that fn returned.
583c89b4e63SNick Mathewson */
584c89b4e63SNick Mathewson static int
585c89b4e63SNick Mathewson evmap_signal_foreach_signal(struct event_base *base,
586c89b4e63SNick Mathewson evmap_signal_foreach_signal_cb fn,
587c89b4e63SNick Mathewson void *arg)
588c89b4e63SNick Mathewson {
589c89b4e63SNick Mathewson struct event_signal_map *sigmap = &base->sigmap;
590c89b4e63SNick Mathewson int r = 0;
591c89b4e63SNick Mathewson int signum;
592c89b4e63SNick Mathewson
593c89b4e63SNick Mathewson for (signum = 0; signum < sigmap->nentries; ++signum) {
594c89b4e63SNick Mathewson struct evmap_signal *ctx = sigmap->entries[signum];
595c89b4e63SNick Mathewson if (!ctx)
596c89b4e63SNick Mathewson continue;
597c89b4e63SNick Mathewson if ((r = fn(base, signum, ctx, arg)))
598c89b4e63SNick Mathewson break;
599c89b4e63SNick Mathewson }
600c89b4e63SNick Mathewson return r;
601c89b4e63SNick Mathewson }
602c89b4e63SNick Mathewson
6038ac3c4c2SNick Mathewson /* Helper for evmap_reinit_: tell the backend to add every fd for which we have
604c89b4e63SNick Mathewson * pending events, with the appropriate combination of EV_READ, EV_WRITE, and
605c89b4e63SNick Mathewson * EV_ET. */
606c89b4e63SNick Mathewson static int
607c89b4e63SNick Mathewson evmap_io_reinit_iter_fn(struct event_base *base, evutil_socket_t fd,
608c89b4e63SNick Mathewson struct evmap_io *ctx, void *arg)
609c89b4e63SNick Mathewson {
610c89b4e63SNick Mathewson const struct eventop *evsel = base->evsel;
611c89b4e63SNick Mathewson void *extra;
612c89b4e63SNick Mathewson int *result = arg;
613c89b4e63SNick Mathewson short events = 0;
614c89b4e63SNick Mathewson struct event *ev;
615c89b4e63SNick Mathewson EVUTIL_ASSERT(ctx);
616c89b4e63SNick Mathewson
617272033efSNick Mathewson extra = ((char*)ctx) + sizeof(struct evmap_io);
618272033efSNick Mathewson if (ctx->nread)
619272033efSNick Mathewson events |= EV_READ;
620ebfd8a89Smaksqwe if (ctx->nwrite)
621272033efSNick Mathewson events |= EV_WRITE;
622b1b69ac7SDiego Giagio if (ctx->nclose)
623b1b69ac7SDiego Giagio events |= EV_CLOSED;
624272033efSNick Mathewson if (evsel->fdinfo_len)
625272033efSNick Mathewson memset(extra, 0, evsel->fdinfo_len);
626c89b4e63SNick Mathewson if (events &&
627c89b4e63SNick Mathewson (ev = LIST_FIRST(&ctx->events)) &&
628c89b4e63SNick Mathewson (ev->ev_events & EV_ET))
629272033efSNick Mathewson events |= EV_ET;
630c89b4e63SNick Mathewson if (evsel->add(base, fd, 0, events, extra) == -1)
631c89b4e63SNick Mathewson *result = -1;
632c89b4e63SNick Mathewson
633c89b4e63SNick Mathewson return 0;
634272033efSNick Mathewson }
635272033efSNick Mathewson
6368ac3c4c2SNick Mathewson /* Helper for evmap_reinit_: tell the backend to add every signal for which we
637c89b4e63SNick Mathewson * have pending events. */
638c89b4e63SNick Mathewson static int
639c89b4e63SNick Mathewson evmap_signal_reinit_iter_fn(struct event_base *base,
640c89b4e63SNick Mathewson int signum, struct evmap_signal *ctx, void *arg)
641272033efSNick Mathewson {
642272033efSNick Mathewson const struct eventop *evsel = base->evsigsel;
643c89b4e63SNick Mathewson int *result = arg;
644272033efSNick Mathewson
645272033efSNick Mathewson if (!LIST_EMPTY(&ctx->events)) {
646c89b4e63SNick Mathewson if (evsel->add(base, signum, 0, EV_SIGNAL, NULL) == -1)
647c89b4e63SNick Mathewson *result = -1;
648272033efSNick Mathewson }
649604569bfSNick Mathewson return 0;
650272033efSNick Mathewson }
651272033efSNick Mathewson
652272033efSNick Mathewson int
6538ac3c4c2SNick Mathewson evmap_reinit_(struct event_base *base)
654272033efSNick Mathewson {
655c89b4e63SNick Mathewson int result = 0;
656272033efSNick Mathewson
657c89b4e63SNick Mathewson evmap_io_foreach_fd(base, evmap_io_reinit_iter_fn, &result);
658c89b4e63SNick Mathewson if (result < 0)
659c89b4e63SNick Mathewson return -1;
660c89b4e63SNick Mathewson evmap_signal_foreach_signal(base, evmap_signal_reinit_iter_fn, &result);
661c89b4e63SNick Mathewson if (result < 0)
662c89b4e63SNick Mathewson return -1;
663604569bfSNick Mathewson return 0;
664272033efSNick Mathewson }
665604569bfSNick Mathewson
6668ac3c4c2SNick Mathewson /* Helper for evmap_delete_all_: delete every event in an event_dlist. */
667c89b4e63SNick Mathewson static int
668c89b4e63SNick Mathewson delete_all_in_dlist(struct event_dlist *dlist)
669c89b4e63SNick Mathewson {
670c89b4e63SNick Mathewson struct event *ev;
671c89b4e63SNick Mathewson while ((ev = LIST_FIRST(dlist)))
672c89b4e63SNick Mathewson event_del(ev);
673c89b4e63SNick Mathewson return 0;
674272033efSNick Mathewson }
675c89b4e63SNick Mathewson
6768ac3c4c2SNick Mathewson /* Helper for evmap_delete_all_: delete every event pending on an fd. */
677c89b4e63SNick Mathewson static int
678c89b4e63SNick Mathewson evmap_io_delete_all_iter_fn(struct event_base *base, evutil_socket_t fd,
679c89b4e63SNick Mathewson struct evmap_io *io_info, void *arg)
680c89b4e63SNick Mathewson {
681c89b4e63SNick Mathewson return delete_all_in_dlist(&io_info->events);
682c89b4e63SNick Mathewson }
683c89b4e63SNick Mathewson
6848ac3c4c2SNick Mathewson /* Helper for evmap_delete_all_: delete every event pending on a signal. */
685c89b4e63SNick Mathewson static int
686c89b4e63SNick Mathewson evmap_signal_delete_all_iter_fn(struct event_base *base, int signum,
687c89b4e63SNick Mathewson struct evmap_signal *sig_info, void *arg)
688c89b4e63SNick Mathewson {
689c89b4e63SNick Mathewson return delete_all_in_dlist(&sig_info->events);
690c89b4e63SNick Mathewson }
691c89b4e63SNick Mathewson
692c89b4e63SNick Mathewson void
6938ac3c4c2SNick Mathewson evmap_delete_all_(struct event_base *base)
694c89b4e63SNick Mathewson {
695c89b4e63SNick Mathewson evmap_signal_foreach_signal(base, evmap_signal_delete_all_iter_fn, NULL);
696c89b4e63SNick Mathewson evmap_io_foreach_fd(base, evmap_io_delete_all_iter_fn, NULL);
697272033efSNick Mathewson }
698272033efSNick Mathewson
69927308aaeSNick Mathewson /** Per-fd structure for use with changelists. It keeps track, for each fd or
70027308aaeSNick Mathewson * signal using the changelist, of where its entry in the changelist is.
70127308aaeSNick Mathewson */
70227308aaeSNick Mathewson struct event_changelist_fdinfo {
70327308aaeSNick Mathewson int idxplus1; /* this is the index +1, so that memset(0) will make it
70427308aaeSNick Mathewson * a no-such-element */
70527308aaeSNick Mathewson };
70627308aaeSNick Mathewson
70727308aaeSNick Mathewson void
7088ac3c4c2SNick Mathewson event_changelist_init_(struct event_changelist *changelist)
70927308aaeSNick Mathewson {
71027308aaeSNick Mathewson changelist->changes = NULL;
71127308aaeSNick Mathewson changelist->changes_size = 0;
71227308aaeSNick Mathewson changelist->n_changes = 0;
71327308aaeSNick Mathewson }
71427308aaeSNick Mathewson
71527308aaeSNick Mathewson /** Helper: return the changelist_fdinfo corresponding to a given change. */
71627308aaeSNick Mathewson static inline struct event_changelist_fdinfo *
71727308aaeSNick Mathewson event_change_get_fdinfo(struct event_base *base,
71827308aaeSNick Mathewson const struct event_change *change)
71927308aaeSNick Mathewson {
72027308aaeSNick Mathewson char *ptr;
72127308aaeSNick Mathewson if (change->read_change & EV_CHANGE_SIGNAL) {
72227308aaeSNick Mathewson struct evmap_signal *ctx;
72327308aaeSNick Mathewson GET_SIGNAL_SLOT(ctx, &base->sigmap, change->fd, evmap_signal);
72427308aaeSNick Mathewson ptr = ((char*)ctx) + sizeof(struct evmap_signal);
72527308aaeSNick Mathewson } else {
72627308aaeSNick Mathewson struct evmap_io *ctx;
72727308aaeSNick Mathewson GET_IO_SLOT(ctx, &base->io, change->fd, evmap_io);
72827308aaeSNick Mathewson ptr = ((char*)ctx) + sizeof(struct evmap_io);
72927308aaeSNick Mathewson }
73027308aaeSNick Mathewson return (void*)ptr;
73127308aaeSNick Mathewson }
73227308aaeSNick Mathewson
733066775e3SNick Mathewson /** Callback helper for event_changelist_assert_ok */
734066775e3SNick Mathewson static int
735066775e3SNick Mathewson event_changelist_assert_ok_foreach_iter_fn(
736066775e3SNick Mathewson struct event_base *base,
737066775e3SNick Mathewson evutil_socket_t fd, struct evmap_io *io, void *arg)
738066775e3SNick Mathewson {
739066775e3SNick Mathewson struct event_changelist *changelist = &base->changelist;
740066775e3SNick Mathewson struct event_changelist_fdinfo *f;
741066775e3SNick Mathewson f = (void*)
742066775e3SNick Mathewson ( ((char*)io) + sizeof(struct evmap_io) );
743066775e3SNick Mathewson if (f->idxplus1) {
744066775e3SNick Mathewson struct event_change *c = &changelist->changes[f->idxplus1 - 1];
745066775e3SNick Mathewson EVUTIL_ASSERT(c->fd == fd);
746066775e3SNick Mathewson }
747066775e3SNick Mathewson return 0;
748066775e3SNick Mathewson }
749066775e3SNick Mathewson
75027308aaeSNick Mathewson /** Make sure that the changelist is consistent with the evmap structures. */
75127308aaeSNick Mathewson static void
75239b3f38dSNick Mathewson event_changelist_assert_ok(struct event_base *base)
75327308aaeSNick Mathewson {
75427308aaeSNick Mathewson int i;
75527308aaeSNick Mathewson struct event_changelist *changelist = &base->changelist;
75627308aaeSNick Mathewson
75727308aaeSNick Mathewson EVUTIL_ASSERT(changelist->changes_size >= changelist->n_changes);
75827308aaeSNick Mathewson for (i = 0; i < changelist->n_changes; ++i) {
75927308aaeSNick Mathewson struct event_change *c = &changelist->changes[i];
76027308aaeSNick Mathewson struct event_changelist_fdinfo *f;
76127308aaeSNick Mathewson EVUTIL_ASSERT(c->fd >= 0);
76227308aaeSNick Mathewson f = event_change_get_fdinfo(base, c);
76327308aaeSNick Mathewson EVUTIL_ASSERT(f);
76427308aaeSNick Mathewson EVUTIL_ASSERT(f->idxplus1 == i + 1);
76527308aaeSNick Mathewson }
76627308aaeSNick Mathewson
767066775e3SNick Mathewson evmap_io_foreach_fd(base,
768066775e3SNick Mathewson event_changelist_assert_ok_foreach_iter_fn,
769066775e3SNick Mathewson NULL);
77027308aaeSNick Mathewson }
77139b3f38dSNick Mathewson
77239b3f38dSNick Mathewson #ifdef DEBUG_CHANGELIST
77339b3f38dSNick Mathewson #define event_changelist_check(base) event_changelist_assert_ok((base))
77427308aaeSNick Mathewson #else
77527308aaeSNick Mathewson #define event_changelist_check(base) ((void)0)
77627308aaeSNick Mathewson #endif
77727308aaeSNick Mathewson
77827308aaeSNick Mathewson void
7798ac3c4c2SNick Mathewson event_changelist_remove_all_(struct event_changelist *changelist,
78027308aaeSNick Mathewson struct event_base *base)
78127308aaeSNick Mathewson {
78227308aaeSNick Mathewson int i;
78327308aaeSNick Mathewson
78427308aaeSNick Mathewson event_changelist_check(base);
78527308aaeSNick Mathewson
78627308aaeSNick Mathewson for (i = 0; i < changelist->n_changes; ++i) {
78727308aaeSNick Mathewson struct event_change *ch = &changelist->changes[i];
78827308aaeSNick Mathewson struct event_changelist_fdinfo *fdinfo =
78927308aaeSNick Mathewson event_change_get_fdinfo(base, ch);
79027308aaeSNick Mathewson EVUTIL_ASSERT(fdinfo->idxplus1 == i + 1);
79127308aaeSNick Mathewson fdinfo->idxplus1 = 0;
79227308aaeSNick Mathewson }
79327308aaeSNick Mathewson
79427308aaeSNick Mathewson changelist->n_changes = 0;
79527308aaeSNick Mathewson
79627308aaeSNick Mathewson event_changelist_check(base);
79727308aaeSNick Mathewson }
79827308aaeSNick Mathewson
79927308aaeSNick Mathewson void
8008ac3c4c2SNick Mathewson event_changelist_freemem_(struct event_changelist *changelist)
80127308aaeSNick Mathewson {
80227308aaeSNick Mathewson if (changelist->changes)
80327308aaeSNick Mathewson mm_free(changelist->changes);
8048ac3c4c2SNick Mathewson event_changelist_init_(changelist); /* zero it all out. */
80527308aaeSNick Mathewson }
80627308aaeSNick Mathewson
80727308aaeSNick Mathewson /** Increase the size of 'changelist' to hold more changes. */
80827308aaeSNick Mathewson static int
80927308aaeSNick Mathewson event_changelist_grow(struct event_changelist *changelist)
81027308aaeSNick Mathewson {
81127308aaeSNick Mathewson int new_size;
81227308aaeSNick Mathewson struct event_change *new_changes;
81327308aaeSNick Mathewson if (changelist->changes_size < 64)
81427308aaeSNick Mathewson new_size = 64;
81527308aaeSNick Mathewson else
81627308aaeSNick Mathewson new_size = changelist->changes_size * 2;
81727308aaeSNick Mathewson
81827308aaeSNick Mathewson new_changes = mm_realloc(changelist->changes,
81927308aaeSNick Mathewson new_size * sizeof(struct event_change));
82027308aaeSNick Mathewson
82127308aaeSNick Mathewson if (EVUTIL_UNLIKELY(new_changes == NULL))
82227308aaeSNick Mathewson return (-1);
82327308aaeSNick Mathewson
82427308aaeSNick Mathewson changelist->changes = new_changes;
82527308aaeSNick Mathewson changelist->changes_size = new_size;
82627308aaeSNick Mathewson
82727308aaeSNick Mathewson return (0);
82827308aaeSNick Mathewson }
82927308aaeSNick Mathewson
83027308aaeSNick Mathewson /** Return a pointer to the changelist entry for the file descriptor or signal
83127308aaeSNick Mathewson * 'fd', whose fdinfo is 'fdinfo'. If none exists, construct it, setting its
83227308aaeSNick Mathewson * old_events field to old_events.
83327308aaeSNick Mathewson */
83427308aaeSNick Mathewson static struct event_change *
83527308aaeSNick Mathewson event_changelist_get_or_construct(struct event_changelist *changelist,
83627308aaeSNick Mathewson evutil_socket_t fd,
83727308aaeSNick Mathewson short old_events,
83827308aaeSNick Mathewson struct event_changelist_fdinfo *fdinfo)
83927308aaeSNick Mathewson {
84027308aaeSNick Mathewson struct event_change *change;
84127308aaeSNick Mathewson
84227308aaeSNick Mathewson if (fdinfo->idxplus1 == 0) {
84327308aaeSNick Mathewson int idx;
84427308aaeSNick Mathewson EVUTIL_ASSERT(changelist->n_changes <= changelist->changes_size);
84527308aaeSNick Mathewson
84627308aaeSNick Mathewson if (changelist->n_changes == changelist->changes_size) {
84727308aaeSNick Mathewson if (event_changelist_grow(changelist) < 0)
84827308aaeSNick Mathewson return NULL;
84927308aaeSNick Mathewson }
85027308aaeSNick Mathewson
85127308aaeSNick Mathewson idx = changelist->n_changes++;
85227308aaeSNick Mathewson change = &changelist->changes[idx];
85327308aaeSNick Mathewson fdinfo->idxplus1 = idx + 1;
85427308aaeSNick Mathewson
85527308aaeSNick Mathewson memset(change, 0, sizeof(struct event_change));
85627308aaeSNick Mathewson change->fd = fd;
85727308aaeSNick Mathewson change->old_events = old_events;
85827308aaeSNick Mathewson } else {
85927308aaeSNick Mathewson change = &changelist->changes[fdinfo->idxplus1 - 1];
86027308aaeSNick Mathewson EVUTIL_ASSERT(change->fd == fd);
86127308aaeSNick Mathewson }
86227308aaeSNick Mathewson return change;
86327308aaeSNick Mathewson }
86427308aaeSNick Mathewson
86527308aaeSNick Mathewson int
8668ac3c4c2SNick Mathewson event_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, short events,
86727308aaeSNick Mathewson void *p)
86827308aaeSNick Mathewson {
86927308aaeSNick Mathewson struct event_changelist *changelist = &base->changelist;
87027308aaeSNick Mathewson struct event_changelist_fdinfo *fdinfo = p;
87127308aaeSNick Mathewson struct event_change *change;
872048bee0aSAzat Khuzhin ev_uint8_t evchange = EV_CHANGE_ADD | (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
87327308aaeSNick Mathewson
87427308aaeSNick Mathewson event_changelist_check(base);
87527308aaeSNick Mathewson
87627308aaeSNick Mathewson change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
87727308aaeSNick Mathewson if (!change)
87827308aaeSNick Mathewson return -1;
87927308aaeSNick Mathewson
88027308aaeSNick Mathewson /* An add replaces any previous delete, but doesn't result in a no-op,
88127308aaeSNick Mathewson * since the delete might fail (because the fd had been closed since
88227308aaeSNick Mathewson * the last add, for instance. */
88327308aaeSNick Mathewson
884ca4b6404SAzat Khuzhin if (events & (EV_READ|EV_SIGNAL))
885ca4b6404SAzat Khuzhin change->read_change = evchange;
886ca4b6404SAzat Khuzhin if (events & EV_WRITE)
887ca4b6404SAzat Khuzhin change->write_change = evchange;
888ca4b6404SAzat Khuzhin if (events & EV_CLOSED)
889ca4b6404SAzat Khuzhin change->close_change = evchange;
89027308aaeSNick Mathewson
89127308aaeSNick Mathewson event_changelist_check(base);
89227308aaeSNick Mathewson return (0);
89327308aaeSNick Mathewson }
89427308aaeSNick Mathewson
89527308aaeSNick Mathewson int
8968ac3c4c2SNick Mathewson event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events,
89727308aaeSNick Mathewson void *p)
89827308aaeSNick Mathewson {
89927308aaeSNick Mathewson struct event_changelist *changelist = &base->changelist;
90027308aaeSNick Mathewson struct event_changelist_fdinfo *fdinfo = p;
90127308aaeSNick Mathewson struct event_change *change;
902048bee0aSAzat Khuzhin ev_uint8_t del = EV_CHANGE_DEL | (events & EV_ET);
90327308aaeSNick Mathewson
90427308aaeSNick Mathewson event_changelist_check(base);
90527308aaeSNick Mathewson change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
90627308aaeSNick Mathewson event_changelist_check(base);
90727308aaeSNick Mathewson if (!change)
90827308aaeSNick Mathewson return -1;
90927308aaeSNick Mathewson
91004ba27ebSMike Smellie /* A delete on an event set that doesn't contain the event to be
91104ba27ebSMike Smellie deleted produces a no-op. This effectively emoves any previous
91204ba27ebSMike Smellie uncommitted add, rather than replacing it: on those platforms where
91304ba27ebSMike Smellie "add, delete, dispatch" is not the same as "no-op, dispatch", we
91404ba27ebSMike Smellie want the no-op behavior.
915cf249e7dSMike Smellie
916c247adc7SNick Mathewson If we have a no-op item, we could remove it it from the list
917c247adc7SNick Mathewson entirely, but really there's not much point: skipping the no-op
918c247adc7SNick Mathewson change when we do the dispatch later is far cheaper than rejuggling
919c247adc7SNick Mathewson the array now.
920cf249e7dSMike Smellie
921cf249e7dSMike Smellie As this stands, it also lets through deletions of events that are
922cf249e7dSMike Smellie not currently set.
92327308aaeSNick Mathewson */
92427308aaeSNick Mathewson
92527308aaeSNick Mathewson if (events & (EV_READ|EV_SIGNAL)) {
92604ba27ebSMike Smellie if (!(change->old_events & (EV_READ | EV_SIGNAL)))
92727308aaeSNick Mathewson change->read_change = 0;
92827308aaeSNick Mathewson else
929ca4b6404SAzat Khuzhin change->read_change = del;
93027308aaeSNick Mathewson }
93127308aaeSNick Mathewson if (events & EV_WRITE) {
93204ba27ebSMike Smellie if (!(change->old_events & EV_WRITE))
93327308aaeSNick Mathewson change->write_change = 0;
93427308aaeSNick Mathewson else
935ca4b6404SAzat Khuzhin change->write_change = del;
93627308aaeSNick Mathewson }
937b1b69ac7SDiego Giagio if (events & EV_CLOSED) {
938b1b69ac7SDiego Giagio if (!(change->old_events & EV_CLOSED))
939b1b69ac7SDiego Giagio change->close_change = 0;
940b1b69ac7SDiego Giagio else
941ca4b6404SAzat Khuzhin change->close_change = del;
942b1b69ac7SDiego Giagio }
94327308aaeSNick Mathewson
94427308aaeSNick Mathewson event_changelist_check(base);
94527308aaeSNick Mathewson return (0);
94627308aaeSNick Mathewson }
94727308aaeSNick Mathewson
9488ac3c4c2SNick Mathewson /* Helper for evmap_check_integrity_: verify that all of the events pending on
949c89b4e63SNick Mathewson * given fd are set up correctly, and that the nread and nwrite counts on that
950c89b4e63SNick Mathewson * fd are correct. */
951c89b4e63SNick Mathewson static int
952c89b4e63SNick Mathewson evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd,
953c89b4e63SNick Mathewson struct evmap_io *io_info, void *arg)
954c89b4e63SNick Mathewson {
955c89b4e63SNick Mathewson struct event *ev;
956b1b69ac7SDiego Giagio int n_read = 0, n_write = 0, n_close = 0;
957c89b4e63SNick Mathewson
958c89b4e63SNick Mathewson /* First, make sure the list itself isn't corrupt. Otherwise,
959c89b4e63SNick Mathewson * running LIST_FOREACH could be an exciting adventure. */
960c89b4e63SNick Mathewson EVUTIL_ASSERT_LIST_OK(&io_info->events, event, ev_io_next);
961c89b4e63SNick Mathewson
962c89b4e63SNick Mathewson LIST_FOREACH(ev, &io_info->events, ev_io_next) {
963c89b4e63SNick Mathewson EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
964c89b4e63SNick Mathewson EVUTIL_ASSERT(ev->ev_fd == fd);
965c89b4e63SNick Mathewson EVUTIL_ASSERT(!(ev->ev_events & EV_SIGNAL));
966b1b69ac7SDiego Giagio EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
967c89b4e63SNick Mathewson if (ev->ev_events & EV_READ)
968c89b4e63SNick Mathewson ++n_read;
969c89b4e63SNick Mathewson if (ev->ev_events & EV_WRITE)
970c89b4e63SNick Mathewson ++n_write;
971b1b69ac7SDiego Giagio if (ev->ev_events & EV_CLOSED)
972b1b69ac7SDiego Giagio ++n_close;
973c89b4e63SNick Mathewson }
974c89b4e63SNick Mathewson
975c89b4e63SNick Mathewson EVUTIL_ASSERT(n_read == io_info->nread);
976c89b4e63SNick Mathewson EVUTIL_ASSERT(n_write == io_info->nwrite);
977b1b69ac7SDiego Giagio EVUTIL_ASSERT(n_close == io_info->nclose);
978c89b4e63SNick Mathewson
979c89b4e63SNick Mathewson return 0;
980c89b4e63SNick Mathewson }
981c89b4e63SNick Mathewson
9828ac3c4c2SNick Mathewson /* Helper for evmap_check_integrity_: verify that all of the events pending
983c89b4e63SNick Mathewson * on given signal are set up correctly. */
984c89b4e63SNick Mathewson static int
985c89b4e63SNick Mathewson evmap_signal_check_integrity_fn(struct event_base *base,
986c89b4e63SNick Mathewson int signum, struct evmap_signal *sig_info, void *arg)
987c89b4e63SNick Mathewson {
988c89b4e63SNick Mathewson struct event *ev;
989c89b4e63SNick Mathewson /* First, make sure the list itself isn't corrupt. */
990c89b4e63SNick Mathewson EVUTIL_ASSERT_LIST_OK(&sig_info->events, event, ev_signal_next);
991c89b4e63SNick Mathewson
992c89b4e63SNick Mathewson LIST_FOREACH(ev, &sig_info->events, ev_io_next) {
993c89b4e63SNick Mathewson EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
994c89b4e63SNick Mathewson EVUTIL_ASSERT(ev->ev_fd == signum);
995c89b4e63SNick Mathewson EVUTIL_ASSERT((ev->ev_events & EV_SIGNAL));
996b1b69ac7SDiego Giagio EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED)));
997c89b4e63SNick Mathewson }
998c89b4e63SNick Mathewson return 0;
999c89b4e63SNick Mathewson }
1000c89b4e63SNick Mathewson
100127737d55SNick Mathewson void
10028ac3c4c2SNick Mathewson evmap_check_integrity_(struct event_base *base)
100327737d55SNick Mathewson {
1004c89b4e63SNick Mathewson evmap_io_foreach_fd(base, evmap_io_check_integrity_fn, NULL);
1005c89b4e63SNick Mathewson evmap_signal_foreach_signal(base, evmap_signal_check_integrity_fn, NULL);
100639b3f38dSNick Mathewson
10078ac3c4c2SNick Mathewson if (base->evsel->add == event_changelist_add_)
100839b3f38dSNick Mathewson event_changelist_assert_ok(base);
100927737d55SNick Mathewson }
1010c89b4e63SNick Mathewson
10118ac3c4c2SNick Mathewson /* Helper type for evmap_foreach_event_: Bundles a function to call on every
1012c89b4e63SNick Mathewson * event, and the user-provided void* to use as its third argument. */
1013c89b4e63SNick Mathewson struct evmap_foreach_event_helper {
1014232055efSNick Mathewson event_base_foreach_event_cb fn;
1015c89b4e63SNick Mathewson void *arg;
1016c89b4e63SNick Mathewson };
1017c89b4e63SNick Mathewson
10188ac3c4c2SNick Mathewson /* Helper for evmap_foreach_event_: calls a provided function on every event
1019c89b4e63SNick Mathewson * pending on a given fd. */
1020c89b4e63SNick Mathewson static int
1021c89b4e63SNick Mathewson evmap_io_foreach_event_fn(struct event_base *base, evutil_socket_t fd,
1022c89b4e63SNick Mathewson struct evmap_io *io_info, void *arg)
1023c89b4e63SNick Mathewson {
1024c89b4e63SNick Mathewson struct evmap_foreach_event_helper *h = arg;
1025c89b4e63SNick Mathewson struct event *ev;
1026c89b4e63SNick Mathewson int r;
1027c89b4e63SNick Mathewson LIST_FOREACH(ev, &io_info->events, ev_io_next) {
1028c89b4e63SNick Mathewson if ((r = h->fn(base, ev, h->arg)))
1029c89b4e63SNick Mathewson return r;
1030c89b4e63SNick Mathewson }
1031c89b4e63SNick Mathewson return 0;
1032c89b4e63SNick Mathewson }
1033c89b4e63SNick Mathewson
10348ac3c4c2SNick Mathewson /* Helper for evmap_foreach_event_: calls a provided function on every event
1035c89b4e63SNick Mathewson * pending on a given signal. */
1036c89b4e63SNick Mathewson static int
1037c89b4e63SNick Mathewson evmap_signal_foreach_event_fn(struct event_base *base, int signum,
1038c89b4e63SNick Mathewson struct evmap_signal *sig_info, void *arg)
1039c89b4e63SNick Mathewson {
1040c89b4e63SNick Mathewson struct event *ev;
1041c89b4e63SNick Mathewson struct evmap_foreach_event_helper *h = arg;
1042c89b4e63SNick Mathewson int r;
1043c89b4e63SNick Mathewson LIST_FOREACH(ev, &sig_info->events, ev_signal_next) {
1044c89b4e63SNick Mathewson if ((r = h->fn(base, ev, h->arg)))
1045c89b4e63SNick Mathewson return r;
1046c89b4e63SNick Mathewson }
1047c89b4e63SNick Mathewson return 0;
1048c89b4e63SNick Mathewson }
1049c89b4e63SNick Mathewson
1050c89b4e63SNick Mathewson int
10518ac3c4c2SNick Mathewson evmap_foreach_event_(struct event_base *base,
1052232055efSNick Mathewson event_base_foreach_event_cb fn, void *arg)
1053c89b4e63SNick Mathewson {
1054c89b4e63SNick Mathewson struct evmap_foreach_event_helper h;
1055c89b4e63SNick Mathewson int r;
1056c89b4e63SNick Mathewson h.fn = fn;
1057c89b4e63SNick Mathewson h.arg = arg;
1058c89b4e63SNick Mathewson if ((r = evmap_io_foreach_fd(base, evmap_io_foreach_event_fn, &h)))
1059c89b4e63SNick Mathewson return r;
1060c89b4e63SNick Mathewson return evmap_signal_foreach_signal(base, evmap_signal_foreach_event_fn, &h);
1061c89b4e63SNick Mathewson }
1062c89b4e63SNick Mathewson
1063