22 changes: 14 additions & 8 deletions libc/src/signal/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -34,7 +42,6 @@ add_entrypoint_object(
SRCS
sigaction.cpp
HDRS
signal.h
../sigaction.h
DEPENDS
.__restore
Expand All @@ -49,9 +56,9 @@ add_entrypoint_object(
SRCS
sigprocmask.cpp
HDRS
signal.h
../sigprocmask.h
DEPENDS
.signal_utils
libc.include.signal
libc.include.sys_syscall
libc.src.__support.OSUtil.osutil
Expand All @@ -63,9 +70,9 @@ add_entrypoint_object(
SRCS
sigemptyset.cpp
HDRS
signal.h
../sigemptyset.h
DEPENDS
.signal_utils
libc.include.errno
libc.include.signal
libc.src.errno.errno
Expand All @@ -76,9 +83,9 @@ add_entrypoint_object(
SRCS
sigaddset.cpp
HDRS
signal.h
../sigaddset.h
DEPENDS
.signal_utils
libc.include.errno
libc.include.signal
libc.src.errno.errno
Expand All @@ -89,7 +96,6 @@ add_entrypoint_object(
SRCS
signal.cpp
HDRS
signal.h
../signal.h
DEPENDS
.sigaction
Expand All @@ -101,9 +107,9 @@ add_entrypoint_object(
SRCS
sigfillset.cpp
HDRS
signal.h
../sigfillset.h
DEPENDS
.signal_utils
libc.include.errno
libc.include.signal
libc.src.errno.errno
Expand All @@ -114,9 +120,9 @@ add_entrypoint_object(
SRCS
sigdelset.cpp
HDRS
signal.h
../sigdelset.h
DEPENDS
.signal_utils
libc.include.errno
libc.include.signal
libc.src.errno.errno
Expand Down
8 changes: 4 additions & 4 deletions libc/src/signal/linux/raise.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

Expand Down
29 changes: 11 additions & 18 deletions libc/src/signal/linux/sigaction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,50 +6,43 @@
//
//===----------------------------------------------------------------------===//

#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 <errno.h>
#include <signal.h>

namespace __llvm_libc {

// TOOD: Some architectures will have their signal trampoline functions in the
// vdso, use those when available.

extern "C" void __restore_rt();

template <typename T, typename V>
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;
}

Expand Down
19 changes: 8 additions & 11 deletions libc/src/signal/linux/sigaddset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <errno.h>
#include <signal.h>

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
19 changes: 8 additions & 11 deletions libc/src/signal/linux/sigdelset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <errno.h>
#include <signal.h>

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
11 changes: 6 additions & 5 deletions libc/src/signal/linux/sigemptyset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <errno.h>
#include <signal.h>

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

Expand Down
13 changes: 6 additions & 7 deletions libc/src/signal/linux/sigfillset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <errno.h>
#include <signal.h>

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

Expand Down
5 changes: 3 additions & 2 deletions libc/src/signal/linux/signal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <signal.h>

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.
Expand Down
55 changes: 0 additions & 55 deletions libc/src/signal/linux/signal.h

This file was deleted.

109 changes: 109 additions & 0 deletions libc/src/signal/linux/signal_utils.h
Original file line number Diff line number Diff line change
@@ -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 <signal.h>
#include <stddef.h>

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<HandlerType *>(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<SiginfoHandlerType *>(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
10 changes: 7 additions & 3 deletions libc/src/signal/linux/sigprocmask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <errno.h>
#include <signal.h>

namespace __llvm_libc {

LLVM_LIBC_FUNCTION(int, sigprocmask,
Expand All @@ -22,7 +26,7 @@ LLVM_LIBC_FUNCTION(int, sigprocmask,
if (!ret)
return 0;

llvmlibc_errno = -ret;
errno = -ret;
return -1;
}

Expand Down
7 changes: 3 additions & 4 deletions libc/src/signal/sigaction.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <signal.h>

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

Expand Down
2 changes: 1 addition & 1 deletion libc/src/signal/sigaddset.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#ifndef LLVM_LIBC_SRC_SIGNAL_SIGEADDSET_H
#define LLVM_LIBC_SRC_SIGNAL_SIGEADDSET_H

#include "include/signal.h"
#include <signal.h>

namespace __llvm_libc {

Expand Down
12 changes: 6 additions & 6 deletions libc/src/stdlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -302,9 +302,9 @@ add_entrypoint_object(
.atexit
)

# add_entrypoint_object(
# abort
# ALIAS
# DEPENDS
# .${LIBC_TARGET_OS}.abort
# )
add_entrypoint_object(
abort
ALIAS
DEPENDS
.${LIBC_TARGET_OS}.abort
)
22 changes: 11 additions & 11 deletions libc/src/stdlib/linux/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ add_entrypoint_object(
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
)
2 changes: 1 addition & 1 deletion libc/test/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ add_subdirectory(dirent)
# 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")
Expand Down
12 changes: 6 additions & 6 deletions libc/test/src/signal/sigaction_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <errno.h>
#include <signal.h>

using __llvm_libc::testing::ErrnoSetterMatcher::Fails;
using __llvm_libc::testing::ErrnoSetterMatcher::Succeeds;

Expand All @@ -25,7 +25,7 @@ TEST(LlvmLibcSigaction, Invalid) {

// 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));
}
Expand All @@ -37,7 +37,7 @@ TEST(LlvmLibcSigaction, CustomAction) {
// 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) {
Expand All @@ -57,7 +57,7 @@ TEST(LlvmLibcSigaction, CustomAction) {
}

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());
Expand Down
26 changes: 13 additions & 13 deletions libc/test/src/stdlib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -231,18 +231,18 @@ if(LLVM_LIBC_FULL_BUILD)
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()