diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile --- a/tests/sys/kern/Makefile +++ b/tests/sys/kern/Makefile @@ -23,6 +23,7 @@ ATF_TESTS_C+= ktrace_test ATF_TESTS_C+= listener_wakeup ATF_TESTS_C+= module_test +ATF_TESTS_C+= prace ATF_TESTS_C+= ptrace_test TEST_METADATA.ptrace_test+= timeout="15" ATF_TESTS_C+= reaper diff --git a/tests/sys/kern/prace.c b/tests/sys/kern/prace.c new file mode 100644 --- /dev/null +++ b/tests/sys/kern/prace.c @@ -0,0 +1,108 @@ +/*- + * Copyright (c) 2024 Klara, Inc. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +static volatile sig_atomic_t caught[NSIG]; + +static void +handler(int signo) +{ + caught[signo]++; +} + +static void +child(int rd, bool poll) +{ + struct timespec timeout = { .tv_nsec = 1000000 }; + sigset_t set0, set1; + int ret; + + sigemptyset(&set0); + sigemptyset(&set1); + sigaddset(&set1, SIGINT); + sigprocmask(SIG_BLOCK, &set1, NULL); + signal(SIGINT, handler); + close(rd); + for (;;) { + ret = poll ? ppoll(NULL, 0, &timeout, &set0) : + pselect(0, NULL, NULL, NULL, &timeout, &set0); + if (ret != 0 && errno != EINTR) + err(1, "p%s()", poll ? "poll" : "select"); + if (ret == 0 && caught[SIGINT]) { + signal(SIGINT, SIG_DFL); + raise(SIGINT); + } + caught[SIGINT] = 0; + } + /* Not reached */ +} + +static void +prace(bool poll) +{ + useconds_t timeout = 1100; + int pd[2], status; + pid_t pid; + + if (pipe(pd) != 0) + err(1, "pipe()"); + if ((pid = fork()) < 0) + err(1, "fork()"); + if (pid == 0) { + close(pd[0]); + child(pd[1], poll); + /* Not reached */ + } + close(pd[1]); + (void)read(pd[0], &pd[0], sizeof(pd[0])); + close(pd[0]); + do { + usleep(timeout); + if (kill(pid, SIGINT) != 0) { + if (errno != ENOENT) + err(1, "kill()"); + break; + } + } while (timeout-- > 900); + (void)kill(pid, SIGKILL); + if (waitpid(pid, &status, 0) < 0) + err(1, "waitpid()"); + ATF_REQUIRE(WIFSIGNALED(status)); + ATF_REQUIRE_MSG(WTERMSIG(status) == SIGKILL, + "child caught SIG%s", sys_signame[WTERMSIG(status)]); +} + +ATF_TC_WITHOUT_HEAD(ppoll_race); +ATF_TC_BODY(ppoll_race, tc) +{ + prace(true); +} + + +ATF_TC_WITHOUT_HEAD(pselect_race); +ATF_TC_BODY(pselect_race, tc) +{ + prace(false); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, ppoll_race); + ATF_TP_ADD_TC(tp, pselect_race); + return (atf_no_error()); +}