diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -201,7 +201,7 @@ } def SignalAPI : PublicAPI<"signal.h"> { - let Types = ["struct sigaction", "__sighandler_t"]; + let Types = ["sigset_t", "struct sigaction", "union sigval", "siginfo_t"]; } def ThreadsAPI : PublicAPI<"threads.h"> { diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -350,20 +350,20 @@ # stdlib.h entrypoints libc.src.stdlib._Exit + libc.src.stdlib.abort libc.src.stdlib.atexit libc.src.stdlib.exit libc.src.stdlib.getenv # signal.h entrypoints - # TODO: Enable signal.h entrypoints after fixing signal.h - # libc.src.signal.raise - # libc.src.signal.sigaction - # libc.src.signal.sigdelset - # libc.src.signal.sigaddset - # libc.src.signal.sigemptyset - # libc.src.signal.sigprocmask - # libc.src.signal.sigfillset - # libc.src.signal.signal + libc.src.signal.raise + libc.src.signal.sigaction + libc.src.signal.sigdelset + libc.src.signal.sigaddset + libc.src.signal.sigemptyset + libc.src.signal.sigprocmask + libc.src.signal.sigfillset + libc.src.signal.signal # threads.h entrypoints libc.src.threads.call_once diff --git a/libc/include/CMakeLists.txt b/libc/include/CMakeLists.txt --- a/libc/include/CMakeLists.txt +++ b/libc/include/CMakeLists.txt @@ -130,8 +130,10 @@ DATA_FILES ../config/${LIBC_TARGET_OS}/signal.h.in DEPENDS + .llvm-libc-macros.signal_macros .llvm-libc-types.struct_sigaction .llvm-libc-types.__sighandler_t + .llvm-libc-types.sigset_t ) add_gen_header( diff --git a/libc/include/llvm-libc-macros/CMakeLists.txt b/libc/include/llvm-libc-macros/CMakeLists.txt --- a/libc/include/llvm-libc-macros/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/CMakeLists.txt @@ -14,6 +14,14 @@ file-seek-macros.h ) +add_header( + signal_macros + HDR + signal-macros.h + DEPENDS + .linux.signal_macros +) + add_header( sys_stat_macros HDR diff --git a/libc/include/llvm-libc-macros/linux/CMakeLists.txt b/libc/include/llvm-libc-macros/linux/CMakeLists.txt --- a/libc/include/llvm-libc-macros/linux/CMakeLists.txt +++ b/libc/include/llvm-libc-macros/linux/CMakeLists.txt @@ -27,3 +27,9 @@ HDR unistd-macros.h ) + +add_header( + signal_macros + HDR + signal-macros.h +) diff --git a/libc/include/llvm-libc-macros/linux/signal-macros.h b/libc/include/llvm-libc-macros/linux/signal-macros.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-macros/linux/signal-macros.h @@ -0,0 +1,78 @@ +//===-- Definition of Linux signal number macros --------------------------===// +// +// 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_MACROS_LINUX_SIGNUM_MACROS_H +#define __LLVM_LIBC_MACROS_LINUX_SIGNUM_MACROS_H + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGBUS 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 +#define SIGURG 23 +#define SIGXCPU 24 +#define SIGXFSZ 25 +#define SIGVTALRM 26 +#define SIGPROF 27 +#define SIGWINCH 28 +#define SIGIO 29 +#define SIGPOLL SIGIO +#define SIGPWR 30 +#define SIGSYS 31 + +// Max signal number +#define NSIG 64 + +// SIGRTMIN is current set to the minimum usable from user mode programs. If +// the libc itself uses some of these signal numbers for private operations, +// then it has to be adjusted in future to reflect that. +#define SIGRTMIN 32 + +#define SIGRTMAX NSIG + +// The kernel sigset is stored as an array of long values. Each bit of this +// array corresponds to a signal, adjusted by 1. That is, bit 0 corresponds +// to signal number 1, bit 1 corresponds to signal number 2 and so on. The +// below macro denotes the size of that array (in number of long words and +// not bytes). +#define __NSIGSET_WORDS (NSIG / (sizeof(unsigned long) * 8)) + +#define SIG_BLOCK 0 // For blocking signals +#define SIG_UNBLOCK 1 // For unblocking signals +#define SIG_SETMASK 2 // For setting signal mask + +// Flag values to be used for setting sigaction.sa_flags. +#define SA_NOCLDSTOP 0x00000001 +#define SA_NOCLDWAIT 0x00000002 +#define SA_SIGINFO 0x00000004 +#define SA_RESTART 0x10000000 +#define SA_RESTORER 0x04000000 + +#define SIG_DFL ((__sighandler_t)0) +#define SIG_IGN ((__sighandler_t)1) +#define SIG_ERR ((__sighandler_t)-1) + +#endif // __LLVM_LIBC_MACROS_LINUX_SIGNUM_MACROS_H diff --git a/libc/include/signal.h.def b/libc/include/llvm-libc-macros/signal-macros.h copy from libc/include/signal.h.def copy to libc/include/llvm-libc-macros/signal-macros.h --- a/libc/include/signal.h.def +++ b/libc/include/llvm-libc-macros/signal-macros.h @@ -1,4 +1,4 @@ -//===-- C standard library header signal.h --------------------------------===// +//===-- Definition of signal number macros --------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,16 +6,11 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SIGNAL_H -#define LLVM_LIBC_SIGNAL_H +#ifndef __LLVM_LIBC_MACROS_SIGNUM_MACROS_H +#define __LLVM_LIBC_MACROS_SIGNUM_MACROS_H -#include <__llvm-libc-common.h> +#ifdef __unix__ +#include "linux/signal-macros.h" +#endif -#define __need_size_t -#include - -%%include_file(${platform_signal}) - -%%public_api() - -#endif // LLVM_LIBC_SIGNAL_H +#endif // __LLVM_LIBC_MACROS_SIGNUM_MACROS_H diff --git a/libc/include/llvm-libc-types/CMakeLists.txt b/libc/include/llvm-libc-types/CMakeLists.txt --- a/libc/include/llvm-libc-types/CMakeLists.txt +++ b/libc/include/llvm-libc-types/CMakeLists.txt @@ -42,7 +42,10 @@ add_header(struct_rlimit HDR struct_rlimit.h DEPENDS .rlim_t) add_header(ssize_t HDR ssize_t.h) add_header(struct_dirent HDR struct_dirent.h DEPENDS .ino_t .off_t) -add_header(struct_sigaction HDR struct_sigaction.h) +add_header(union_sigval HDR union_sigval.h) +add_header(siginfo_t HDR siginfo_t.h DEPENDS .union_sigval .pid_t .uid_t) +add_header(sigset_t HDR sigset_t.h DEPENDS libc.include.llvm-libc-macros.signal_macros) +add_header(struct_sigaction HDR struct_sigaction.h DEPENDS .sigset_t .siginfo_t) add_header(time_t HDR time_t.h) add_header(struct_timespec HDR struct_timespec.h DEPENDS .time_t) add_header( diff --git a/libc/include/llvm-libc-types/siginfo_t.h b/libc/include/llvm-libc-types/siginfo_t.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-types/siginfo_t.h @@ -0,0 +1,29 @@ +//===-- Definition of siginfo_t type +//---------------------------------------===// +// +// 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_TYPES_SIGINFO_T_H__ +#define __LLVM_LIBC_TYPES_SIGINFO_T_H__ + +#include +#include +#include + +typedef struct { + int si_signo; + int si_code; + int si_errno; + pid_t si_pid; + uid_t si_uid; + void *si_addr; + int si_status; + long si_band; + union sigval si_value; +} siginfo_t; + +#endif // __LLVM_LIBC_TYPES_SIGINFO_T_H__ diff --git a/libc/include/llvm-libc-types/sigset_t.h b/libc/include/llvm-libc-types/sigset_t.h new file mode 100644 --- /dev/null +++ b/libc/include/llvm-libc-types/sigset_t.h @@ -0,0 +1,20 @@ +//===-- Definition of sigset_t type ---------------------------------------===// +// +// 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_TYPES_SIGSET_T_H__ +#define __LLVM_LIBC_TYPES_SIGSET_T_H__ + +#include + +// This definition can be adjusted/specialized for different targets and +// platforms as necessary. This definition works for Linux on most targets. +typedef struct { + unsigned long __signals[__NSIGSET_WORDS]; +} sigset_t; + +#endif // __LLVM_LIBC_TYPES_SIGSET_T_H__ diff --git a/libc/include/llvm-libc-types/struct_sigaction.h b/libc/include/llvm-libc-types/struct_sigaction.h --- a/libc/include/llvm-libc-types/struct_sigaction.h +++ b/libc/include/llvm-libc-types/struct_sigaction.h @@ -9,14 +9,22 @@ #ifndef __LLVM_LIBC_TYPES_SIGACTION_H__ #define __LLVM_LIBC_TYPES_SIGACTION_H__ -struct __sigaction { +#include +#include + +struct sigaction { union { void (*sa_handler)(int); - void (*sa_action)(int, siginfo_t *, void *); + void (*sa_sigaction)(int, siginfo_t *, void *); }; sigset_t sa_mask; int sa_flags; +#ifdef __unix__ + // This field is present on linux for most targets. void (*sa_restorer)(void); +#endif }; +typedef void (*__sighandler_t)(int); + #endif // __LLVM_LIBC_TYPES_SIGACTION_H__ diff --git a/libc/include/signal.h.def b/libc/include/llvm-libc-types/union_sigval.h copy from libc/include/signal.h.def copy to libc/include/llvm-libc-types/union_sigval.h --- a/libc/include/signal.h.def +++ b/libc/include/llvm-libc-types/union_sigval.h @@ -1,4 +1,4 @@ -//===-- C standard library header signal.h --------------------------------===// +//===-- Definition of type union sigval -----------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,16 +6,12 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SIGNAL_H -#define LLVM_LIBC_SIGNAL_H +#ifndef __LLVM_LIBC_TYPES_UNION_SIGVAL_H__ +#define __LLVM_LIBC_TYPES_UNION_SIGVAL_H__ -#include <__llvm-libc-common.h> +union sigval { + int sival_int; + void *sival_ptr; +}; -#define __need_size_t -#include - -%%include_file(${platform_signal}) - -%%public_api() - -#endif // LLVM_LIBC_SIGNAL_H +#endif // __LLVM_LIBC_TYPES_UNION_SIGVAL_H__ diff --git a/libc/include/signal.h.def b/libc/include/signal.h.def --- a/libc/include/signal.h.def +++ b/libc/include/signal.h.def @@ -14,7 +14,7 @@ #define __need_size_t #include -%%include_file(${platform_signal}) +#include %%public_api() diff --git a/libc/spec/posix.td b/libc/spec/posix.td --- a/libc/spec/posix.td +++ b/libc/spec/posix.td @@ -4,6 +4,9 @@ def RestrictedSigSetType : RestrictedPtrType; def ConstRestrictedSigSetType : ConstType; +def SigInfoType : NamedType<"siginfo_t">; +def UnionSigVal : NamedType<"union sigval">; + def StructSigaction : NamedType<"struct sigaction">; def StructSigactionPtr : PtrType; def ConstStructSigactionPtr : ConstType; @@ -243,8 +246,10 @@ "signal.h", [], // Macros [ + SigInfoType, SigSetType, StructSigaction, + UnionSigVal, ], [], // Enumerations [ diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt --- a/libc/src/CMakeLists.txt +++ b/libc/src/CMakeLists.txt @@ -24,6 +24,6 @@ # The signal API is currently disabled as signal.h is incorrect. # since assert uses the signal API, we disable assert also. # add_subdirectory(assert) -# add_subdirectory(signal) +add_subdirectory(signal) add_subdirectory(threads) add_subdirectory(time) diff --git a/libc/src/signal/linux/CMakeLists.txt b/libc/src/signal/linux/CMakeLists.txt --- a/libc/src/signal/linux/CMakeLists.txt +++ b/libc/src/signal/linux/CMakeLists.txt @@ -1,12 +1,20 @@ +add_header_library( + signal_utils + HDRS + signal_utils.h + DEPENDS + libc.include.sys_syscall + libc.src.__support.OSUtil.osutil +) add_entrypoint_object( raise SRCS raise.cpp HDRS - signal.h ../raise.h DEPENDS + .signal_utils libc.include.signal libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -34,7 +42,6 @@ SRCS sigaction.cpp HDRS - signal.h ../sigaction.h DEPENDS .__restore @@ -49,9 +56,9 @@ SRCS sigprocmask.cpp HDRS - signal.h ../sigprocmask.h DEPENDS + .signal_utils libc.include.signal libc.include.sys_syscall libc.src.__support.OSUtil.osutil @@ -63,9 +70,9 @@ SRCS sigemptyset.cpp HDRS - signal.h ../sigemptyset.h DEPENDS + .signal_utils libc.include.errno libc.include.signal libc.src.errno.errno @@ -76,9 +83,9 @@ SRCS sigaddset.cpp HDRS - signal.h ../sigaddset.h DEPENDS + .signal_utils libc.include.errno libc.include.signal libc.src.errno.errno @@ -89,7 +96,6 @@ SRCS signal.cpp HDRS - signal.h ../signal.h DEPENDS .sigaction @@ -101,9 +107,9 @@ SRCS sigfillset.cpp HDRS - signal.h ../sigfillset.h DEPENDS + .signal_utils libc.include.errno libc.include.signal libc.src.errno.errno @@ -114,9 +120,9 @@ SRCS sigdelset.cpp HDRS - signal.h ../sigdelset.h DEPENDS + .signal_utils libc.include.errno libc.include.signal libc.src.errno.errno diff --git a/libc/src/signal/linux/raise.cpp b/libc/src/signal/linux/raise.cpp --- a/libc/src/signal/linux/raise.cpp +++ b/libc/src/signal/linux/raise.cpp @@ -7,19 +7,19 @@ //===----------------------------------------------------------------------===// #include "src/signal/raise.h" -#include "src/signal/linux/signal.h" +#include "src/signal/linux/signal_utils.h" #include "src/__support/common.h" namespace __llvm_libc { LLVM_LIBC_FUNCTION(int, raise, (int sig)) { - __llvm_libc::Sigset sigset; - __llvm_libc::block_all_signals(sigset); + ::sigset_t sigset; + 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); + restore_signals(sigset); return ret; } diff --git a/libc/src/signal/linux/sigaction.cpp b/libc/src/signal/linux/sigaction.cpp --- a/libc/src/signal/linux/sigaction.cpp +++ b/libc/src/signal/linux/sigaction.cpp @@ -6,13 +6,14 @@ // //===----------------------------------------------------------------------===// -#define __LLVM_LIBC_INTERNAL_SIGACTION #include "src/signal/sigaction.h" -#include "src/errno/llvmlibc_errno.h" -#include "src/signal/linux/signal.h" +#include "src/signal/linux/signal_utils.h" #include "src/__support/common.h" +#include +#include + namespace __llvm_libc { // TOOD: Some architectures will have their signal trampoline functions in the @@ -20,36 +21,28 @@ extern "C" void __restore_rt(); -template -static void copy_sigaction(T &dest, const V &source) { - dest.sa_handler = source.sa_handler; - dest.sa_mask = source.sa_mask; - dest.sa_flags = source.sa_flags; - dest.sa_restorer = source.sa_restorer; -} - LLVM_LIBC_FUNCTION(int, sigaction, - (int signal, const struct __sigaction *__restrict libc_new, - struct __sigaction *__restrict libc_old)) { - struct sigaction kernel_new; + (int signal, const struct sigaction *__restrict libc_new, + struct sigaction *__restrict libc_old)) { + KernelSigaction kernel_new; if (libc_new) { - copy_sigaction(kernel_new, *libc_new); + kernel_new = *libc_new; if (!(kernel_new.sa_flags & SA_RESTORER)) { kernel_new.sa_flags |= SA_RESTORER; kernel_new.sa_restorer = __restore_rt; } } - struct sigaction kernel_old; + KernelSigaction kernel_old; int ret = syscall(SYS_rt_sigaction, signal, libc_new ? &kernel_new : nullptr, libc_old ? &kernel_old : nullptr, sizeof(sigset_t)); if (ret) { - llvmlibc_errno = -ret; + errno = -ret; return -1; } if (libc_old) - copy_sigaction(*libc_old, kernel_old); + *libc_old = kernel_old; return 0; } diff --git a/libc/src/signal/linux/sigaddset.cpp b/libc/src/signal/linux/sigaddset.cpp --- a/libc/src/signal/linux/sigaddset.cpp +++ b/libc/src/signal/linux/sigaddset.cpp @@ -7,22 +7,19 @@ //===----------------------------------------------------------------------===// #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" +#include "src/signal/linux/signal_utils.h" + +#include +#include namespace __llvm_libc { LLVM_LIBC_FUNCTION(int, 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; + if (set != nullptr && add_signal(*set, signum)) + return 0; + errno = EINVAL; + return -1; } } // namespace __llvm_libc diff --git a/libc/src/signal/linux/sigdelset.cpp b/libc/src/signal/linux/sigdelset.cpp --- a/libc/src/signal/linux/sigdelset.cpp +++ b/libc/src/signal/linux/sigdelset.cpp @@ -7,22 +7,19 @@ //===----------------------------------------------------------------------===// #include "src/signal/sigdelset.h" -#include "include/errno.h" -#include "src/errno/llvmlibc_errno.h" -#include "src/signal/linux/signal.h" - #include "src/__support/common.h" +#include "src/signal/linux/signal_utils.h" + +#include +#include namespace __llvm_libc { LLVM_LIBC_FUNCTION(int, sigdelset, (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->delset(signum); - return 0; + if (set != nullptr && delete_signal(*set, signum)) + return 0; + errno = EINVAL; + return -1; } } // namespace __llvm_libc diff --git a/libc/src/signal/linux/sigemptyset.cpp b/libc/src/signal/linux/sigemptyset.cpp --- a/libc/src/signal/linux/sigemptyset.cpp +++ b/libc/src/signal/linux/sigemptyset.cpp @@ -7,20 +7,21 @@ //===----------------------------------------------------------------------===// #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/signal/linux/signal_utils.h" #include "src/__support/common.h" +#include +#include + namespace __llvm_libc { LLVM_LIBC_FUNCTION(int, sigemptyset, (sigset_t * set)) { if (!set) { - llvmlibc_errno = EINVAL; + errno = EINVAL; return -1; } - *set = __llvm_libc::Sigset::empty_set(); + *set = empty_set(); return 0; } diff --git a/libc/src/signal/linux/sigfillset.cpp b/libc/src/signal/linux/sigfillset.cpp --- a/libc/src/signal/linux/sigfillset.cpp +++ b/libc/src/signal/linux/sigfillset.cpp @@ -7,21 +7,20 @@ //===----------------------------------------------------------------------===// #include "src/signal/sigfillset.h" -#include "include/errno.h" -#include "src/errno/llvmlibc_errno.h" -#include "src/signal/linux/signal.h" - #include "src/__support/common.h" +#include "src/signal/linux/signal_utils.h" + +#include +#include namespace __llvm_libc { LLVM_LIBC_FUNCTION(int, sigfillset, (sigset_t * set)) { if (!set) { - llvmlibc_errno = EINVAL; + errno = EINVAL; return -1; } - auto *sigset = reinterpret_cast<__llvm_libc::Sigset *>(set); - *sigset = __llvm_libc::Sigset::fullset(); + *set = full_set(); return 0; } diff --git a/libc/src/signal/linux/signal.h b/libc/src/signal/linux/signal.h deleted file mode 100644 --- a/libc/src/signal/linux/signal.h +++ /dev/null @@ -1,55 +0,0 @@ -//===-- Internal header for Linux signals -----------------------*- 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_LINUX_SIGNAL_H -#define LLVM_LIBC_SRC_SIGNAL_LINUX_SIGNAL_H - -#include "include/sys/syscall.h" // For syscall numbers. -#include "src/__support/OSUtil/syscall.h" // For internal syscall function. - -#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 native_sigset; - - constexpr static Sigset fullset() { return {-1UL}; } - constexpr static Sigset empty_set() { return {0}; } - - constexpr void addset(int signal) { native_sigset |= (1L << (signal - 1)); } - - constexpr void delset(int signal) { native_sigset &= ~(1L << (signal - 1)); } - - operator sigset_t() const { return native_sigset; } -}; - -constexpr static Sigset ALL = Sigset::fullset(); - -static inline int block_all_signals(Sigset &set) { - sigset_t native_sigset = ALL; - sigset_t old_set = set; - int ret = __llvm_libc::syscall(SYS_rt_sigprocmask, SIG_BLOCK, &native_sigset, - &old_set, sizeof(sigset_t)); - set = {old_set}; - return ret; -} - -static inline int restore_signals(const Sigset &set) { - sigset_t native_sigset = set; - return __llvm_libc::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &native_sigset, - nullptr, sizeof(sigset_t)); -} - -} // namespace __llvm_libc - -#endif // LLVM_LIBC_SRC_SIGNAL_LINUX_SIGNAL_H diff --git a/libc/src/signal/linux/signal.cpp b/libc/src/signal/linux/signal.cpp --- a/libc/src/signal/linux/signal.cpp +++ b/libc/src/signal/linux/signal.cpp @@ -6,16 +6,17 @@ // //===----------------------------------------------------------------------===// -#define __LLVM_LIBC_INTERNAL_SIGACTION #include "src/signal/signal.h" #include "src/signal/sigaction.h" #include "src/__support/common.h" +#include + namespace __llvm_libc { LLVM_LIBC_FUNCTION(sighandler_t, signal, (int signum, sighandler_t handler)) { - struct __sigaction action, old; + 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. diff --git a/libc/src/signal/linux/signal_utils.h b/libc/src/signal/linux/signal_utils.h new file mode 100644 --- /dev/null +++ b/libc/src/signal/linux/signal_utils.h @@ -0,0 +1,109 @@ +//===-- Internal header for Linux signals -----------------------*- 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_LINUX_SIGNAL_UTILS_H +#define LLVM_LIBC_SRC_SIGNAL_LINUX_SIGNAL_UTILS_H + +#include "include/sys/syscall.h" // For syscall numbers. +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. + +#include +#include + +namespace __llvm_libc { + +// The POSIX definition of struct sigaction and the sigaction data structure +// expected by the rt_sigaction syscall differ in their definition. So, we +// define the equivalent of the what the kernel expects to help with making +// the rt_sigaction syscall. +// +// NOTE: Though the kernel definition does not have a union to include the +// handler taking siginfo_t * argument, one can set sa_handler to sa_sigaction +// if SA_SIGINFO is set in sa_flags. +struct KernelSigaction { + using HandlerType = void(int); + using SiginfoHandlerType = void(int, siginfo_t *, void *); + + KernelSigaction &operator=(const struct sigaction &sa) { + sa_flags = sa.sa_flags; + sa_restorer = sa.sa_restorer; + sa_mask = sa.sa_mask; + if (sa_flags & SA_SIGINFO) { + sa_handler = reinterpret_cast(sa.sa_sigaction); + } else { + sa_handler = sa.sa_handler; + } + return *this; + } + + operator struct sigaction() const { + struct sigaction sa; + sa.sa_flags = sa_flags; + sa.sa_mask = sa_mask; + sa.sa_restorer = sa_restorer; + if (sa_flags & SA_SIGINFO) + sa.sa_sigaction = reinterpret_cast(sa_handler); + else + sa.sa_handler = sa_handler; + return sa; + } + + HandlerType *sa_handler; + unsigned long sa_flags; + void (*sa_restorer)(void); + // Our public definition of sigset_t matches that of the kernel's definition. + // So, we can use the public sigset_t type here. + sigset_t sa_mask; +}; + +static constexpr size_t BITS_PER_SIGWORD = sizeof(unsigned long) * 8; + +constexpr sigset_t full_set() { return sigset_t{{-1UL}}; } + +constexpr sigset_t empty_set() { return sigset_t{{0}}; } + +// Set the bit corresponding to |signal| in |set|. Return true on success +// and false on failure. The function will fail if |signal| is greater than +// NSIG or negative. +constexpr inline bool add_signal(sigset_t &set, int signal) { + if (signal > NSIG || signal <= 0) + return false; + size_t n = size_t(signal) - 1; + size_t word = n / BITS_PER_SIGWORD; + size_t bit = n % BITS_PER_SIGWORD; + set.__signals[word] |= (1UL << bit); + return true; +} + +// Reset the bit corresponding to |signal| in |set|. Return true on success +// and false on failure. The function will fail if |signal| is greater than +// NSIG or negative. +constexpr inline bool delete_signal(sigset_t &set, int signal) { + if (signal > NSIG || signal <= 0) + return false; + size_t n = size_t(signal) - 1; + size_t word = n / BITS_PER_SIGWORD; + size_t bit = n % BITS_PER_SIGWORD; + set.__signals[word] &= ~(1UL << bit); + return true; +} + +static inline int block_all_signals(sigset_t &set) { + sigset_t full = full_set(); + return __llvm_libc::syscall(SYS_rt_sigprocmask, SIG_BLOCK, &full, &set, + sizeof(sigset_t)); +} + +static inline int restore_signals(const sigset_t &set) { + return __llvm_libc::syscall(SYS_rt_sigprocmask, SIG_SETMASK, &set, nullptr, + sizeof(sigset_t)); +} + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_SIGNAL_LINUX_SIGNAL_UTILS_H diff --git a/libc/src/signal/linux/sigprocmask.cpp b/libc/src/signal/linux/sigprocmask.cpp --- a/libc/src/signal/linux/sigprocmask.cpp +++ b/libc/src/signal/linux/sigprocmask.cpp @@ -7,11 +7,15 @@ //===----------------------------------------------------------------------===// #include "src/signal/sigprocmask.h" -#include "src/errno/llvmlibc_errno.h" -#include "src/signal/linux/signal.h" +#include "include/sys/syscall.h" // For syscall numbers. +#include "src/__support/OSUtil/syscall.h" // For internal syscall function. +#include "src/signal/linux/signal_utils.h" #include "src/__support/common.h" +#include +#include + namespace __llvm_libc { LLVM_LIBC_FUNCTION(int, sigprocmask, @@ -22,7 +26,7 @@ if (!ret) return 0; - llvmlibc_errno = -ret; + errno = -ret; return -1; } diff --git a/libc/src/signal/sigaction.h b/libc/src/signal/sigaction.h --- a/libc/src/signal/sigaction.h +++ b/libc/src/signal/sigaction.h @@ -9,13 +9,12 @@ #ifndef LLVM_LIBC_SRC_SIGNAL_SIGACTION_H #define LLVM_LIBC_SRC_SIGNAL_SIGACTION_H -#define __LLVM_LIBC_INTERNAL_SIGACTION -#include "include/signal.h" +#include namespace __llvm_libc { -int sigaction(int signal, const struct __sigaction *__restrict libc_new, - struct __sigaction *__restrict libc_old); +int sigaction(int signal, const struct sigaction *__restrict libc_new, + struct sigaction *__restrict libc_old); } // namespace __llvm_libc diff --git a/libc/src/signal/sigaddset.h b/libc/src/signal/sigaddset.h --- a/libc/src/signal/sigaddset.h +++ b/libc/src/signal/sigaddset.h @@ -9,7 +9,7 @@ #ifndef LLVM_LIBC_SRC_SIGNAL_SIGEADDSET_H #define LLVM_LIBC_SRC_SIGNAL_SIGEADDSET_H -#include "include/signal.h" +#include namespace __llvm_libc { diff --git a/libc/src/stdlib/CMakeLists.txt b/libc/src/stdlib/CMakeLists.txt --- a/libc/src/stdlib/CMakeLists.txt +++ b/libc/src/stdlib/CMakeLists.txt @@ -302,9 +302,9 @@ .atexit ) -# add_entrypoint_object( -# abort -# ALIAS -# DEPENDS -# .${LIBC_TARGET_OS}.abort -# ) +add_entrypoint_object( + abort + ALIAS + DEPENDS + .${LIBC_TARGET_OS}.abort +) diff --git a/libc/src/stdlib/linux/CMakeLists.txt b/libc/src/stdlib/linux/CMakeLists.txt --- a/libc/src/stdlib/linux/CMakeLists.txt +++ b/libc/src/stdlib/linux/CMakeLists.txt @@ -10,14 +10,14 @@ libc.src.__support.OSUtil.osutil ) -# add_entrypoint_object( -# abort -# SRCS -# abort.cpp -# HDRS -# ../abort.h -# DEPENDS -# libc.include.stdlib -# libc.src.signal.raise -# ._Exit -# ) +add_entrypoint_object( + abort + SRCS + abort.cpp + HDRS + ../abort.h + DEPENDS + libc.include.stdlib + libc.src.signal.raise + ._Exit +) diff --git a/libc/test/src/CMakeLists.txt b/libc/test/src/CMakeLists.txt --- a/libc/test/src/CMakeLists.txt +++ b/libc/test/src/CMakeLists.txt @@ -50,7 +50,7 @@ # The signal API is currently disabled as signal.h is incorrect. # since assert uses the signal API, we disable assert also. # add_subdirectory(assert) -# add_subdirectory(signal) +add_subdirectory(signal) add_subdirectory(time) if(${LIBC_TARGET_OS} STREQUAL "linux") diff --git a/libc/test/src/signal/sigaction_test.cpp b/libc/test/src/signal/sigaction_test.cpp --- a/libc/test/src/signal/sigaction_test.cpp +++ b/libc/test/src/signal/sigaction_test.cpp @@ -6,15 +6,15 @@ // //===----------------------------------------------------------------------===// -#include "include/errno.h" -#define __LLVM_LIBC_INTERNAL_SIGACTION -#include "include/signal.h" #include "src/signal/raise.h" #include "src/signal/sigaction.h" #include "test/ErrnoSetterMatcher.h" #include "utils/UnitTest/Test.h" +#include +#include + using __llvm_libc::testing::ErrnoSetterMatcher::Fails; using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds; @@ -25,7 +25,7 @@ // SIGKILL cannot have its action changed, but it can be examined. TEST(LlvmLibcSigaction, Sigkill) { - struct __sigaction action; + struct sigaction action; EXPECT_THAT(__llvm_libc::sigaction(SIGKILL, nullptr, &action), Succeeds()); EXPECT_THAT(__llvm_libc::sigaction(SIGKILL, &action, nullptr), Fails(EINVAL)); } @@ -37,7 +37,7 @@ // Zero this incase tests get run multiple times in the future. sigusr1Count = 0; - struct __sigaction action; + struct sigaction action; EXPECT_THAT(__llvm_libc::sigaction(SIGUSR1, nullptr, &action), Succeeds()); action.sa_handler = +[](int signal) { @@ -57,7 +57,7 @@ } TEST(LlvmLibcSigaction, Ignore) { - struct __sigaction action; + struct sigaction action; EXPECT_THAT(__llvm_libc::sigaction(SIGUSR1, nullptr, &action), Succeeds()); action.sa_handler = SIG_IGN; EXPECT_THAT(__llvm_libc::sigaction(SIGUSR1, &action, nullptr), Succeeds()); diff --git a/libc/test/src/stdlib/CMakeLists.txt b/libc/test/src/stdlib/CMakeLists.txt --- a/libc/test/src/stdlib/CMakeLists.txt +++ b/libc/test/src/stdlib/CMakeLists.txt @@ -231,18 +231,18 @@ libc.src.__support.CPP.utility ) - # add_libc_unittest( - # abort_test - # SUITE - # libc_stdlib_unittests - # SRCS - # abort_test.cpp - # DEPENDS - # libc.include.stdlib - # libc.include.signal - # libc.src.stdlib.abort - # libc.src.stdlib._Exit - # libc.src.signal.raise - # ) + add_libc_unittest( + abort_test + SUITE + libc_stdlib_unittests + SRCS + abort_test.cpp + DEPENDS + libc.include.stdlib + libc.include.signal + libc.src.stdlib.abort + libc.src.stdlib._Exit + libc.src.signal.raise + ) endif()