diff --git a/event-internal.h b/event-internal.h index f9de18ad..7388a597 100644 --- a/event-internal.h +++ b/event-internal.h @@ -158,6 +158,9 @@ struct event_changelist { #ifndef _EVENT_DISABLE_DEBUG_MODE /* Global internal flag: set to one if debug mode is on. */ extern int _event_debug_mode_on; +#define EVENT_DEBUG_MODE_IS_ON() (_event_debug_mode_on) +#else +#define EVENT_DEBUG_MODE_IS_ON() (0) #endif struct event_base { diff --git a/evmap.c b/evmap.c index b11ec3c9..cb28002a 100644 --- a/evmap.c +++ b/evmap.c @@ -264,6 +264,7 @@ evmap_io_add(struct event_base *base, evutil_socket_t fd, struct event *ev) struct evmap_io *ctx = NULL; int nread, nwrite, retval = 0; short res = 0, old = 0; + struct event *old_ev; EVUTIL_ASSERT(fd == ev->ev_fd); @@ -300,6 +301,13 @@ evmap_io_add(struct event_base *base, evutil_socket_t fd, struct event *ev) (int)fd); return -1; } + if (EVENT_DEBUG_MODE_IS_ON() && + (old_ev = TAILQ_FIRST(&ctx->events)) && + (old_ev->ev_events&EV_ET) != (ev->ev_events&EV_ET)) { + event_warnx("Tried to mix edge-triggered and non-edge-triggered" + " events on fd %d", (int)fd); + return -1; + } if (res) { void *extra = ((char*)ctx) + sizeof(struct evmap_io); diff --git a/test/regress_et.c b/test/regress_et.c index 98f3dcf2..87ecc5ba 100644 --- a/test/regress_et.c +++ b/test/regress_et.c @@ -149,7 +149,49 @@ test_edgetriggered(void *et) evutil_closesocket(pair[1]); } +static void +test_edgetriggered_mix_error(void *data_) +{ + struct basic_test_data *data = data_; + struct event_base *base; + struct event *ev_et=NULL, *ev_lt=NULL; + +#ifdef _EVENT_DISABLE_DEBUG_MODE + if (1) + tt_skip(); +#endif + + event_enable_debug_mode(); + + base = event_base_new(); + + /* try mixing edge-triggered and level-triggered to make sure it fails*/ + ev_et = event_new(base, data->pair[0], EV_READ|EV_ET, read_cb, ev_et); + ev_lt = event_new(base, data->pair[0], EV_READ, read_cb, ev_lt); + + /* Add edge-triggered, then level-triggered. Get an error. */ + tt_int_op(0, ==, event_add(ev_et, NULL)); + tt_int_op(-1, ==, event_add(ev_lt, NULL)); + tt_int_op(EV_READ, ==, event_pending(ev_et, EV_READ, NULL)); + tt_int_op(0, ==, event_pending(ev_lt, EV_READ, NULL)); + + tt_int_op(0, ==, event_del(ev_et)); + /* Add level-triggered, then edge-triggered. Get an error. */ + tt_int_op(0, ==, event_add(ev_lt, NULL)); + tt_int_op(-1, ==, event_add(ev_et, NULL)); + tt_int_op(EV_READ, ==, event_pending(ev_lt, EV_READ, NULL)); + tt_int_op(0, ==, event_pending(ev_et, EV_READ, NULL)); + +end: + if (ev_et) + event_free(ev_et); + if (ev_lt) + event_free(ev_lt); +} + struct testcase_t edgetriggered_testcases[] = { { "et", test_edgetriggered, TT_FORK, NULL, NULL }, + { "et_mix_error", test_edgetriggered_mix_error, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NO_LOGS, &basic_setup, NULL }, END_OF_TESTCASES };