summaryrefslogtreecommitdiff
path: root/test/regress_et.c
diff options
context:
space:
mode:
authorIsidor Kouvelas <kouvelas@arista.com>2018-10-31 00:09:38 +0300
committerAzat Khuzhin <a3at.mail@gmail.com>2018-10-31 01:21:07 +0300
commit77c0e510581b88242d7d7bcff4954cedc5613554 (patch)
tree11eae40e9a1e559942c96dd6d828bc46dad6cc8b /test/regress_et.c
parentaa07cbac644174eb6fdff6a11bf5b68521970d13 (diff)
downloadlibevent-77c0e510581b88242d7d7bcff4954cedc5613554.tar.gz
Cover ET with multiple events for same fd
[ azat: test cleanup ]
Diffstat (limited to 'test/regress_et.c')
-rw-r--r--test/regress_et.c100
1 files changed, 93 insertions, 7 deletions
diff --git a/test/regress_et.c b/test/regress_et.c
index f75c59b3..b9bd317e 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)
{
@@ -106,13 +114,7 @@ test_edgetriggered(void *et)
/* 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;
-
+ 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 "));
@@ -196,9 +198,93 @@ 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;
+ int *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_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
};