root/opal/mca/event/libevent2022/libevent/evmap.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. hashsocket
  2. eqsocket
  3. evmap_io_initmap
  4. evmap_io_clear
  5. evmap_io_initmap
  6. evmap_io_clear
  7. evmap_make_space
  8. evmap_signal_initmap
  9. evmap_signal_clear
  10. evmap_io_init
  11. evmap_io_add
  12. evmap_io_del
  13. evmap_io_active
  14. evmap_signal_init
  15. evmap_signal_add
  16. evmap_signal_del
  17. evmap_signal_active
  18. evmap_io_get_fdinfo
  19. event_changelist_init
  20. event_change_get_fdinfo
  21. event_changelist_check
  22. event_changelist_remove_all
  23. event_changelist_freemem
  24. event_changelist_grow
  25. event_changelist_get_or_construct
  26. event_changelist_add
  27. event_changelist_del
  28. evmap_check_integrity

   1 /*
   2  * Copyright (c) 2007-2012 Niels Provos and Nick Mathewson
   3  *
   4  * Redistribution and use in source and binary forms, with or without
   5  * modification, are permitted provided that the following conditions
   6  * are met:
   7  * 1. Redistributions of source code must retain the above copyright
   8  *    notice, this list of conditions and the following disclaimer.
   9  * 2. Redistributions in binary form must reproduce the above copyright
  10  *    notice, this list of conditions and the following disclaimer in the
  11  *    documentation and/or other materials provided with the distribution.
  12  * 3. The name of the author may not be used to endorse or promote products
  13  *    derived from this software without specific prior written permission.
  14  *
  15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25  */
  26 #include "event2/event-config.h"
  27 
  28 #ifdef WIN32
  29 #include <winsock2.h>
  30 #define WIN32_LEAN_AND_MEAN
  31 #include <windows.h>
  32 #undef WIN32_LEAN_AND_MEAN
  33 #endif
  34 #include <sys/types.h>
  35 #if !defined(WIN32) && defined(_EVENT_HAVE_SYS_TIME_H)
  36 #include <sys/time.h>
  37 #endif
  38 #include <sys/queue.h>
  39 #include <stdio.h>
  40 #include <stdlib.h>
  41 #ifndef WIN32
  42 #include <unistd.h>
  43 #endif
  44 #include <errno.h>
  45 #include <signal.h>
  46 #include <string.h>
  47 #include <time.h>
  48 
  49 #include "event-internal.h"
  50 #include "evmap-internal.h"
  51 #include "mm-internal.h"
  52 #include "changelist-internal.h"
  53 
  54 /** An entry for an evmap_io list: notes all the events that want to read or
  55         write on a given fd, and the number of each.
  56   */
  57 struct evmap_io {
  58         struct event_list events;
  59         ev_uint16_t nread;
  60         ev_uint16_t nwrite;
  61 };
  62 
  63 /* An entry for an evmap_signal list: notes all the events that want to know
  64    when a signal triggers. */
  65 struct evmap_signal {
  66         struct event_list events;
  67 };
  68 
  69 /* On some platforms, fds start at 0 and increment by 1 as they are
  70    allocated, and old numbers get used.  For these platforms, we
  71    implement io maps just like signal maps: as an array of pointers to
  72    struct evmap_io.  But on other platforms (windows), sockets are not
  73    0-indexed, not necessarily consecutive, and not necessarily reused.
  74    There, we use a hashtable to implement evmap_io.
  75 */
  76 #ifdef EVMAP_USE_HT
  77 struct event_map_entry {
  78         HT_ENTRY(event_map_entry) map_node;
  79         evutil_socket_t fd;
  80         union { /* This is a union in case we need to make more things that can
  81                            be in the hashtable. */
  82                 struct evmap_io evmap_io;
  83         } ent;
  84 };
  85 
  86 /* Helper used by the event_io_map hashtable code; tries to return a good hash
  87  * of the fd in e->fd. */
  88 static inline unsigned
  89 hashsocket(struct event_map_entry *e)
  90 {
  91         /* On win32, in practice, the low 2-3 bits of a SOCKET seem not to
  92          * matter.  Our hashtable implementation really likes low-order bits,
  93          * though, so let's do the rotate-and-add trick. */
  94         unsigned h = (unsigned) e->fd;
  95         h += (h >> 2) | (h << 30);
  96         return h;
  97 }
  98 
  99 /* Helper used by the event_io_map hashtable code; returns true iff e1 and e2
 100  * have the same e->fd. */
 101 static inline int
 102 eqsocket(struct event_map_entry *e1, struct event_map_entry *e2)
 103 {
 104         return e1->fd == e2->fd;
 105 }
 106 
 107 HT_PROTOTYPE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket)
 108 HT_GENERATE(event_io_map, event_map_entry, map_node, hashsocket, eqsocket,
 109                         0.5, mm_malloc, mm_realloc, mm_free)
 110 
 111 #define GET_IO_SLOT(x, map, slot, type)                                 \
 112         do {                                                            \
 113                 struct event_map_entry _key, *_ent;                     \
 114                 _key.fd = slot;                                         \
 115                 _ent = HT_FIND(event_io_map, map, &_key);               \
 116                 (x) = _ent ? &_ent->ent.type : NULL;                    \
 117         } while (0);
 118 
 119 #define GET_IO_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len)      \
 120         do {                                                            \
 121                 struct event_map_entry _key, *_ent;                     \
 122                 _key.fd = slot;                                         \
 123                 _HT_FIND_OR_INSERT(event_io_map, map_node, hashsocket, map, \
 124                     event_map_entry, &_key, ptr,                        \
 125                     {                                                   \
 126                             _ent = *ptr;                                \
 127                     },                                                  \
 128                     {                                                   \
 129                             _ent = mm_calloc(1,sizeof(struct event_map_entry)+fdinfo_len); \
 130                             if (EVUTIL_UNLIKELY(_ent == NULL))          \
 131                                     return (-1);                        \
 132                             _ent->fd = slot;                            \
 133                             (ctor)(&_ent->ent.type);                    \
 134                             _HT_FOI_INSERT(map_node, map, &_key, _ent, ptr) \
 135                                 });                                     \
 136                 (x) = &_ent->ent.type;                                  \
 137         } while (0)
 138 
 139 void evmap_io_initmap(struct event_io_map *ctx)
 140 {
 141         HT_INIT(event_io_map, ctx);
 142 }
 143 
 144 void evmap_io_clear(struct event_io_map *ctx)
 145 {
 146         struct event_map_entry **ent, **next, *this;
 147         for (ent = HT_START(event_io_map, ctx); ent; ent = next) {
 148                 this = *ent;
 149                 next = HT_NEXT_RMV(event_io_map, ctx, ent);
 150                 mm_free(this);
 151         }
 152         HT_CLEAR(event_io_map, ctx); /* remove all storage held by the ctx. */
 153 }
 154 #endif
 155 
 156 /* Set the variable 'x' to the field in event_map 'map' with fields of type
 157    'struct type *' corresponding to the fd or signal 'slot'.  Set 'x' to NULL
 158    if there are no entries for 'slot'.  Does no bounds-checking. */
 159 #define GET_SIGNAL_SLOT(x, map, slot, type)                     \
 160         (x) = (struct type *)((map)->entries[slot])
 161 /* As GET_SLOT, but construct the entry for 'slot' if it is not present,
 162    by allocating enough memory for a 'struct type', and initializing the new
 163    value by calling the function 'ctor' on it.  Makes the function
 164    return -1 on allocation failure.
 165  */
 166 #define GET_SIGNAL_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len)  \
 167         do {                                                            \
 168                 if ((map)->entries[slot] == NULL) {                     \
 169                         (map)->entries[slot] =                          \
 170                             mm_calloc(1,sizeof(struct type)+fdinfo_len); \
 171                         if (EVUTIL_UNLIKELY((map)->entries[slot] == NULL)) \
 172                                 return (-1);                            \
 173                         (ctor)((struct type *)(map)->entries[slot]);    \
 174                 }                                                       \
 175                 (x) = (struct type *)((map)->entries[slot]);            \
 176         } while (0)
 177 
 178 /* If we aren't using hashtables, then define the IO_SLOT macros and functions
 179    as thin aliases over the SIGNAL_SLOT versions. */
 180 #ifndef EVMAP_USE_HT
 181 #define GET_IO_SLOT(x,map,slot,type) GET_SIGNAL_SLOT(x,map,slot,type)
 182 #define GET_IO_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)   \
 183         GET_SIGNAL_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len)
 184 #define FDINFO_OFFSET sizeof(struct evmap_io)
 185 void
 186 evmap_io_initmap(struct event_io_map* ctx)
 187 {
 188         evmap_signal_initmap(ctx);
 189 }
 190 void
 191 evmap_io_clear(struct event_io_map* ctx)
 192 {
 193         evmap_signal_clear(ctx);
 194 }
 195 #endif
 196 
 197 
 198 /** Expand 'map' with new entries of width 'msize' until it is big enough
 199         to store a value in 'slot'.
 200  */
 201 static int
 202 evmap_make_space(struct event_signal_map *map, int slot, int msize)
 203 {
 204         if (map->nentries <= slot) {
 205                 int nentries = map->nentries ? map->nentries : 32;
 206                 void **tmp;
 207 
 208                 while (nentries <= slot)
 209                         nentries <<= 1;
 210 
 211                 tmp = (void **)mm_realloc(map->entries, nentries * msize);
 212                 if (tmp == NULL)
 213                         return (-1);
 214 
 215                 memset(&tmp[map->nentries], 0,
 216                     (nentries - map->nentries) * msize);
 217 
 218                 map->nentries = nentries;
 219                 map->entries = tmp;
 220         }
 221 
 222         return (0);
 223 }
 224 
 225 void
 226 evmap_signal_initmap(struct event_signal_map *ctx)
 227 {
 228         ctx->nentries = 0;
 229         ctx->entries = NULL;
 230 }
 231 
 232 void
 233 evmap_signal_clear(struct event_signal_map *ctx)
 234 {
 235         if (ctx->entries != NULL) {
 236                 int i;
 237                 for (i = 0; i < ctx->nentries; ++i) {
 238                         if (ctx->entries[i] != NULL)
 239                                 mm_free(ctx->entries[i]);
 240                 }
 241                 mm_free(ctx->entries);
 242                 ctx->entries = NULL;
 243         }
 244         ctx->nentries = 0;
 245 }
 246 
 247 
 248 /* code specific to file descriptors */
 249 
 250 /** Constructor for struct evmap_io */
 251 static void
 252 evmap_io_init(struct evmap_io *entry)
 253 {
 254         TAILQ_INIT(&entry->events);
 255         entry->nread = 0;
 256         entry->nwrite = 0;
 257 }
 258 
 259 
 260 /* return -1 on error, 0 on success if nothing changed in the event backend,
 261  * and 1 on success if something did. */
 262 int
 263 evmap_io_add(struct event_base *base, evutil_socket_t fd, struct event *ev)
 264 {
 265         const struct eventop *evsel = base->evsel;
 266         struct event_io_map *io = &base->io;
 267         struct evmap_io *ctx = NULL;
 268         int nread, nwrite, retval = 0;
 269         short res = 0, old = 0;
 270         struct event *old_ev;
 271 
 272         EVUTIL_ASSERT(fd == ev->ev_fd);
 273 
 274         if (fd < 0)
 275                 return 0;
 276 
 277 #ifndef EVMAP_USE_HT
 278         if (fd >= io->nentries) {
 279                 if (evmap_make_space(io, fd, sizeof(struct evmap_io *)) == -1)
 280                         return (-1);
 281         }
 282 #endif
 283         GET_IO_SLOT_AND_CTOR(ctx, io, fd, evmap_io, evmap_io_init,
 284                                                  evsel->fdinfo_len);
 285 
 286         nread = ctx->nread;
 287         nwrite = ctx->nwrite;
 288 
 289         if (nread)
 290                 old |= EV_READ;
 291         if (nwrite)
 292                 old |= EV_WRITE;
 293 
 294         if (ev->ev_events & EV_READ) {
 295                 if (++nread == 1)
 296                         res |= EV_READ;
 297         }
 298         if (ev->ev_events & EV_WRITE) {
 299                 if (++nwrite == 1)
 300                         res |= EV_WRITE;
 301         }
 302         if (EVUTIL_UNLIKELY(nread > 0xffff || nwrite > 0xffff)) {
 303                 event_warnx("Too many events reading or writing on fd %d",
 304                     (int)fd);
 305                 return -1;
 306         }
 307         if (EVENT_DEBUG_MODE_IS_ON() &&
 308             (old_ev = TAILQ_FIRST(&ctx->events)) &&
 309             (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) {
 310                 event_warnx("Tried to mix edge-triggered and non-edge-triggered"
 311                     " events on fd %d", (int)fd);
 312                 return -1;
 313         }
 314 
 315         if (res) {
 316                 void *extra = ((char*)ctx) + sizeof(struct evmap_io);
 317                 /* XXX(niels): we cannot mix edge-triggered and
 318                  * level-triggered, we should probably assert on
 319                  * this. */
 320                 if (evsel->add(base, ev->ev_fd,
 321                         old, (ev->ev_events & EV_ET) | res, extra) == -1)
 322                         return (-1);
 323                 retval = 1;
 324         }
 325 
 326         ctx->nread = (ev_uint16_t) nread;
 327         ctx->nwrite = (ev_uint16_t) nwrite;
 328         TAILQ_INSERT_TAIL(&ctx->events, ev, ev_io_next);
 329 
 330         return (retval);
 331 }
 332 
 333 /* return -1 on error, 0 on success if nothing changed in the event backend,
 334  * and 1 on success if something did. */
 335 int
 336 evmap_io_del(struct event_base *base, evutil_socket_t fd, struct event *ev)
 337 {
 338         const struct eventop *evsel = base->evsel;
 339         struct event_io_map *io = &base->io;
 340         struct evmap_io *ctx;
 341         int nread, nwrite, retval = 0;
 342         short res = 0, old = 0;
 343 
 344         if (fd < 0)
 345                 return 0;
 346 
 347         EVUTIL_ASSERT(fd == ev->ev_fd);
 348 
 349 #ifndef EVMAP_USE_HT
 350         if (fd >= io->nentries)
 351                 return (-1);
 352 #endif
 353 
 354         GET_IO_SLOT(ctx, io, fd, evmap_io);
 355 
 356         nread = ctx->nread;
 357         nwrite = ctx->nwrite;
 358 
 359         if (nread)
 360                 old |= EV_READ;
 361         if (nwrite)
 362                 old |= EV_WRITE;
 363 
 364         if (ev->ev_events & EV_READ) {
 365                 if (--nread == 0)
 366                         res |= EV_READ;
 367                 EVUTIL_ASSERT(nread >= 0);
 368         }
 369         if (ev->ev_events & EV_WRITE) {
 370                 if (--nwrite == 0)
 371                         res |= EV_WRITE;
 372                 EVUTIL_ASSERT(nwrite >= 0);
 373         }
 374 
 375         if (res) {
 376                 void *extra = ((char*)ctx) + sizeof(struct evmap_io);
 377                 if (evsel->del(base, ev->ev_fd, old, res, extra) == -1)
 378                         return (-1);
 379                 retval = 1;
 380         }
 381 
 382         ctx->nread = nread;
 383         ctx->nwrite = nwrite;
 384         TAILQ_REMOVE(&ctx->events, ev, ev_io_next);
 385 
 386         return (retval);
 387 }
 388 
 389 void
 390 evmap_io_active(struct event_base *base, evutil_socket_t fd, short events)
 391 {
 392         struct event_io_map *io = &base->io;
 393         struct evmap_io *ctx;
 394         struct event *ev;
 395 
 396 #ifndef EVMAP_USE_HT
 397         EVUTIL_ASSERT(fd < io->nentries);
 398 #endif
 399         GET_IO_SLOT(ctx, io, fd, evmap_io);
 400 
 401         EVUTIL_ASSERT(ctx);
 402         TAILQ_FOREACH(ev, &ctx->events, ev_io_next) {
 403                 if (ev->ev_events & events)
 404                         event_active_nolock(ev, ev->ev_events & events, 1);
 405         }
 406 }
 407 
 408 /* code specific to signals */
 409 
 410 static void
 411 evmap_signal_init(struct evmap_signal *entry)
 412 {
 413         TAILQ_INIT(&entry->events);
 414 }
 415 
 416 
 417 int
 418 evmap_signal_add(struct event_base *base, int sig, struct event *ev)
 419 {
 420         const struct eventop *evsel = base->evsigsel;
 421         struct event_signal_map *map = &base->sigmap;
 422         struct evmap_signal *ctx = NULL;
 423 
 424         if (sig >= map->nentries) {
 425                 if (evmap_make_space(
 426                         map, sig, sizeof(struct evmap_signal *)) == -1)
 427                         return (-1);
 428         }
 429         GET_SIGNAL_SLOT_AND_CTOR(ctx, map, sig, evmap_signal, evmap_signal_init,
 430             base->evsigsel->fdinfo_len);
 431 
 432         if (TAILQ_EMPTY(&ctx->events)) {
 433                 if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL)
 434                     == -1)
 435                         return (-1);
 436         }
 437 
 438         TAILQ_INSERT_TAIL(&ctx->events, ev, ev_signal_next);
 439 
 440         return (1);
 441 }
 442 
 443 int
 444 evmap_signal_del(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;
 449 
 450         if (sig >= map->nentries)
 451                 return (-1);
 452 
 453         GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
 454 
 455         if (TAILQ_FIRST(&ctx->events) == TAILQ_LAST(&ctx->events, event_list)) {
 456                 if (evsel->del(base, ev->ev_fd, 0, EV_SIGNAL, NULL) == -1)
 457                         return (-1);
 458         }
 459 
 460         TAILQ_REMOVE(&ctx->events, ev, ev_signal_next);
 461 
 462         return (1);
 463 }
 464 
 465 void
 466 evmap_signal_active(struct event_base *base, evutil_socket_t sig, int ncalls)
 467 {
 468         struct event_signal_map *map = &base->sigmap;
 469         struct evmap_signal *ctx;
 470         struct event *ev;
 471 
 472         EVUTIL_ASSERT(sig < map->nentries);
 473         GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
 474 
 475         TAILQ_FOREACH(ev, &ctx->events, ev_signal_next)
 476                 event_active_nolock(ev, EV_SIGNAL, ncalls);
 477 }
 478 
 479 void *
 480 evmap_io_get_fdinfo(struct event_io_map *map, evutil_socket_t fd)
 481 {
 482         struct evmap_io *ctx;
 483         GET_IO_SLOT(ctx, map, fd, evmap_io);
 484         if (ctx)
 485                 return ((char*)ctx) + sizeof(struct evmap_io);
 486         else
 487                 return NULL;
 488 }
 489 
 490 /** Per-fd structure for use with changelists.  It keeps track, for each fd or
 491  * signal using the changelist, of where its entry in the changelist is.
 492  */
 493 struct event_changelist_fdinfo {
 494         int idxplus1; /* this is the index +1, so that memset(0) will make it
 495                        * a no-such-element */
 496 };
 497 
 498 void
 499 event_changelist_init(struct event_changelist *changelist)
 500 {
 501         changelist->changes = NULL;
 502         changelist->changes_size = 0;
 503         changelist->n_changes = 0;
 504 }
 505 
 506 /** Helper: return the changelist_fdinfo corresponding to a given change. */
 507 static inline struct event_changelist_fdinfo *
 508 event_change_get_fdinfo(struct event_base *base,
 509     const struct event_change *change)
 510 {
 511         char *ptr;
 512         if (change->read_change & EV_CHANGE_SIGNAL) {
 513                 struct evmap_signal *ctx;
 514                 GET_SIGNAL_SLOT(ctx, &base->sigmap, change->fd, evmap_signal);
 515                 ptr = ((char*)ctx) + sizeof(struct evmap_signal);
 516         } else {
 517                 struct evmap_io *ctx;
 518                 GET_IO_SLOT(ctx, &base->io, change->fd, evmap_io);
 519                 ptr = ((char*)ctx) + sizeof(struct evmap_io);
 520         }
 521         return (void*)ptr;
 522 }
 523 
 524 #ifdef DEBUG_CHANGELIST
 525 /** Make sure that the changelist is consistent with the evmap structures. */
 526 static void
 527 event_changelist_check(struct event_base *base)
 528 {
 529         int i;
 530         struct event_changelist *changelist = &base->changelist;
 531 
 532         EVUTIL_ASSERT(changelist->changes_size >= changelist->n_changes);
 533         for (i = 0; i < changelist->n_changes; ++i) {
 534                 struct event_change *c = &changelist->changes[i];
 535                 struct event_changelist_fdinfo *f;
 536                 EVUTIL_ASSERT(c->fd >= 0);
 537                 f = event_change_get_fdinfo(base, c);
 538                 EVUTIL_ASSERT(f);
 539                 EVUTIL_ASSERT(f->idxplus1 == i + 1);
 540         }
 541 
 542         for (i = 0; i < base->io.nentries; ++i) {
 543                 struct evmap_io *io = base->io.entries[i];
 544                 struct event_changelist_fdinfo *f;
 545                 if (!io)
 546                         continue;
 547                 f = (void*)
 548                     ( ((char*)io) + sizeof(struct evmap_io) );
 549                 if (f->idxplus1) {
 550                         struct event_change *c = &changelist->changes[f->idxplus1 - 1];
 551                         EVUTIL_ASSERT(c->fd == i);
 552                 }
 553         }
 554 }
 555 #else
 556 #define event_changelist_check(base)  ((void)0)
 557 #endif
 558 
 559 void
 560 event_changelist_remove_all(struct event_changelist *changelist,
 561     struct event_base *base)
 562 {
 563         int i;
 564 
 565         event_changelist_check(base);
 566 
 567         for (i = 0; i < changelist->n_changes; ++i) {
 568                 struct event_change *ch = &changelist->changes[i];
 569                 struct event_changelist_fdinfo *fdinfo =
 570                     event_change_get_fdinfo(base, ch);
 571                 EVUTIL_ASSERT(fdinfo->idxplus1 == i + 1);
 572                 fdinfo->idxplus1 = 0;
 573         }
 574 
 575         changelist->n_changes = 0;
 576 
 577         event_changelist_check(base);
 578 }
 579 
 580 void
 581 event_changelist_freemem(struct event_changelist *changelist)
 582 {
 583         if (changelist->changes)
 584                 mm_free(changelist->changes);
 585         event_changelist_init(changelist); /* zero it all out. */
 586 }
 587 
 588 /** Increase the size of 'changelist' to hold more changes. */
 589 static int
 590 event_changelist_grow(struct event_changelist *changelist)
 591 {
 592         int new_size;
 593         struct event_change *new_changes;
 594         if (changelist->changes_size < 64)
 595                 new_size = 64;
 596         else
 597                 new_size = changelist->changes_size * 2;
 598 
 599         new_changes = mm_realloc(changelist->changes,
 600             new_size * sizeof(struct event_change));
 601 
 602         if (EVUTIL_UNLIKELY(new_changes == NULL))
 603                 return (-1);
 604 
 605         changelist->changes = new_changes;
 606         changelist->changes_size = new_size;
 607 
 608         return (0);
 609 }
 610 
 611 /** Return a pointer to the changelist entry for the file descriptor or signal
 612  * 'fd', whose fdinfo is 'fdinfo'.  If none exists, construct it, setting its
 613  * old_events field to old_events.
 614  */
 615 static struct event_change *
 616 event_changelist_get_or_construct(struct event_changelist *changelist,
 617     evutil_socket_t fd,
 618     short old_events,
 619     struct event_changelist_fdinfo *fdinfo)
 620 {
 621         struct event_change *change;
 622 
 623         if (fdinfo->idxplus1 == 0) {
 624                 int idx;
 625                 EVUTIL_ASSERT(changelist->n_changes <= changelist->changes_size);
 626 
 627                 if (changelist->n_changes == changelist->changes_size) {
 628                         if (event_changelist_grow(changelist) < 0)
 629                                 return NULL;
 630                 }
 631 
 632                 idx = changelist->n_changes++;
 633                 change = &changelist->changes[idx];
 634                 fdinfo->idxplus1 = idx + 1;
 635 
 636                 memset(change, 0, sizeof(struct event_change));
 637                 change->fd = fd;
 638                 change->old_events = old_events;
 639         } else {
 640                 change = &changelist->changes[fdinfo->idxplus1 - 1];
 641                 EVUTIL_ASSERT(change->fd == fd);
 642         }
 643         return change;
 644 }
 645 
 646 int
 647 event_changelist_add(struct event_base *base, evutil_socket_t fd, short old, short events,
 648     void *p)
 649 {
 650         struct event_changelist *changelist = &base->changelist;
 651         struct event_changelist_fdinfo *fdinfo = p;
 652         struct event_change *change;
 653 
 654         event_changelist_check(base);
 655 
 656         change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
 657         if (!change)
 658                 return -1;
 659 
 660         /* An add replaces any previous delete, but doesn't result in a no-op,
 661          * since the delete might fail (because the fd had been closed since
 662          * the last add, for instance. */
 663 
 664         if (events & (EV_READ|EV_SIGNAL)) {
 665                 change->read_change = EV_CHANGE_ADD |
 666                     (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
 667         }
 668         if (events & EV_WRITE) {
 669                 change->write_change = EV_CHANGE_ADD |
 670                     (events & (EV_ET|EV_PERSIST|EV_SIGNAL));
 671         }
 672 
 673         event_changelist_check(base);
 674         return (0);
 675 }
 676 
 677 int
 678 event_changelist_del(struct event_base *base, evutil_socket_t fd, short old, short events,
 679     void *p)
 680 {
 681         struct event_changelist *changelist = &base->changelist;
 682         struct event_changelist_fdinfo *fdinfo = p;
 683         struct event_change *change;
 684 
 685         event_changelist_check(base);
 686         change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
 687         event_changelist_check(base);
 688         if (!change)
 689                 return -1;
 690 
 691         /* A delete removes any previous add, rather than replacing it:
 692            on those platforms where "add, delete, dispatch" is not the same
 693            as "no-op, dispatch", we want the no-op behavior.
 694 
 695            As well as checking the current operation we should also check
 696            the original set of events to make sure were not ignoring
 697            the case where the add operation is present on an event that
 698            was already set.
 699 
 700            If we have a no-op item, we could remove it it from the list
 701            entirely, but really there's not much point: skipping the no-op
 702            change when we do the dispatch later is far cheaper than rejuggling
 703            the array now.
 704 
 705            As this stands, it also lets through deletions of events that are
 706            not currently set.
 707          */
 708 
 709         if (events & (EV_READ|EV_SIGNAL)) {
 710                 if (!(change->old_events & (EV_READ | EV_SIGNAL)) &&
 711                     (change->read_change & EV_CHANGE_ADD))
 712                         change->read_change = 0;
 713                 else
 714                         change->read_change = EV_CHANGE_DEL;
 715         }
 716         if (events & EV_WRITE) {
 717                 if (!(change->old_events & EV_WRITE) &&
 718                     (change->write_change & EV_CHANGE_ADD))
 719                         change->write_change = 0;
 720                 else
 721                         change->write_change = EV_CHANGE_DEL;
 722         }
 723 
 724         event_changelist_check(base);
 725         return (0);
 726 }
 727 
 728 void
 729 evmap_check_integrity(struct event_base *base)
 730 {
 731 #define EVLIST_X_SIGFOUND 0x1000
 732 #define EVLIST_X_IOFOUND 0x2000
 733 
 734         evutil_socket_t i;
 735         struct event *ev;
 736         struct event_io_map *io = &base->io;
 737         struct event_signal_map *sigmap = &base->sigmap;
 738 #ifdef EVMAP_USE_HT
 739         struct event_map_entry **mapent;
 740 #endif
 741         int nsignals, ntimers, nio;
 742         nsignals = ntimers = nio = 0;
 743 
 744         TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
 745                 EVUTIL_ASSERT(ev->ev_flags & EVLIST_INSERTED);
 746                 EVUTIL_ASSERT(ev->ev_flags & EVLIST_INIT);
 747                 ev->ev_flags &= ~(EVLIST_X_SIGFOUND|EVLIST_X_IOFOUND);
 748         }
 749 
 750 #ifdef EVMAP_USE_HT
 751         HT_FOREACH(mapent, event_io_map, io) {
 752                 struct evmap_io *ctx = &(*mapent)->ent.evmap_io;
 753                 i = (*mapent)->fd;
 754 #else
 755         for (i = 0; i < io->nentries; ++i) {
 756                 struct evmap_io *ctx = io->entries[i];
 757 
 758                 if (!ctx)
 759                         continue;
 760 #endif
 761 
 762                 TAILQ_FOREACH(ev, &ctx->events, ev_io_next) {
 763                         EVUTIL_ASSERT(!(ev->ev_flags & EVLIST_X_IOFOUND));
 764                         EVUTIL_ASSERT(ev->ev_fd == i);
 765                         ev->ev_flags |= EVLIST_X_IOFOUND;
 766                         nio++;
 767                 }
 768         }
 769 
 770         for (i = 0; i < sigmap->nentries; ++i) {
 771                 struct evmap_signal *ctx = sigmap->entries[i];
 772                 if (!ctx)
 773                         continue;
 774 
 775                 TAILQ_FOREACH(ev, &ctx->events, ev_signal_next) {
 776                         EVUTIL_ASSERT(!(ev->ev_flags & EVLIST_X_SIGFOUND));
 777                         EVUTIL_ASSERT(ev->ev_fd == i);
 778                         ev->ev_flags |= EVLIST_X_SIGFOUND;
 779                         nsignals++;
 780                 }
 781         }
 782 
 783         TAILQ_FOREACH(ev, &base->eventqueue, ev_next) {
 784                 if (ev->ev_events & (EV_READ|EV_WRITE)) {
 785                         EVUTIL_ASSERT(ev->ev_flags & EVLIST_X_IOFOUND);
 786                         --nio;
 787                 }
 788                 if (ev->ev_events & EV_SIGNAL) {
 789                         EVUTIL_ASSERT(ev->ev_flags & EVLIST_X_SIGFOUND);
 790                         --nsignals;
 791                 }
 792         }
 793 
 794         EVUTIL_ASSERT(nio == 0);
 795         EVUTIL_ASSERT(nsignals == 0);
 796         /* There is no "EVUTIL_ASSERT(ntimers == 0)": eventqueue is only for
 797          * pending signals and io events.
 798          */
 799 }

/* [<][>][^][v][top][bottom][index][help] */