diff options
-rw-r--r-- | Tests/Kernel/CMakeLists.txt | 1 | ||||
-rw-r--r-- | Tests/Kernel/TestSigWait.cpp | 179 |
2 files changed, 180 insertions, 0 deletions
diff --git a/Tests/Kernel/CMakeLists.txt b/Tests/Kernel/CMakeLists.txt index ef37bc29dc..4cec637dc3 100644 --- a/Tests/Kernel/CMakeLists.txt +++ b/Tests/Kernel/CMakeLists.txt @@ -42,6 +42,7 @@ set(LIBTEST_BASED_SOURCES TestProcFS.cpp TestProcFSWrite.cpp TestSigAltStack.cpp + TestSigWait.cpp ) foreach(libtest_source IN LISTS LIBTEST_BASED_SOURCES) diff --git a/Tests/Kernel/TestSigWait.cpp b/Tests/Kernel/TestSigWait.cpp new file mode 100644 index 0000000000..5e61199d10 --- /dev/null +++ b/Tests/Kernel/TestSigWait.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (c) 2021, Idan Horowitz <idan.horowitz@serenityos.org> + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <LibTest/TestCase.h> +#include <signal.h> +#include <time.h> +#include <unistd.h> + +TEST_CASE(sigwait) +{ + sigset_t mask; + + int rc = sigemptyset(&mask); + EXPECT_EQ(rc, 0); + rc = sigaddset(&mask, SIGUSR1); + EXPECT_EQ(rc, 0); + rc = sigprocmask(SIG_BLOCK, &mask, nullptr); + EXPECT_EQ(rc, 0); + + int child_pid = fork(); + EXPECT(child_pid >= 0); + if (child_pid == 0) { + sleep(1); + kill(getppid(), SIGUSR1); + exit(EXIT_SUCCESS); + } else { + int sig; + rc = sigwait(&mask, &sig); + EXPECT_EQ(rc, 0); + EXPECT_EQ(sig, SIGUSR1); + } + + // cancel pending signal + struct sigaction act_ignore = { { SIG_IGN }, 0, 0 }; + rc = sigaction(SIGUSR1, &act_ignore, nullptr); + EXPECT_EQ(rc, 0); + rc = sigprocmask(SIG_UNBLOCK, &mask, nullptr); + EXPECT_EQ(rc, 0); + struct sigaction act_default = { { SIG_DFL }, 0, 0 }; + rc = sigaction(SIGUSR1, &act_default, nullptr); + EXPECT_EQ(rc, 0); + sigset_t pending; + rc = sigpending(&pending); + EXPECT_EQ(rc, 0); + EXPECT_EQ(pending, 0u); +} + +TEST_CASE(sigwaitinfo) +{ + sigset_t mask; + + int rc = sigemptyset(&mask); + EXPECT_EQ(rc, 0); + rc = sigaddset(&mask, SIGUSR1); + EXPECT_EQ(rc, 0); + rc = sigprocmask(SIG_BLOCK, &mask, nullptr); + EXPECT_EQ(rc, 0); + + int child_pid = fork(); + EXPECT(child_pid >= 0); + if (child_pid == 0) { + sleep(1); + kill(getppid(), SIGUSR1); + exit(EXIT_SUCCESS); + } else { + siginfo_t info; + rc = sigwaitinfo(&mask, &info); + EXPECT_EQ(rc, SIGUSR1); + EXPECT_EQ(info.si_signo, SIGUSR1); + } + + // cancel pending signal + struct sigaction act_ignore = { { SIG_IGN }, 0, 0 }; + rc = sigaction(SIGUSR1, &act_ignore, nullptr); + EXPECT_EQ(rc, 0); + rc = sigprocmask(SIG_UNBLOCK, &mask, nullptr); + EXPECT_EQ(rc, 0); + struct sigaction act_default = { { SIG_DFL }, 0, 0 }; + rc = sigaction(SIGUSR1, &act_default, nullptr); + EXPECT_EQ(rc, 0); + sigset_t pending; + rc = sigpending(&pending); + EXPECT_EQ(rc, 0); + EXPECT_EQ(pending, 0u); +} + +TEST_CASE(sigtimedwait_normal) +{ + sigset_t mask; + + int rc = sigemptyset(&mask); + EXPECT_EQ(rc, 0); + rc = sigaddset(&mask, SIGUSR1); + EXPECT_EQ(rc, 0); + rc = sigprocmask(SIG_BLOCK, &mask, nullptr); + EXPECT_EQ(rc, 0); + + int child_pid = fork(); + EXPECT(child_pid >= 0); + if (child_pid == 0) { + sleep(1); + kill(getppid(), SIGUSR1); + exit(EXIT_SUCCESS); + } else { + siginfo_t info; + struct timespec timeout = { .tv_sec = 2, .tv_nsec = 0 }; + rc = sigtimedwait(&mask, &info, &timeout); + EXPECT_EQ(rc, SIGUSR1); + EXPECT_EQ(info.si_signo, SIGUSR1); + } + + // cancel pending signal + struct sigaction act_ignore = { { SIG_IGN }, 0, 0 }; + rc = sigaction(SIGUSR1, &act_ignore, nullptr); + EXPECT_EQ(rc, 0); + rc = sigprocmask(SIG_UNBLOCK, &mask, nullptr); + EXPECT_EQ(rc, 0); + struct sigaction act_default = { { SIG_DFL }, 0, 0 }; + rc = sigaction(SIGUSR1, &act_default, nullptr); + EXPECT_EQ(rc, 0); + sigset_t pending; + rc = sigpending(&pending); + EXPECT_EQ(rc, 0); + EXPECT_EQ(pending, 0u); +} + +TEST_CASE(sigtimedwait_poll) +{ + sigset_t mask; + + int rc = sigemptyset(&mask); + EXPECT_EQ(rc, 0); + rc = sigaddset(&mask, SIGUSR1); + EXPECT_EQ(rc, 0); + rc = sigprocmask(SIG_BLOCK, &mask, nullptr); + EXPECT_EQ(rc, 0); + + struct timespec poll_timeout = { .tv_sec = 0, .tv_nsec = 0 }; + rc = sigtimedwait(&mask, nullptr, &poll_timeout); + EXPECT_EQ(rc, -1); + EXPECT_EQ(errno, EAGAIN); + + kill(getpid(), SIGUSR1); + + siginfo_t info; + rc = sigtimedwait(&mask, &info, &poll_timeout); + EXPECT_EQ(rc, SIGUSR1); + EXPECT_EQ(info.si_signo, SIGUSR1); + + // cancel pending signal + struct sigaction act_ignore = { { SIG_IGN }, 0, 0 }; + rc = sigaction(SIGUSR1, &act_ignore, nullptr); + EXPECT_EQ(rc, 0); + rc = sigprocmask(SIG_UNBLOCK, &mask, nullptr); + EXPECT_EQ(rc, 0); + struct sigaction act_default = { { SIG_DFL }, 0, 0 }; + rc = sigaction(SIGUSR1, &act_default, nullptr); + EXPECT_EQ(rc, 0); + sigset_t pending; + rc = sigpending(&pending); + EXPECT_EQ(rc, 0); + EXPECT_EQ(pending, 0u); +} + +TEST_CASE(sigtimedwait_timeout) +{ + sigset_t mask; + int rc = sigemptyset(&mask); + EXPECT_EQ(rc, 0); + rc = sigaddset(&mask, SIGUSR1); + EXPECT_EQ(rc, 0); + struct timespec timeout = { .tv_sec = 1, .tv_nsec = 0 }; + rc = sigtimedwait(&mask, nullptr, &timeout); + EXPECT_EQ(rc, -1); + EXPECT_EQ(errno, EAGAIN); +} |