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
MFC after:	2 weeks
Sponsored by:	The FreeBSD Foundation
This commit is contained in:
Mark Johnston 2022-05-24 20:16:32 -04:00
parent 524dadf7a8
commit d6d4f9b45e
2 changed files with 128 additions and 2 deletions

View file

@ -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"

View file

@ -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);
}