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