summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/syncevo/SuspendFlags.cpp79
-rw-r--r--src/syncevo/SuspendFlags.h42
2 files changed, 88 insertions, 33 deletions
diff --git a/src/syncevo/SuspendFlags.cpp b/src/syncevo/SuspendFlags.cpp
index b47a8524..0f46bc49 100644
--- a/src/syncevo/SuspendFlags.cpp
+++ b/src/syncevo/SuspendFlags.cpp
@@ -36,9 +36,11 @@ SE_BEGIN_CXX
SuspendFlags::SuspendFlags() :
m_level(Logger::INFO),
m_state(NORMAL),
+ m_receivedSignals(0),
m_lastSuspend(0),
m_senderFD(-1),
- m_receiverFD(-1)
+ m_receiverFD(-1),
+ m_activeSignals(0)
{
}
@@ -148,10 +150,14 @@ boost::shared_ptr<SuspendFlags::StateBlocker> SuspendFlags::block(boost::weak_pt
return res;
}
-boost::shared_ptr<SuspendFlags::Guard> SuspendFlags::activate()
+boost::shared_ptr<SuspendFlags::Guard> SuspendFlags::activate(uint32_t sigmask)
{
SE_LOG_DEBUG(NULL, "SuspendFlags: (re)activating, currently %s",
m_senderFD > 0 ? "active" : "inactive");
+ if (m_senderFD > 0) {
+ return m_guard.lock();
+ }
+
int fds[2];
if (pipe(fds)) {
SE_THROW(StringPrintf("allocating pipe for signals failed: %s", strerror(errno)));
@@ -163,8 +169,11 @@ boost::shared_ptr<SuspendFlags::Guard> SuspendFlags::activate()
m_receiverFD = fds[0];
SE_LOG_DEBUG(NULL, "SuspendFlags: activating signal handler(s) with fds %d->%d",
m_senderFD, m_receiverFD);
- sigaction(SIGINT, NULL, &m_oldSigInt);
- sigaction(SIGTERM, NULL, &m_oldSigTerm);
+ for (int sig = 0; sig < 32; sig++) {
+ if (sigmask & (1<<sig)) {
+ sigaction(sig, NULL, m_oldSignalHandlers + sig);
+ }
+ }
struct sigaction new_action;
memset(&new_action, 0, sizeof(new_action));
@@ -173,22 +182,27 @@ boost::shared_ptr<SuspendFlags::Guard> SuspendFlags::activate()
// don't let processing of SIGINT be interrupted
// of SIGTERM and vice versa, if we are doing the
// handling
- if (m_oldSigInt.sa_handler == SIG_DFL) {
- sigaddset(&new_action.sa_mask, SIGINT);
- }
- if (m_oldSigTerm.sa_handler == SIG_DFL) {
- sigaddset(&new_action.sa_mask, SIGTERM);
- }
- if (m_oldSigInt.sa_handler == SIG_DFL) {
- sigaction(SIGINT, &new_action, NULL);
- SE_LOG_DEBUG(NULL, "SuspendFlags: catch SIGINT");
+ for (int sig = 0; sig < 32; sig++) {
+ if (sigmask & (1<<sig)) {
+ if (m_oldSignalHandlers[sig].sa_handler == SIG_DFL) {
+ sigaddset(&new_action.sa_mask, sig);
+ }
+ }
}
- if (m_oldSigTerm.sa_handler == SIG_DFL) {
- sigaction(SIGTERM, &new_action, NULL);
- SE_LOG_DEBUG(NULL, "SuspendFlags: catch SIGTERM");
+
+ for (int sig = 0; sig < 32; sig++) {
+ if (sigmask & (1<<sig)) {
+ if (m_oldSignalHandlers[sig].sa_handler == SIG_DFL) {
+ sigaction(sig, &new_action, NULL);
+ SE_LOG_DEBUG(NULL, "SuspendFlags: catch signal %d", sig);
+ }
+ }
}
+ m_activeSignals = sigmask;
+ boost::shared_ptr<Guard> guard(new GLibGuard(m_receiverFD));
+ m_guard = guard;
- return boost::shared_ptr<Guard>(new GLibGuard(m_receiverFD));
+ return guard;
}
void SuspendFlags::deactivate()
@@ -196,14 +210,19 @@ void SuspendFlags::deactivate()
SE_LOG_DEBUG(NULL, "SuspendFlags: deactivating fds %d->%d",
m_senderFD, m_receiverFD);
if (m_receiverFD >= 0) {
- sigaction(SIGTERM, &m_oldSigTerm, NULL);
- sigaction(SIGINT, &m_oldSigInt, NULL);
+ for (int sig = 0; sig < 32; sig++) {
+ if (m_activeSignals & (1<<sig)) {
+ sigaction(sig, m_oldSignalHandlers + sig, NULL);
+ }
+ }
+ m_activeSignals = 0;
SE_LOG_DEBUG(NULL, "SuspendFlags: close m_receiverFD %d", m_receiverFD);
close(m_receiverFD);
SE_LOG_DEBUG(NULL, "SuspendFlags: close m_senderFD %d", m_senderFD);
close(m_senderFD);
m_receiverFD = -1;
m_senderFD = -1;
+ m_guard.reset();
SE_LOG_DEBUG(NULL, "SuspendFlags: done with deactivation");
}
}
@@ -245,19 +264,24 @@ void SuspendFlags::handleSignal(int sig)
msg = SUSPEND_AGAIN;
}
break;
- case SuspendFlags::ABORT:
+ case ABORT:
msg = ABORT_AGAIN;
break;
- case SuspendFlags::ABORT_AGAIN:
- case SuspendFlags::SUSPEND_AGAIN:
+ case ABORT_AGAIN:
+ case SUSPEND_AGAIN:
+ case ABORT_MAX:
// shouldn't happen
+ msg = ABORT_MAX;
break;
}
+ default:
+ msg = ABORT_MAX;
break;
}
}
if (me.m_senderFD >= 0) {
- write(me.m_senderFD, &msg, 1);
+ unsigned char msg2[2] = { (unsigned char)(ABORT_MAX + sig), msg };
+ write(me.m_senderFD, msg2, msg == ABORT_MAX ? 1 : 2);
}
}
@@ -282,10 +306,13 @@ void SuspendFlags::printSignals()
case ABORT_AGAIN:
str = "Already aborting as requested earlier ...";
break;
+ default: {
+ int sig = msg - ABORT_MAX;
+ SE_LOG_DEBUG(NULL, "reveived signal %d", sig);
+ m_receivedSignals |= 1<<sig;
}
- if (!str) {
- SE_LOG_DEBUG(NULL, "internal error: received invalid signal msg %d", msg);
- } else {
+ }
+ if (str) {
SE_LOG(NULL, m_level, "%s", str);
}
m_stateChanged(*this);
diff --git a/src/syncevo/SuspendFlags.h b/src/syncevo/SuspendFlags.h
index a45c1154..e6f9c07f 100644
--- a/src/syncevo/SuspendFlags.h
+++ b/src/syncevo/SuspendFlags.h
@@ -56,7 +56,9 @@ class SuspendFlags
/** suspend sync request received again (only written to event FD, not returned by getState()) */
SUSPEND_AGAIN,
/** abort sync request received again (only written to event FD, not returned by getState()) */
- ABORT_AGAIN
+ ABORT_AGAIN,
+
+ ABORT_MAX
};
/** access to singleton */
@@ -73,6 +75,12 @@ class SuspendFlags
State getState() const;
/**
+ * Returns or-ed mask of all signals handled so far.
+ * See activate().
+ */
+ uint32_t getReceivedSignals() const { return m_receivedSignals; }
+
+ /**
* Throws a "aborting as requested by user" StatusException with
* LOCERR_USERABORT as status code if the current state is not
* NORMAL. In other words, suspend and abort are both
@@ -83,7 +91,7 @@ class SuspendFlags
/**
* Users of this class can read a single char for each received
* signal from this file descriptor. The char is the State that
- * was entered by that signal. This can be used to be notified
+ * was entered by that signal. This can be used to be notified
* immediately about changes, without having to poll.
*
* -1 if not activated.
@@ -96,11 +104,25 @@ class SuspendFlags
};
/**
- * Allocate file descriptors, set signal handlers for SIGINT and
- * SIGTERM. Once the returned guard is freed, it will
- * automatically deactivate signal handling.
+ * Allocate file descriptors, set signal handlers for the chosen
+ * signals (SIGINT and SIGTERM by default). Once the returned
+ * guard is freed, it will automatically deactivate signal
+ * handling.
+ *
+ * Additional signals like SIGURG or SIGIO may also be used. It is
+ * unlikely that any library used by SyncEvolution occupies these
+ * signals for its own use.
+ *
+ * Only SIGINT and SIGTERM influence the overall State. All
+ * received signals, including SIGINT and SIGTERM, are recorded
+ * and can be retrieved via getReceivedSignals().
+ *
+ * It is possible to call activate multiple times. All following
+ * calls do nothing except creating a new reference to the same
+ * guard. In particular they cannot add or remove handled
+ * signals.
*/
- boost::shared_ptr<Guard> activate();
+ boost::shared_ptr<Guard> activate(uint32_t sigmask = (1<<SIGINT)|(1<<SIGTERM));
/**
* Retrieve state changes pushed into pipe by signal
@@ -162,12 +184,18 @@ class SuspendFlags
/** state as observed by signal handler */
State m_state;
+ /** or-ed bit mask of all received signals */
+ uint32_t m_receivedSignals;
+
/** time is measured inside signal handler */
time_t m_lastSuspend;
int m_senderFD, m_receiverFD;
- struct sigaction m_oldSigInt, m_oldSigTerm;
+ // For the sake of simplicity we only support signals in the 1-31 range.
+ uint32_t m_activeSignals;
+ struct sigaction m_oldSignalHandlers[32];
+ boost::weak_ptr<Guard> m_guard;
boost::weak_ptr<StateBlocker> m_suspendBlocker, m_abortBlocker;
boost::shared_ptr<StateBlocker> block(boost::weak_ptr<StateBlocker> &blocker);
};