mirror of
https://github.com/dankamongmen/notcurses
synced 2025-03-10 01:29:05 -04:00
[signals] use an alternate signal stack #2424
This commit is contained in:
parent
59e3e00e3d
commit
9190d3bdfa
@ -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);
|
26
src/lib/unixsig.h
Normal file
26
src/lib/unixsig.h
Normal file
@ -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…
x
Reference in New Issue
Block a user