diff options
author | Vernon Mauery <vernon.mauery@linux.intel.com> | 2019-03-20 13:00:20 -0700 |
---|---|---|
committer | Vernon Mauery <vernon.mauery@linux.intel.com> | 2019-03-20 13:00:20 -0700 |
commit | 3719c2fc50d33dbe407eb5351d94252406ccec9e (patch) | |
tree | f96d26558e8b56170f4b9ad7059e01be13bd8505 /libipmid | |
parent | f0bedac613c5cedd2b6560aa84823da0c264017b (diff) | |
download | phosphor-host-ipmid-3719c2fc50d33dbe407eb5351d94252406ccec9e.tar.gz phosphor-host-ipmid-3719c2fc50d33dbe407eb5351d94252406ccec9e.zip |
Add generic signal handling API to work with boost::asio
This allows providers or the main application to handle POSIX signals
using a callback chain. Each handler can return continueExecution or
breakExecution to stop the signal handling chain or allow it to
continue. Each handler is registered with a priority and upon reciept of
a signal, each handler is executed in priority order until the end of
the list is reached or one returns with breakExecution.
Change-Id: Idd83625eb1a2d3bdafc92bdd839e0d6386177ff2
Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
Diffstat (limited to 'libipmid')
-rw-r--r-- | libipmid/Makefile.am | 1 | ||||
-rw-r--r-- | libipmid/signals.cpp | 106 |
2 files changed, 107 insertions, 0 deletions
diff --git a/libipmid/Makefile.am b/libipmid/Makefile.am index ac35bbf..e4899e1 100644 --- a/libipmid/Makefile.am +++ b/libipmid/Makefile.am @@ -13,6 +13,7 @@ pkgconfig_DATA = libipmid.pc lib_LTLIBRARIES = libipmid.la libipmid_la_SOURCES = \ sdbus-asio.cpp \ + signals.cpp \ systemintf-sdbus.cpp libipmid_la_LDFLAGS = \ $(SYSTEMD_LIBS) \ diff --git a/libipmid/signals.cpp b/libipmid/signals.cpp new file mode 100644 index 0000000..3838e95 --- /dev/null +++ b/libipmid/signals.cpp @@ -0,0 +1,106 @@ +#include <forward_list> +#include <ipmid/api.hpp> +#include <memory> +#include <phosphor-logging/log.hpp> +#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); +} |