[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
This commit is contained in:
Alex Brachet 2020-03-02 03:47:21 -05:00
parent 802b22b5c8
commit cd76a02639
16 changed files with 364 additions and 6 deletions

View File

@ -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",
];
}

View File

@ -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

View File

@ -15,6 +15,9 @@ add_entrypoint_library(
# signal.h entrypoints
raise
sigaddset
sigemptyset
sigprocmask
)
add_entrypoint_library(

View File

@ -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,
];
}

View File

@ -6,9 +6,46 @@ add_entrypoint_object(
HDRS
signal.h
../raise.h
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
)

View File

@ -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

View File

@ -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

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
)

View File

@ -8,6 +8,7 @@
#include "include/signal.h"
#include "src/signal/raise.h"
#include "utils/UnitTest/Test.h"
TEST(SignalTest, Raise) {

View File

@ -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);
}

View File

@ -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);
}