aboutsummaryrefslogtreecommitdiff
path: root/src/libutil/signals.hh
diff options
context:
space:
mode:
authorJade Lovelace <lix@jade.fyi>2024-03-09 22:36:47 -0800
committerJade Lovelace <lix@jade.fyi>2024-03-11 00:52:09 -0700
commit8be7030299699edd3732411d8d97f237a67fbc08 (patch)
tree118f6c5c8dfac9ae9c65f54c5eb5942323324b17 /src/libutil/signals.hh
parenta9b813cc3bcf89f03de0db96fc2e88d1c83b8303 (diff)
util.hh: split out signals stuff
Copies part of the changes of ac89bb064aeea85a62b82a6daf0ecca7190a28b7 Change-Id: I9ce601875cd6d4db5eb1132d7835c5bab9f126d8
Diffstat (limited to 'src/libutil/signals.hh')
-rw-r--r--src/libutil/signals.hh93
1 files changed, 93 insertions, 0 deletions
diff --git a/src/libutil/signals.hh b/src/libutil/signals.hh
new file mode 100644
index 000000000..c58dc37cf
--- /dev/null
+++ b/src/libutil/signals.hh
@@ -0,0 +1,93 @@
+#pragma once
+/// @file
+
+#include "types.hh"
+#include "error.hh"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <signal.h>
+
+#include <atomic>
+#include <functional>
+#include <sstream>
+
+namespace nix {
+
+/* User interruption. */
+
+extern std::atomic<bool> _isInterrupted;
+
+extern thread_local std::function<bool()> interruptCheck;
+
+void setInterruptThrown();
+
+void _interrupted();
+
+void inline checkInterrupt()
+{
+ if (_isInterrupted || (interruptCheck && interruptCheck()))
+ _interrupted();
+}
+
+MakeError(Interrupted, BaseError);
+
+void restoreSignals();
+
+
+/**
+ * Start a thread that handles various signals. Also block those signals
+ * on the current thread (and thus any threads created by it).
+ * Saves the signal mask before changing the mask to block those signals.
+ * See saveSignalMask().
+ */
+void startSignalHandlerThread();
+
+/**
+ * Saves the signal mask, which is the signal mask that nix will restore
+ * before creating child processes.
+ * See setChildSignalMask() to set an arbitrary signal mask instead of the
+ * current mask.
+ */
+void saveSignalMask();
+
+/**
+ * Sets the signal mask. Like saveSignalMask() but for a signal set that doesn't
+ * necessarily match the current thread's mask.
+ * See saveSignalMask() to set the saved mask to the current mask.
+ */
+void setChildSignalMask(sigset_t *sigs);
+
+struct InterruptCallback
+{
+ virtual ~InterruptCallback() { };
+};
+
+/**
+ * Register a function that gets called on SIGINT (in a non-signal
+ * context).
+ */
+std::unique_ptr<InterruptCallback> createInterruptCallback(
+ std::function<void()> callback);
+
+void triggerInterrupt();
+
+/**
+ * A RAII class that causes the current thread to receive SIGUSR1 when
+ * the signal handler thread receives SIGINT. That is, this allows
+ * SIGINT to be multiplexed to multiple threads.
+ */
+struct ReceiveInterrupts
+{
+ pthread_t target;
+ std::unique_ptr<InterruptCallback> callback;
+
+ ReceiveInterrupts()
+ : target(pthread_self())
+ , callback(createInterruptCallback([&]() { pthread_kill(target, SIGUSR1); }))
+ { }
+};
+
+};