diff options
Diffstat (limited to 'test/regress_et.c')
-rw-r--r-- | test/regress_et.c | 146 |
1 files changed, 106 insertions, 40 deletions
diff --git a/test/regress_et.c b/test/regress_et.c index f75c59b3b7a7..1b1f819eda19 100644 --- a/test/regress_et.c +++ b/test/regress_et.c @@ -51,6 +51,14 @@ static int was_et = 0; +static int base_supports_et(struct event_base *base) +{ + return + (!strcmp(event_base_get_method(base), "epoll") || + !strcmp(event_base_get_method(base), "epoll (with changelist)") || + !strcmp(event_base_get_method(base), "kqueue")); +} + static void read_cb(evutil_socket_t fd, short event, void *arg) { @@ -67,19 +75,14 @@ read_cb(evutil_socket_t fd, short event, void *arg) event_del(arg); } -#ifdef _WIN32 -#define LOCAL_SOCKETPAIR_AF AF_INET -#else -#define LOCAL_SOCKETPAIR_AF AF_UNIX -#endif - static void -test_edgetriggered(void *et) +test_edgetriggered(void *data_) { + struct basic_test_data *data = data_; + struct event_base *base = data->base; + evutil_socket_t *pair = data->pair; struct event *ev = NULL; - struct event_base *base = NULL; const char *test = "test string"; - evutil_socket_t pair[2] = {-1,-1}; int supports_et; /* On Linux 3.2.1 (at least, as patched by Fedora and tested by Nick), @@ -88,39 +91,21 @@ test_edgetriggered(void *et) * get edge-triggered behavior. Yuck! Linux 3.1.9 didn't have this * problem. */ -#ifdef __linux__ - if (evutil_ersatz_socketpair_(AF_INET, SOCK_STREAM, 0, pair) == -1) { - tt_abort_perror("socketpair"); - } -#else - if (evutil_socketpair(LOCAL_SOCKETPAIR_AF, SOCK_STREAM, 0, pair) == -1) { - tt_abort_perror("socketpair"); - } -#endif called = was_et = 0; tt_int_op(send(pair[0], test, (int)strlen(test)+1, 0), >, 0); - shutdown(pair[0], EVUTIL_SHUT_WR); - - /* Initalize the event library */ - base = event_base_new(); - - if (!strcmp(event_base_get_method(base), "epoll") || - !strcmp(event_base_get_method(base), "epoll (with changelist)") || - !strcmp(event_base_get_method(base), "kqueue")) - supports_et = 1; - else - supports_et = 0; + tt_int_op(shutdown(pair[0], EVUTIL_SHUT_WR), ==, 0); + supports_et = base_supports_et(base); TT_BLATHER(("Checking for edge-triggered events with %s, which should %s" "support edge-triggering", event_base_get_method(base), supports_et?"":"not ")); - /* Initalize one event */ + /* Initialize one event */ ev = event_new(base, pair[1], EV_READ|EV_ET|EV_PERSIST, read_cb, &ev); - - event_add(ev, NULL); + tt_assert(ev != NULL); + tt_int_op(event_add(ev, NULL), ==, 0); /* We're going to call the dispatch function twice. The first invocation * will read a single byte from pair[1] in either case. If we're edge @@ -129,8 +114,8 @@ test_edgetriggered(void *et) * do nothing. If we're level triggered, the second invocation of * event_base_loop will also activate the event (because there's still * data to read). */ - event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE); - event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE); + tt_int_op(event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE), ==, 0); + tt_int_op(event_base_loop(base,EVLOOP_NONBLOCK|EVLOOP_ONCE), ==, 0); if (supports_et) { tt_int_op(called, ==, 1); @@ -140,15 +125,11 @@ test_edgetriggered(void *et) tt_assert(!was_et); } - end: +end: if (ev) { event_del(ev); event_free(ev); } - if (base) - event_base_free(base); - evutil_closesocket(pair[0]); - evutil_closesocket(pair[1]); } static void @@ -196,9 +177,94 @@ end: event_base_free(base); } +static int read_notification_count; +static int last_read_notification_was_et; +static void +read_notification_cb(evutil_socket_t fd, short event, void *arg) +{ + read_notification_count++; + last_read_notification_was_et = (event & EV_ET); +} + +static int write_notification_count; +static int last_write_notification_was_et; +static void +write_notification_cb(evutil_socket_t fd, short event, void *arg) +{ + write_notification_count++; + last_write_notification_was_et = (event & EV_ET); +} + +/* After two or more events have been registered for the same + * file descriptor using EV_ET, if one of the events is + * deleted, then the epoll_ctl() call issued by libevent drops + * the EPOLLET flag resulting in level triggered + * notifications. + */ +static void +test_edge_triggered_multiple_events(void *data_) +{ + struct basic_test_data *data = data_; + struct event *read_ev = NULL; + struct event *write_ev = NULL; + const char c = 'A'; + struct event_base *base = data->base; + evutil_socket_t *pair = data->pair; + + if (!base_supports_et(base)) { + tt_skip(); + return; + } + + read_notification_count = 0; + last_read_notification_was_et = 0; + write_notification_count = 0; + last_write_notification_was_et = 0; + + /* Make pair[1] readable */ + tt_int_op(send(pair[0], &c, 1, 0), >, 0); + + read_ev = event_new(base, pair[1], EV_READ|EV_ET|EV_PERSIST, + read_notification_cb, NULL); + write_ev = event_new(base, pair[1], EV_WRITE|EV_ET|EV_PERSIST, + write_notification_cb, NULL); + + event_add(read_ev, NULL); + event_add(write_ev, NULL); + event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE); + event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE); + + tt_assert(last_read_notification_was_et); + tt_int_op(read_notification_count, ==, 1); + tt_assert(last_write_notification_was_et); + tt_int_op(write_notification_count, ==, 1); + + event_del(read_ev); + + /* trigger acitivity second time for the backend that can have multiple + * events for one fd (like kqueue) */ + close(pair[0]); + pair[0] = -1; + + /* Verify that we are still edge-triggered for write notifications */ + event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE); + event_base_loop(base, EVLOOP_NONBLOCK|EVLOOP_ONCE); + tt_assert(last_write_notification_was_et); + tt_int_op(write_notification_count, ==, 2); + +end: + if (read_ev) + event_free(read_ev); + if (write_ev) + event_free(write_ev); +} + struct testcase_t edgetriggered_testcases[] = { - { "et", test_edgetriggered, TT_FORK, NULL, NULL }, + { "et", test_edgetriggered, + TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, NULL }, { "et_mix_error", test_edgetriggered_mix_error, TT_FORK|TT_NEED_SOCKETPAIR|TT_NO_LOGS, &basic_setup, NULL }, + { "et_multiple_events", test_edge_triggered_multiple_events, + TT_FORK|TT_NEED_BASE|TT_NEED_SOCKETPAIR, &basic_setup, NULL }, END_OF_TESTCASES }; |