summaryrefslogtreecommitdiff
path: root/test/regress_et.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/regress_et.c')
-rw-r--r--test/regress_et.c144
1 files changed, 105 insertions, 39 deletions
diff --git a/test/regress_et.c b/test/regress_et.c
index f75c59b3..5fa87a39 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 */
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
};