blob: 5eca6ad73e904c6eb19f44494c773a117f01f59d [file] [log] [blame]
Ed Tanous778418d2020-08-17 23:20:21 -07001#include <boost/asio/signal_set.hpp>
Vernon Mauery3719c2f2019-03-20 13:00:20 -07002#include <ipmid/api.hpp>
George Liub4b40912024-07-17 16:14:17 +08003#include <phosphor-logging/lg2.hpp>
Patrick Williamsfbc6c9d2023-05-10 07:50:16 -05004
5#include <forward_list>
6#include <memory>
Vernon Mauery3719c2f2019-03-20 13:00:20 -07007#include <vector>
8
Vernon Mauery3719c2f2019-03-20 13:00:20 -07009namespace
10{
11
12class 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 {
George Liub4b40912024-07-17 16:14:17 +080050 lg2::error("Error in common signal handler, "
51 "signal: {SIGNAL}, error: {ERROR}",
52 "SIGNAL", sigNum, "ERROR", ec.message());
Vernon Mauery3719c2f2019-03-20 13:00:20 -070053 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
82std::vector<std::unique_ptr<SignalHandler>> signals;
83
84} // namespace
85
86void 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();
Patrick Williams1318a5e2024-08-16 15:19:54 -0400102 signals[signalNumber] =
103 std::make_unique<SignalHandler>(io, signalNumber);
Vernon Mauery3719c2f2019-03-20 13:00:20 -0700104 }
105 signals[signalNumber]->registerHandler(priority, handler);
106}