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