[libc] Add signal

Summary:
This patch adds a Linux implementation for `signal`
It also fixes `ASSERT|EXPECT_THAT` macros

Reviewers: sivachandra, PaulkaToast, MaskRay

Reviewed By: sivachandra

Subscribers: mgorny, tschuett, libc-commits

Differential Revision: https://reviews.llvm.org/D76536
This commit is contained in:
Alex Brachet 2020-03-22 14:15:47 -04:00
parent b89ae50795
commit ca04d0c8fd
9 changed files with 146 additions and 6 deletions

View File

@ -194,9 +194,16 @@ def StructSigactionDefn : TypeDecl<"struct sigaction"> {
}];
}
def SighandlerTDefn : TypeDecl<"__sighandler_t"> {
let Decl = [{
typedef void(*__sighandler_t)(int);
}];
}
def SignalAPI : PublicAPI<"signal.h"> {
let TypeDeclarations = [
StructSigactionDefn,
SighandlerTDefn,
];
let Functions = [
@ -205,6 +212,7 @@ def SignalAPI : PublicAPI<"signal.h"> {
"sigprocmask",
"sigemptyset",
"sigaddset",
"signal",
];
}

View File

@ -23,6 +23,7 @@ add_entrypoint_library(
sigaddset
sigemptyset
sigprocmask
signal
# stdlib.h entrypoints
_Exit

View File

@ -16,6 +16,8 @@ def StdC : StandardSpec<"stdc"> {
PtrType IntPtr = PtrType<IntType>;
NamedType SigHandlerT = NamedType<"__sighandler_t">;
HeaderSpec Assert = HeaderSpec<
"assert.h",
[
@ -226,10 +228,16 @@ def StdC : StandardSpec<"stdc"> {
],
[
SizeTType,
SigHandlerT,
],
[], // Enumerations
[
FunctionSpec<"raise", RetValSpec<IntType>, [ArgSpec<IntType>]>,
FunctionSpec<
"signal",
RetValSpec<SigHandlerT>,
[ArgSpec<IntType>, ArgSpec<SigHandlerT>]
>,
]
>;

View File

@ -84,3 +84,15 @@ add_entrypoint_object(
errno_h
signal_h
)
add_entrypoint_object(
signal
SRCS
signal.cpp
HDRS
signal.h
../signal.h
DEPENDS
sigaction
signal_h
)

View File

@ -0,0 +1,26 @@
//===------------------ Linux implementation of signal --------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
#define __LLVM_LIBC_INTERNAL_SIGACTION
#include "src/signal/signal.h"
#include "src/signal/sigaction.h"
#include "src/__support/common.h"
namespace __llvm_libc {
sighandler_t LLVM_LIBC_ENTRYPOINT(signal)(int signum, sighandler_t handler) {
struct __sigaction action, old;
action.sa_handler = handler;
action.sa_flags = SA_RESTART;
// Errno will already be set so no need to worry about changing errno here.
return __llvm_libc::sigaction(signum, &action, &old) == -1 ? SIG_ERR
: old.sa_handler;
}
} // namespace __llvm_libc

22
libc/src/signal/signal.h Normal file
View File

@ -0,0 +1,22 @@
//===------------- Implementation header for signal ------------*- 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_SIGNAL_H
#define LLVM_LIBC_SRC_SIGNAL_SIGNAL_H
#include "include/signal.h"
namespace __llvm_libc {
using sighandler_t = __sighandler_t;
sighandler_t signal(int signum, sighandler_t handler);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_SIGNAL_SIGNAL_H

View File

@ -52,3 +52,18 @@ add_libc_unittest(
signal_h
__errno_location
)
add_libc_unittest(
signal_test
SUITE
libc_signal_unittests
SRCS
signal_test.cpp
DEPENDS
signal
signal_h
sigaction
raise
__errno_location
errno_h
)

View File

@ -0,0 +1,41 @@
//===------------------------ Unittests for signal ------------------------===//
//
// 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/signal.h"
#include "utils/UnitTest/ErrnoSetterMatcher.h"
#include "utils/UnitTest/Test.h"
using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;
TEST(Signal, Invalid) {
llvmlibc_errno = 0;
__llvm_libc::sighandler_t valid = +[](int) {};
EXPECT_THAT((void *)__llvm_libc::signal(0, valid),
Fails(EINVAL, (void *)SIG_ERR));
EXPECT_THAT((void *)__llvm_libc::signal(65, valid),
Fails(EINVAL, (void *)SIG_ERR));
}
static int sum;
TEST(Signal, Basic) {
// In case test get run multiple times.
sum = 0;
ASSERT_NE(__llvm_libc::signal(SIGUSR1, +[](int) { sum++; }),
SIG_ERR);
ASSERT_THAT(__llvm_libc::raise(SIGUSR1), Succeeds());
EXPECT_EQ(sum, 1);
for (int i = 0; i < 10; i++)
ASSERT_THAT(__llvm_libc::raise(SIGUSR1), Succeeds());
EXPECT_EQ(sum, 11);
}

View File

@ -249,13 +249,20 @@ private:
#define UNIQUE_VAR(prefix) __CAT(prefix, __LINE__)
#define EXPECT_THAT(MATCH, MATCHER) \
auto UNIQUE_VAR(__matcher) = (MATCHER); \
__llvm_libc::testing::Test::testMatch( \
Ctx, UNIQUE_VAR(__matcher).match((MATCH)), UNIQUE_VAR(__matcher), \
#MATCH, #MATCHER, __FILE__, __LINE__)
do { \
auto UNIQUE_VAR(__matcher) = (MATCHER); \
__llvm_libc::testing::Test::testMatch( \
Ctx, UNIQUE_VAR(__matcher).match((MATCH)), UNIQUE_VAR(__matcher), \
#MATCH, #MATCHER, __FILE__, __LINE__); \
} while (0)
#define ASSERT_THAT(MATCH, MATCHER) \
if (!EXPECT_THAT(MATCH, MATCHER)) \
return
do { \
auto UNIQUE_VAR(__matcher) = (MATCHER); \
if (!__llvm_libc::testing::Test::testMatch( \
Ctx, UNIQUE_VAR(__matcher).match((MATCH)), UNIQUE_VAR(__matcher), \
#MATCH, #MATCHER, __FILE__, __LINE__)) \
return; \
} while (0)
#endif // LLVM_LIBC_UTILS_UNITTEST_H