| Ed Tanous | 778418d | 2020-08-17 23:20:21 -0700 | [diff] [blame] | 1 | #include <boost/asio/signal_set.hpp> | 
| Vernon Mauery | 3719c2f | 2019-03-20 13:00:20 -0700 | [diff] [blame] | 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 | } |