blob: 757103a4690271f64e19e7e4a22267dd87b135b3 [file] [log] [blame]
#include <boost/asio/signal_set.hpp>
#include <ipmid/api.hpp>
#include <phosphor-logging/log.hpp>
#include <forward_list>
#include <memory>
#include <vector>
using namespace phosphor::logging;
namespace
{
class SignalHandler
{
public:
SignalHandler(std::shared_ptr<boost::asio::io_context>& io, int sigNum) :
signal(std::make_unique<boost::asio::signal_set>(*io, sigNum))
{
asyncWait();
}
~SignalHandler()
{
// unregister with asio to unmask the signal
signal->cancel();
signal->clear();
}
void registerHandler(int prio,
const std::function<SignalResponse(int)>& handler)
{
// check for initial placement
if (handlers.empty() || std::get<0>(handlers.front()) < prio)
{
handlers.emplace_front(std::make_tuple(prio, handler));
return;
}
// walk the list and put it in the right place
auto j = handlers.begin();
for (auto i = j; i != handlers.end() && std::get<0>(*i) > prio; i++)
{
j = i;
}
handlers.emplace_after(j, std::make_tuple(prio, handler));
}
void handleSignal(const boost::system::error_code& ec, int sigNum)
{
if (ec)
{
log<level::ERR>("Error in common signal handler",
entry("SIGNAL=%d", sigNum),
entry("ERROR=%s", ec.message().c_str()));
return;
}
for (auto h = handlers.begin(); h != handlers.end(); h++)
{
std::function<SignalResponse(int)>& handler = std::get<1>(*h);
if (handler(sigNum) == SignalResponse::breakExecution)
{
break;
}
}
// start the wait for the next signal
asyncWait();
}
protected:
void asyncWait()
{
signal->async_wait([this](const boost::system::error_code& ec,
int sigNum) { handleSignal(ec, sigNum); });
}
std::forward_list<std::tuple<int, std::function<SignalResponse(int)>>>
handlers;
std::unique_ptr<boost::asio::signal_set> signal;
};
// SIGRTMAX is defined as a non-constexpr function call and thus cannot be used
// as an array size. Get around this by making a vector and resizing it the
// first time it is needed
std::vector<std::unique_ptr<SignalHandler>> signals;
} // namespace
void registerSignalHandler(int priority, int signalNumber,
const std::function<SignalResponse(int)>& handler)
{
if (signalNumber >= SIGRTMAX)
{
return;
}
if (signals.empty())
{
signals.resize(SIGRTMAX);
}
if (!signals[signalNumber])
{
std::shared_ptr<boost::asio::io_context> io = getIoContext();
signals[signalNumber] = std::make_unique<SignalHandler>(io,
signalNumber);
}
signals[signalNumber]->registerHandler(priority, handler);
}