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