Notcurses 3.0.16
a blingful library for TUIs and character graphics
Loading...
Searching...
No Matches
unixsig.c File Reference
#include <stdio.h>
#include <signal.h>
#include <stdatomic.h>
#include "internal.h"
Include dependency graph for unixsig.c:

Go to the source code of this file.

Functions

int block_signals (sigset_t *old_blocked_signals)
 
int unblock_signals (const sigset_t *old_blocked_signals)
 
int drop_signals (void *nc, void **altstack)
 
void setup_alt_sig_stack (void)
 
int setup_signals (void *vnc, bool no_quit_sigs, bool no_winch_sigs, int(*handler)(void *, void **, int))
 

Function Documentation

◆ block_signals()

int block_signals ( sigset_t *  old_blocked_signals)

Definition at line 82 of file unixsig.c.

82 {
83 if(pthread_sigmask(SIG_BLOCK, &wblock_signals, old_blocked_signals)){
84 return -1;
85 }
86 return 0;
87}

◆ drop_signals()

int drop_signals ( void *  nc,
void **  altstack 
)

Definition at line 104 of file unixsig.c.

104 {
105 int ret = -1;
106 void* expected = nc;
107 if(!altstack){ // came in via signal handler
108 return 0;
109 }
110 *altstack = NULL;
111 pthread_mutex_lock(&lock);
112 if(atomic_compare_exchange_strong(&signal_nc, &expected, nc)){
113 if(handling_winch){
114 sigaction(SIGWINCH, &old_winch, NULL);
115 sigaction(SIGCONT, &old_cont, NULL);
116 handling_winch = false;
117 }
118 if(handling_fatals){
119 sigaction(SIGABRT, &old_abrt, NULL);
120 sigaction(SIGBUS, &old_bus, NULL);
121 sigaction(SIGFPE, &old_fpe, NULL);
122 sigaction(SIGILL, &old_ill, NULL);
123 sigaction(SIGINT, &old_int, NULL);
124 sigaction(SIGQUIT, &old_quit, NULL);
125 sigaction(SIGSEGV, &old_segv, NULL);
126 sigaction(SIGTERM, &old_term, NULL);
127 handling_fatals = false;
128 }
129 if(alt_signal_stack.ss_sp){
130 alt_signal_stack.ss_flags = SS_DISABLE;
131 if(sigaltstack(&alt_signal_stack, NULL)){
132 if(errno != EPERM){
133 fprintf(stderr, "couldn't remove alternate signal stack (%s)", strerror(errno));
134 }
135 }
136 }
137 *altstack = alt_signal_stack.ss_sp;
138 alt_signal_stack.ss_sp = NULL;
139 ret = !atomic_compare_exchange_strong(&signal_nc, &expected, NULL);
140 }
141 pthread_mutex_unlock(&lock);
142 if(ret){
143 fprintf(stderr, "signals weren't registered for %p (had %p)", nc, expected);
144 }
145 // we might not have established any handlers in setup_signals(); always
146 // return 0 here, for now...
147 return 0;
148}
return NULL
Definition termdesc.h:229
Here is the caller graph for this function:

◆ setup_alt_sig_stack()

void setup_alt_sig_stack ( void  )

Definition at line 182 of file unixsig.c.

182 {
183 pthread_mutex_lock(&lock);
184 if(alt_signal_stack.ss_sp){
185 if(sigaltstack(&alt_signal_stack, NULL)){
186 logerror("error installing alternate signal stack (%s)", strerror(errno));
187 }
188 }
189 pthread_mutex_unlock(&lock);
190}
#define logerror(fmt,...)
Definition logging.h:32

◆ setup_signals()

int setup_signals ( void *  vnc,
bool  no_quit_sigs,
bool  no_winch_sigs,
int(*)(void *, void **, int)  handler 
)

Definition at line 195 of file unixsig.c.

196 {
197 notcurses* nc = vnc;
198 void* expected = NULL;
199 struct sigaction sa;
200 // don't register ourselves if we don't intend to set up signal handlers
201 // we expect NULL (nothing registered), and want to register nc
202 if(!atomic_compare_exchange_strong(&signal_nc, &expected, nc)){
203 fprintf(stderr, "%p is already registered for signals (provided %p)" NL, expected, nc);
204 return -1;
205 }
206 pthread_mutex_lock(&lock);
207 if(!no_winch_sigs){
208 memset(&sa, 0, sizeof(sa));
209 sa.sa_handler = sigwinch_handler;
210 sigaddset(&sa.sa_mask, SIGWINCH);
211 sigaddset(&sa.sa_mask, SIGCONT);
212 int ret = 0;
213 ret |= sigaction(SIGWINCH, &sa, &old_winch);
214 ret |= sigaction(SIGCONT, &sa, &old_cont);
215 if(ret){
216 atomic_store(&signal_nc, NULL);
217 pthread_mutex_unlock(&lock);
218 fprintf(stderr, "error installing term signal handler (%s)" NL, strerror(errno));
219 return -1;
220 }
221 // we're not going to be restoring the old mask at exit, as who knows,
222 // they might have masked more things afterwards.
223 pthread_sigmask(SIG_BLOCK, &sa.sa_mask, NULL);
224 handling_winch = true;
225 }
226 if(!no_quit_sigs){
227 memset(&sa, 0, sizeof(sa));
228// AddressSanitizer doesn't want us to use sigaltstack(). we could force everyone
229// to export ASAN_OPTIONS=use_sigaltstack=0, or just not fuck with the alternate
230// signal stack when built with ASAN.
231#ifndef USE_ASAN
232#ifdef _SC_SIGSTKSZ
233 long minstksz = sysconf(_SC_SIGSTKSZ);
234#else
235 long minstksz = 0;
236#endif
237 if(minstksz <= 0){
238 minstksz = SIGSTKSZ * 4;
239 }
240 alt_signal_stack.ss_sp = malloc(minstksz);
241 if(alt_signal_stack.ss_sp == NULL){
242 fprintf(stderr, "warning: couldn't create %ldB alternate signal stack (%s)" NL, minstksz, strerror(errno));
243 }else{
244 alt_signal_stack.ss_size = minstksz;
245 if(sigaltstack(&alt_signal_stack, NULL)){
246 fprintf(stderr, "warning: couldn't set up %ldB alternate signal stack (%s)" NL, minstksz, strerror(errno));
247 free(alt_signal_stack.ss_sp);
248 alt_signal_stack.ss_sp = NULL;
249 alt_signal_stack.ss_size = 0;
250 }else{
251 sa.sa_flags = SA_ONSTACK;
252 }
253 }
254#endif
255 fatal_callback = handler;
256 sa.sa_sigaction = fatal_handler;
257 sigaddset(&sa.sa_mask, SIGABRT);
258 sigaddset(&sa.sa_mask, SIGBUS);
259 sigaddset(&sa.sa_mask, SIGFPE);
260 sigaddset(&sa.sa_mask, SIGILL);
261 sigaddset(&sa.sa_mask, SIGINT);
262 sigaddset(&sa.sa_mask, SIGQUIT);
263 sigaddset(&sa.sa_mask, SIGSEGV);
264 sigaddset(&sa.sa_mask, SIGTERM);
265 // don't try to handle fatal signals twice, and use our alternative stack
266 sa.sa_flags |= SA_SIGINFO | SA_RESETHAND;
267 int ret = 0;
268 ret |= sigaction(SIGABRT, &sa, &old_abrt);
269 ret |= sigaction(SIGBUS, &sa, &old_bus);
270 ret |= sigaction(SIGFPE, &sa, &old_fpe);
271 ret |= sigaction(SIGILL, &sa, &old_ill);
272 ret |= sigaction(SIGINT, &sa, &old_int);
273 ret |= sigaction(SIGQUIT, &sa, &old_quit);
274 ret |= sigaction(SIGSEGV, &sa, &old_segv);
275 ret |= sigaction(SIGTERM, &sa, &old_term);
276 if(ret){
277 atomic_store(&signal_nc, NULL);
278 pthread_mutex_unlock(&lock);
279 fprintf(stderr, "error installing fatal signal handlers (%s)" NL, strerror(errno));
280 return -1;
281 }
282 handling_fatals = true;
283 }
284 // we don't really want to go blocking SIGSEGV etc while we write, but
285 // we *do* temporarily block user-initiated signals.
286 sigaddset(&wblock_signals, SIGINT);
287 sigaddset(&wblock_signals, SIGTERM);
288 sigaddset(&wblock_signals, SIGQUIT);
289 pthread_mutex_unlock(&lock);
290 return 0;
291}
void sigwinch_handler(int signo)
Definition in.c:31
Here is the call graph for this function:
Here is the caller graph for this function:

◆ unblock_signals()

int unblock_signals ( const sigset_t *  old_blocked_signals)

Definition at line 89 of file unixsig.c.

89 {
90 if(pthread_sigmask(SIG_SETMASK, old_blocked_signals, NULL)){
91 return -1;
92 }
93 return 0;
94}