| Vernon Mauery | 3719c2f | 2019-03-20 13:00:20 -0700 | [diff] [blame] | 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 | } |