[libc-commits] [libc] cd76a02 - [libc] Add sigprocmask
Alex Brachet via libc-commits
libc-commits at lists.llvm.org
Mon Mar 2 00:48:14 PST 2020
Author: Alex Brachet
Date: 2020-03-02T03:47:21-05:00
New Revision: cd76a0263990b0991fb91726070ac09a6a74c547
URL: https://github.com/llvm/llvm-project/commit/cd76a0263990b0991fb91726070ac09a6a74c547
DIFF: https://github.com/llvm/llvm-project/commit/cd76a0263990b0991fb91726070ac09a6a74c547.diff
LOG: [libc] Add sigprocmask
Summary: This patch adds `sigprocmask`, `sigemptyset` and `sigaddset`
Reviewers: sivachandra, MaskRay, gchatelet
Reviewed By: sivachandra
Subscribers: mgorny, tschuett, libc-commits
Differential Revision: https://reviews.llvm.org/D75026
Added:
libc/src/signal/linux/sigaddset.cpp
libc/src/signal/linux/sigemptyset.cpp
libc/src/signal/linux/sigprocmask.cpp
libc/src/signal/sigaddset.h
libc/src/signal/sigemptyset.h
libc/src/signal/sigprocmask.h
libc/test/src/signal/sigaddset_test.cpp
libc/test/src/signal/sigprocmask_test.cpp
Modified:
libc/config/linux/api.td
libc/include/signal.h.def
libc/lib/CMakeLists.txt
libc/spec/posix.td
libc/src/signal/linux/CMakeLists.txt
libc/src/signal/linux/signal.h
libc/test/src/signal/CMakeLists.txt
libc/test/src/signal/raise_test.cpp
Removed:
################################################################################
diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td
index ebb4883f4ba5..3ed556a93c03 100644
--- a/libc/config/linux/api.td
+++ b/libc/config/linux/api.td
@@ -135,12 +135,11 @@ def SysMManAPI : PublicAPI<"sys/mman.h"> {
}
def SignalAPI : PublicAPI<"signal.h"> {
- let TypeDeclarations = [
- SizeT, // This is needed by <linux/signal.h>.
- ];
-
let Functions = [
"raise",
+ "sigprocmask",
+ "sigemptyset",
+ "sigaddset",
];
}
diff --git a/libc/include/signal.h.def b/libc/include/signal.h.def
index 9e4209551374..a8d422ec81d0 100644
--- a/libc/include/signal.h.def
+++ b/libc/include/signal.h.def
@@ -11,8 +11,11 @@
#include <__llvm-libc-common.h>
-%%public_api()
+#define __need_size_t
+#include <stddef.h>
%%include_file(${platform_signal})
+%%public_api()
+
#endif // LLVM_LIBC_SIGNAL_H
diff --git a/libc/lib/CMakeLists.txt b/libc/lib/CMakeLists.txt
index cccb7937d297..b4ab4109d167 100644
--- a/libc/lib/CMakeLists.txt
+++ b/libc/lib/CMakeLists.txt
@@ -15,6 +15,9 @@ add_entrypoint_library(
# signal.h entrypoints
raise
+ sigaddset
+ sigemptyset
+ sigprocmask
)
add_entrypoint_library(
diff --git a/libc/spec/posix.td b/libc/spec/posix.td
index b2ad036d63b0..edd670a5f149 100644
--- a/libc/spec/posix.td
+++ b/libc/spec/posix.td
@@ -1,3 +1,9 @@
+def SigSetType : NamedType<"sigset_t">;
+def SigSetPtrType : PtrType<SigSetType>;
+def ConstSigSetPtrType : ConstType<SigSetPtrType>;
+def RestrictSigSetType : RestrictedPtrType<SigSetType>;
+def ConstRestrictSigSetType : ConstType<RestrictSigSetType>;
+
def POSIX : StandardSpec<"POSIX"> {
NamedType OffTType = NamedType<"off_t">;
@@ -128,8 +134,33 @@ def POSIX : StandardSpec<"POSIX"> {
]
>;
+ HeaderSpec Signal = HeaderSpec<
+ "signal.h",
+ [], // Macros
+ [], // Types
+ [], // Enumerations
+ [
+ FunctionSpec<
+ "sigprocmask",
+ RetValSpec<IntType>,
+ [ArgSpec<IntType>, ArgSpec<ConstRestrictSigSetType>, ArgSpec<RestrictSigSetType>]
+ >,
+ FunctionSpec<
+ "sigemptyset",
+ RetValSpec<IntType>,
+ [ArgSpec<SigSetPtrType>]
+ >,
+ FunctionSpec<
+ "sigaddset",
+ RetValSpec<IntType>,
+ [ArgSpec<SigSetPtrType>]
+ >,
+ ]
+ >;
+
let Headers = [
Errno,
SysMMan,
+ Signal,
];
}
diff --git a/libc/src/signal/linux/CMakeLists.txt b/libc/src/signal/linux/CMakeLists.txt
index a475a5853cd1..53bf5fc0f56b 100644
--- a/libc/src/signal/linux/CMakeLists.txt
+++ b/libc/src/signal/linux/CMakeLists.txt
@@ -9,6 +9,43 @@ add_entrypoint_object(
DEPENDS
sys_syscall_h
linux_syscall_h
+ signal_h
+)
+
+add_entrypoint_object(
+ sigprocmask
+ SRCS
+ sigprocmask.cpp
+ HDRS
+ signal.h
+ ../sigprocmask.h
+ DEPENDS
+ sys_syscall_h
+ linux_syscall_h
+ __errno_location
+ signal_h
+)
+
+add_entrypoint_object(
+ sigemptyset
+ SRCS
+ sigemptyset.cpp
+ HDRS
+ signal.h
+ ../sigemptyset.h
+ DEPENDS
+ __errno_location
+ signal_h
+)
+
+add_entrypoint_object(
+ sigaddset
+ SRCS
+ sigaddset.cpp
+ HDRS
+ signal.h
+ ../sigaddset.h
+ DEPENDS
__errno_location
signal_h
)
diff --git a/libc/src/signal/linux/sigaddset.cpp b/libc/src/signal/linux/sigaddset.cpp
new file mode 100644
index 000000000000..bd6c02def82d
--- /dev/null
+++ b/libc/src/signal/linux/sigaddset.cpp
@@ -0,0 +1,28 @@
+//===----------------- Linux implementation of sigaddset ------------------===//
+//
+// 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/sigaddset.h"
+#include "include/errno.h" // For E* macros.
+#include "src/errno/llvmlibc_errno.h"
+#include "src/signal/linux/signal.h"
+
+#include "src/__support/common.h"
+
+namespace __llvm_libc {
+
+int LLVM_LIBC_ENTRYPOINT(sigaddset)(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->addset(signum);
+ return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/signal/linux/sigemptyset.cpp b/libc/src/signal/linux/sigemptyset.cpp
new file mode 100644
index 000000000000..6114900d3650
--- /dev/null
+++ b/libc/src/signal/linux/sigemptyset.cpp
@@ -0,0 +1,27 @@
+//===--------------- Linux implementation of sigemptyset ------------------===//
+//
+// 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/sigemptyset.h"
+#include "include/errno.h" // For E* macros.
+#include "src/errno/llvmlibc_errno.h"
+#include "src/signal/linux/signal.h"
+
+#include "src/__support/common.h"
+
+namespace __llvm_libc {
+
+int LLVM_LIBC_ENTRYPOINT(sigemptyset)(sigset_t *set) {
+ if (!set) {
+ llvmlibc_errno = EINVAL;
+ return -1;
+ }
+ *set = __llvm_libc::Sigset::emptySet();
+ return 0;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/signal/linux/signal.h b/libc/src/signal/linux/signal.h
index f70185ee39a7..93b33596580f 100644
--- a/libc/src/signal/linux/signal.h
+++ b/libc/src/signal/linux/signal.h
@@ -24,6 +24,11 @@ struct Sigset {
sigset_t nativeSigset;
constexpr static Sigset fullset() { return {-1UL}; }
+ constexpr static Sigset emptySet() { return {0}; }
+
+ constexpr void addset(int signal) {
+ nativeSigset |= (1L << (signal - 1));
+ }
operator sigset_t() const { return nativeSigset; }
};
@@ -33,8 +38,10 @@ constexpr static Sigset all = Sigset::fullset();
static inline int block_all_signals(Sigset &set) {
sigset_t nativeSigset = all;
sigset_t oldSet = set;
- return __llvm_libc::syscall(SYS_rt_sigprocmask, SIG_BLOCK, &nativeSigset,
+ int ret = __llvm_libc::syscall(SYS_rt_sigprocmask, SIG_BLOCK, &nativeSigset,
&oldSet, sizeof(sigset_t));
+ set = {oldSet};
+ return ret;
}
static inline int restore_signals(const Sigset &set) {
diff --git a/libc/src/signal/linux/sigprocmask.cpp b/libc/src/signal/linux/sigprocmask.cpp
new file mode 100644
index 000000000000..18f238b6c97e
--- /dev/null
+++ b/libc/src/signal/linux/sigprocmask.cpp
@@ -0,0 +1,28 @@
+//===--------------- Linux implementation of sigprocmask ------------------===//
+//
+// 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/sigprocmask.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(sigprocmask)(int how, const sigset_t *__restrict set,
+ sigset_t *__restrict oldset) {
+ int ret = __llvm_libc::syscall(SYS_rt_sigprocmask, how, set, oldset,
+ sizeof(sigset_t));
+ if (!ret)
+ return 0;
+
+ llvmlibc_errno = -ret;
+ return -1;
+}
+
+} // namespace __llvm_libc
diff --git a/libc/src/signal/sigaddset.h b/libc/src/signal/sigaddset.h
new file mode 100644
index 000000000000..d25e6dc5f7ea
--- /dev/null
+++ b/libc/src/signal/sigaddset.h
@@ -0,0 +1,20 @@
+//===------------- Implementation header for sigaddset ---------*- 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_SIGEADDSET_H
+#define LLVM_LIBC_SRC_SIGNAL_SIGEADDSET_H
+
+#include "include/signal.h"
+
+namespace __llvm_libc {
+
+int sigaddset(sigset_t *set, int signum);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SIGNAL_SIGEADDSET_H
diff --git a/libc/src/signal/sigemptyset.h b/libc/src/signal/sigemptyset.h
new file mode 100644
index 000000000000..6f991633fbbd
--- /dev/null
+++ b/libc/src/signal/sigemptyset.h
@@ -0,0 +1,20 @@
+//===------------ Implementation header for sigemptyset --------*- 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_SIGEMPTYSET_H
+#define LLVM_LIBC_SRC_SIGNAL_SIGEMPTYSET_H
+
+#include "include/signal.h"
+
+namespace __llvm_libc {
+
+int sigemptyset(sigset_t *set);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SIGNAL_SIGEMPTYSET_H
diff --git a/libc/src/signal/sigprocmask.h b/libc/src/signal/sigprocmask.h
new file mode 100644
index 000000000000..0e959ca2ea83
--- /dev/null
+++ b/libc/src/signal/sigprocmask.h
@@ -0,0 +1,21 @@
+//===------------ Implementation header for sigprocmask --------*- 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_SIGPROCMASK_H
+#define LLVM_LIBC_SRC_SIGNAL_SIGPROCMASK_H
+
+#include "include/signal.h"
+
+namespace __llvm_libc {
+
+int sigprocmask(int how, const sigset_t *__restrict set,
+ sigset_t *__restrict oldset);
+
+} // namespace __llvm_libc
+
+#endif // LLVM_LIBC_SRC_SIGNAL_SIGPROCMASK_H
diff --git a/libc/test/src/signal/CMakeLists.txt b/libc/test/src/signal/CMakeLists.txt
index dd1cc3b8b5d3..38f6961920d1 100644
--- a/libc/test/src/signal/CMakeLists.txt
+++ b/libc/test/src/signal/CMakeLists.txt
@@ -10,3 +10,30 @@ add_libc_unittest(
raise
signal_h
)
+
+add_libc_unittest(
+ sigprocmask_test
+ SUITE
+ libc_signal_unittests
+ SRCS
+ sigprocmask_test.cpp
+ DEPENDS
+ raise
+ sigprocmask
+ sigaddset
+ sigemptyset
+ signal_h
+ __errno_location
+)
+
+add_libc_unittest(
+ sigaddset_test
+ SUITE
+ libc_signal_unittests
+ SRCS
+ sigaddset_test.cpp
+ DEPENDS
+ sigaddset
+ signal_h
+ __errno_location
+)
diff --git a/libc/test/src/signal/raise_test.cpp b/libc/test/src/signal/raise_test.cpp
index 882fee49e26e..eea890ae6b74 100644
--- a/libc/test/src/signal/raise_test.cpp
+++ b/libc/test/src/signal/raise_test.cpp
@@ -8,6 +8,7 @@
#include "include/signal.h"
#include "src/signal/raise.h"
+
#include "utils/UnitTest/Test.h"
TEST(SignalTest, Raise) {
diff --git a/libc/test/src/signal/sigaddset_test.cpp b/libc/test/src/signal/sigaddset_test.cpp
new file mode 100644
index 000000000000..58df1feb1a2d
--- /dev/null
+++ b/libc/test/src/signal/sigaddset_test.cpp
@@ -0,0 +1,42 @@
+//===----------------------- Unittests for sigaddset ----------------------===//
+//
+// 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/errno/llvmlibc_errno.h"
+#include "src/signal/sigaddset.h"
+
+#include "utils/UnitTest/Test.h"
+
+// This tests invalid inputs and ensures errno is properly set.
+TEST(SignalTest, SigaddsetInvalid) {
+ llvmlibc_errno = 0;
+ EXPECT_EQ(__llvm_libc::sigaddset(nullptr, SIGSEGV), -1);
+ EXPECT_EQ(llvmlibc_errno, EINVAL);
+
+ sigset_t sigset;
+ llvmlibc_errno = 0;
+ EXPECT_EQ(__llvm_libc::sigaddset(&sigset, -1), -1);
+ EXPECT_EQ(llvmlibc_errno, EINVAL);
+
+ // This doesn't use NSIG because __llvm_libc::sigaddset error checking is
+ // against sizeof(sigset_t) not NSIG.
+ constexpr int bitsInSigsetT = 8 * sizeof(sigset_t);
+
+ llvmlibc_errno = 0;
+ EXPECT_EQ(__llvm_libc::sigaddset(&sigset, bitsInSigsetT + 1), -1);
+ EXPECT_EQ(llvmlibc_errno, EINVAL);
+
+ llvmlibc_errno = 0;
+ EXPECT_EQ(__llvm_libc::sigaddset(&sigset, 0), -1);
+ EXPECT_EQ(llvmlibc_errno, EINVAL);
+
+ llvmlibc_errno = 0;
+ EXPECT_EQ(__llvm_libc::sigaddset(&sigset, bitsInSigsetT), 0);
+ EXPECT_EQ(llvmlibc_errno, 0);
+}
diff --git a/libc/test/src/signal/sigprocmask_test.cpp b/libc/test/src/signal/sigprocmask_test.cpp
new file mode 100644
index 000000000000..a0918d11c7f5
--- /dev/null
+++ b/libc/test/src/signal/sigprocmask_test.cpp
@@ -0,0 +1,64 @@
+//===--------------------- Unittests for sigprocmask ----------------------===//
+//
+// 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/errno/llvmlibc_errno.h"
+#include "src/signal/raise.h"
+#include "src/signal/sigaddset.h"
+#include "src/signal/sigemptyset.h"
+#include "src/signal/sigprocmask.h"
+
+#include "utils/UnitTest/Test.h"
+
+class SignalTest : public __llvm_libc::testing::Test {
+ sigset_t oldSet;
+
+public:
+ void SetUp() override { __llvm_libc::sigprocmask(0, nullptr, &oldSet); }
+
+ void TearDown() override {
+ __llvm_libc::sigprocmask(SIG_SETMASK, &oldSet, nullptr);
+ }
+};
+
+// This tests for invalid input.
+TEST_F(SignalTest, SigprocmaskInvalid) {
+ sigset_t valid;
+ // 17 and -4 are out of the range for sigprocmask's how paramater.
+ llvmlibc_errno = 0;
+ EXPECT_EQ(__llvm_libc::sigprocmask(17, &valid, nullptr), -1);
+ EXPECT_EQ(llvmlibc_errno, EINVAL);
+
+ llvmlibc_errno = 0;
+ EXPECT_EQ(__llvm_libc::sigprocmask(-4, &valid, nullptr), -1);
+ EXPECT_EQ(llvmlibc_errno, EINVAL);
+
+ // This pointer is out of this processes address range.
+ sigset_t *invalid = reinterpret_cast<sigset_t *>(-1);
+
+ llvmlibc_errno = 0;
+ EXPECT_EQ(__llvm_libc::sigprocmask(SIG_SETMASK, invalid, nullptr), -1);
+ EXPECT_EQ(llvmlibc_errno, EFAULT);
+
+ llvmlibc_errno = 0;
+ EXPECT_EQ(__llvm_libc::sigprocmask(-4, nullptr, invalid), -1);
+ EXPECT_EQ(llvmlibc_errno, EFAULT);
+}
+
+// This tests that when nothing is blocked, a process gets killed and alse tests
+// that when signals are blocked they are not delivered to the process.
+TEST_F(SignalTest, BlockUnblock) {
+ sigset_t sigset;
+ EXPECT_EQ(__llvm_libc::sigemptyset(&sigset), 0);
+ EXPECT_EQ(__llvm_libc::sigprocmask(SIG_SETMASK, &sigset, nullptr), 0);
+ EXPECT_DEATH([] { __llvm_libc::raise(SIGUSR1); }, SIGUSR1);
+ EXPECT_EQ(__llvm_libc::sigaddset(&sigset, SIGUSR1), 0);
+ EXPECT_EQ(__llvm_libc::sigprocmask(SIG_SETMASK, &sigset, nullptr), 0);
+ EXPECT_EXITS([] { __llvm_libc::raise(SIGUSR1); }, 0);
+}
More information about the libc-commits
mailing list