[signals] use an alternate signal stack #2424

pull/2427/head
nick black 3 years ago
parent 59e3e00e3d
commit 9190d3bdfa
No known key found for this signature in database
GPG Key ID: 5F43400C21CBFACC

@ -9,6 +9,7 @@
#include "visual-details.h"
#include "notcurses/direct.h"
#include "internal.h"
#include "unixsig.h"
// conform to the foreground and background channels of 'channels'
static int

@ -3,6 +3,7 @@
#include <unistd.h>
#include "automaton.h"
#include "internal.h"
#include "unixsig.h"
#include "render.h"
#include "in.h"
@ -2161,6 +2162,7 @@ read_inputs_nblock(inputctx* ictx){
static void*
input_thread(void* vmarshall){
setup_alt_sig_stack();
inputctx* ictx = vmarshall;
if(prep_all_keys(ictx) || build_cflow_automaton(ictx)){
ictx->failed = true;

@ -1510,14 +1510,6 @@ int get_tty_fd(FILE* ttyfp);
// If you only want to check n < 4 channels, just duplicate one.
bool check_gradient_args(uint64_t ul, uint64_t ur, uint64_t bl, uint64_t br);
int setup_signals(void* nc, bool no_quit_sigs, bool no_winch_sig,
int(*handler)(void*));
int drop_signals(void* nc);
// block a few signals for the duration of a write to the terminal.
int block_signals(sigset_t* old_blocked_signals);
int unblock_signals(const sigset_t* old_blocked_signals);
// takes a signed starting coordinate (where -1 indicates the cursor's
// position), and an unsigned vector (where 0 indicates "everything
// remaining", i.e. to the right and below). returns 0 iff everything

@ -16,6 +16,7 @@
#include <inttypes.h>
#include <notcurses/direct.h>
#include "compat/compat.h"
#include "unixsig.h"
#include "banner.h"
#define ESC "\x1b"

@ -3,6 +3,7 @@
#include <unistd.h>
#include <notcurses/direct.h>
#include "internal.h"
#include "unixsig.h"
sig_atomic_t sigcont_seen_for_render = 0;

@ -50,6 +50,9 @@ static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
static bool handling_winch;
static bool handling_fatals;
// alternate signal stack (per-thread; call setup_alt_sig_stack() to use)
static stack_t alt_signal_stack;
// saved signal actions, restored in drop_signals() FIXME make an array
static struct sigaction old_winch;
static struct sigaction old_cont;
@ -104,6 +107,15 @@ int drop_signals(void* nc){
sigaction(SIGTERM, &old_term, NULL);
handling_fatals = false;
}
if(alt_signal_stack.ss_sp){
alt_signal_stack.ss_flags = SS_DISABLE;
if(sigaltstack(&alt_signal_stack, NULL)){
if(errno != EPERM){
fprintf(stderr, "couldn't remove alternate signal stack (%s)\n", strerror(errno));
}
}
free(alt_signal_stack.ss_sp);
}
ret = !atomic_compare_exchange_strong(&signal_nc, &expected, NULL);
}
pthread_mutex_unlock(&lock);
@ -145,6 +157,16 @@ fatal_handler(int signo, siginfo_t* siginfo, void* v){
}
}
// the alternate signal stack is a thread property; any other threads we
// create ought go ahead and install the same alternate signal stack.
void setup_alt_sig_stack(void){
pthread_mutex_lock(&lock);
if(alt_signal_stack.ss_sp){
sigaltstack(&alt_signal_stack, NULL);
}
pthread_mutex_unlock(&lock);
}
// this both sets up our signal handlers (unless that behavior has been
// inhibited), and ensures that only one notcurses/ncdirect context is active
// at any given time.
@ -171,7 +193,7 @@ int setup_signals(void* vnc, bool no_quit_sigs, bool no_winch_sigs,
if(ret){
atomic_store(&signal_nc, NULL);
pthread_mutex_unlock(&lock);
fprintf(stderr, "Error installing term signal handler (%s)\n", strerror(errno));
fprintf(stderr, "error installing term signal handler (%s)\n", strerror(errno));
return -1;
}
// we're not going to be restoring the old mask at exit, as who knows,
@ -180,6 +202,17 @@ int setup_signals(void* vnc, bool no_quit_sigs, bool no_winch_sigs,
handling_winch = true;
}
if(!no_quit_sigs){
alt_signal_stack.ss_size = SIGSTKSZ * 4;
alt_signal_stack.ss_sp = malloc(alt_signal_stack.ss_size);
if(alt_signal_stack.ss_sp == NULL){
fprintf(stderr, "warning: couldn't create alternate signal stack (%s)\n", strerror(errno));
}else{
if(sigaltstack(&alt_signal_stack, NULL)){
fprintf(stderr, "warning: couldn't set up alternate signal stack (%s)\n", strerror(errno));
free(alt_signal_stack.ss_sp);
alt_signal_stack.ss_sp = NULL;
}
}
memset(&sa, 0, sizeof(sa));
fatal_callback = handler;
sa.sa_sigaction = fatal_handler;
@ -191,7 +224,8 @@ int setup_signals(void* vnc, bool no_quit_sigs, bool no_winch_sigs,
sigaddset(&sa.sa_mask, SIGQUIT);
sigaddset(&sa.sa_mask, SIGSEGV);
sigaddset(&sa.sa_mask, SIGTERM);
sa.sa_flags = SA_SIGINFO | SA_RESETHAND; // don't try fatal signals twice
// don't try to handle fatal signals twice, and use our alternative stack
sa.sa_flags = SA_ONSTACK | SA_SIGINFO | SA_RESETHAND;
int ret = 0;
ret |= sigaction(SIGABRT, &sa, &old_abrt);
ret |= sigaction(SIGBUS, &sa, &old_bus);
@ -210,7 +244,7 @@ int setup_signals(void* vnc, bool no_quit_sigs, bool no_winch_sigs,
handling_fatals = true;
}
// we don't really want to go blocking SIGSEGV etc while we write, but
// we *do* temporarily block user-inititated signals.
// we *do* temporarily block user-initiated signals.
sigaddset(&wblock_signals, SIGINT);
sigaddset(&wblock_signals, SIGTERM);
sigaddset(&wblock_signals, SIGQUIT);

@ -0,0 +1,26 @@
#ifndef NOTCURSES_UNIXSIG
#define NOTCURSES_UNIXSIG
#ifdef __cplusplus
extern "C" {
#endif
#include <signal.h>
int setup_signals(void* nc, bool no_quit_sigs, bool no_winch_sig,
int(*handler)(void*));
int drop_signals(void* nc);
// block a few signals for the duration of a write to the terminal.
int block_signals(sigset_t* old_blocked_signals);
int unblock_signals(const sigset_t* old_blocked_signals);
// the alternate signal stack is a thread property; any other threads we
// create ought go ahead and install the same alternate signal stack.
void setup_alt_sig_stack(void);
#ifdef __cplusplus
}
#endif
#endif
Loading…
Cancel
Save