xref: /aosp_15_r20/external/libbrillo/brillo/asynchronous_signal_handler.cc (revision 1a96fba65179ea7d3f56207137718607415c5953)
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