git: f2ce33a640fd - stable/13 - kqueue tests: Add new EVFILT_TIMER regression tests from upstream

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Wed, 08 Jun 2022 00:45:00 UTC
The branch stable/13 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=f2ce33a640fddeb0763d4114bc7f06aa521effd0

commit f2ce33a640fddeb0763d4114bc7f06aa521effd0
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2022-05-25 00:16:32 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2022-06-08 00:42:25 +0000

    kqueue tests: Add new EVFILT_TIMER regression tests from upstream
    
    One of the tests exposes the regression reported in PR 264131.
    
    One test is disabled because FreeBSD does not support setting EV_ONESHOT
    on an already-added periodic timer.  Though, in this case the flag is
    simply ignored, which isn't ideal.
    
    One test is slightly modified to set EV_ADD when reconfiguring a
    disabled timer per some commentary in PR 258412.
    
    Ideally we would re-import the test suite from libkqueue but there is a
    fair bit of divergence so this will require some effort.  This just gets
    us one small step closer while increasing test coverage.
    
    PR:             258412
    Sponsored by:   The FreeBSD Foundation
    
    (cherry picked from commit d6d4f9b45e0be306bdaf53b2133b2cd0f7642167)
---
 tests/sys/kqueue/libkqueue/config.h |   1 +
 tests/sys/kqueue/libkqueue/timer.c  | 129 +++++++++++++++++++++++++++++++++++-
 2 files changed, 128 insertions(+), 2 deletions(-)

diff --git a/tests/sys/kqueue/libkqueue/config.h b/tests/sys/kqueue/libkqueue/config.h
index a204092a2ab2..41a67837efe8 100644
--- a/tests/sys/kqueue/libkqueue/config.h
+++ b/tests/sys/kqueue/libkqueue/config.h
@@ -7,6 +7,7 @@
 #undef HAVE_NOTE_TRUNCATE
 #define HAVE_EVFILT_TIMER 1
 #define HAVE_EVFILT_USER 1
+#define WITH_NATIVE_KQUEUE_BUGS 0
 #define PROGRAM "libkqueue-test"
 #define VERSION "0.1"
 #define TARGET "freebsd"
diff --git a/tests/sys/kqueue/libkqueue/timer.c b/tests/sys/kqueue/libkqueue/timer.c
index 330c22c62bc5..aa9d41ce6bf8 100644
--- a/tests/sys/kqueue/libkqueue/timer.c
+++ b/tests/sys/kqueue/libkqueue/timer.c
@@ -182,7 +182,84 @@ test_periodic(void)
 }
 
 static void
-disable_and_enable(void)
+test_periodic_modify(void)
+{
+    const char *test_id = "kevent(EVFILT_TIMER, periodic_modify)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    test_no_kevents();
+
+    EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    /* Retrieve the event */
+    kev.flags = EV_ADD | EV_CLEAR;
+    kev.data = 1;
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    /* Check if the event occurs again */
+    EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 500, NULL);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    kev.flags = EV_ADD | EV_CLEAR;
+    sleep(1);
+    kev.data = 2;	/* Should have fired twice */
+
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    /* Delete the event */
+    kev.flags = EV_DELETE;
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    success();
+}
+
+#if WITH_NATIVE_KQUEUE_BUGS
+static void
+test_periodic_to_oneshot(void)
+{
+    const char *test_id = "kevent(EVFILT_TIMER, period_to_oneshot)";
+    struct kevent kev;
+
+    test_begin(test_id);
+
+    test_no_kevents();
+
+    EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD, 0, 1000, NULL);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    /* Retrieve the event */
+    kev.flags = EV_ADD | EV_CLEAR;
+    kev.data = 1;
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    /* Check if the event occurs again */
+    sleep(1);
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    /* Switch to oneshot */
+    EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ONESHOT, 0, 500, NULL);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+    kev.flags = EV_ADD | EV_CLEAR | EV_ONESHOT;
+
+    sleep(1);
+    kev.data = 1;	/* Should have fired once */
+
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    success();
+}
+#endif
+
+static void
+test_disable_and_enable(void)
 {
     const char *test_id = "kevent(EVFILT_TIMER, EV_DISABLE and EV_ENABLE)";
     struct kevent kev;
@@ -618,6 +695,49 @@ test_update_timing(void)
     success();
 }
 
+static void
+test_dispatch(void)
+{
+    const char *test_id = "kevent(EVFILT_TIMER, EV_ADD | EV_DISPATCH)";
+    struct kevent kev;
+
+    test_no_kevents();
+
+    EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_DISPATCH, 0, 200, NULL);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+
+    /* Get one event */
+    kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
+    kev.data = 1;
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    /* Confirm that the knote is disabled due to EV_DISPATCH */
+    usleep(500000);
+    test_no_kevents();
+
+    /* Enable the knote and make sure no events are pending */
+    EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_ADD | EV_ENABLE | EV_DISPATCH, 0, 200, NULL);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+    test_no_kevents();
+
+    /* Get the next event */
+    usleep(1100000); /* 1100 ms */
+    kev.flags = EV_ADD | EV_CLEAR | EV_DISPATCH;
+    kev.data = 5;
+    kevent_cmp(&kev, kevent_get(kqfd));
+
+    /* Remove the knote and ensure the event no longer fires */
+    EV_SET(&kev, vnode_fd, EVFILT_TIMER, EV_DELETE, 0, 0, NULL);
+    if (kevent(kqfd, &kev, 1, NULL, 0, NULL) < 0)
+        err(1, "%s", test_id);
+    usleep(500000); /* 500ms */
+    test_no_kevents();
+
+    success();
+}
+
 void
 test_evfilt_timer(void)
 {
@@ -627,6 +747,10 @@ test_evfilt_timer(void)
     test_kevent_timer_get();
     test_oneshot();
     test_periodic();
+    test_periodic_modify();
+#if WITH_NATIVE_KQUEUE_BUGS
+    test_periodic_to_oneshot();
+#endif
     test_abstime();
     test_abstime_epoch();
     test_abstime_preboot();
@@ -636,6 +760,7 @@ test_evfilt_timer(void)
     test_update_expired();
     test_update_timing();
     test_update_periodic();
-    disable_and_enable();
+    test_disable_and_enable();
+    test_dispatch();
     close(kqfd);
 }