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:
parent
9d03c2b08b
commit
50f621b241
11 changed files with 134 additions and 51 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue