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