[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