[libc] Add Initial Support for Signals

Summary:
This patch adds signal support on Linux. The current implementation gets the SIG* macros and types like `sigset_t` from <linux/signals.h>

This patch also adds raise(3), and internal routines  `block_all_signals` and `restore_signals`

Reviewers: sivachandra, MaskRay, gchatelet

Reviewed By: sivachandra

Subscribers: libc-commits, mgorny, tschuett

Differential Revision: https://reviews.llvm.org/D74528
This commit is contained in:
Alex Brachet 2020-02-20 14:05:34 -05:00
parent 064cd2ecdb
commit 5d2baa956a
16 changed files with 265 additions and 0 deletions

View File

@ -133,3 +133,13 @@ def SysMManAPI : PublicAPI<"sys/mman.h"> {
"munmap",
];
}
def SignalAPI : PublicAPI<"signal.h"> {
let TypeDeclarations = [
SizeT, // This is needed by <linux/signal.h>.
];
let Functions = [
"raise",
];
}

View File

@ -0,0 +1,11 @@
//===---------------- Linux specific signal.h definitions -----------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
%%begin()
#include <linux/signal.h>

View File

@ -45,6 +45,16 @@ add_gen_header(
../config/${LIBC_TARGET_OS}/errno.h.in
)
add_gen_header(
signal_h
DEF_FILE signal.h.def
PARAMS
platform_signal=../config/${LIBC_TARGET_OS}/signal.h.in
GEN_HDR signal.h
DATA_FILES
../config/${LIBC_TARGET_OS}/signal.h.in
)
# TODO: Not all platforms will have a include/sys directory. Add the sys
# directory and the targets for sys/*.h files conditional to the OS requiring
# them.

18
libc/include/signal.h.def Normal file
View File

@ -0,0 +1,18 @@
//===---------------- C standard library header signal.h ------------------===//
//
// 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_SIGNAL_H
#define LLVM_LIBC_SIGNAL_H
#include <__llvm-libc-common.h>
%%public_api()
%%include_file(${platform_signal})
#endif // LLVM_LIBC_SIGNAL_H

View File

@ -12,6 +12,9 @@ add_entrypoint_library(
# sys/mman.h entrypoints
mmap
munmap
# signal.h entrypoints
raise
)
add_entrypoint_library(

View File

@ -67,8 +67,53 @@ def Linux : StandardSpec<"Linux"> {
[] // Functions
>;
HeaderSpec Signal = HeaderSpec<
"signal.h",
[
Macro<"NSIG">,
Macro<"SIGHUP">,
Macro<"SIGINT">,
Macro<"SIGQUIT">,
Macro<"SIGILL">,
Macro<"SIGTRAP">,
Macro<"SIGABRT">,
Macro<"SIGIOT">,
Macro<"SIGBUS">,
Macro<"SIGFPE">,
Macro<"SIGKILL">,
Macro<"SIGUSR1">,
Macro<"SIGSEGV">,
Macro<"SIGUSR2">,
Macro<"SIGPIPE">,
Macro<"SIGALRM">,
Macro<"SIGTERM">,
Macro<"SIGSTKFLT">,
Macro<"SIGCHLD">,
Macro<"SIGCONT">,
Macro<"SIGSTOP">,
Macro<"SIGTSTP">,
Macro<"SIGTTIN">,
Macro<"SIGTTOU">,
Macro<"SIGURG">,
Macro<"SIGXCPU">,
Macro<"SIGXFSZ">,
Macro<"SIGVTALRM">,
Macro<"SIGPROF">,
Macro<"SIGWINCH">,
Macro<"SIGIO">,
Macro<"SIGPOLL">,
Macro<"SIGPWR">,
Macro<"SIGSYS">,
Macro<"SIGUNUSED">,
],
[], // Types
[] // Functions
>;
let Headers = [
Errno,
SysMMan,
Signal,
];
}

View File

@ -179,10 +179,34 @@ def StdC : StandardSpec<"stdc"> {
[] // Functions
>;
HeaderSpec Signal = HeaderSpec<
"signal.h",
[
Macro<"SIG_BLOCK">,
Macro<"SIG_UNBLOCK">,
Macro<"SIG_SETMASK">,
Macro<"SIGABRT">,
Macro<"SIGFPE">,
Macro<"SIGILL">,
Macro<"SIGINT">,
Macro<"SIGSEGV">,
Macro<"SIGTERM">
],
[
NamedType<"sigset_t">,
SizeTType,
],
[
FunctionSpec<"raise", RetValSpec<IntType>, [ArgSpec<IntType>]>,
]
>;
let Headers = [
Errno,
Math,
String,
StdIO,
Signal,
];
}

View File

@ -1,5 +1,6 @@
add_subdirectory(errno)
add_subdirectory(math)
add_subdirectory(signal)
add_subdirectory(string)
# TODO: Add this target conditional to the target OS.
add_subdirectory(sys)

View File

@ -0,0 +1,4 @@
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${LIBC_TARGET_OS})
add_subdirectory(${LIBC_TARGET_OS})
endif()

View File

@ -0,0 +1,14 @@
add_entrypoint_object(
raise
SRCS
raise.cpp
HDRS
signal.h
../raise.h
DEPENDS
sys_syscall_h
linux_syscall_h
__errno_location
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
//
//===----------------------------------------------------------------------===//
#include "src/signal/raise.h"
#include "src/signal/linux/signal.h"
#include "src/__support/common.h"
namespace __llvm_libc {
int LLVM_LIBC_ENTRYPOINT(raise)(int sig) {
__llvm_libc::Sigset sigset;
int got = __llvm_libc::block_all_signals(sigset);
long pid = __llvm_libc::syscall(SYS_getpid);
long tid = __llvm_libc::syscall(SYS_gettid);
int ret = __llvm_libc::syscall(SYS_tgkill, pid, tid, sig);
__llvm_libc::restore_signals(sigset);
return ret;
}
} // namespace __llvm_libc

View File

@ -0,0 +1,49 @@
//===----------------- Internal header for Linux signals ------------------===//
//
// 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_LINUX_SIGNAL_H
#define LLVM_LIBC_SRC_SIGNAL_LINUX_SIGNAL_H
#include "config/linux/syscall.h" // For internal syscall function.
#include "include/sys/syscall.h" // For syscall numbers.
#include "include/signal.h"
static_assert(sizeof(sigset_t) * 8 >= NSIG, "sigset_t cannot hold all signals");
namespace __llvm_libc {
// Using this internally defined type will make it easier in the future to port
// to different architectures.
struct Sigset {
sigset_t nativeSigset;
constexpr static Sigset fullset() { return {-1UL}; }
operator sigset_t() const { return nativeSigset; }
};
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,
&oldSet, sizeof(sigset_t));
}
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));
}
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_SIGNAL_LINUX_SIGNAL_H

20
libc/src/signal/raise.h Normal file
View File

@ -0,0 +1,20 @@
//===------------- Implementation header for raise function ------ *-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_RAISE_H
#define LLVM_LIBC_SRC_SIGNAL_RAISE_H
#include "include/signal.h"
namespace __llvm_libc {
int raise(int sig);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_SIGNAL_RAISE_H

View File

@ -1,3 +1,4 @@
add_subdirectory(errno)
add_subdirectory(signal)
add_subdirectory(string)
add_subdirectory(sys)

View File

@ -0,0 +1,12 @@
add_libc_testsuite(libc_signal_unittests)
add_libc_unittest(
raise_test
SUITE
libc_signal_unittests
SRCS
raise_test.cpp
DEPENDS
raise
signal_h
)

View File

@ -0,0 +1,17 @@
//===----------------------- Unittests for raise --------------------------===//
//
// 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/signal.h"
#include "src/signal/raise.h"
#include "utils/UnitTest/Test.h"
TEST(SignalTest, Raise) {
// SIGCONT is ingored unless stopped, so we can use it to check the return
// value of raise without needing to block.
EXPECT_EQ(__llvm_libc::raise(SIGCONT), 0);
}