Make debug mode catch mixed ET and non-ET events on an fd

Of the backends that support edge-triggered IO, most (all?) do not
support attempts to mix edge-triggered and level-triggered IO on the
same FD.  With debugging mode enabled, we now detect and refuse attempts
to add a level-triggered IO event to an fd that already has an
edge-triggered IO event, and vice versa.
This commit is contained in:
Nick Mathewson 2010-04-28 11:51:56 -04:00
parent a5208fe422
commit cb6707405c
3 changed files with 53 additions and 0 deletions

View File

@ -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 {

View File

@ -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);

View File

@ -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
};