Skip to content

Commit

Permalink
libutil: Provide alternatives to startSignalHandlerThread
Browse files Browse the repository at this point in the history
  • Loading branch information
roberth committed Feb 1, 2023
1 parent ceef5f9 commit a2a4b4f
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 4 deletions.
43 changes: 41 additions & 2 deletions src/libutil/util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1699,13 +1699,38 @@ void triggerInterrupt()
}

static sigset_t savedSignalMask;
static bool savedSignalMaskIsSet = false;

void setChildSignalMask(sigset_t *sigs) {
assert(sigs); // C style function, but think of sigs as a reference

#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE
sigemptyset(&savedSignalMask);
// There's no "assign" or "copy" function, so we rely on (math) idempotence
// of the or operator: a or a = a.
sigorset(&savedSignalMask, sigs, sigs);
#else
// Without sigorset, our best bet is to assume that sigset_t is a type that
// can be assigned directly, such as is the case for a sigset_t defined as
// an integer type.
savedSignalMask = *sigs;
#endif

savedSignalMaskIsSet = true;
}

void saveSignalMask() {
if (sigprocmask(SIG_BLOCK, nullptr, &savedSignalMask))
throw SysError("querying signal mask");

savedSignalMaskIsSet = true;
}

void startSignalHandlerThread()
{
updateWindowSize();

if (sigprocmask(SIG_BLOCK, nullptr, &savedSignalMask))
throw SysError("querying signal mask");
saveSignalMask();

sigset_t set;
sigemptyset(&set);
Expand All @@ -1722,6 +1747,20 @@ void startSignalHandlerThread()

static void restoreSignals()
{
// If startSignalHandlerThread wasn't called, that means we're not running
// in a proper libmain process, but a process that presumably manages its
// own signal handlers. Such a process should call either
// - initNix(), to be a proper libmain process
// - startSignalHandlerThread(), to resemble libmain regarding signal
// handling only
// - saveSignalMask(), for processes that define their own signal handling
// thread
// TODO: Warn about this? Have a default signal mask? The latter depends on
// whether we should generally inherit signal masks from the caller.
// I don't know what the larger unix ecosystem expects from us here.
if (!savedSignalMaskIsSet)
return;

if (sigprocmask(SIG_SETMASK, &savedSignalMask, nullptr))
throw SysError("restoring signals");
}
Expand Down
20 changes: 18 additions & 2 deletions src/libutil/util.hh
Original file line number Diff line number Diff line change
Expand Up @@ -340,7 +340,10 @@ void setStackSize(size_t stackSize);


/* Restore the original inherited Unix process context (such as signal
masks, stack size). */
masks, stack size).
See startSignalHandlerThread(), saveSignalMask().
*/
void restoreProcessContext(bool restoreMounts = true);

/* Save the current mount namespace. Ignored if called more than
Expand Down Expand Up @@ -643,9 +646,22 @@ class Callback;


/* Start a thread that handles various signals. Also block those signals
on the current thread (and thus any threads created by it). */
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() { };
Expand Down

0 comments on commit a2a4b4f

Please sign in to comment.