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