xref: /llvm-project/libc/src/signal/linux/signal_utils.h (revision 5ff3ff33ff930e4ec49da7910612d8a41eb068cb)
1215c9fa4SSiva Chandra Reddy //===-- Internal header for Linux signals -----------------------*- C++ -*-===//
2215c9fa4SSiva Chandra Reddy //
3215c9fa4SSiva Chandra Reddy // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4215c9fa4SSiva Chandra Reddy // See https://llvm.org/LICENSE.txt for license information.
5215c9fa4SSiva Chandra Reddy // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6215c9fa4SSiva Chandra Reddy //
7215c9fa4SSiva Chandra Reddy //===----------------------------------------------------------------------===//
8215c9fa4SSiva Chandra Reddy 
9215c9fa4SSiva Chandra Reddy #ifndef LLVM_LIBC_SRC_SIGNAL_LINUX_SIGNAL_UTILS_H
10215c9fa4SSiva Chandra Reddy #define LLVM_LIBC_SRC_SIGNAL_LINUX_SIGNAL_UTILS_H
11215c9fa4SSiva Chandra Reddy 
12f626a350SNick Desaulniers #include "hdr/types/sigset_t.h"
13215c9fa4SSiva Chandra Reddy #include "src/__support/OSUtil/syscall.h" // For internal syscall function.
146363320bSSiva Chandra Reddy #include "src/__support/common.h"
15*5ff3ff33SPetr Hosek #include "src/__support/macros/config.h"
16215c9fa4SSiva Chandra Reddy 
17f626a350SNick Desaulniers #include <signal.h> // sigaction
18215c9fa4SSiva Chandra Reddy #include <stddef.h>
198910cc27SPetr Hosek #include <sys/syscall.h>          // For syscall numbers.
20215c9fa4SSiva Chandra Reddy 
21*5ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL {
22215c9fa4SSiva Chandra Reddy 
23215c9fa4SSiva Chandra Reddy // The POSIX definition of struct sigaction and the sigaction data structure
24215c9fa4SSiva Chandra Reddy // expected by the rt_sigaction syscall differ in their definition. So, we
25215c9fa4SSiva Chandra Reddy // define the equivalent of the what the kernel expects to help with making
26215c9fa4SSiva Chandra Reddy // the rt_sigaction syscall.
27215c9fa4SSiva Chandra Reddy //
28215c9fa4SSiva Chandra Reddy // NOTE: Though the kernel definition does not have a union to include the
29215c9fa4SSiva Chandra Reddy // handler taking siginfo_t * argument, one can set sa_handler to sa_sigaction
30215c9fa4SSiva Chandra Reddy // if SA_SIGINFO is set in sa_flags.
31215c9fa4SSiva Chandra Reddy struct KernelSigaction {
326363320bSSiva Chandra Reddy   LIBC_INLINE KernelSigaction &operator=(const struct sigaction &sa) {
33215c9fa4SSiva Chandra Reddy     sa_flags = sa.sa_flags;
34215c9fa4SSiva Chandra Reddy     sa_restorer = sa.sa_restorer;
35215c9fa4SSiva Chandra Reddy     sa_mask = sa.sa_mask;
36215c9fa4SSiva Chandra Reddy     if (sa_flags & SA_SIGINFO) {
37e68a0320SNick Desaulniers       sa_sigaction = sa.sa_sigaction;
38215c9fa4SSiva Chandra Reddy     } else {
39215c9fa4SSiva Chandra Reddy       sa_handler = sa.sa_handler;
40215c9fa4SSiva Chandra Reddy     }
41215c9fa4SSiva Chandra Reddy     return *this;
42215c9fa4SSiva Chandra Reddy   }
43215c9fa4SSiva Chandra Reddy 
446363320bSSiva Chandra Reddy   LIBC_INLINE operator struct sigaction() const {
45215c9fa4SSiva Chandra Reddy     struct sigaction sa;
46f0a3954eSMichael Jones     sa.sa_flags = static_cast<int>(sa_flags);
47215c9fa4SSiva Chandra Reddy     sa.sa_mask = sa_mask;
48215c9fa4SSiva Chandra Reddy     sa.sa_restorer = sa_restorer;
49215c9fa4SSiva Chandra Reddy     if (sa_flags & SA_SIGINFO)
50e68a0320SNick Desaulniers       sa.sa_sigaction = sa_sigaction;
51215c9fa4SSiva Chandra Reddy     else
52215c9fa4SSiva Chandra Reddy       sa.sa_handler = sa_handler;
53215c9fa4SSiva Chandra Reddy     return sa;
54215c9fa4SSiva Chandra Reddy   }
55215c9fa4SSiva Chandra Reddy 
56e68a0320SNick Desaulniers   union {
57e68a0320SNick Desaulniers     void (*sa_handler)(int);
58e68a0320SNick Desaulniers     void (*sa_sigaction)(int, siginfo_t *, void *);
59e68a0320SNick Desaulniers   };
60215c9fa4SSiva Chandra Reddy   unsigned long sa_flags;
61215c9fa4SSiva Chandra Reddy   void (*sa_restorer)(void);
62215c9fa4SSiva Chandra Reddy   // Our public definition of sigset_t matches that of the kernel's definition.
63215c9fa4SSiva Chandra Reddy   // So, we can use the public sigset_t type here.
64215c9fa4SSiva Chandra Reddy   sigset_t sa_mask;
65215c9fa4SSiva Chandra Reddy };
66215c9fa4SSiva Chandra Reddy 
67215c9fa4SSiva Chandra Reddy static constexpr size_t BITS_PER_SIGWORD = sizeof(unsigned long) * 8;
68215c9fa4SSiva Chandra Reddy 
696363320bSSiva Chandra Reddy LIBC_INLINE constexpr sigset_t full_set() { return sigset_t{{-1UL}}; }
70215c9fa4SSiva Chandra Reddy 
716363320bSSiva Chandra Reddy LIBC_INLINE constexpr sigset_t empty_set() { return sigset_t{{0}}; }
72215c9fa4SSiva Chandra Reddy 
73215c9fa4SSiva Chandra Reddy // Set the bit corresponding to |signal| in |set|. Return true on success
74215c9fa4SSiva Chandra Reddy // and false on failure. The function will fail if |signal| is greater than
75215c9fa4SSiva Chandra Reddy // NSIG or negative.
766363320bSSiva Chandra Reddy LIBC_INLINE constexpr bool add_signal(sigset_t &set, int signal) {
77215c9fa4SSiva Chandra Reddy   if (signal > NSIG || signal <= 0)
78215c9fa4SSiva Chandra Reddy     return false;
79215c9fa4SSiva Chandra Reddy   size_t n = size_t(signal) - 1;
80215c9fa4SSiva Chandra Reddy   size_t word = n / BITS_PER_SIGWORD;
81215c9fa4SSiva Chandra Reddy   size_t bit = n % BITS_PER_SIGWORD;
82215c9fa4SSiva Chandra Reddy   set.__signals[word] |= (1UL << bit);
83215c9fa4SSiva Chandra Reddy   return true;
84215c9fa4SSiva Chandra Reddy }
85215c9fa4SSiva Chandra Reddy 
86215c9fa4SSiva Chandra Reddy // Reset the bit corresponding to |signal| in |set|. Return true on success
87215c9fa4SSiva Chandra Reddy // and false on failure. The function will fail if |signal| is greater than
88215c9fa4SSiva Chandra Reddy // NSIG or negative.
896363320bSSiva Chandra Reddy LIBC_INLINE constexpr bool delete_signal(sigset_t &set, int signal) {
90215c9fa4SSiva Chandra Reddy   if (signal > NSIG || signal <= 0)
91215c9fa4SSiva Chandra Reddy     return false;
92215c9fa4SSiva Chandra Reddy   size_t n = size_t(signal) - 1;
93215c9fa4SSiva Chandra Reddy   size_t word = n / BITS_PER_SIGWORD;
94215c9fa4SSiva Chandra Reddy   size_t bit = n % BITS_PER_SIGWORD;
95215c9fa4SSiva Chandra Reddy   set.__signals[word] &= ~(1UL << bit);
96215c9fa4SSiva Chandra Reddy   return true;
97215c9fa4SSiva Chandra Reddy }
98215c9fa4SSiva Chandra Reddy 
996363320bSSiva Chandra Reddy LIBC_INLINE int block_all_signals(sigset_t &set) {
100215c9fa4SSiva Chandra Reddy   sigset_t full = full_set();
101b6bc9d72SGuillaume Chatelet   return LIBC_NAMESPACE::syscall_impl<int>(SYS_rt_sigprocmask, SIG_BLOCK, &full,
102f0a3954eSMichael Jones                                            &set, sizeof(sigset_t));
103215c9fa4SSiva Chandra Reddy }
104215c9fa4SSiva Chandra Reddy 
1056363320bSSiva Chandra Reddy LIBC_INLINE int restore_signals(const sigset_t &set) {
106b6bc9d72SGuillaume Chatelet   return LIBC_NAMESPACE::syscall_impl<int>(SYS_rt_sigprocmask, SIG_SETMASK,
107b6bc9d72SGuillaume Chatelet                                            &set, nullptr, sizeof(sigset_t));
108215c9fa4SSiva Chandra Reddy }
109215c9fa4SSiva Chandra Reddy 
110*5ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL
111215c9fa4SSiva Chandra Reddy 
112215c9fa4SSiva Chandra Reddy #endif // LLVM_LIBC_SRC_SIGNAL_LINUX_SIGNAL_UTILS_H
113