blob: 363bf4ae66f1ee88fe1dcb741f363961985a3699 [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>
5#include <unistd.h>
6#include <initializer_list>
7
Alex Perrycb7da4b2019-08-28 19:35:56 -07008#include "glog/logging.h"
Austin Schuh6c590f82019-09-11 19:23:12 -07009
10namespace aos {
11namespace ipc_lib {
12
Alex Perrycb7da4b2019-08-28 19:35:56 -070013SignalFd::SignalFd(::std::initializer_list<unsigned int> signals) {
Austin Schuh6c590f82019-09-11 19:23:12 -070014 // Build up the mask with the provided signals.
Brian Silverman407cc532019-11-03 11:40:56 -080015 CHECK_EQ(0, sigemptyset(&blocked_mask_));
Austin Schuh6c590f82019-09-11 19:23:12 -070016 for (int signal : signals) {
Brian Silverman407cc532019-11-03 11:40:56 -080017 CHECK_EQ(0, sigaddset(&blocked_mask_, signal));
Austin Schuh6c590f82019-09-11 19:23:12 -070018 }
19 // Then build a signalfd. Make it nonblocking so it works well with an epoll
20 // loop, and have it close on exec.
Brian Silverman407cc532019-11-03 11:40:56 -080021 PCHECK((fd_ = signalfd(-1, &blocked_mask_, SFD_NONBLOCK | SFD_CLOEXEC)) != 0);
Austin Schuh6c590f82019-09-11 19:23:12 -070022 // Now that we have a consumer of the signal, block the signals so the
Brian Silverman407cc532019-11-03 11:40:56 -080023 // signalfd gets them. Record which ones we actually blocked, so we can
24 // unblock just those later.
25 sigset_t old_mask;
26 CHECK_EQ(0, pthread_sigmask(SIG_BLOCK, &blocked_mask_, &old_mask));
27 for (int signal : signals) {
28 if (sigismember(&old_mask, signal)) {
29 CHECK_EQ(0, sigdelset(&blocked_mask_, signal));
30 }
31 }
Austin Schuh6c590f82019-09-11 19:23:12 -070032}
33
34SignalFd::~SignalFd() {
Brian Silverman407cc532019-11-03 11:40:56 -080035 // Unwind the constructor. Unblock the signals and close the fd. Verify nobody
36 // else unblocked the signals we're supposed to unblock in the meantime.
37 sigset_t old_mask;
38 CHECK_EQ(0, pthread_sigmask(SIG_UNBLOCK, &blocked_mask_, &old_mask));
39 sigset_t unblocked_mask;
40 CHECK_EQ(0, sigandset(&unblocked_mask, &blocked_mask_, &old_mask));
41 if (memcmp(&unblocked_mask, &blocked_mask_, sizeof(unblocked_mask)) != 0) {
42 LOG(FATAL) << "Some other code unblocked one or more of our signals";
43 }
Alex Perrycb7da4b2019-08-28 19:35:56 -070044 PCHECK(close(fd_) == 0);
Austin Schuh6c590f82019-09-11 19:23:12 -070045}
46
47signalfd_siginfo SignalFd::Read() {
48 signalfd_siginfo result;
49
50 const int ret =
51 read(fd_, static_cast<void *>(&result), sizeof(signalfd_siginfo));
52 // If we didn't get the right amount of data, signal that there was a problem
53 // by setting the signal number to 0.
54 if (ret != static_cast<int>(sizeof(signalfd_siginfo))) {
55 result.ssi_signo = 0;
Brian Silverman407cc532019-11-03 11:40:56 -080056 } else {
57 CHECK_NE(0u, result.ssi_signo);
Austin Schuh6c590f82019-09-11 19:23:12 -070058 }
59 return result;
60}
61
62} // namespace ipc_lib
63} // namespace aos