1
0
Fork 0
mirror of https://github.com/NixOS/nix synced 2025-06-29 06:21:14 +02:00

Better signals interface

This avoids some CPP and accidentally using Unix stuff in client code.
This commit is contained in:
John Ericson 2024-04-04 12:25:01 -04:00
parent 9d03c2b08b
commit 50f621b241
11 changed files with 134 additions and 51 deletions

View file

@ -50,7 +50,7 @@ public:
*/
if (count == 0) continue;
if (fds[0].revents & POLLHUP) {
triggerInterrupt();
unix::triggerInterrupt();
break;
}
/* This will only happen on macOS. We sleep a bit to

View file

@ -1,5 +1,14 @@
#pragma once
///@file
/**
* @file
*
* Implementation of some inline definitions for Unix signals, and also
* some extra Unix-only interfaces.
*
* (The only reason everything about signals isn't Unix-only is some
* no-op definitions are provided on Windows to avoid excess CPP in
* downstream code.)
*/
#include "types.hh"
#include "error.hh"
@ -24,22 +33,20 @@ namespace nix {
/* User interruption. */
namespace unix {
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);
/**
* 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);
/**
* Start a thread that handles various signals. Also block those signals
@ -63,27 +70,27 @@ void saveSignalMask();
*/
void restoreSignals();
/**
* 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();
}
static inline void setInterrupted(bool isInterrupted)
{
unix::_isInterrupted = isInterrupted;
}
static inline bool getInterrupted()
{
return unix::_isInterrupted;
}
void inline checkInterrupt()
{
using namespace unix;
if (_isInterrupted || (interruptCheck && interruptCheck()))
_interrupted();
}
/**
* A RAII class that causes the current thread to receive SIGUSR1 when
* the signal handler thread receives SIGINT. That is, this allows

View file

@ -8,17 +8,22 @@
namespace nix {
std::atomic<bool> _isInterrupted = false;
using namespace unix;
std::atomic<bool> unix::_isInterrupted = false;
namespace unix {
static thread_local bool interruptThrown = false;
thread_local std::function<bool()> interruptCheck;
}
thread_local std::function<bool()> unix::interruptCheck;
void setInterruptThrown()
{
interruptThrown = true;
unix::interruptThrown = true;
}
void _interrupted()
void unix::_interrupted()
{
/* Block user interrupts while an exception is being handled.
Throwing an exception while another exception is being handled
@ -65,7 +70,7 @@ static void signalHandlerThread(sigset_t set)
}
}
void triggerInterrupt()
void unix::triggerInterrupt()
{
_isInterrupted = true;
@ -96,7 +101,7 @@ void triggerInterrupt()
static sigset_t savedSignalMask;
static bool savedSignalMaskIsSet = false;
void setChildSignalMask(sigset_t * sigs)
void unix::setChildSignalMask(sigset_t * sigs)
{
assert(sigs); // C style function, but think of sigs as a reference
@ -115,14 +120,14 @@ void setChildSignalMask(sigset_t * sigs)
savedSignalMaskIsSet = true;
}
void saveSignalMask() {
void unix::saveSignalMask() {
if (sigprocmask(SIG_BLOCK, nullptr, &savedSignalMask))
throw SysError("querying signal mask");
savedSignalMaskIsSet = true;
}
void startSignalHandlerThread()
void unix::startSignalHandlerThread()
{
updateWindowSize();
@ -141,7 +146,7 @@ void startSignalHandlerThread()
std::thread(signalHandlerThread, set).detach();
}
void restoreSignals()
void unix::restoreSignals()
{
// If startSignalHandlerThread wasn't called, that means we're not running
// in a proper libmain process, but a process that presumably manages its