diff --git a/epoll.c b/epoll.c index a0df0d21..e6f5db24 100644 --- a/epoll.c +++ b/epoll.c @@ -281,7 +281,7 @@ epoll_apply_one_change(struct event_base *base, return 0; } - if ((ch->read_change|ch->write_change) & EV_CHANGE_ET) + if ((ch->read_change|ch->write_change|ch->close_change) & EV_CHANGE_ET) events |= EPOLLET; memset(&epev, 0, sizeof(epev)); diff --git a/evmap.c b/evmap.c index ffc991f5..e4e35c68 100644 --- a/evmap.c +++ b/evmap.c @@ -432,7 +432,7 @@ evmap_io_active_(struct event_base *base, evutil_socket_t fd, short events) if (NULL == ctx) return; LIST_FOREACH(ev, &ctx->events, ev_io_next) { - if (ev->ev_events & events) + if (ev->ev_events & (events & ~EV_ET)) event_active_nolock_(ev, ev->ev_events & events, 1); } } diff --git a/test/regress.c b/test/regress.c index dce58d5d..b1a0849a 100644 --- a/test/regress.c +++ b/test/regress.c @@ -387,7 +387,7 @@ record_event_cb(evutil_socket_t s, short what, void *ptr) } static void -test_simpleclose(void *ptr) +test_simpleclose_rw(void *ptr) { /* Test that a close of FD is detected as a read and as a write. */ struct event_base *base = event_base_new(); @@ -469,6 +469,61 @@ end: event_base_free(base); } +static void +test_simpleclose(void *ptr) +{ + struct basic_test_data *data = ptr; + struct event_base *base = data->base; + evutil_socket_t *pair = data->pair; + const char *flags = (const char *)data->setup_data; + int et = !!strstr(flags, "ET"); + int persist = !!strstr(flags, "persist"); + short events = EV_CLOSED | (et ? EV_ET : 0) | (persist ? EV_PERSIST : 0); + struct event *ev = NULL; + short got_event; + + if (!(event_base_get_features(data->base) & EV_FEATURE_EARLY_CLOSE)) + tt_skip(); + + /* XXX: should this code moved to regress_et.c ? */ + if (et && !(event_base_get_features(data->base) & EV_FEATURE_ET)) + tt_skip(); + + ev = event_new(base, pair[0], events, record_event_cb, &got_event); + tt_assert(ev); + tt_assert(!event_add(ev, NULL)); + + got_event = 0; + if (strstr(flags, "close")) { + tt_assert(!close(pair[1])); + /* avoid closing in setup routines */ + pair[1] = -1; + } else if (strstr(flags, "shutdown")) { + tt_assert(!shutdown(pair[1], EVUTIL_SHUT_WR)); + } else { + tt_abort_msg("unknown flags"); + } + + /* w/o edge-triggerd but w/ persist it will not stop */ + if (!et && persist) { + struct timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 10000; + tt_assert(!event_base_loopexit(base, &tv)); + } + + /* via close() */ + if (pair[1] == -1) { + tt_int_op(event_base_loop(base, EVLOOP_NONBLOCK), ==, 0); + } else { + tt_int_op(event_base_loop(base, EVLOOP_NONBLOCK), ==, !persist); + tt_int_op(got_event, ==, (events & ~EV_PERSIST)); + } + +end: + if (ev) + event_free(ev); +} static void test_multiple(void) @@ -3461,8 +3516,35 @@ struct testcase_t main_testcases[] = { LEGACY(simpleread, TT_ISOLATED), LEGACY(simpleread_multiple, TT_ISOLATED), LEGACY(simplewrite, TT_ISOLATED), - { "simpleclose", test_simpleclose, TT_FORK, &basic_setup, - NULL }, + { "simpleclose_rw", test_simpleclose_rw, TT_FORK, &basic_setup, NULL }, + /* simpleclose */ + { "simpleclose_close", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"close" }, + { "simpleclose_shutdown", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"shutdown" }, + /* simpleclose_*_persist */ + { "simpleclose_close_persist", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"close_persist" }, + { "simpleclose_shutdown_persist", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"shutdown_persist" }, + /* simpleclose_*_et */ + { "simpleclose_close_et", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"close_ET" }, + { "simpleclose_shutdown_et", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"shutdown_ET" }, + /* simpleclose_*_persist_et */ + { "simpleclose_close_persist_et", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"close_persist_ET" }, + { "simpleclose_shutdown_persist_et", test_simpleclose, + TT_FORK|TT_NEED_SOCKETPAIR|TT_NEED_BASE, + &basic_setup, (void *)"shutdown_persist_ET" }, LEGACY(multiple, TT_ISOLATED), LEGACY(persistent, TT_ISOLATED), LEGACY(combined, TT_ISOLATED),