summaryrefslogtreecommitdiffstats
path: root/sigchainlib
diff options
context:
space:
mode:
Diffstat (limited to 'sigchainlib')
-rw-r--r--sigchainlib/sigchain.cc53
-rw-r--r--sigchainlib/sigchain.h3
-rw-r--r--sigchainlib/sigchain_dummy.cc6
3 files changed, 58 insertions, 4 deletions
diff --git a/sigchainlib/sigchain.cc b/sigchainlib/sigchain.cc
index 0359ed3db..1391d147a 100644
--- a/sigchainlib/sigchain.cc
+++ b/sigchainlib/sigchain.cc
@@ -39,7 +39,7 @@ typedef int (*SigActionFnPtr)(int, const struct sigaction*, struct sigaction*);
class SignalAction {
public:
- SignalAction() : claimed_(false), uses_old_style_(false) {
+ SignalAction() : claimed_(false), uses_old_style_(false), special_handler_(nullptr) {
}
// Claim the signal and keep the action specified.
@@ -77,10 +77,19 @@ class SignalAction {
return uses_old_style_;
}
+ void SetSpecialHandler(SpecialSignalHandlerFn fn) {
+ special_handler_ = fn;
+ }
+
+ SpecialSignalHandlerFn GetSpecialHandler() {
+ return special_handler_;
+ }
+
private:
- struct sigaction action_; // Action to be performed.
- bool claimed_; // Whether signal is claimed or not.
- bool uses_old_style_; // Action is created using signal(). Use sa_handler.
+ struct sigaction action_; // Action to be performed.
+ bool claimed_; // Whether signal is claimed or not.
+ bool uses_old_style_; // Action is created using signal(). Use sa_handler.
+ SpecialSignalHandlerFn special_handler_; // A special handler executed before user handlers.
};
// User's signal handlers
@@ -109,9 +118,16 @@ static void CheckSignalValid(int signal) {
}
}
+// Sigchainlib's own handler so we can ensure a managed handler is called first even if nobody
+// claimed a chain. Simply forward to InvokeUserSignalHandler.
+static void sigchainlib_managed_handler_sigaction(int sig, siginfo_t* info, void* context) {
+ InvokeUserSignalHandler(sig, info, context);
+}
+
// Claim a signal chain for a particular signal.
extern "C" void ClaimSignalChain(int signal, struct sigaction* oldaction) {
CheckSignalValid(signal);
+
user_sigactions[signal].Claim(*oldaction);
}
@@ -131,6 +147,15 @@ extern "C" void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context)
abort();
}
+ // Do we have a managed handler? If so, run it first.
+ SpecialSignalHandlerFn managed = user_sigactions[sig].GetSpecialHandler();
+ if (managed != nullptr) {
+ // Call the handler. If it succeeds, we're done.
+ if (managed(sig, info, context)) {
+ return;
+ }
+ }
+
const struct sigaction& action = user_sigactions[sig].GetAction();
if (user_sigactions[sig].OldStyle()) {
if (action.sa_handler != nullptr) {
@@ -303,5 +328,25 @@ extern "C" void InitializeSignalChain() {
initialized = true;
}
+extern "C" void SetSpecialSignalHandlerFn(int signal, SpecialSignalHandlerFn fn) {
+ CheckSignalValid(signal);
+
+ // Set the managed_handler.
+ user_sigactions[signal].SetSpecialHandler(fn);
+
+ // In case the chain isn't claimed, claim it for ourself so we can ensure the managed handler
+ // goes first.
+ if (!user_sigactions[signal].IsClaimed()) {
+ struct sigaction tmp;
+ tmp.sa_sigaction = sigchainlib_managed_handler_sigaction;
+ sigemptyset(&tmp.sa_mask);
+ tmp.sa_flags = SA_SIGINFO | SA_ONSTACK;
+#if !defined(__APPLE__) && !defined(__mips__)
+ tmp.sa_restorer = nullptr;
+#endif
+ user_sigactions[signal].Claim(tmp);
+ }
+}
+
} // namespace art
diff --git a/sigchainlib/sigchain.h b/sigchainlib/sigchain.h
index 79b76a74d..01ccedf49 100644
--- a/sigchainlib/sigchain.h
+++ b/sigchainlib/sigchain.h
@@ -27,6 +27,9 @@ extern "C" void ClaimSignalChain(int signal, struct sigaction* oldaction);
extern "C" void UnclaimSignalChain(int signal);
+typedef bool (*SpecialSignalHandlerFn)(int, siginfo_t*, void*);
+extern "C" void SetSpecialSignalHandlerFn(int signal, SpecialSignalHandlerFn fn);
+
extern "C" void InvokeUserSignalHandler(int sig, siginfo_t* info, void* context);
extern "C" void EnsureFrontOfChain(int signal, struct sigaction* expected_action);
diff --git a/sigchainlib/sigchain_dummy.cc b/sigchainlib/sigchain_dummy.cc
index 70a4f7116..8495a5417 100644
--- a/sigchainlib/sigchain_dummy.cc
+++ b/sigchainlib/sigchain_dummy.cc
@@ -78,6 +78,12 @@ extern "C" void EnsureFrontOfChain(int signal ATTRIBUTE_UNUSED,
abort();
}
+extern "C" void SetSpecialSignalHandlerFn(int signal ATTRIBUTE_UNUSED,
+ SpecialSignalHandlerFn fn ATTRIBUTE_UNUSED) {
+ log("SetSpecialSignalHandlerFn is not exported by the main executable.");
+ abort();
+}
+
#pragma GCC diagnostic pop
} // namespace art