ipc/chromium/src/third_party/libevent/evmap.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     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"
    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>
    49 #include "event-internal.h"
    50 #include "evmap-internal.h"
    51 #include "mm-internal.h"
    52 #include "changelist-internal.h"
    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 };
    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 };
    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 };
    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 }
    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 }
   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)
   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);
   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)
   139 void evmap_io_initmap(struct event_io_map *ctx)
   140 {
   141 	HT_INIT(event_io_map, ctx);
   142 }
   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
   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)
   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
   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;
   208 		while (nentries <= slot)
   209 			nentries <<= 1;
   211 		tmp = (void **)mm_realloc(map->entries, nentries * msize);
   212 		if (tmp == NULL)
   213 			return (-1);
   215 		memset(&tmp[map->nentries], 0,
   216 		    (nentries - map->nentries) * msize);
   218 		map->nentries = nentries;
   219 		map->entries = tmp;
   220 	}
   222 	return (0);
   223 }
   225 void
   226 evmap_signal_initmap(struct event_signal_map *ctx)
   227 {
   228 	ctx->nentries = 0;
   229 	ctx->entries = NULL;
   230 }
   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 }
   248 /* code specific to file descriptors */
   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 }
   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;
   272 	EVUTIL_ASSERT(fd == ev->ev_fd);
   274 	if (fd < 0)
   275 		return 0;
   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);
   286 	nread = ctx->nread;
   287 	nwrite = ctx->nwrite;
   289 	if (nread)
   290 		old |= EV_READ;
   291 	if (nwrite)
   292 		old |= EV_WRITE;
   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 	}
   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 	}
   326 	ctx->nread = (ev_uint16_t) nread;
   327 	ctx->nwrite = (ev_uint16_t) nwrite;
   328 	TAILQ_INSERT_TAIL(&ctx->events, ev, ev_io_next);
   330 	return (retval);
   331 }
   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;
   344 	if (fd < 0)
   345 		return 0;
   347 	EVUTIL_ASSERT(fd == ev->ev_fd);
   349 #ifndef EVMAP_USE_HT
   350 	if (fd >= io->nentries)
   351 		return (-1);
   352 #endif
   354 	GET_IO_SLOT(ctx, io, fd, evmap_io);
   356 	nread = ctx->nread;
   357 	nwrite = ctx->nwrite;
   359 	if (nread)
   360 		old |= EV_READ;
   361 	if (nwrite)
   362 		old |= EV_WRITE;
   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 	}
   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 	}
   382 	ctx->nread = nread;
   383 	ctx->nwrite = nwrite;
   384 	TAILQ_REMOVE(&ctx->events, ev, ev_io_next);
   386 	return (retval);
   387 }
   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;
   396 #ifndef EVMAP_USE_HT
   397 	EVUTIL_ASSERT(fd < io->nentries);
   398 #endif
   399 	GET_IO_SLOT(ctx, io, fd, evmap_io);
   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 }
   408 /* code specific to signals */
   410 static void
   411 evmap_signal_init(struct evmap_signal *entry)
   412 {
   413 	TAILQ_INIT(&entry->events);
   414 }
   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;
   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);
   432 	if (TAILQ_EMPTY(&ctx->events)) {
   433 		if (evsel->add(base, ev->ev_fd, 0, EV_SIGNAL, NULL)
   434 		    == -1)
   435 			return (-1);
   436 	}
   438 	TAILQ_INSERT_TAIL(&ctx->events, ev, ev_signal_next);
   440 	return (1);
   441 }
   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;
   450 	if (sig >= map->nentries)
   451 		return (-1);
   453 	GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
   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 	}
   460 	TAILQ_REMOVE(&ctx->events, ev, ev_signal_next);
   462 	return (1);
   463 }
   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;
   472 	EVUTIL_ASSERT(sig < map->nentries);
   473 	GET_SIGNAL_SLOT(ctx, map, sig, evmap_signal);
   475 	TAILQ_FOREACH(ev, &ctx->events, ev_signal_next)
   476 		event_active_nolock(ev, EV_SIGNAL, ncalls);
   477 }
   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 }
   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 };
   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 }
   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 }
   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;
   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 	}
   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
   559 void
   560 event_changelist_remove_all(struct event_changelist *changelist,
   561     struct event_base *base)
   562 {
   563 	int i;
   565 	event_changelist_check(base);
   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 	}
   575 	changelist->n_changes = 0;
   577 	event_changelist_check(base);
   578 }
   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 }
   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;
   599 	new_changes = mm_realloc(changelist->changes,
   600 	    new_size * sizeof(struct event_change));
   602 	if (EVUTIL_UNLIKELY(new_changes == NULL))
   603 		return (-1);
   605 	changelist->changes = new_changes;
   606 	changelist->changes_size = new_size;
   608 	return (0);
   609 }
   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;
   623 	if (fdinfo->idxplus1 == 0) {
   624 		int idx;
   625 		EVUTIL_ASSERT(changelist->n_changes <= changelist->changes_size);
   627 		if (changelist->n_changes == changelist->changes_size) {
   628 			if (event_changelist_grow(changelist) < 0)
   629 				return NULL;
   630 		}
   632 		idx = changelist->n_changes++;
   633 		change = &changelist->changes[idx];
   634 		fdinfo->idxplus1 = idx + 1;
   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 }
   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;
   654 	event_changelist_check(base);
   656 	change = event_changelist_get_or_construct(changelist, fd, old, fdinfo);
   657 	if (!change)
   658 		return -1;
   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. */
   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 	}
   673 	event_changelist_check(base);
   674 	return (0);
   675 }
   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;
   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;
   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.
   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.
   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.
   705 	   As this stands, it also lets through deletions of events that are
   706 	   not currently set.
   707 	 */
   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 	}
   724 	event_changelist_check(base);
   725 	return (0);
   726 }
   728 void
   729 evmap_check_integrity(struct event_base *base)
   730 {
   731 #define EVLIST_X_SIGFOUND 0x1000
   732 #define EVLIST_X_IOFOUND 0x2000
   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;
   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 	}
   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];
   758 		if (!ctx)
   759 			continue;
   760 #endif
   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 	}
   770 	for (i = 0; i < sigmap->nentries; ++i) {
   771 		struct evmap_signal *ctx = sigmap->entries[i];
   772 		if (!ctx)
   773 			continue;
   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 	}
   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 	}
   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 }

mercurial