1290001Sglebius/* 2290001Sglebius * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson 3290001Sglebius * 4290001Sglebius * Redistribution and use in source and binary forms, with or without 5290001Sglebius * modification, are permitted provided that the following conditions 6290001Sglebius * are met: 7290001Sglebius * 1. Redistributions of source code must retain the above copyright 8290001Sglebius * notice, this list of conditions and the following disclaimer. 9290001Sglebius * 2. Redistributions in binary form must reproduce the above copyright 10290001Sglebius * notice, this list of conditions and the following disclaimer in the 11290001Sglebius * documentation and/or other materials provided with the distribution. 12290001Sglebius * 3. The name of the author may not be used to endorse or promote products 13290001Sglebius * derived from this software without specific prior written permission. 14290001Sglebius * 15290001Sglebius * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16290001Sglebius * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17290001Sglebius * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18290001Sglebius * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19290001Sglebius * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20290001Sglebius * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21290001Sglebius * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22290001Sglebius * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23290001Sglebius * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24290001Sglebius * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25290001Sglebius */ 26290001Sglebius#include "event2/event-config.h" 27290001Sglebius#include "evconfig-private.h" 28290001Sglebius 29290001Sglebius#ifdef _WIN32 30290001Sglebius#include <winsock2.h> 31290001Sglebius#define WIN32_LEAN_AND_MEAN 32290001Sglebius#include <windows.h> 33290001Sglebius#undef WIN32_LEAN_AND_MEAN 34290001Sglebius#endif 35290001Sglebius#include <sys/types.h> 36290001Sglebius#if !defined(_WIN32) && defined(EVENT__HAVE_SYS_TIME_H) 37290001Sglebius#include <sys/time.h> 38290001Sglebius#endif 39290001Sglebius#include <sys/queue.h> 40290001Sglebius#include <stdio.h> 41290001Sglebius#include <stdlib.h> 42290001Sglebius#ifndef _WIN32 43290001Sglebius#include <unistd.h> 44290001Sglebius#endif 45290001Sglebius#include <errno.h> 46290001Sglebius#include <signal.h> 47290001Sglebius#include <string.h> 48290001Sglebius#include <time.h> 49290001Sglebius 50290001Sglebius#include "event-internal.h" 51290001Sglebius#include "evmap-internal.h" 52290001Sglebius#include "mm-internal.h" 53290001Sglebius#include "changelist-internal.h" 54290001Sglebius 55290001Sglebius/** An entry for an evmap_io list: notes all the events that want to read or 56290001Sglebius write on a given fd, and the number of each. 57290001Sglebius */ 58290001Sglebiusstruct evmap_io { 59290001Sglebius struct event_dlist events; 60290001Sglebius ev_uint16_t nread; 61290001Sglebius ev_uint16_t nwrite; 62290001Sglebius ev_uint16_t nclose; 63290001Sglebius}; 64290001Sglebius 65290001Sglebius/* An entry for an evmap_signal list: notes all the events that want to know 66290001Sglebius when a signal triggers. */ 67290001Sglebiusstruct evmap_signal { 68290001Sglebius struct event_dlist events; 69290001Sglebius}; 70290001Sglebius 71290001Sglebius/* On some platforms, fds start at 0 and increment by 1 as they are 72290001Sglebius allocated, and old numbers get used. For these platforms, we 73290001Sglebius implement io maps just like signal maps: as an array of pointers to 74290001Sglebius struct evmap_io. But on other platforms (windows), sockets are not 75290001Sglebius 0-indexed, not necessarily consecutive, and not necessarily reused. 76290001Sglebius There, we use a hashtable to implement evmap_io. 77290001Sglebius*/ 78290001Sglebius#ifdef EVMAP_USE_HT 79290001Sglebiusstruct event_map_entry { 80290001Sglebius HT_ENTRY(event_map_entry) map_node; 81290001Sglebius evutil_socket_t fd; 82290001Sglebius union { /* This is a union in case we need to make more things that can 83290001Sglebius be in the hashtable. */ 84290001Sglebius struct evmap_io evmap_io; 85290001Sglebius } ent; 86290001Sglebius}; 87290001Sglebius 88290001Sglebius/* Helper used by the event_io_map hashtable code; tries to return a good hash 89290001Sglebius * of the fd in e->fd. */ 90290001Sglebiusstatic inline unsigned 91290001Sglebiushashsocket(struct event_map_entry *e) 92290001Sglebius{ 93290001Sglebius /* On win32, in practice, the low 2-3 bits of a SOCKET seem not to 94290001Sglebius * matter. Our hashtable implementation really likes low-order bits, 95290001Sglebius * though, so let's do the rotate-and-add trick. */ 96290001Sglebius unsigned h = (unsigned) e->fd; 97290001Sglebius h += (h >> 2) | (h << 30); 98290001Sglebius return h; 99290001Sglebius} 100290001Sglebius 101290001Sglebius/* Helper used by the event_io_map hashtable code; returns true iff e1 and e2 102290001Sglebius * have the same e->fd. */ 103290001Sglebiusstatic inline int 104290001Sglebiuseqsocket(struct event_map_entry *e1, struct event_map_entry *e2) 105290001Sglebius{ 106290001Sglebius return e1->fd == e2->fd; 107290001Sglebius} 108290001Sglebius 109290001SglebiusHT_PROTOTYPE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket) 110290001SglebiusHT_GENERATE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket, 111290001Sglebius 0.5, mm_malloc, mm_realloc, mm_free) 112290001Sglebius 113290001Sglebius#define GET_IO_SLOT(x, map, slot, type) \ 114290001Sglebius do { \ 115290001Sglebius struct event_map_entry key_, *ent_; \ 116290001Sglebius key_.fd = slot; \ 117290001Sglebius ent_ = HT_FIND(event_io_map, map, &key_); \ 118290001Sglebius (x) = ent_ ? &ent_->ent.type : NULL; \ 119290001Sglebius } while (0); 120290001Sglebius 121290001Sglebius#define GET_IO_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \ 122290001Sglebius do { \ 123290001Sglebius struct event_map_entry key_, *ent_; \ 124290001Sglebius key_.fd = slot; \ 125290001Sglebius HT_FIND_OR_INSERT_(event_io_map, map_node, hashsocket, map, \ 126290001Sglebius event_map_entry, &key_, ptr, \ 127290001Sglebius { \ 128290001Sglebius ent_ = *ptr; \ 129290001Sglebius }, \ 130290001Sglebius { \ 131290001Sglebius ent_ = mm_calloc(1,sizeof(struct event_map_entry)+fdinfo_len); \ 132290001Sglebius if (EVUTIL_UNLIKELY(ent_ == NULL)) \ 133290001Sglebius return (-1); \ 134290001Sglebius ent_->fd = slot; \ 135290001Sglebius (ctor)(&ent_->ent.type); \ 136290001Sglebius HT_FOI_INSERT_(map_node, map, &key_, ent_, ptr) \ 137290001Sglebius }); \ 138290001Sglebius (x) = &ent_->ent.type; \ 139290001Sglebius } while (0) 140290001Sglebius 141290001Sglebiusvoid evmap_io_initmap_(struct event_io_map *ctx) 142290001Sglebius{ 143290001Sglebius HT_INIT(event_io_map, ctx); 144290001Sglebius} 145290001Sglebius 146290001Sglebiusvoid evmap_io_clear_(struct event_io_map *ctx) 147290001Sglebius{ 148290001Sglebius struct event_map_entry **ent, **next, *this; 149290001Sglebius for (ent = HT_START(event_io_map, ctx); ent; ent = next) { 150290001Sglebius this = *ent; 151290001Sglebius next = HT_NEXT_RMV(event_io_map, ctx, ent); 152290001Sglebius mm_free(this); 153290001Sglebius } 154290001Sglebius HT_CLEAR(event_io_map, ctx); /* remove all storage held by the ctx. */ 155290001Sglebius} 156290001Sglebius#endif 157290001Sglebius 158290001Sglebius/* Set the variable 'x' to the field in event_map 'map' with fields of type 159290001Sglebius 'struct type *' corresponding to the fd or signal 'slot'. Set 'x' to NULL 160290001Sglebius if there are no entries for 'slot'. Does no bounds-checking. */ 161290001Sglebius#define GET_SIGNAL_SLOT(x, map, slot, type) \ 162290001Sglebius (x) = (struct type *)((map)->entries[slot]) 163290001Sglebius/* As GET_SLOT, but construct the entry for 'slot' if it is not present, 164290001Sglebius by allocating enough memory for a 'struct type', and initializing the new 165290001Sglebius value by calling the function 'ctor' on it. Makes the function 166290001Sglebius return -1 on allocation failure. 167290001Sglebius */ 168290001Sglebius#define GET_SIGNAL_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \ 169290001Sglebius do { \ 170290001Sglebius if ((map)->entries[slot] == NULL) { \ 171290001Sglebius (map)->entries[slot] = \ 172290001Sglebius mm_calloc(1,sizeof(struct type)+fdinfo_len); \ 173290001Sglebius if (EVUTIL_UNLIKELY((map)->entries[slot] == NULL)) \ 174290001Sglebius return (-1); \ 175290001Sglebius (ctor)((struct type *)(map)->entries[slot]); \ 176290001Sglebius } \ 177290001Sglebius (x) = (struct type *)((map)->entries[slot]); \ 178290001Sglebius } while (0) 179290001Sglebius 180290001Sglebius/* If we aren't using hashtables, then define the IO_SLOT macros and functions 181290001Sglebius as thin aliases over the SIGNAL_SLOT versions. */ 182290001Sglebius#ifndef EVMAP_USE_HT 183290001Sglebius#define GET_IO_SLOT(x,map,slot,type) GET_SIGNAL_SLOT(x,map,slot,type) 184290001Sglebius#define GET_IO_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len) \ 185290001Sglebius GET_SIGNAL_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len) 186290001Sglebius#define FDINFO_OFFSET sizeof(struct evmap_io) 187290001Sglebiusvoid 188290001Sglebiusevmap_io_initmap_(struct event_io_map* ctx) 189290001Sglebius{ 190290001Sglebius evmap_signal_initmap_(ctx); 191290001Sglebius} 192290001Sglebiusvoid 193290001Sglebiusevmap_io_clear_(struct event_io_map* ctx) 194290001Sglebius{ 195290001Sglebius evmap_signal_clear_(ctx); 196290001Sglebius} 197290001Sglebius#endif 198290001Sglebius 199290001Sglebius 200290001Sglebius/** Expand 'map' with new entries of width 'msize' until it is big enough 201290001Sglebius to store a value in 'slot'. 202290001Sglebius */ 203290001Sglebiusstatic int 204290001Sglebiusevmap_make_space(struct event_signal_map *map, int slot, int msize) 205290001Sglebius{ 206290001Sglebius if (map->nentries <= slot) { 207290001Sglebius int nentries = map->nentries ? map->nentries : 32; 208290001Sglebius void **tmp; 209290001Sglebius 210290001Sglebius while (nentries <= slot) 211290001Sglebius nentries <<= 1; 212290001Sglebius 213290001Sglebius tmp = (void **)mm_realloc(map->entries, nentries * msize); 214290001Sglebius if (tmp == NULL) 215290001Sglebius return (-1); 216290001Sglebius 217290001Sglebius memset(&tmp[map->nentries], 0, 218290001Sglebius (nentries - map->nentries) * msize); 219290001Sglebius 220290001Sglebius map->nentries = nentries; 221290001Sglebius map->entries = tmp; 222290001Sglebius } 223290001Sglebius 224290001Sglebius return (0); 225290001Sglebius} 226290001Sglebius 227290001Sglebiusvoid 228290001Sglebiusevmap_signal_initmap_(struct event_signal_map *ctx) 229290001Sglebius{ 230290001Sglebius ctx->nentries = 0; 231290001Sglebius ctx->entries = NULL; 232290001Sglebius} 233290001Sglebius 234290001Sglebiusvoid 235290001Sglebiusevmap_signal_clear_(struct event_signal_map *ctx) 236290001Sglebius{ 237290001Sglebius if (ctx->entries != NULL) { 238290001Sglebius int i; 239290001Sglebius for (i = 0; i < ctx->nentries; ++i) { 240290001Sglebius if (ctx->entries[i] != NULL) 241290001Sglebius mm_free(ctx->entries[i]); 242290001Sglebius } 243290001Sglebius mm_free(ctx->entries); 244290001Sglebius ctx->entries = NULL; 245290001Sglebius } 246290001Sglebius ctx->nentries = 0; 247290001Sglebius} 248290001Sglebius 249290001Sglebius 250290001Sglebius/* code specific to file descriptors */ 251290001Sglebius 252290001Sglebius/** Constructor for struct evmap_io */ 253290001Sglebiusstatic void 254290001Sglebiusevmap_io_init(struct evmap_io *entry) 255290001Sglebius{ 256290001Sglebius LIST_INIT(&entry->events); 257290001Sglebius entry->nread = 0; 258290001Sglebius entry->nwrite = 0; 259290001Sglebius entry->nclose = 0; 260290001Sglebius} 261290001Sglebius 262290001Sglebius 263290001Sglebius/* return -1 on error, 0 on success if nothing changed in the event backend, 264290001Sglebius * and 1 on success if something did. */ 265290001Sglebiusint 266290001Sglebiusevmap_io_add_(struct event_base *base, evutil_socket_t fd, struct event *ev) 267290001Sglebius{ 268290001Sglebius const struct eventop *evsel = base->evsel; 269290001Sglebius struct event_io_map *io = &base->io; 270290001Sglebius struct evmap_io *ctx = NULL; 271290001Sglebius int nread, nwrite, nclose, retval = 0; 272290001Sglebius short res = 0, old = 0; 273290001Sglebius struct event *old_ev; 274290001Sglebius 275290001Sglebius EVUTIL_ASSERT(fd == ev->ev_fd); 276290001Sglebius 277290001Sglebius if (fd < 0) 278290001Sglebius return 0; 279290001Sglebius 280290001Sglebius#ifndef EVMAP_USE_HT 281290001Sglebius if (fd >= io->nentries) { 282290001Sglebius if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1) 283290001Sglebius return (-1); 284290001Sglebius } 285290001Sglebius#endif 286290001Sglebius GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init, 287290001Sglebius evsel->fdinfo_len); 288290001Sglebius 289290001Sglebius nread = ctx->nread; 290290001Sglebius nwrite = ctx->nwrite; 291290001Sglebius nclose = ctx->nclose; 292290001Sglebius 293290001Sglebius if (nread) 294290001Sglebius old |= EV_READ; 295290001Sglebius if (nwrite) 296290001Sglebius old |= EV_WRITE; 297290001Sglebius if (nclose) 298290001Sglebius old |= EV_CLOSED; 299290001Sglebius 300290001Sglebius if (ev->ev_events & EV_READ) { 301290001Sglebius if (++nread == 1) 302290001Sglebius res |= EV_READ; 303290001Sglebius } 304290001Sglebius if (ev->ev_events & EV_WRITE) { 305290001Sglebius if (++nwrite == 1) 306290001Sglebius res |= EV_WRITE; 307290001Sglebius } 308290001Sglebius if (ev->ev_events & EV_CLOSED) { 309290001Sglebius if (++nclose == 1) 310290001Sglebius res |= EV_CLOSED; 311290001Sglebius } 312290001Sglebius if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff || nclose > 0xffff)) { 313290001Sglebius event_warnx("Too many events reading or writing on fd %d", 314290001Sglebius (int)fd); 315290001Sglebius return -1; 316290001Sglebius } 317290001Sglebius if (EVENT_DEBUG_MODE_IS_ON() && 318290001Sglebius (old_ev = LIST_FIRST(&ctx->events)) && 319290001Sglebius (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) { 320290001Sglebius event_warnx("Tried to mix edge-triggered and non-edge-triggered" 321290001Sglebius " events on fd %d", (int)fd); 322290001Sglebius return -1; 323290001Sglebius } 324290001Sglebius 325290001Sglebius if (res) { 326290001Sglebius void *extra = ((char*)ctx) + sizeof(struct evmap_io); 327290001Sglebius /* XXX(niels): we cannot mix edge-triggered and 328290001Sglebius * level-triggered, we should probably assert on 329290001Sglebius * this. */ 330290001Sglebius if (evsel->add(base, ev->ev_fd, 331290001Sglebius old, (ev->ev_events & EV_ET) | res, extra) == -1) 332290001Sglebius return (-1); 333290001Sglebius retval = 1; 334290001Sglebius } 335290001Sglebius 336290001Sglebius ctx->nread = (ev_uint16_t) nread; 337290001Sglebius ctx->nwrite = (ev_uint16_t) nwrite; 338290001Sglebius ctx->nclose = (ev_uint16_t) nclose; 339290001Sglebius LIST_INSERT_HEAD(&ctx->events, ev, ev_io_next); 340290001Sglebius 341290001Sglebius return (retval); 342290001Sglebius} 343290001Sglebius 344290001Sglebius/* return -1 on error, 0 on success if nothing changed in the event backend, 345290001Sglebius * and 1 on success if something did. */ 346290001Sglebiusint 347290001Sglebiusevmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev) 348290001Sglebius{ 349290001Sglebius const struct eventop *evsel = base->evsel; 350290001Sglebius struct event_io_map *io = &base->io; 351290001Sglebius struct evmap_io *ctx; 352290001Sglebius int nread, nwrite, nclose, retval = 0; 353290001Sglebius short res = 0, old = 0; 354290001Sglebius 355290001Sglebius if (fd < 0) 356290001Sglebius return 0; 357290001Sglebius 358290001Sglebius EVUTIL_ASSERT(fd == ev->ev_fd); 359290001Sglebius 360290001Sglebius#ifndef EVMAP_USE_HT 361290001Sglebius if (fd >= io->nentries) 362290001Sglebius return (-1); 363290001Sglebius#endif 364290001Sglebius 365290001Sglebius GET_IO_SLOT(ctx, io, fd, evmap_io); 366290001Sglebius 367290001Sglebius nread = ctx->nread; 368290001Sglebius nwrite = ctx->nwrite; 369290001Sglebius nclose = ctx->nclose; 370290001Sglebius 371290001Sglebius if (nread) 372290001Sglebius old |= EV_READ; 373290001Sglebius if (nwrite) 374290001Sglebius old |= EV_WRITE; 375290001Sglebius if (nclose) 376290001Sglebius old |= EV_CLOSED; 377290001Sglebius 378290001Sglebius if (ev->ev_events & EV_READ) { 379290001Sglebius if (--nread == 0) 380290001Sglebius res |= EV_READ; 381290001Sglebius EVUTIL_ASSERT(nread >= 0); 382290001Sglebius } 383290001Sglebius if (ev->ev_events & EV_WRITE) { 384290001Sglebius if (--nwrite == 0) 385290001Sglebius res |= EV_WRITE; 386290001Sglebius EVUTIL_ASSERT(nwrite >= 0); 387290001Sglebius } 388290001Sglebius if (ev->ev_events & EV_CLOSED) { 389290001Sglebius if (--nclose == 0) 390290001Sglebius res |= EV_CLOSED; 391290001Sglebius EVUTIL_ASSERT(nclose >= 0); 392290001Sglebius } 393290001Sglebius 394290001Sglebius if (res) { 395290001Sglebius void *extra = ((char*)ctx) + sizeof(struct evmap_io); 396290001Sglebius if (evsel->del(base, ev->ev_fd, old, res, extra) == -1) { 397290001Sglebius retval = -1; 398290001Sglebius } else { 399290001Sglebius retval = 1; 400290001Sglebius } 401290001Sglebius } 402290001Sglebius 403290001Sglebius ctx->nread = nread; 404290001Sglebius ctx->nwrite = nwrite; 405290001Sglebius ctx->nclose = nclose; 406290001Sglebius LIST_REMOVE(ev, ev_io_next); 407290001Sglebius 408290001Sglebius return (retval); 409290001Sglebius} 410290001Sglebius 411290001Sglebiusvoid 412290001Sglebiusevmap_io_active_(struct event_base *base, evutil_socket_t fd, short events) 413290001Sglebius{ 414290001Sglebius struct event_io_map *io = &base->io; 415290001Sglebius struct evmap_io *ctx; 416290001Sglebius struct event *ev; 417290001Sglebius 418290001Sglebius#ifndef EVMAP_USE_HT 419290001Sglebius if (fd < 0 || fd >= io->nentries) 420290001Sglebius return; 421290001Sglebius#endif 422290001Sglebius GET_IO_SLOT(ctx, io, fd, evmap_io); 423290001Sglebius 424290001Sglebius if (NULL == ctx) 425290001Sglebius return; 426290001Sglebius LIST_FOREACH(ev, &ctx->events, ev_io_next) { 427290001Sglebius if (ev->ev_events & events) 428290001Sglebius event_active_nolock_(ev, ev->ev_events & events, 1); 429290001Sglebius } 430290001Sglebius} 431290001Sglebius 432290001Sglebius/* code specific to signals */ 433290001Sglebius 434290001Sglebiusstatic void 435290001Sglebiusevmap_signal_init(struct evmap_signal *entry) 436290001Sglebius{ 437290001Sglebius LIST_INIT(&entry->events); 438290001Sglebius} 439290001Sglebius 440290001Sglebius 441290001Sglebiusint 442290001Sglebiusevmap_signal_add_(struct event_base *base, int sig, struct event *ev) 443290001Sglebius{ 444290001Sglebius const struct eventop *evsel = base->evsigsel; 445290001Sglebius struct event_signal_map *map = &base->sigmap; 446290001Sglebius struct evmap_signal *ctx = NULL; 447290001Sglebius 448290001Sglebius if (sig >= map->nentries) { 449290001Sglebius if (evmap_make_space( 450290001Sglebius map, sig, sizeof(struct evmap_signal *)) == -1) 451290001Sglebius return (-1); 452290001Sglebius } 453290001Sglebius GET_SIGNAL_SLOT_AND_CTOR(ctx, map, sig, evmap_signal, evmap_signal_init, 454290001Sglebius base->evsigsel->fdinfo_len); 455290001Sglebius 456290001Sglebius if (LIST_EMPTY(&ctx->events)) { 457290001Sglebius if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL) 458290001Sglebius == -1) 459290001Sglebius return (-1); 460290001Sglebius } 461290001Sglebius 462290001Sglebius LIST_INSERT_HEAD(&ctx->events, ev, ev_signal_next); 463290001Sglebius 464290001Sglebius return (1); 465290001Sglebius} 466290001Sglebius 467290001Sglebiusint 468290001Sglebiusevmap_signal_del_(struct event_base *base, int sig, struct event *ev) 469290001Sglebius{ 470290001Sglebius const struct eventop *evsel = base->evsigsel; 471290001Sglebius struct event_signal_map *map = &base->sigmap; 472290001Sglebius struct evmap_signal *ctx; 473290001Sglebius 474290001Sglebius if (sig >= map->nentries) 475290001Sglebius return (-1); 476290001Sglebius 477290001Sglebius GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal); 478290001Sglebius 479290001Sglebius LIST_REMOVE(ev, ev_signal_next); 480290001Sglebius 481290001Sglebius if (LIST_FIRST(&ctx->events) == NULL) { 482290001Sglebius if (evsel->del(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1) 483290001Sglebius return (-1); 484290001Sglebius } 485290001Sglebius 486290001Sglebius return (1); 487290001Sglebius} 488290001Sglebius 489290001Sglebiusvoid 490290001Sglebiusevmap_signal_active_(struct event_base *base, evutil_socket_t sig, int ncalls) 491290001Sglebius{ 492290001Sglebius struct event_signal_map *map = &base->sigmap; 493290001Sglebius struct evmap_signal *ctx; 494290001Sglebius struct event *ev; 495290001Sglebius 496290001Sglebius if (sig < 0 || sig >= map->nentries) 497290001Sglebius return; 498290001Sglebius GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal); 499290001Sglebius 500290001Sglebius if (!ctx) 501290001Sglebius return; 502290001Sglebius LIST_FOREACH(ev, &ctx->events, ev_signal_next) 503290001Sglebius event_active_nolock_(ev, EV_SIGNAL, ncalls); 504290001Sglebius} 505290001Sglebius 506290001Sglebiusvoid * 507290001Sglebiusevmap_io_get_fdinfo_(struct event_io_map *map, evutil_socket_t fd) 508290001Sglebius{ 509290001Sglebius struct evmap_io *ctx; 510290001Sglebius GET_IO_SLOT(ctx, map, fd, evmap_io); 511290001Sglebius if (ctx) 512290001Sglebius return ((char*)ctx) + sizeof(struct evmap_io); 513290001Sglebius else 514290001Sglebius return NULL; 515290001Sglebius} 516290001Sglebius 517290001Sglebius/* Callback type for evmap_io_foreach_fd */ 518290001Sglebiustypedef int (*evmap_io_foreach_fd_cb)( 519290001Sglebius struct event_base *, evutil_socket_t, struct evmap_io *, void *); 520290001Sglebius 521290001Sglebius/* Multipurpose helper function: Iterate over every file descriptor event_base 522290001Sglebius * for which we could have EV_READ or EV_WRITE events. For each such fd, call 523290001Sglebius * fn(base, signum, evmap_io, arg), where fn is the user-provided 524290001Sglebius * function, base is the event_base, signum is the signal number, evmap_io 525290001Sglebius * is an evmap_io structure containing a list of events pending on the 526290001Sglebius * file descriptor, and arg is the user-supplied argument. 527290001Sglebius * 528290001Sglebius * If fn returns 0, continue on to the next signal. Otherwise, return the same 529290001Sglebius * value that fn returned. 530290001Sglebius * 531290001Sglebius * Note that there is no guarantee that the file descriptors will be processed 532290001Sglebius * in any particular order. 533290001Sglebius */ 534290001Sglebiusstatic int 535290001Sglebiusevmap_io_foreach_fd(struct event_base *base, 536290001Sglebius evmap_io_foreach_fd_cb fn, 537290001Sglebius void *arg) 538290001Sglebius{ 539290001Sglebius evutil_socket_t fd; 540290001Sglebius struct event_io_map *iomap = &base->io; 541290001Sglebius int r = 0; 542290001Sglebius#ifdef EVMAP_USE_HT 543290001Sglebius struct event_map_entry **mapent; 544290001Sglebius HT_FOREACH(mapent, event_io_map, iomap) { 545290001Sglebius struct evmap_io *ctx = &(*mapent)->ent.evmap_io; 546290001Sglebius fd = (*mapent)->fd; 547290001Sglebius#else 548290001Sglebius for (fd = 0; fd < iomap->nentries; ++fd) { 549290001Sglebius struct evmap_io *ctx = iomap->entries[fd]; 550290001Sglebius if (!ctx) 551290001Sglebius continue; 552290001Sglebius#endif 553290001Sglebius if ((r = fn(base, fd, ctx, arg))) 554290001Sglebius break; 555290001Sglebius } 556290001Sglebius return r; 557290001Sglebius} 558290001Sglebius 559290001Sglebius/* Callback type for evmap_signal_foreach_signal */ 560290001Sglebiustypedef int (*evmap_signal_foreach_signal_cb)( 561290001Sglebius struct event_base *, int, struct evmap_signal *, void *); 562290001Sglebius 563290001Sglebius/* Multipurpose helper function: Iterate over every signal number in the 564290001Sglebius * event_base for which we could have signal events. For each such signal, 565290001Sglebius * call fn(base, signum, evmap_signal, arg), where fn is the user-provided 566290001Sglebius * function, base is the event_base, signum is the signal number, evmap_signal 567290001Sglebius * is an evmap_signal structure containing a list of events pending on the 568290001Sglebius * signal, and arg is the user-supplied argument. 569290001Sglebius * 570290001Sglebius * If fn returns 0, continue on to the next signal. Otherwise, return the same 571290001Sglebius * value that fn returned. 572290001Sglebius */ 573290001Sglebiusstatic int 574290001Sglebiusevmap_signal_foreach_signal(struct event_base *base, 575290001Sglebius evmap_signal_foreach_signal_cb fn, 576290001Sglebius void *arg) 577290001Sglebius{ 578290001Sglebius struct event_signal_map *sigmap = &base->sigmap; 579290001Sglebius int r = 0; 580290001Sglebius int signum; 581290001Sglebius 582290001Sglebius for (signum = 0; signum < sigmap->nentries; ++signum) { 583290001Sglebius struct evmap_signal *ctx = sigmap->entries[signum]; 584290001Sglebius if (!ctx) 585290001Sglebius continue; 586290001Sglebius if ((r = fn(base, signum, ctx, arg))) 587290001Sglebius break; 588290001Sglebius } 589290001Sglebius return r; 590290001Sglebius} 591290001Sglebius 592290001Sglebius/* Helper for evmap_reinit_: tell the backend to add every fd for which we have 593290001Sglebius * pending events, with the appropriate combination of EV_READ, EV_WRITE, and 594290001Sglebius * EV_ET. */ 595290001Sglebiusstatic int 596290001Sglebiusevmap_io_reinit_iter_fn(struct event_base *base, evutil_socket_t fd, 597290001Sglebius struct evmap_io *ctx, void *arg) 598290001Sglebius{ 599290001Sglebius const struct eventop *evsel = base->evsel; 600290001Sglebius void *extra; 601290001Sglebius int *result = arg; 602290001Sglebius short events = 0; 603290001Sglebius struct event *ev; 604290001Sglebius EVUTIL_ASSERT(ctx); 605290001Sglebius 606290001Sglebius extra = ((char*)ctx) + sizeof(struct evmap_io); 607290001Sglebius if (ctx->nread) 608290001Sglebius events |= EV_READ; 609290001Sglebius if (ctx->nwrite) 610290001Sglebius events |= EV_WRITE; 611290001Sglebius if (ctx->nclose) 612290001Sglebius events |= EV_CLOSED; 613290001Sglebius if (evsel->fdinfo_len) 614290001Sglebius memset(extra, 0, evsel->fdinfo_len); 615290001Sglebius if (events && 616290001Sglebius (ev = LIST_FIRST(&ctx->events)) && 617290001Sglebius (ev->ev_events & EV_ET)) 618290001Sglebius events |= EV_ET; 619290001Sglebius if (evsel->add(base, fd, 0, events, extra) == -1) 620290001Sglebius *result = -1; 621290001Sglebius 622290001Sglebius return 0; 623290001Sglebius} 624290001Sglebius 625290001Sglebius/* Helper for evmap_reinit_: tell the backend to add every signal for which we 626290001Sglebius * have pending events. */ 627290001Sglebiusstatic int 628290001Sglebiusevmap_signal_reinit_iter_fn(struct event_base *base, 629290001Sglebius int signum, struct evmap_signal *ctx, void *arg) 630290001Sglebius{ 631290001Sglebius const struct eventop *evsel = base->evsigsel; 632290001Sglebius int *result = arg; 633290001Sglebius 634290001Sglebius if (!LIST_EMPTY(&ctx->events)) { 635290001Sglebius if (evsel->add(base, signum, 0, EV_SIGNAL, NULL) == -1) 636290001Sglebius *result = -1; 637290001Sglebius } 638290001Sglebius return 0; 639290001Sglebius} 640290001Sglebius 641290001Sglebiusint 642290001Sglebiusevmap_reinit_(struct event_base *base) 643290001Sglebius{ 644290001Sglebius int result = 0; 645290001Sglebius 646290001Sglebius evmap_io_foreach_fd(base, evmap_io_reinit_iter_fn, &result); 647290001Sglebius if (result < 0) 648290001Sglebius return -1; 649290001Sglebius evmap_signal_foreach_signal(base, evmap_signal_reinit_iter_fn, &result); 650290001Sglebius if (result < 0) 651290001Sglebius return -1; 652290001Sglebius return 0; 653290001Sglebius} 654290001Sglebius 655290001Sglebius/* Helper for evmap_delete_all_: delete every event in an event_dlist. */ 656290001Sglebiusstatic int 657290001Sglebiusdelete_all_in_dlist(struct event_dlist *dlist) 658290001Sglebius{ 659290001Sglebius struct event *ev; 660290001Sglebius while ((ev = LIST_FIRST(dlist))) 661290001Sglebius event_del(ev); 662290001Sglebius return 0; 663290001Sglebius} 664290001Sglebius 665290001Sglebius/* Helper for evmap_delete_all_: delete every event pending on an fd. */ 666290001Sglebiusstatic int 667290001Sglebiusevmap_io_delete_all_iter_fn(struct event_base *base, evutil_socket_t fd, 668290001Sglebius struct evmap_io *io_info, void *arg) 669290001Sglebius{ 670290001Sglebius return delete_all_in_dlist(&io_info->events); 671290001Sglebius} 672290001Sglebius 673290001Sglebius/* Helper for evmap_delete_all_: delete every event pending on a signal. */ 674290001Sglebiusstatic int 675290001Sglebiusevmap_signal_delete_all_iter_fn(struct event_base *base, int signum, 676290001Sglebius struct evmap_signal *sig_info, void *arg) 677290001Sglebius{ 678290001Sglebius return delete_all_in_dlist(&sig_info->events); 679290001Sglebius} 680290001Sglebius 681290001Sglebiusvoid 682290001Sglebiusevmap_delete_all_(struct event_base *base) 683290001Sglebius{ 684290001Sglebius evmap_signal_foreach_signal(base, evmap_signal_delete_all_iter_fn, NULL); 685290001Sglebius evmap_io_foreach_fd(base, evmap_io_delete_all_iter_fn, NULL); 686290001Sglebius} 687290001Sglebius 688290001Sglebius/** Per-fd structure for use with changelists. It keeps track, for each fd or 689290001Sglebius * signal using the changelist, of where its entry in the changelist is. 690290001Sglebius */ 691290001Sglebiusstruct event_changelist_fdinfo { 692290001Sglebius int idxplus1; /* this is the index +1, so that memset(0) will make it 693290001Sglebius * a no-such-element */ 694290001Sglebius}; 695290001Sglebius 696290001Sglebiusvoid 697290001Sglebiusevent_changelist_init_(struct event_changelist *changelist) 698290001Sglebius{ 699290001Sglebius changelist->changes = NULL; 700290001Sglebius changelist->changes_size = 0; 701290001Sglebius changelist->n_changes = 0; 702290001Sglebius} 703290001Sglebius 704290001Sglebius/** Helper: return the changelist_fdinfo corresponding to a given change. */ 705290001Sglebiusstatic inline struct event_changelist_fdinfo * 706290001Sglebiusevent_change_get_fdinfo(struct event_base *base, 707290001Sglebius const struct event_change *change) 708290001Sglebius{ 709290001Sglebius char *ptr; 710290001Sglebius if (change->read_change & EV_CHANGE_SIGNAL) { 711290001Sglebius struct evmap_signal *ctx; 712290001Sglebius GET_SIGNAL_SLOT(ctx, &base->sigmap, change->fd, evmap_signal); 713290001Sglebius ptr = ((char*)ctx) + sizeof(struct evmap_signal); 714290001Sglebius } else { 715290001Sglebius struct evmap_io *ctx; 716290001Sglebius GET_IO_SLOT(ctx, &base->io, change->fd, evmap_io); 717290001Sglebius ptr = ((char*)ctx) + sizeof(struct evmap_io); 718290001Sglebius } 719290001Sglebius return (void*)ptr; 720290001Sglebius} 721290001Sglebius 722290001Sglebius/** Callback helper for event_changelist_assert_ok */ 723290001Sglebiusstatic int 724290001Sglebiusevent_changelist_assert_ok_foreach_iter_fn( 725290001Sglebius struct event_base *base, 726290001Sglebius evutil_socket_t fd, struct evmap_io *io, void *arg) 727290001Sglebius{ 728290001Sglebius struct event_changelist *changelist = &base->changelist; 729290001Sglebius struct event_changelist_fdinfo *f; 730290001Sglebius f = (void*) 731290001Sglebius ( ((char*)io) + sizeof(struct evmap_io) ); 732290001Sglebius if (f->idxplus1) { 733290001Sglebius struct event_change *c = &changelist->changes[f->idxplus1 - 1]; 734290001Sglebius EVUTIL_ASSERT(c->fd == fd); 735290001Sglebius } 736290001Sglebius return 0; 737290001Sglebius} 738290001Sglebius 739290001Sglebius/** Make sure that the changelist is consistent with the evmap structures. */ 740290001Sglebiusstatic void 741290001Sglebiusevent_changelist_assert_ok(struct event_base *base) 742290001Sglebius{ 743290001Sglebius int i; 744290001Sglebius struct event_changelist *changelist = &base->changelist; 745290001Sglebius 746290001Sglebius EVUTIL_ASSERT(changelist->changes_size >= changelist->n_changes); 747290001Sglebius for (i = 0; i < changelist->n_changes; ++i) { 748290001Sglebius struct event_change *c = &changelist->changes[i]; 749290001Sglebius struct event_changelist_fdinfo *f; 750290001Sglebius EVUTIL_ASSERT(c->fd >= 0); 751290001Sglebius f = event_change_get_fdinfo(base, c); 752290001Sglebius EVUTIL_ASSERT(f); 753290001Sglebius EVUTIL_ASSERT(f->idxplus1 == i + 1); 754290001Sglebius } 755290001Sglebius 756290001Sglebius evmap_io_foreach_fd(base, 757290001Sglebius event_changelist_assert_ok_foreach_iter_fn, 758290001Sglebius NULL); 759290001Sglebius} 760290001Sglebius 761290001Sglebius#ifdef DEBUG_CHANGELIST 762290001Sglebius#define event_changelist_check(base) event_changelist_assert_ok((base)) 763290001Sglebius#else 764290001Sglebius#define event_changelist_check(base) ((void)0) 765290001Sglebius#endif 766290001Sglebius 767290001Sglebiusvoid 768290001Sglebiusevent_changelist_remove_all_(struct event_changelist *changelist, 769290001Sglebius struct event_base *base) 770290001Sglebius{ 771290001Sglebius int i; 772290001Sglebius 773290001Sglebius event_changelist_check(base); 774290001Sglebius 775290001Sglebius for (i = 0; i < changelist->n_changes; ++i) { 776290001Sglebius struct event_change *ch = &changelist->changes[i]; 777290001Sglebius struct event_changelist_fdinfo *fdinfo = 778290001Sglebius event_change_get_fdinfo(base, ch); 779290001Sglebius EVUTIL_ASSERT(fdinfo->idxplus1 == i + 1); 780290001Sglebius fdinfo->idxplus1 = 0; 781290001Sglebius } 782290001Sglebius 783290001Sglebius changelist->n_changes = 0; 784290001Sglebius 785290001Sglebius event_changelist_check(base); 786290001Sglebius} 787290001Sglebius 788290001Sglebiusvoid 789290001Sglebiusevent_changelist_freemem_(struct event_changelist *changelist) 790290001Sglebius{ 791290001Sglebius if (changelist->changes) 792290001Sglebius mm_free(changelist->changes); 793290001Sglebius event_changelist_init_(changelist); /* zero it all out. */ 794290001Sglebius} 795290001Sglebius 796290001Sglebius/** Increase the size of 'changelist' to hold more changes. */ 797290001Sglebiusstatic int 798290001Sglebiusevent_changelist_grow(struct event_changelist *changelist) 799290001Sglebius{ 800290001Sglebius int new_size; 801290001Sglebius struct event_change *new_changes; 802290001Sglebius if (changelist->changes_size < 64) 803290001Sglebius new_size = 64; 804290001Sglebius else 805290001Sglebius new_size = changelist->changes_size * 2; 806290001Sglebius 807290001Sglebius new_changes = mm_realloc(changelist->changes, 808290001Sglebius new_size * sizeof(struct event_change)); 809290001Sglebius 810290001Sglebius if (EVUTIL_UNLIKELY(new_changes == NULL)) 811290001Sglebius return (-1); 812290001Sglebius 813290001Sglebius changelist->changes = new_changes; 814290001Sglebius changelist->changes_size = new_size; 815290001Sglebius 816290001Sglebius return (0); 817290001Sglebius} 818290001Sglebius 819290001Sglebius/** Return a pointer to the changelist entry for the file descriptor or signal 820290001Sglebius * 'fd', whose fdinfo is 'fdinfo'. If none exists, construct it, setting its 821290001Sglebius * old_events field to old_events. 822290001Sglebius */ 823290001Sglebiusstatic struct event_change * 824290001Sglebiusevent_changelist_get_or_construct(struct event_changelist *changelist, 825290001Sglebius evutil_socket_t fd, 826290001Sglebius short old_events, 827290001Sglebius struct event_changelist_fdinfo *fdinfo) 828290001Sglebius{ 829290001Sglebius struct event_change *change; 830290001Sglebius 831290001Sglebius if (fdinfo->idxplus1 == 0) { 832290001Sglebius int idx; 833290001Sglebius EVUTIL_ASSERT(changelist->n_changes <= changelist->changes_size); 834290001Sglebius 835290001Sglebius if (changelist->n_changes == changelist->changes_size) { 836290001Sglebius if (event_changelist_grow(changelist) < 0) 837290001Sglebius return NULL; 838290001Sglebius } 839290001Sglebius 840290001Sglebius idx = changelist->n_changes++; 841290001Sglebius change = &changelist->changes[idx]; 842290001Sglebius fdinfo->idxplus1 = idx + 1; 843290001Sglebius 844290001Sglebius memset(change, 0, sizeof(struct event_change)); 845290001Sglebius change->fd = fd; 846290001Sglebius change->old_events = old_events; 847290001Sglebius } else { 848290001Sglebius change = &changelist->changes[fdinfo->idxplus1 - 1]; 849290001Sglebius EVUTIL_ASSERT(change->fd == fd); 850290001Sglebius } 851290001Sglebius return change; 852290001Sglebius} 853290001Sglebius 854290001Sglebiusint 855290001Sglebiusevent_changelist_add_(struct event_base *base, evutil_socket_t fd, short old, short events, 856290001Sglebius void *p) 857290001Sglebius{ 858290001Sglebius struct event_changelist *changelist = &base->changelist; 859290001Sglebius struct event_changelist_fdinfo *fdinfo = p; 860290001Sglebius struct event_change *change; 861290001Sglebius 862290001Sglebius event_changelist_check(base); 863290001Sglebius 864290001Sglebius change = event_changelist_get_or_construct(changelist, fd, old, fdinfo); 865290001Sglebius if (!change) 866290001Sglebius return -1; 867290001Sglebius 868290001Sglebius /* An add replaces any previous delete, but doesn't result in a no-op, 869290001Sglebius * since the delete might fail (because the fd had been closed since 870290001Sglebius * the last add, for instance. */ 871290001Sglebius 872290001Sglebius if (events & (EV_READ|EV_SIGNAL)) { 873290001Sglebius change->read_change = EV_CHANGE_ADD | 874290001Sglebius (events & (EV_ET|EV_PERSIST|EV_SIGNAL)); 875290001Sglebius } 876290001Sglebius if (events & EV_WRITE) { 877290001Sglebius change->write_change = EV_CHANGE_ADD | 878290001Sglebius (events & (EV_ET|EV_PERSIST|EV_SIGNAL)); 879290001Sglebius } 880290001Sglebius if (events & EV_CLOSED) { 881290001Sglebius change->close_change = EV_CHANGE_ADD | 882290001Sglebius (events & (EV_ET|EV_PERSIST|EV_SIGNAL)); 883290001Sglebius } 884290001Sglebius 885290001Sglebius event_changelist_check(base); 886290001Sglebius return (0); 887290001Sglebius} 888290001Sglebius 889290001Sglebiusint 890290001Sglebiusevent_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events, 891290001Sglebius void *p) 892290001Sglebius{ 893290001Sglebius struct event_changelist *changelist = &base->changelist; 894290001Sglebius struct event_changelist_fdinfo *fdinfo = p; 895290001Sglebius struct event_change *change; 896290001Sglebius 897290001Sglebius event_changelist_check(base); 898290001Sglebius change = event_changelist_get_or_construct(changelist, fd, old, fdinfo); 899290001Sglebius event_changelist_check(base); 900290001Sglebius if (!change) 901290001Sglebius return -1; 902290001Sglebius 903290001Sglebius /* A delete on an event set that doesn't contain the event to be 904290001Sglebius deleted produces a no-op. This effectively emoves any previous 905290001Sglebius uncommitted add, rather than replacing it: on those platforms where 906290001Sglebius "add, delete, dispatch" is not the same as "no-op, dispatch", we 907290001Sglebius want the no-op behavior. 908290001Sglebius 909290001Sglebius If we have a no-op item, we could remove it it from the list 910290001Sglebius entirely, but really there's not much point: skipping the no-op 911290001Sglebius change when we do the dispatch later is far cheaper than rejuggling 912290001Sglebius the array now. 913290001Sglebius 914290001Sglebius As this stands, it also lets through deletions of events that are 915290001Sglebius not currently set. 916290001Sglebius */ 917290001Sglebius 918290001Sglebius if (events & (EV_READ|EV_SIGNAL)) { 919290001Sglebius if (!(change->old_events & (EV_READ | EV_SIGNAL))) 920290001Sglebius change->read_change = 0; 921290001Sglebius else 922290001Sglebius change->read_change = EV_CHANGE_DEL; 923290001Sglebius } 924290001Sglebius if (events & EV_WRITE) { 925290001Sglebius if (!(change->old_events & EV_WRITE)) 926290001Sglebius change->write_change = 0; 927290001Sglebius else 928290001Sglebius change->write_change = EV_CHANGE_DEL; 929290001Sglebius } 930290001Sglebius if (events & EV_CLOSED) { 931290001Sglebius if (!(change->old_events & EV_CLOSED)) 932290001Sglebius change->close_change = 0; 933290001Sglebius else 934290001Sglebius change->close_change = EV_CHANGE_DEL; 935290001Sglebius } 936290001Sglebius 937290001Sglebius event_changelist_check(base); 938290001Sglebius return (0); 939290001Sglebius} 940290001Sglebius 941290001Sglebius/* Helper for evmap_check_integrity_: verify that all of the events pending on 942290001Sglebius * given fd are set up correctly, and that the nread and nwrite counts on that 943290001Sglebius * fd are correct. */ 944290001Sglebiusstatic int 945290001Sglebiusevmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd, 946290001Sglebius struct evmap_io *io_info, void *arg) 947290001Sglebius{ 948290001Sglebius struct event *ev; 949290001Sglebius int n_read = 0, n_write = 0, n_close = 0; 950290001Sglebius 951290001Sglebius /* First, make sure the list itself isn't corrupt. Otherwise, 952290001Sglebius * running LIST_FOREACH could be an exciting adventure. */ 953290001Sglebius EVUTIL_ASSERT_LIST_OK(&io_info->events, event, ev_io_next); 954290001Sglebius 955290001Sglebius LIST_FOREACH(ev, &io_info->events, ev_io_next) { 956290001Sglebius EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED); 957290001Sglebius EVUTIL_ASSERT(ev->ev_fd == fd); 958290001Sglebius EVUTIL_ASSERT(!(ev->ev_events & EV_SIGNAL)); 959290001Sglebius EVUTIL_ASSERT((ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))); 960290001Sglebius if (ev->ev_events & EV_READ) 961290001Sglebius ++n_read; 962290001Sglebius if (ev->ev_events & EV_WRITE) 963290001Sglebius ++n_write; 964290001Sglebius if (ev->ev_events & EV_CLOSED) 965290001Sglebius ++n_close; 966290001Sglebius } 967290001Sglebius 968290001Sglebius EVUTIL_ASSERT(n_read == io_info->nread); 969290001Sglebius EVUTIL_ASSERT(n_write == io_info->nwrite); 970290001Sglebius EVUTIL_ASSERT(n_close == io_info->nclose); 971290001Sglebius 972290001Sglebius return 0; 973290001Sglebius} 974290001Sglebius 975290001Sglebius/* Helper for evmap_check_integrity_: verify that all of the events pending 976290001Sglebius * on given signal are set up correctly. */ 977290001Sglebiusstatic int 978290001Sglebiusevmap_signal_check_integrity_fn(struct event_base *base, 979290001Sglebius int signum, struct evmap_signal *sig_info, void *arg) 980290001Sglebius{ 981290001Sglebius struct event *ev; 982290001Sglebius /* First, make sure the list itself isn't corrupt. */ 983290001Sglebius EVUTIL_ASSERT_LIST_OK(&sig_info->events, event, ev_signal_next); 984290001Sglebius 985290001Sglebius LIST_FOREACH(ev, &sig_info->events, ev_io_next) { 986290001Sglebius EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED); 987290001Sglebius EVUTIL_ASSERT(ev->ev_fd == signum); 988290001Sglebius EVUTIL_ASSERT((ev->ev_events & EV_SIGNAL)); 989290001Sglebius EVUTIL_ASSERT(!(ev->ev_events & (EV_READ|EV_WRITE|EV_CLOSED))); 990290001Sglebius } 991290001Sglebius return 0; 992290001Sglebius} 993290001Sglebius 994290001Sglebiusvoid 995290001Sglebiusevmap_check_integrity_(struct event_base *base) 996290001Sglebius{ 997290001Sglebius evmap_io_foreach_fd(base, evmap_io_check_integrity_fn, NULL); 998290001Sglebius evmap_signal_foreach_signal(base, evmap_signal_check_integrity_fn, NULL); 999290001Sglebius 1000290001Sglebius if (base->evsel->add == event_changelist_add_) 1001290001Sglebius event_changelist_assert_ok(base); 1002290001Sglebius} 1003290001Sglebius 1004290001Sglebius/* Helper type for evmap_foreach_event_: Bundles a function to call on every 1005290001Sglebius * event, and the user-provided void* to use as its third argument. */ 1006290001Sglebiusstruct evmap_foreach_event_helper { 1007290001Sglebius event_base_foreach_event_cb fn; 1008290001Sglebius void *arg; 1009290001Sglebius}; 1010290001Sglebius 1011290001Sglebius/* Helper for evmap_foreach_event_: calls a provided function on every event 1012290001Sglebius * pending on a given fd. */ 1013290001Sglebiusstatic int 1014290001Sglebiusevmap_io_foreach_event_fn(struct event_base *base, evutil_socket_t fd, 1015290001Sglebius struct evmap_io *io_info, void *arg) 1016290001Sglebius{ 1017290001Sglebius struct evmap_foreach_event_helper *h = arg; 1018290001Sglebius struct event *ev; 1019290001Sglebius int r; 1020290001Sglebius LIST_FOREACH(ev, &io_info->events, ev_io_next) { 1021290001Sglebius if ((r = h->fn(base, ev, h->arg))) 1022290001Sglebius return r; 1023290001Sglebius } 1024290001Sglebius return 0; 1025290001Sglebius} 1026290001Sglebius 1027290001Sglebius/* Helper for evmap_foreach_event_: calls a provided function on every event 1028290001Sglebius * pending on a given signal. */ 1029290001Sglebiusstatic int 1030290001Sglebiusevmap_signal_foreach_event_fn(struct event_base *base, int signum, 1031290001Sglebius struct evmap_signal *sig_info, void *arg) 1032290001Sglebius{ 1033290001Sglebius struct event *ev; 1034290001Sglebius struct evmap_foreach_event_helper *h = arg; 1035290001Sglebius int r; 1036290001Sglebius LIST_FOREACH(ev, &sig_info->events, ev_signal_next) { 1037290001Sglebius if ((r = h->fn(base, ev, h->arg))) 1038290001Sglebius return r; 1039290001Sglebius } 1040290001Sglebius return 0; 1041290001Sglebius} 1042290001Sglebius 1043290001Sglebiusint 1044290001Sglebiusevmap_foreach_event_(struct event_base *base, 1045290001Sglebius event_base_foreach_event_cb fn, void *arg) 1046290001Sglebius{ 1047290001Sglebius struct evmap_foreach_event_helper h; 1048290001Sglebius int r; 1049290001Sglebius h.fn = fn; 1050290001Sglebius h.arg = arg; 1051290001Sglebius if ((r = evmap_io_foreach_fd(base, evmap_io_foreach_event_fn, &h))) 1052290001Sglebius return r; 1053290001Sglebius return evmap_signal_foreach_signal(base, evmap_signal_foreach_event_fn, &h); 1054290001Sglebius} 1055290001Sglebius 1056