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 #include <base/message_loop/message_loop.h> 15 #include <base/posix/eintr_wrapper.h> 16 17 namespace { 18 const int kInvalidDescriptor = -1; 19 } // namespace 20 21 namespace brillo { 22 23 AsynchronousSignalHandler::AsynchronousSignalHandler() 24 : descriptor_(kInvalidDescriptor) { 25 CHECK_EQ(sigemptyset(&signal_mask_), 0) << "Failed to initialize signal mask"; 26 CHECK_EQ(sigemptyset(&saved_signal_mask_), 0) 27 << "Failed to initialize signal mask"; 28 } 29 30 AsynchronousSignalHandler::~AsynchronousSignalHandler() { 31 if (descriptor_ != kInvalidDescriptor) { 32 MessageLoop::current()->CancelTask(fd_watcher_task_); 33 34 if (IGNORE_EINTR(close(descriptor_)) != 0) 35 PLOG(WARNING) << "Failed to close file descriptor"; 36 37 descriptor_ = kInvalidDescriptor; 38 CHECK_EQ(0, sigprocmask(SIG_SETMASK, &saved_signal_mask_, nullptr)); 39 } 40 } 41 42 void AsynchronousSignalHandler::Init() { 43 CHECK_EQ(kInvalidDescriptor, descriptor_); 44 CHECK_EQ(0, sigprocmask(SIG_BLOCK, &signal_mask_, &saved_signal_mask_)); 45 descriptor_ = 46 signalfd(descriptor_, &signal_mask_, SFD_CLOEXEC | SFD_NONBLOCK); 47 CHECK_NE(kInvalidDescriptor, descriptor_); 48 fd_watcher_task_ = MessageLoop::current()->WatchFileDescriptor( 49 FROM_HERE, 50 descriptor_, 51 MessageLoop::WatchMode::kWatchRead, 52 true, 53 base::Bind(&AsynchronousSignalHandler::OnFileCanReadWithoutBlocking, 54 base::Unretained(this))); 55 CHECK(fd_watcher_task_ != MessageLoop::kTaskIdNull) 56 << "Watching shutdown pipe failed."; 57 } 58 59 void AsynchronousSignalHandler::RegisterHandler(int signal, 60 const SignalHandler& callback) { 61 registered_callbacks_[signal] = callback; 62 CHECK_EQ(0, sigaddset(&signal_mask_, signal)); 63 UpdateSignals(); 64 } 65 66 void AsynchronousSignalHandler::UnregisterHandler(int signal) { 67 Callbacks::iterator callback_it = registered_callbacks_.find(signal); 68 if (callback_it != registered_callbacks_.end()) { 69 registered_callbacks_.erase(callback_it); 70 ResetSignal(signal); 71 } 72 } 73 74 void AsynchronousSignalHandler::OnFileCanReadWithoutBlocking() { 75 struct signalfd_siginfo info; 76 while (base::ReadFromFD(descriptor_, 77 reinterpret_cast<char*>(&info), sizeof(info))) { 78 int signal = info.ssi_signo; 79 Callbacks::iterator callback_it = registered_callbacks_.find(signal); 80 if (callback_it == registered_callbacks_.end()) { 81 LOG(WARNING) << "Unable to find a signal handler for signal: " << signal; 82 // Can happen if a signal has been called multiple time, and the callback 83 // asked to be unregistered the first time. 84 continue; 85 } 86 const SignalHandler& callback = callback_it->second; 87 bool must_unregister = callback.Run(info); 88 if (must_unregister) { 89 UnregisterHandler(signal); 90 } 91 } 92 } 93 94 void AsynchronousSignalHandler::ResetSignal(int signal) { 95 CHECK_EQ(0, sigdelset(&signal_mask_, signal)); 96 UpdateSignals(); 97 } 98 99 void AsynchronousSignalHandler::UpdateSignals() { 100 if (descriptor_ != kInvalidDescriptor) { 101 CHECK_EQ(0, sigprocmask(SIG_SETMASK, &saved_signal_mask_, nullptr)); 102 CHECK_EQ(0, sigprocmask(SIG_BLOCK, &signal_mask_, nullptr)); 103 CHECK_EQ(descriptor_, 104 signalfd(descriptor_, &signal_mask_, SFD_CLOEXEC | SFD_NONBLOCK)); 105 } 106 } 107 108 } // namespace brillo 109