blob: 3689b7e47fc85bec0f385403655d4eadae426da4 [file] [log] [blame]
Austin Schuh6c590f82019-09-11 19:23:12 -07001#include "aos/ipc_lib/signalfd.h"
2
3#include <signal.h>
4#include <sys/types.h>
Austin Schuh8d2e3fa2020-09-10 23:01:55 -07005#if __has_feature(memory_sanitizer)
6#include <sanitizer/msan_interface.h>
7#endif
Austin Schuh6c590f82019-09-11 19:23:12 -07008#include <unistd.h>
Tyler Chatow85c32c92021-07-31 11:58:51 -07009
Austin Schuh6c590f82019-09-11 19:23:12 -070010#include <initializer_list>
11
Alex Perrycb7da4b2019-08-28 19:35:56 -070012#include "glog/logging.h"
Austin Schuh6c590f82019-09-11 19:23:12 -070013
14namespace aos {
15namespace ipc_lib {
Austin Schuh8d2e3fa2020-09-10 23:01:55 -070016namespace {
17
18// Wrapper which propagates msan information.
19// TODO(Brian): Drop this once we have <https://reviews.llvm.org/D82411> to
20// intercept this function natively.
21int wrapped_sigandset(sigset_t *dest, const sigset_t *left,
22 const sigset_t *right) {
23#if __has_feature(memory_sanitizer)
24 if (left) {
25 __msan_check_mem_is_initialized(left, sizeof(*left));
26 }
27 if (right) {
28 __msan_check_mem_is_initialized(right, sizeof(*right));
29 }
30#endif
31 const int r = sigandset(dest, left, right);
32#if __has_feature(memory_sanitizer)
33 if (!r && dest) {
34 __msan_unpoison(dest, sizeof(*dest));
35 }
36#endif
37 return r;
38}
39
40// Wrapper which propagates msan information.
41// TODO(Brian): Drop this once we have
42// <https://reviews.llvm.org/rG89ae290b58e20fc5f56b7bfae4b34e7fef06e1b1> to
43// intercept this function natively.
44int wrapped_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) {
45#if __has_feature(memory_sanitizer)
46 if (set) {
47 __msan_check_mem_is_initialized(set, sizeof(*set));
48 }
49#endif
50 const int r = pthread_sigmask(how, set, oldset);
51#if __has_feature(memory_sanitizer)
52 if (!r && oldset) {
53 __msan_unpoison(oldset, sizeof(*oldset));
54 }
55#endif
56 return r;
57}
58
59} // namespace
Austin Schuh6c590f82019-09-11 19:23:12 -070060
Alex Perrycb7da4b2019-08-28 19:35:56 -070061SignalFd::SignalFd(::std::initializer_list<unsigned int> signals) {
Austin Schuh6c590f82019-09-11 19:23:12 -070062 // Build up the mask with the provided signals.
Brian Silverman407cc532019-11-03 11:40:56 -080063 CHECK_EQ(0, sigemptyset(&blocked_mask_));
Austin Schuh6c590f82019-09-11 19:23:12 -070064 for (int signal : signals) {
Brian Silverman407cc532019-11-03 11:40:56 -080065 CHECK_EQ(0, sigaddset(&blocked_mask_, signal));
Austin Schuh6c590f82019-09-11 19:23:12 -070066 }
67 // Then build a signalfd. Make it nonblocking so it works well with an epoll
68 // loop, and have it close on exec.
Brian Silverman407cc532019-11-03 11:40:56 -080069 PCHECK((fd_ = signalfd(-1, &blocked_mask_, SFD_NONBLOCK | SFD_CLOEXEC)) != 0);
Austin Schuh6c590f82019-09-11 19:23:12 -070070 // Now that we have a consumer of the signal, block the signals so the
Brian Silverman407cc532019-11-03 11:40:56 -080071 // signalfd gets them. Record which ones we actually blocked, so we can
72 // unblock just those later.
73 sigset_t old_mask;
Austin Schuh8d2e3fa2020-09-10 23:01:55 -070074 CHECK_EQ(0, wrapped_pthread_sigmask(SIG_BLOCK, &blocked_mask_, &old_mask));
Brian Silverman407cc532019-11-03 11:40:56 -080075 for (int signal : signals) {
76 if (sigismember(&old_mask, signal)) {
77 CHECK_EQ(0, sigdelset(&blocked_mask_, signal));
78 }
79 }
Austin Schuh6c590f82019-09-11 19:23:12 -070080}
81
Tyler Chatow85c32c92021-07-31 11:58:51 -070082namespace {
83// sizeof(sigset_t) is larger than the bytes actually used to represent all
84// signals. This size is only the bytes initialized. _NSIG is 1-indexed.
85static constexpr size_t kSigSetSize = (_NSIG - 1) / 8;
86
87// If the size of the mask changes, we should check that we still have
88// correct behavior.
89static_assert(kSigSetSize == 8 && kSigSetSize <= sizeof(sigset_t));
90} // namespace
91
Austin Schuh6c590f82019-09-11 19:23:12 -070092SignalFd::~SignalFd() {
Brian Silverman407cc532019-11-03 11:40:56 -080093 // Unwind the constructor. Unblock the signals and close the fd. Verify nobody
94 // else unblocked the signals we're supposed to unblock in the meantime.
95 sigset_t old_mask;
Austin Schuh8d2e3fa2020-09-10 23:01:55 -070096 CHECK_EQ(0, wrapped_pthread_sigmask(SIG_UNBLOCK, &blocked_mask_, &old_mask));
Brian Silverman407cc532019-11-03 11:40:56 -080097 sigset_t unblocked_mask;
Austin Schuh8d2e3fa2020-09-10 23:01:55 -070098 CHECK_EQ(0, wrapped_sigandset(&unblocked_mask, &blocked_mask_, &old_mask));
Tyler Chatow85c32c92021-07-31 11:58:51 -070099 if (memcmp(&unblocked_mask, &blocked_mask_, kSigSetSize) != 0) {
Brian Silverman407cc532019-11-03 11:40:56 -0800100 LOG(FATAL) << "Some other code unblocked one or more of our signals";
101 }
Alex Perrycb7da4b2019-08-28 19:35:56 -0700102 PCHECK(close(fd_) == 0);
Austin Schuh6c590f82019-09-11 19:23:12 -0700103}
104
105signalfd_siginfo SignalFd::Read() {
106 signalfd_siginfo result;
107
108 const int ret =
109 read(fd_, static_cast<void *>(&result), sizeof(signalfd_siginfo));
110 // If we didn't get the right amount of data, signal that there was a problem
111 // by setting the signal number to 0.
112 if (ret != static_cast<int>(sizeof(signalfd_siginfo))) {
113 result.ssi_signo = 0;
Brian Silverman407cc532019-11-03 11:40:56 -0800114 } else {
115 CHECK_NE(0u, result.ssi_signo);
Austin Schuh6c590f82019-09-11 19:23:12 -0700116 }
117 return result;
118}
119
120} // namespace ipc_lib
121} // namespace aos