/** An entry for an evmap_io list: notes all the events that want to read or writeonagivenfd,andthenumberofeach.
*/ struct evmap_io { struct event_dlist events;
ev_uint16_t nread;
ev_uint16_t nwrite;
ev_uint16_t nclose;
};
/* An entry for an evmap_signal list: notes all the events that want to know
when a signal triggers. */ struct evmap_signal { struct event_dlist events;
};
/* On some platforms, fds start at 0 and increment by 1 as they are allocated,andoldnumbersgetused.Fortheseplatforms,we implementiomapsjustlikesignalmaps:asanarrayofpointersto structevmap_io.Butonotherplatforms(windows),socketsarenot 0-indexed,notnecessarilyconsecutive,andnotnecessarilyreused. There,weuseahashtabletoimplementevmap_io.
*/ #ifdef EVMAP_USE_HT struct event_map_entry {
HT_ENTRY(event_map_entry) map_node;
evutil_socket_t fd; union { /* This is a union in case we need to make more things that can
be in the hashtable. */ struct evmap_io evmap_io;
} ent;
};
/* Helper used by the event_io_map hashtable code; tries to return a good hash
* of the fd in e->fd. */ staticinlineunsigned
hashsocket(struct event_map_entry *e)
{ /* On win32, in practice, the low 2-3 bits of a SOCKET seem not to *matter.Ourhashtableimplementationreallylikeslow-orderbits,
* though, so let's do the rotate-and-add trick. */ unsigned h = (unsigned) e->fd;
h += (h >> 2) | (h << 30); return h;
}
/* Helper used by the event_io_map hashtable code; returns true iff e1 and e2
* have the same e->fd. */ staticinlineint
eqsocket(struct event_map_entry *e1, struct event_map_entry *e2)
{ return e1->fd == e2->fd;
}
void evmap_io_clear_(struct event_io_map *ctx)
{ struct event_map_entry **ent, **next, *this; for (ent = HT_START(event_io_map, ctx); ent; ent = next) { this = *ent;
next = HT_NEXT_RMV(event_io_map, ctx, ent);
mm_free(this);
}
HT_CLEAR(event_io_map, ctx); /* remove all storage held by the ctx. */
} #endif
/* Set the variable 'x' to the field in event_map 'map' with fields of type 'structtype*'correspondingtothefdorsignal'slot'.Set'x'toNULL
if there are no entries for 'slot'. Does no bounds-checking. */ #define GET_SIGNAL_SLOT(x, map, slot, type) \
(x) = (struct type *)((map)->entries[slot]) /* As GET_SLOT, but construct the entry for 'slot' if it is not present, byallocatingenoughmemoryfora'structtype',andinitializingthenew valuebycallingthefunction'ctor'onit.Makesthefunction return-1onallocationfailure.
*/ #define GET_SIGNAL_SLOT_AND_CTOR(x, map, slot, type, ctor, fdinfo_len) \ do { \ if ((map)->entries[slot] == NULL) { \
(map)->entries[slot] = \
mm_calloc(1,sizeof(struct type)+fdinfo_len); \ if (EVUTIL_UNLIKELY((map)->entries[slot] == NULL)) \ return (-1); \
(ctor)((struct type *)(map)->entries[slot]); \
} \
(x) = (struct type *)((map)->entries[slot]); \
} while (0)
/* If we aren't using hashtables, then define the IO_SLOT macros and functions
as thin aliases over the SIGNAL_SLOT versions. */ #ifndef EVMAP_USE_HT #define GET_IO_SLOT(x,map,slot,type) GET_SIGNAL_SLOT(x,map,slot,type) #define GET_IO_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len) \
GET_SIGNAL_SLOT_AND_CTOR(x,map,slot,type,ctor,fdinfo_len) #define FDINFO_OFFSET sizeof(struct evmap_io) void
evmap_io_initmap_(struct event_io_map* ctx)
{
evmap_signal_initmap_(ctx);
} void
evmap_io_clear_(struct event_io_map* ctx)
{
evmap_signal_clear_(ctx);
} #endif
/** Expand 'map' with new entries of width 'msize' until it is big enough tostoreavaluein'slot'.
*/ staticint
evmap_make_space(struct event_signal_map *map, int slot, int msize)
{ if (map->nentries <= slot) { int nentries = map->nentries ? map->nentries : 32; void **tmp;
/* return -1 on error, 0 on success if nothing changed in the event backend,
* and 1 on success if something did. */ int
evmap_io_del_(struct event_base *base, evutil_socket_t fd, struct event *ev)
{ conststruct eventop *evsel = base->evsel; struct event_io_map *io = &base->io; struct evmap_io *ctx; int nread, nwrite, nclose, retval = 0; short res = 0, old = 0;
if (fd < 0) return0;
EVUTIL_ASSERT(fd == ev->ev_fd);
#ifndef EVMAP_USE_HT if (fd >= io->nentries) return (-1); #endif
/* Callback type for evmap_signal_foreach_signal */ typedefint (*evmap_signal_foreach_signal_cb)( struct event_base *, int, struct evmap_signal *, void *);
/* Multipurpose helper function: Iterate over every signal number in the *event_baseforwhichwecouldhavesignalevents.Foreachsuchsignal, *callfn(base,signum,evmap_signal,arg),wherefnistheuser-provided *function,baseistheevent_base,signumisthesignalnumber,evmap_signal *isanevmap_signalstructurecontainingalistofeventspendingonthe *signal,andargistheuser-suppliedargument. * *Iffnreturns0,continueontothenextsignal.Otherwise,returnthesame *valuethatfnreturned.
*/ staticint
evmap_signal_foreach_signal(struct event_base *base,
evmap_signal_foreach_signal_cb fn, void *arg)
{ struct event_signal_map *sigmap = &base->sigmap; int r = 0; int signum;
for (signum = 0; signum < sigmap->nentries; ++signum) { struct evmap_signal *ctx = sigmap->entries[signum]; if (!ctx) continue; if ((r = fn(base, signum, ctx, arg))) break;
} return r;
}
/* Helper for evmap_reinit_: tell the backend to add every fd for which we have *pendingevents,withtheappropriatecombinationofEV_READ,EV_WRITE,and
* EV_ET. */ staticint
evmap_io_reinit_iter_fn(struct event_base *base, evutil_socket_t fd, struct evmap_io *ctx, void *arg)
{ conststruct eventop *evsel = base->evsel; void *extra; int *result = arg; short events = 0; struct event *ev;
EVUTIL_ASSERT(ctx);
extra = ((char*)ctx) + sizeof(struct evmap_io); if (ctx->nread)
events |= EV_READ; if (ctx->nwrite)
events |= EV_WRITE; if (ctx->nclose)
events |= EV_CLOSED; if (evsel->fdinfo_len)
memset(extra, 0, evsel->fdinfo_len); if (events &&
(ev = LIST_FIRST(&ctx->events)) &&
(ev->ev_events & EV_ET))
events |= EV_ET; if (evsel->add(base, fd, 0, events, extra) == -1)
*result = -1;
return0;
}
/* Helper for evmap_reinit_: tell the backend to add every signal for which we
* have pending events. */ staticint
evmap_signal_reinit_iter_fn(struct event_base *base, int signum, struct evmap_signal *ctx, void *arg)
{ conststruct eventop *evsel = base->evsigsel; int *result = arg;
if (!LIST_EMPTY(&ctx->events)) { if (evsel->add(base, signum, 0, EV_SIGNAL, NULL) == -1)
*result = -1;
} return0;
}
int
evmap_reinit_(struct event_base *base)
{ int result = 0;
evmap_io_foreach_fd(base, evmap_io_reinit_iter_fn, &result); if (result < 0) return -1;
evmap_signal_foreach_signal(base, evmap_signal_reinit_iter_fn, &result); if (result < 0) return -1; return0;
}
/* Helper for evmap_delete_all_: delete every event in an event_dlist. */ staticint
delete_all_in_dlist(struct event_dlist *dlist)
{ struct event *ev; while ((ev = LIST_FIRST(dlist)))
event_del(ev); return0;
}
/* Helper for evmap_delete_all_: delete every event pending on an fd. */ staticint
evmap_io_delete_all_iter_fn(struct event_base *base, evutil_socket_t fd, struct evmap_io *io_info, void *arg)
{ return delete_all_in_dlist(&io_info->events);
}
/* Helper for evmap_delete_all_: delete every event pending on a signal. */ staticint
evmap_signal_delete_all_iter_fn(struct event_base *base, int signum, struct evmap_signal *sig_info, void *arg)
{ return delete_all_in_dlist(&sig_info->events);
}
/** Per-fd structure for use with changelists. It keeps track, for each fd or *signalusingthechangelist,ofwhereitsentryinthechangelistis.
*/ struct event_changelist_fdinfo { int idxplus1; /* this is the index +1, so that memset(0) will make it
* a no-such-element */
};
/** Make sure that the changelist is consistent with the evmap structures. */ staticvoid
event_changelist_assert_ok(struct event_base *base)
{ int i; struct event_changelist *changelist = &base->changelist;
EVUTIL_ASSERT(changelist->changes_size >= changelist->n_changes); for (i = 0; i < changelist->n_changes; ++i) { struct event_change *c = &changelist->changes[i]; struct event_changelist_fdinfo *f;
EVUTIL_ASSERT(c->fd >= 0);
f = event_change_get_fdinfo(base, c);
EVUTIL_ASSERT(f);
EVUTIL_ASSERT(f->idxplus1 == i + 1);
}
void
event_changelist_remove_all_(struct event_changelist *changelist, struct event_base *base)
{ int i;
event_changelist_check(base);
for (i = 0; i < changelist->n_changes; ++i) { struct event_change *ch = &changelist->changes[i]; struct event_changelist_fdinfo *fdinfo =
event_change_get_fdinfo(base, ch);
EVUTIL_ASSERT(fdinfo->idxplus1 == i + 1);
fdinfo->idxplus1 = 0;
}
changelist->n_changes = 0;
event_changelist_check(base);
}
void
event_changelist_freemem_(struct event_changelist *changelist)
{ if (changelist->changes)
mm_free(changelist->changes);
event_changelist_init_(changelist); /* zero it all out. */
}
/** Increase the size of 'changelist' to hold more changes. */ staticint
event_changelist_grow(struct event_changelist *changelist)
{ int new_size; struct event_change *new_changes; if (changelist->changes_size < 64)
new_size = 64; else
new_size = changelist->changes_size * 2;
/** Return a pointer to the changelist entry for the file descriptor or signal *'fd',whosefdinfois'fdinfo'.Ifnoneexists,constructit,settingits *old_eventsfieldtoold_events.
*/ staticstruct event_change *
event_changelist_get_or_construct(struct event_changelist *changelist,
evutil_socket_t fd, short old_events, struct event_changelist_fdinfo *fdinfo)
{ struct event_change *change;
if (fdinfo->idxplus1 == 0) { int idx;
EVUTIL_ASSERT(changelist->n_changes <= changelist->changes_size);
if (changelist->n_changes == changelist->changes_size) { if (event_changelist_grow(changelist) < 0) return NULL;
}
change = event_changelist_get_or_construct(changelist, fd, old, fdinfo); if (!change) return -1;
/* An add replaces any previous delete, but doesn't result in a no-op, *sincethedeletemightfail(becausethefdhadbeenclosedsince
* the last add, for instance. */
if (events & (EV_READ|EV_SIGNAL))
change->read_change = evchange; if (events & EV_WRITE)
change->write_change = evchange; if (events & EV_CLOSED)
change->close_change = evchange;
event_changelist_check(base); return (0);
}
int
event_changelist_del_(struct event_base *base, evutil_socket_t fd, short old, short events, void *p)
{ struct event_changelist *changelist = &base->changelist; struct event_changelist_fdinfo *fdinfo = p; struct event_change *change;
ev_uint8_t del = EV_CHANGE_DEL | (events & EV_ET);
/* A delete on an event set that doesn't contain the event to be deletedproducesano-op.Thiseffectivelyemovesanyprevious uncommittedadd,ratherthanreplacingit:onthoseplatformswhere "add,delete,dispatch"isnotthesameas"no-op,dispatch",we wanttheno-opbehavior.
if (events & (EV_READ|EV_SIGNAL)) { if (!(change->old_events & (EV_READ | EV_SIGNAL)))
change->read_change = 0; else
change->read_change = del;
} if (events & EV_WRITE) { if (!(change->old_events & EV_WRITE))
change->write_change = 0; else
change->write_change = del;
} if (events & EV_CLOSED) { if (!(change->old_events & EV_CLOSED))
change->close_change = 0; else
change->close_change = del;
}
event_changelist_check(base); return (0);
}
/* Helper for evmap_check_integrity_: verify that all of the events pending on *givenfdaresetupcorrectly,andthatthenreadandnwritecountsonthat
* fd are correct. */ staticint
evmap_io_check_integrity_fn(struct event_base *base, evutil_socket_t fd, struct evmap_io *io_info, void *arg)
{ struct event *ev; int n_read = 0, n_write = 0, n_close = 0;
/* First, make sure the list itself isn't corrupt. Otherwise,
* running LIST_FOREACH could be an exciting adventure. */
EVUTIL_ASSERT_LIST_OK(&io_info->events, event, ev_io_next);
/* Helper for evmap_check_integrity_: verify that all of the events pending
* on given signal are set up correctly. */ staticint
evmap_signal_check_integrity_fn(struct event_base *base, int signum, struct evmap_signal *sig_info, void *arg)
{ struct event *ev; /* First, make sure the list itself isn't corrupt. */
EVUTIL_ASSERT_LIST_OK(&sig_info->events, event, ev_signal_next);
if (base->evsel->add == event_changelist_add_)
event_changelist_assert_ok(base);
}
/* Helper type for evmap_foreach_event_: Bundles a function to call on every
* event, and the user-provided void* to use as its third argument. */ struct evmap_foreach_event_helper {
event_base_foreach_event_cb fn; void *arg;
};
/* Helper for evmap_foreach_event_: calls a provided function on every event
* pending on a given fd. */ staticint
evmap_io_foreach_event_fn(struct event_base *base, evutil_socket_t fd, struct evmap_io *io_info, void *arg)
{ struct evmap_foreach_event_helper *h = arg; struct event *ev; int r;
LIST_FOREACH(ev, &io_info->events, ev_io_next) { if ((r = h->fn(base, ev, h->arg))) return r;
} return0;
}
/* Helper for evmap_foreach_event_: calls a provided function on every event
* pending on a given signal. */ staticint
evmap_signal_foreach_event_fn(struct event_base *base, int signum, struct evmap_signal *sig_info, void *arg)
{ struct event *ev; struct evmap_foreach_event_helper *h = arg; int r;
LIST_FOREACH(ev, &sig_info->events, ev_signal_next) { if ((r = h->fn(base, ev, h->arg))) return r;
} return0;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.