changeSignal(SIG_BLOCK, sigNum);
}
-void signalBlockAll()
+void signalBlockAllExcept(const std::initializer_list<int>& signals)
{
::sigset_t set;
if(-1 == ::sigfillset(&set)) {
throw UtilsException("Error in sigfillset: " + msg);
}
+ for(const int s: signals) {
+ if(-1 == ::sigaddset(&set, s)) {
+ const std::string msg = getSystemErrorMessage();
+ LOGE("Error in sigaddset: " << msg);
+ throw UtilsException("Error in sigaddset: " + msg);
+ }
+ }
setSignalMask(SIG_BLOCK, set);
}
changeSignal(SIG_UNBLOCK, sigNum);
}
+void signalIgnore(const std::initializer_list<int>& signals)
+{
+ struct ::sigaction act;
+ act.sa_handler = SIG_IGN;
+
+ for(const int s: signals) {
+ if(-1 == ::sigaction(s, &act, nullptr)) {
+ const std::string msg = getSystemErrorMessage();
+ LOGE("Error in sigaction: " << msg);
+ throw UtilsException("Error in sigaction: " + msg);
+ }
+ }
+}
+
} // namespace utils
#ifndef COMMON_UTILS_SIGNAL_HPP
#define COMMON_UTILS_SIGNAL_HPP
+#include <initializer_list>
#include <csignal>
namespace utils {
::sigset_t getSignalMask();
bool isSignalBlocked(const int sigNum);
-void signalBlockAll();
+void signalBlockAllExcept(const std::initializer_list<int>& signals);
void signalBlock(const int sigNum);
void signalUnblock(const int sigNum);
+void signalIgnore(const std::initializer_list<int>& signals);
} // namespace utils
{
Lock lock(mMutex);
+ ::sigset_t set = getSignalMask();
+
+ int error = ::signalfd(mFD, &set, SFD_CLOEXEC);
+ if (error != mFD) {
+ const std::string msg = getSystemErrorMessage();
+ LOGE("Error in signalfd: " << msg);
+ throw UtilsException("Error in signalfd: " + msg);
+ }
+
+ mCallbacks.insert({sigNum, callback});
+}
+
+void SignalFD::setHandlerAndBlock(const int sigNum, const Callback&& callback)
+{
+ Lock lock(mMutex);
+
bool isBlocked = isSignalBlocked(sigNum);
::sigset_t set = getSignalMask();
SignalFD& operator=(const SignalFD&) = delete;
/**
- * Add a callback for a specified signal
+ * Add a callback for a specified signal.
+ * Doesn't block the signal.
*
* @param sigNum number of the signal
* @param callback handler callback
void setHandler(const int sigNum, const Callback&& callback);
/**
+ * Add a callback for a specified signal
+ * Blocks the asynchronous signal handling.
+ *
+ * @param sigNum number of the signal
+ * @param callback handler callback
+ */
+ void setHandlerAndBlock(const int sigNum, const Callback&& callback);
+
+ /**
* @return signal file descriptor
*/
int getFD() const;
try {
// Block all signals
// Server will unblock handled signals
- utils::signalBlockAll();
+ utils::signalBlockAllExcept({SIGTERM});
+
+ // TODO: SIGTERM used by lxc, get rid of this
+ utils::signalIgnore({SIGTERM});
Server server(CONFIG_PATH);
server.run(runAsRoot);
mConfigPath(configPath),
mSignalFD(mDispatcher.getPoll())
{
- mSignalFD.setHandler(SIGINT, [this](int) {
+ mSignalFD.setHandlerAndBlock(SIGUSR1, [this] (int) {
+ LOGD("Received SIGUSR1 - triggering update.");
+ mIsUpdate = true;
mStopLatch.set();
});
- mSignalFD.setHandler(SIGTERM, [this] (int) {
+ mSignalFD.setHandlerAndBlock(SIGINT, [this](int) {
mStopLatch.set();
});
- mSignalFD.setHandler(SIGUSR1, [this] (int) {
- LOGD("Received SIGUSR1 - triggering update.");
- mIsUpdate = true;
+ mSignalFD.setHandler(SIGTERM, [this] (int) {
mStopLatch.set();
});
}
namespace {
-volatile sig_atomic_t gAsyncSignal = 0;
+volatile sig_atomic_t gAsyncSignal;
struct Fixture {
Fixture()
{
+ gAsyncSignal = 0;
::signal(SIGINT, &Fixture::signalHandler);
}
~Fixture()
{
::signal(SIGINT, SIG_DFL);
+ gAsyncSignal = 0;
}
static void signalHandler(int s)
{
- // Signal should never propagate to this handler
gAsyncSignal = s;
}
- static bool isSignalHandled() {
- return gAsyncSignal == 0;
+ static bool isAsyncHandlerCalled() {
+ return gAsyncSignal != 0;
}
};
{
ipc::epoll::EventPoll poll;
SignalFD s(poll);
- s.setHandler(SIGUSR1, [](const int) {});
- s.setHandler(SIGINT, [](const int) {});
+ s.setHandlerAndBlock(SIGUSR1, [](const int) {});
+ s.setHandlerAndBlock(SIGINT, [](const int) {});
::raise(SIGINT);
std::this_thread::sleep_for(std::chrono::milliseconds(TIMEOUT));
- BOOST_REQUIRE(isSignalHandled());
+ BOOST_REQUIRE(!isAsyncHandlerCalled());
}
BOOST_AUTO_TEST_CASE(SignalHandler)
::raise(SIGINT);
poll.dispatchIteration(TIMEOUT);
BOOST_REQUIRE(isSignalCalled);
- BOOST_REQUIRE(isSignalHandled());
+ BOOST_REQUIRE(!isAsyncHandlerCalled());
}
BOOST_AUTO_TEST_SUITE_END()