blob: 051a6549d8c9f22ffb008e62352e3b65b874d703 [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>
9#include <initializer_list>
10
Alex Perrycb7da4b2019-08-28 19:35:56 -070011#include "glog/logging.h"
Austin Schuh6c590f82019-09-11 19:23:12 -070012
13namespace aos {
14namespace ipc_lib {
Austin Schuh8d2e3fa2020-09-10 23:01:55 -070015namespace {
16
17// Wrapper which propagates msan information.
18// TODO(Brian): Drop this once we have <https://reviews.llvm.org/D82411> to
19// intercept this function natively.
20int wrapped_sigandset(sigset_t *dest, const sigset_t *left,
21 const sigset_t *right) {
22#if __has_feature(memory_sanitizer)
23 if (left) {
24 __msan_check_mem_is_initialized(left, sizeof(*left));
25 }
26 if (right) {
27 __msan_check_mem_is_initialized(right, sizeof(*right));
28 }
29#endif
30 const int r = sigandset(dest, left, right);
31#if __has_feature(memory_sanitizer)
32 if (!r && dest) {
33 __msan_unpoison(dest, sizeof(*dest));
34 }
35#endif
36 return r;
37}
38
39// Wrapper which propagates msan information.
40// TODO(Brian): Drop this once we have
41// <https://reviews.llvm.org/rG89ae290b58e20fc5f56b7bfae4b34e7fef06e1b1> to
42// intercept this function natively.
43int wrapped_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset) {
44#if __has_feature(memory_sanitizer)
45 if (set) {
46 __msan_check_mem_is_initialized(set, sizeof(*set));
47 }
48#endif
49 const int r = pthread_sigmask(how, set, oldset);
50#if __has_feature(memory_sanitizer)
51 if (!r && oldset) {
52 __msan_unpoison(oldset, sizeof(*oldset));
53 }
54#endif
55 return r;
56}
57
58} // namespace
Austin Schuh6c590f82019-09-11 19:23:12 -070059
Alex Perrycb7da4b2019-08-28 19:35:56 -070060SignalFd::SignalFd(::std::initializer_list<unsigned int> signals) {
Austin Schuh6c590f82019-09-11 19:23:12 -070061 // Build up the mask with the provided signals.
Brian Silverman407cc532019-11-03 11:40:56 -080062 CHECK_EQ(0, sigemptyset(&blocked_mask_));
Austin Schuh6c590f82019-09-11 19:23:12 -070063 for (int signal : signals) {
Brian Silverman407cc532019-11-03 11:40:56 -080064 CHECK_EQ(0, sigaddset(&blocked_mask_, signal));
Austin Schuh6c590f82019-09-11 19:23:12 -070065 }
66 // Then build a signalfd. Make it nonblocking so it works well with an epoll
67 // loop, and have it close on exec.
Brian Silverman407cc532019-11-03 11:40:56 -080068 PCHECK((fd_ = signalfd(-1, &blocked_mask_, SFD_NONBLOCK | SFD_CLOEXEC)) != 0);
Austin Schuh6c590f82019-09-11 19:23:12 -070069 // Now that we have a consumer of the signal, block the signals so the
Brian Silverman407cc532019-11-03 11:40:56 -080070 // signalfd gets them. Record which ones we actually blocked, so we can
71 // unblock just those later.
72 sigset_t old_mask;
Austin Schuh8d2e3fa2020-09-10 23:01:55 -070073 CHECK_EQ(0, wrapped_pthread_sigmask(SIG_BLOCK, &blocked_mask_, &old_mask));
Brian Silverman407cc532019-11-03 11:40:56 -080074 for (int signal : signals) {
75 if (sigismember(&old_mask, signal)) {
76 CHECK_EQ(0, sigdelset(&blocked_mask_, signal));
77 }
78 }
Austin Schuh6c590f82019-09-11 19:23:12 -070079}
80
81SignalFd::~SignalFd() {
Brian Silverman407cc532019-11-03 11:40:56 -080082 // Unwind the constructor. Unblock the signals and close the fd. Verify nobody
83 // else unblocked the signals we're supposed to unblock in the meantime.
84 sigset_t old_mask;
Austin Schuh8d2e3fa2020-09-10 23:01:55 -070085 CHECK_EQ(0, wrapped_pthread_sigmask(SIG_UNBLOCK, &blocked_mask_, &old_mask));
Brian Silverman407cc532019-11-03 11:40:56 -080086 sigset_t unblocked_mask;
Austin Schuh8d2e3fa2020-09-10 23:01:55 -070087 CHECK_EQ(0, wrapped_sigandset(&unblocked_mask, &blocked_mask_, &old_mask));
Brian Silverman407cc532019-11-03 11:40:56 -080088 if (memcmp(&unblocked_mask, &blocked_mask_, sizeof(unblocked_mask)) != 0) {
89 LOG(FATAL) << "Some other code unblocked one or more of our signals";
90 }
Alex Perrycb7da4b2019-08-28 19:35:56 -070091 PCHECK(close(fd_) == 0);
Austin Schuh6c590f82019-09-11 19:23:12 -070092}
93
94signalfd_siginfo SignalFd::Read() {
95 signalfd_siginfo result;
96
97 const int ret =
98 read(fd_, static_cast<void *>(&result), sizeof(signalfd_siginfo));
99 // If we didn't get the right amount of data, signal that there was a problem
100 // by setting the signal number to 0.
101 if (ret != static_cast<int>(sizeof(signalfd_siginfo))) {
102 result.ssi_signo = 0;
Brian Silverman407cc532019-11-03 11:40:56 -0800103 } else {
104 CHECK_NE(0u, result.ssi_signo);
Austin Schuh6c590f82019-09-11 19:23:12 -0700105 }
106 return result;
107}
108
109} // namespace ipc_lib
110} // namespace aos