aboutsummaryrefslogtreecommitdiff
path: root/tests/sys/kqueue/kqueue_fork.c
diff options
context:
space:
mode:
Diffstat (limited to 'tests/sys/kqueue/kqueue_fork.c')
-rw-r--r--tests/sys/kqueue/kqueue_fork.c36
1 files changed, 36 insertions, 0 deletions
diff --git a/tests/sys/kqueue/kqueue_fork.c b/tests/sys/kqueue/kqueue_fork.c
index ad8f69056e07..03b831e4f77c 100644
--- a/tests/sys/kqueue/kqueue_fork.c
+++ b/tests/sys/kqueue/kqueue_fork.c
@@ -269,10 +269,46 @@ ATF_TC_BODY(cponfork_notes, tc)
cponfork_notes_mask_check(info.si_status, true);
}
+/*
+ * Exercise a rare race: while the kernel is copying knotes during a fork, try
+ * to set things up so that a new knote is activated while the copy is still in
+ * progress.
+ */
+ATF_TC_WITHOUT_HEAD(cponfork_timer_race);
+ATF_TC_BODY(cponfork_timer_race, tc)
+{
+ struct kevent ev;
+ int error, kq, status;
+ pid_t pid;
+
+ for (int i = 0; i < 100; i++) {
+ kq = kqueuex(KQUEUE_CPONFORK);
+ ATF_REQUIRE(kq >= 0);
+
+ EV_SET(&ev, 0, EVFILT_TIMER, EV_ADD | EV_ENABLE, NOTE_NSECONDS,
+ 1, NULL);
+ error = kevent(kq, &ev, 1, NULL, 0, NULL);
+ ATF_REQUIRE(error == 0);
+
+ pid = fork();
+ ATF_REQUIRE(pid != -1);
+ if (pid == 0)
+ _exit(0);
+
+ error = waitpid(pid, &status, 0);
+ ATF_REQUIRE(error != -1);
+ ATF_REQUIRE(WIFEXITED(status));
+ ATF_REQUIRE_EQ(WEXITSTATUS(status), 0);
+
+ ATF_REQUIRE(close(kq) == 0);
+ }
+}
+
ATF_TP_ADD_TCS(tp)
{
ATF_TP_ADD_TC(tp, shared_table_filt_sig);
ATF_TP_ADD_TC(tp, cponfork_notes);
+ ATF_TP_ADD_TC(tp, cponfork_timer_race);
return (atf_no_error());
}