1 // Copyright 2014 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "brillo/asynchronous_signal_handler.h"
6
7 #include <signal.h>
8 #include <sys/types.h>
9 #include <unistd.h>
10
11 #include <base/bind.h>
12 #include <base/files/file_util.h>
13 #include <base/logging.h>
14
15 namespace brillo {
16
AsynchronousSignalHandler()17 AsynchronousSignalHandler::AsynchronousSignalHandler() {
18 CHECK_EQ(sigemptyset(&signal_mask_), 0) << "Failed to initialize signal mask";
19 CHECK_EQ(sigemptyset(&saved_signal_mask_), 0)
20 << "Failed to initialize signal mask";
21 }
22
~AsynchronousSignalHandler()23 AsynchronousSignalHandler::~AsynchronousSignalHandler() {
24 fd_watcher_ = nullptr;
25
26 if (!descriptor_.is_valid())
27 return;
28
29 // Close FD before restoring sigprocmask.
30 descriptor_.reset();
31 CHECK_EQ(0, sigprocmask(SIG_SETMASK, &saved_signal_mask_, nullptr));
32 }
33
Init()34 void AsynchronousSignalHandler::Init() {
35 // Making sure it is not yet initialized.
36 CHECK(!descriptor_.is_valid());
37
38 // Set sigprocmask before creating signalfd.
39 CHECK_EQ(0, sigprocmask(SIG_BLOCK, &signal_mask_, &saved_signal_mask_));
40
41 // Creating signalfd, and start watching it.
42 descriptor_.reset(signalfd(-1, &signal_mask_, SFD_CLOEXEC | SFD_NONBLOCK));
43 CHECK(descriptor_.is_valid());
44 fd_watcher_ = base::FileDescriptorWatcher::WatchReadable(
45 descriptor_.get(),
46 base::BindRepeating(&AsynchronousSignalHandler::OnReadable,
47 base::Unretained(this)));
48 CHECK(fd_watcher_) << "Watching signalfd failed.";
49 }
50
RegisterHandler(int signal,const SignalHandler & callback)51 void AsynchronousSignalHandler::RegisterHandler(int signal,
52 const SignalHandler& callback) {
53 registered_callbacks_[signal] = callback;
54 CHECK_EQ(0, sigaddset(&signal_mask_, signal));
55 UpdateSignals();
56 }
57
UnregisterHandler(int signal)58 void AsynchronousSignalHandler::UnregisterHandler(int signal) {
59 Callbacks::iterator callback_it = registered_callbacks_.find(signal);
60 if (callback_it == registered_callbacks_.end())
61 return;
62 registered_callbacks_.erase(callback_it);
63 CHECK_EQ(0, sigdelset(&signal_mask_, signal));
64 UpdateSignals();
65 }
66
OnReadable()67 void AsynchronousSignalHandler::OnReadable() {
68 struct signalfd_siginfo info;
69 while (base::ReadFromFD(descriptor_.get(),
70 reinterpret_cast<char*>(&info), sizeof(info))) {
71 int signal = info.ssi_signo;
72 Callbacks::iterator callback_it = registered_callbacks_.find(signal);
73 if (callback_it == registered_callbacks_.end()) {
74 LOG(WARNING) << "Unable to find a signal handler for signal: " << signal;
75 // Can happen if a signal has been called multiple time, and the callback
76 // asked to be unregistered the first time.
77 continue;
78 }
79 const SignalHandler& callback = callback_it->second;
80 bool must_unregister = callback.Run(info);
81 if (must_unregister)
82 UnregisterHandler(signal);
83 }
84 }
85
UpdateSignals()86 void AsynchronousSignalHandler::UpdateSignals() {
87 if (!descriptor_.is_valid())
88 return;
89 sigset_t mask;
90 #ifdef __ANDROID__
91 CHECK_EQ(0, sigemptyset(&mask));
92 for (size_t i = 0; i < NSIG; ++i) {
93 if (sigismember(&signal_mask_, i) == 1 || sigismember(&saved_signal_mask_, i) == 1) {
94 CHECK_EQ(0, sigaddset(&mask, i));
95 }
96 }
97 #else
98 CHECK_EQ(0, sigorset(&mask, &signal_mask_, &saved_signal_mask_));
99 #endif
100 CHECK_EQ(0, sigprocmask(SIG_SETMASK, &mask, nullptr));
101 CHECK_EQ(
102 descriptor_.get(),
103 signalfd(descriptor_.get(), &signal_mask_, SFD_CLOEXEC | SFD_NONBLOCK));
104 }
105
106 } // namespace brillo
107