diff --git a/libc/src/signal/linux/CMakeLists.txt b/libc/src/signal/linux/CMakeLists.txt --- a/libc/src/signal/linux/CMakeLists.txt +++ b/libc/src/signal/linux/CMakeLists.txt @@ -94,3 +94,29 @@ sigaction signal_h ) + +add_entrypoint_object( + sigfillset + SRCS + sigfillset.cpp + HDRS + signal.h + ../sigfillset.h + DEPENDS + __errno_location + errno_h + signal_h +) + +add_entrypoint_object( + sigdelset + SRCS + sigdelset.cpp + HDRS + signal.h + ../sigdelset.h + DEPENDS + __errno_location + errno_h + signal_h +) diff --git a/libc/src/signal/linux/sigdelset.cpp b/libc/src/signal/linux/sigdelset.cpp new file mode 100644 --- /dev/null +++ b/libc/src/signal/linux/sigdelset.cpp @@ -0,0 +1,28 @@ +//===----------------- Linux implementation of sigdelset ------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/signal/sigdelset.h" +#include "include/errno.h" +#include "src/errno/llvmlibc_errno.h" +#include "src/signal/linux/signal.h" + +#include "src/__support/common.h" + +namespace __llvm_libc { + +int LLVM_LIBC_ENTRYPOINT(sigdelset)(sigset_t *set, int signum) { + if (!set || (unsigned)(signum - 1) >= (8 * sizeof(sigset_t))) { + llvmlibc_errno = EINVAL; + return -1; + } + auto *sigset = reinterpret_cast<__llvm_libc::Sigset *>(set); + sigset->delset(signum); + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/signal/linux/sigfillset.cpp b/libc/src/signal/linux/sigfillset.cpp new file mode 100644 --- /dev/null +++ b/libc/src/signal/linux/sigfillset.cpp @@ -0,0 +1,28 @@ +//===----------------- Linux implementation of sigfillset -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/signal/sigfillset.h" +#include "include/errno.h" +#include "src/errno/llvmlibc_errno.h" +#include "src/signal/linux/signal.h" + +#include "src/__support/common.h" + +namespace __llvm_libc { + +int LLVM_LIBC_ENTRYPOINT(sigfillset)(sigset_t *set) { + if (!set) { + llvmlibc_errno = EINVAL; + return -1; + } + auto *sigset = reinterpret_cast<__llvm_libc::Sigset *>(set); + *sigset = __llvm_libc::Sigset::fullset(); + return 0; +} + +} // namespace __llvm_libc diff --git a/libc/src/signal/linux/signal.h b/libc/src/signal/linux/signal.h --- a/libc/src/signal/linux/signal.h +++ b/libc/src/signal/linux/signal.h @@ -26,9 +26,9 @@ constexpr static Sigset fullset() { return {-1UL}; } constexpr static Sigset emptySet() { return {0}; } - constexpr void addset(int signal) { - nativeSigset |= (1L << (signal - 1)); - } + constexpr void addset(int signal) { nativeSigset |= (1L << (signal - 1)); } + + constexpr void delset(int signal) { nativeSigset &= ~(1L << (signal - 1)); } operator sigset_t() const { return nativeSigset; } }; @@ -39,16 +39,15 @@ sigset_t nativeSigset = all; sigset_t oldSet = set; int ret = __llvm_libc::syscall(SYS_rt_sigprocmask, SIG_BLOCK, &nativeSigset, - &oldSet, sizeof(sigset_t)); + &oldSet, sizeof(sigset_t)); set = {oldSet}; return ret; } static inline int restore_signals(const Sigset &set) { sigset_t nativeSigset = set; - return __llvm_libc::syscall(SYS_rt_sigprocmask, SIG_SETMASK, - &nativeSigset, nullptr, - sizeof(sigset_t)); + return __llvm_libc::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &nativeSigset, + nullptr, sizeof(sigset_t)); } } // namespace __llvm_libc diff --git a/libc/src/signal/sigdelset.h b/libc/src/signal/sigdelset.h new file mode 100644 --- /dev/null +++ b/libc/src/signal/sigdelset.h @@ -0,0 +1,20 @@ +//===------------- Implementation header for sigdelset ---------*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SIGNAL_SIGDELSET_H +#define LLVM_LIBC_SRC_SIGNAL_SIGDELSET_H + +#include "include/signal.h" + +namespace __llvm_libc { + +int sigdelset(sigset_t *set, int signum); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SIGNAL_SIGDELSET_H diff --git a/libc/src/signal/sigfillset.h b/libc/src/signal/sigfillset.h new file mode 100644 --- /dev/null +++ b/libc/src/signal/sigfillset.h @@ -0,0 +1,20 @@ +//===------------- Implementation header for sigfillset --------*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_SIGNAL_SIGFILLSET_H +#define LLVM_LIBC_SRC_SIGNAL_SIGFILLSET_H + +#include "include/signal.h" + +namespace __llvm_libc { + +int sigfillset(sigset_t *set); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SIGNAL_SIGFILLSET_H diff --git a/libc/test/src/signal/CMakeLists.txt b/libc/test/src/signal/CMakeLists.txt --- a/libc/test/src/signal/CMakeLists.txt +++ b/libc/test/src/signal/CMakeLists.txt @@ -66,3 +66,34 @@ __errno_location errno_h ) + +add_libc_unittest( + sigfillset_test + SUITE + libc_signal_unittests + SRCS + sigfillset_test.cpp + DEPENDS + sigfillset + sigprocmask + signal_h + raise + errno_h + __errno_location +) + +add_libc_unittest( + sigdelset_test + SUITE + libc_signal_unittests + SRCS + sigdelset_test.cpp + DEPENDS + sigdelset + sigfillset + sigprocmask + signal_h + raise + errno_h + __errno_location +) diff --git a/libc/test/src/signal/sigdelset_test.cpp b/libc/test/src/signal/sigdelset_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/signal/sigdelset_test.cpp @@ -0,0 +1,36 @@ +//===--------------------- Unittests for sigdelset ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "include/errno.h" +#include "include/signal.h" +#include "src/signal/raise.h" +#include "src/signal/sigdelset.h" +#include "src/signal/sigfillset.h" +#include "src/signal/sigprocmask.h" + +#include "utils/UnitTest/ErrnoSetterMatcher.h" +#include "utils/UnitTest/Test.h" + +TEST(Sigdelset, Invalid) { + using __llvm_libc::testing::ErrnoSetterMatcher::Fails; + // Invalid set. + EXPECT_THAT(__llvm_libc::sigdelset(nullptr, SIGUSR1), Fails(EINVAL)); + + sigset_t set; + // Valid set, invalid signum. + EXPECT_THAT(__llvm_libc::sigdelset(&set, -1), Fails(EINVAL)); +} + +TEST(Sigdelset, UnblockOne) { + using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; + sigset_t set; + EXPECT_THAT(__llvm_libc::sigfillset(&set), Succeeds()); + EXPECT_THAT(__llvm_libc::sigdelset(&set, SIGUSR1), Succeeds()); + EXPECT_THAT(__llvm_libc::sigprocmask(SIG_SETMASK, &set, nullptr), Succeeds()); + EXPECT_DEATH([] { __llvm_libc::raise(SIGUSR1); }, SIGUSR1); +} diff --git a/libc/test/src/signal/sigfillset_test.cpp b/libc/test/src/signal/sigfillset_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/signal/sigfillset_test.cpp @@ -0,0 +1,29 @@ +//===-------------------- Unittests for sigfillset ------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "include/errno.h" +#include "include/signal.h" +#include "src/signal/raise.h" +#include "src/signal/sigfillset.h" +#include "src/signal/sigprocmask.h" + +#include "utils/UnitTest/ErrnoSetterMatcher.h" +#include "utils/UnitTest/Test.h" + +TEST(Sigfillset, Invalid) { + using __llvm_libc::testing::ErrnoSetterMatcher::Fails; + EXPECT_THAT(__llvm_libc::sigfillset(nullptr), Fails(EINVAL)); +} + +TEST(Sigfillset, BlocksAll) { + using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; + sigset_t set; + EXPECT_THAT(__llvm_libc::sigfillset(&set), Succeeds()); + EXPECT_THAT(__llvm_libc::sigprocmask(SIG_SETMASK, &set, nullptr), Succeeds()); + EXPECT_EXITS([] { __llvm_libc::raise(SIGUSR1); }, 0); +}