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