1 #include <boost/asio/signal_set.hpp> 2 #include <forward_list> 3 #include <ipmid/api.hpp> 4 #include <memory> 5 #include <phosphor-logging/log.hpp> 6 #include <vector> 7 8 using namespace phosphor::logging; 9 10 namespace 11 { 12 13 class SignalHandler 14 { 15 public: 16 SignalHandler(std::shared_ptr<boost::asio::io_context>& io, int sigNum) : 17 signal(std::make_unique<boost::asio::signal_set>(*io, sigNum)) 18 { 19 asyncWait(); 20 } 21 22 ~SignalHandler() 23 { 24 // unregister with asio to unmask the signal 25 signal->cancel(); 26 signal->clear(); 27 } 28 29 void registerHandler(int prio, 30 const std::function<SignalResponse(int)>& handler) 31 { 32 // check for initial placement 33 if (handlers.empty() || std::get<0>(handlers.front()) < prio) 34 { 35 handlers.emplace_front(std::make_tuple(prio, handler)); 36 return; 37 } 38 // walk the list and put it in the right place 39 auto j = handlers.begin(); 40 for (auto i = j; i != handlers.end() && std::get<0>(*i) > prio; i++) 41 { 42 j = i; 43 } 44 handlers.emplace_after(j, std::make_tuple(prio, handler)); 45 } 46 47 void handleSignal(const boost::system::error_code& ec, int sigNum) 48 { 49 if (ec) 50 { 51 log<level::ERR>("Error in common signal handler", 52 entry("SIGNAL=%d", sigNum), 53 entry("ERROR=%s", ec.message().c_str())); 54 return; 55 } 56 for (auto h = handlers.begin(); h != handlers.end(); h++) 57 { 58 std::function<SignalResponse(int)>& handler = std::get<1>(*h); 59 if (handler(sigNum) == SignalResponse::breakExecution) 60 { 61 break; 62 } 63 } 64 // start the wait for the next signal 65 asyncWait(); 66 } 67 68 protected: 69 void asyncWait() 70 { 71 signal->async_wait([this](const boost::system::error_code& ec, 72 int sigNum) { handleSignal(ec, sigNum); }); 73 } 74 75 std::forward_list<std::tuple<int, std::function<SignalResponse(int)>>> 76 handlers; 77 std::unique_ptr<boost::asio::signal_set> signal; 78 }; 79 80 // SIGRTMAX is defined as a non-constexpr function call and thus cannot be used 81 // as an array size. Get around this by making a vector and resizing it the 82 // first time it is needed 83 std::vector<std::unique_ptr<SignalHandler>> signals; 84 85 } // namespace 86 87 void registerSignalHandler(int priority, int signalNumber, 88 const std::function<SignalResponse(int)>& handler) 89 { 90 if (signalNumber >= SIGRTMAX) 91 { 92 return; 93 } 94 95 if (signals.empty()) 96 { 97 signals.resize(SIGRTMAX); 98 } 99 100 if (!signals[signalNumber]) 101 { 102 std::shared_ptr<boost::asio::io_context> io = getIoContext(); 103 signals[signalNumber] = 104 std::make_unique<SignalHandler>(io, signalNumber); 105 } 106 signals[signalNumber]->registerHandler(priority, handler); 107 } 108