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