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