NeoMutt  2025-01-09-117-gace867
Teaching an old dog new tricks
DOXYGEN
Loading...
Searching...
No Matches
signal2.h File Reference

Signal handling. More...

#include "config.h"
#include <signal.h>
#include <stdbool.h>
+ Include dependency graph for signal2.h:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Macros

#define ASSERT_STOP   (*(volatile int *) 0 = 0)
 
#define ASSERT(COND)
 

Typedefs

typedef void(* sig_handler_t) (int sig)
 

Functions

static void show_backtrace (void)
 
void assertion_dump (const char *file, int line, const char *func, const char *cond)
 Dump some debugging info before we stop the program.
 
void mutt_sig_allow_interrupt (bool allow)
 Allow/disallow Ctrl-C (SIGINT)
 
void mutt_sig_block (void)
 Block signals during critical operations.
 
void mutt_sig_block_system (void)
 Block signals before calling exec()
 
void mutt_sig_empty_handler (int sig)
 Dummy signal handler.
 
void mutt_sig_exit_handler (int sig)
 Notify the user and shutdown gracefully.
 
void mutt_sig_init (sig_handler_t sig_fn, sig_handler_t exit_fn, sig_handler_t segv_fn)
 Initialise the signal handling.
 
void mutt_sig_reset_child_signals (void)
 Reset ignored signals back to the default.
 
void mutt_sig_unblock (void)
 Restore previously blocked signals.
 
void mutt_sig_unblock_system (bool restore)
 Restore previously blocked signals.
 

Variables

volatile sig_atomic_t SigInt
 true after SIGINT is received
 
volatile sig_atomic_t SigWinch
 true after SIGWINCH is received
 
sig_handler_t OldSegvHandler
 Old SEGV handler, it could have been set by ASAN.
 

Detailed Description

Signal handling.

Authors
  • Richard Russon

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see http://www.gnu.org/licenses/.

Definition in file signal2.h.

Macro Definition Documentation

◆ ASSERT_STOP

#define ASSERT_STOP   (*(volatile int *) 0 = 0)

Definition at line 58 of file signal2.h.

◆ ASSERT

#define ASSERT (   COND)
Value:
do \
{ \
if (!(COND)) \
{ \
assertion_dump(__FILE__, __LINE__, __func__, #COND); \
} \
} while (false);
#define ASSERT_STOP
Definition: signal2.h:58

Definition at line 60 of file signal2.h.

Typedef Documentation

◆ sig_handler_t

typedef void(* sig_handler_t) (int sig)

Definition at line 46 of file signal2.h.

Function Documentation

◆ show_backtrace()

static void show_backtrace ( void  )
inlinestatic

Definition at line 33 of file signal2.h.

33{} // LCOV_EXCL_LINE

◆ assertion_dump()

void assertion_dump ( const char *  file,
int  line,
const char *  func,
const char *  cond 
)

Dump some debugging info before we stop the program.

Parameters
fileSource file
lineLine of source
funcFunction
condAssertion condition

Definition at line 362 of file signal.c.

363{
364 endwin();
366 printf("%s:%d:%s() -- assertion failed (%s)\n", file, line, func, cond);
367}
void show_backtrace(void)
Log the program's call stack.
Definition: backtrace.c:39
int endwin(void)
+ Here is the call graph for this function:

◆ mutt_sig_allow_interrupt()

void mutt_sig_allow_interrupt ( bool  allow)

Allow/disallow Ctrl-C (SIGINT)

Parameters
allowTrue to allow Ctrl-C to interrupt signals

Allow the user to interrupt some long operations.

Definition at line 316 of file signal.c.

317{
318 struct sigaction sa = { 0 };
319
320 sa.sa_handler = SigHandler;
321#ifdef SA_RESTART
322 if (!allow)
323 sa.sa_flags |= SA_RESTART;
324#endif
325 sigaction(SIGINT, &sa, NULL);
326}
static sig_handler_t SigHandler
Function to handle other signals, e.g. SIGINT (2)
Definition: signal.c:60
+ Here is the caller graph for this function:

◆ mutt_sig_block()

void mutt_sig_block ( void  )

Block signals during critical operations.

It's important that certain signals don't interfere with critical operations. Call mutt_sig_unblock() to restore the signals' behaviour.

Definition at line 228 of file signal.c.

229{
230 if (SignalsBlocked)
231 return;
232
233 sigemptyset(&Sigset);
234 sigaddset(&Sigset, SIGTERM);
235 sigaddset(&Sigset, SIGHUP);
236 sigaddset(&Sigset, SIGTSTP);
237 sigaddset(&Sigset, SIGINT);
238 sigaddset(&Sigset, SIGWINCH);
239 sigprocmask(SIG_BLOCK, &Sigset, 0);
240 SignalsBlocked = true;
241}
static sigset_t Sigset
A set of signals used by mutt_sig_block(), mutt_sig_unblock()
Definition: signal.c:42
static bool SignalsBlocked
true when signals are blocked, e.g.
Definition: signal.c:53
+ Here is the caller graph for this function:

◆ mutt_sig_block_system()

void mutt_sig_block_system ( void  )

Block signals before calling exec()

It's important that certain signals don't interfere with the child process. Call mutt_sig_unblock_system() to restore the signals' behaviour.

Definition at line 261 of file signal.c.

262{
264 return;
265
266 struct sigaction sa = { 0 };
267
268 /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD before exec */
269 sa.sa_handler = SIG_IGN;
270 sa.sa_flags = 0;
271 sigemptyset(&sa.sa_mask);
272 sigaction(SIGINT, &sa, &SysOldInt);
273 sigaction(SIGQUIT, &sa, &SysOldQuit);
274
275 sigemptyset(&SigsetSys);
276 sigaddset(&SigsetSys, SIGCHLD);
277 sigprocmask(SIG_BLOCK, &SigsetSys, 0);
278 SysSignalsBlocked = true;
279}
static bool SysSignalsBlocked
true when system signals are blocked, e.g.
Definition: signal.c:57
static struct sigaction SysOldQuit
Backup of SIGQUIT handler, when mutt_sig_block_system() is called.
Definition: signal.c:49
static sigset_t SigsetSys
A set of signals used by mutt_sig_block_system(), mutt_sig_unblock_system()
Definition: signal.c:44
static struct sigaction SysOldInt
Backup of SIGINT handler, when mutt_sig_block_system() is called.
Definition: signal.c:47
+ Here is the caller graph for this function:

◆ mutt_sig_empty_handler()

void mutt_sig_empty_handler ( int  sig)

Dummy signal handler.

Parameters
sigSignal number, e.g. SIGINT

Useful for signals that we can't ignore, or don't want to do anything with.

Definition at line 131 of file signal.c.

132{
133}
+ Here is the caller graph for this function:

◆ mutt_sig_exit_handler()

void mutt_sig_exit_handler ( int  sig)

Notify the user and shutdown gracefully.

Parameters
sigSignal number, e.g. SIGINT

Definition at line 139 of file signal.c.

140{
141 exit_print_string("Caught signal ");
142 exit_print_int(sig);
144#ifdef HAVE_DECL_SYS_SIGLIST
145 exit_print_string(sys_siglist[sig]);
146#elif (defined(__sun__) && defined(__svr4__))
147 exit_print_string(_sys_siglist[sig]);
148#elif (defined(__alpha) && defined(__osf__))
149 exit_print_string(__sys_siglist[sig]);
150#endif
151 exit_print_string("... Exiting\n");
152 exit(0);
153}
static void exit_print_int(int n)
AS-safe version of printf("%d", n)
Definition: signal.c:95
static void exit_print_string(const char *str)
AS-safe version of printf("%s", str)
Definition: signal.c:113
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_sig_init()

void mutt_sig_init ( sig_handler_t  sig_fn,
sig_handler_t  exit_fn,
sig_handler_t  segv_fn 
)

Initialise the signal handling.

Parameters
sig_fnFunction to handle signals
exit_fnFunction to call on uncaught signals
segv_fnFunction to call on a segfault (Segmentation Violation)

Set up handlers to ignore or catch signals of interest. We use three handlers for the signals we want to catch, ignore, or exit.

Definition at line 164 of file signal.c.

165{
166 if (sig_fn)
167 SigHandler = sig_fn;
168
169 if (exit_fn)
170 ExitHandler = exit_fn;
171
172 if (segv_fn)
173 SegvHandler = segv_fn;
174
175 struct sigaction act = { 0 };
176 struct sigaction old_act = { 0 };
177
178 sigemptyset(&act.sa_mask);
179 act.sa_flags = 0;
180 act.sa_handler = SIG_IGN;
181 sigaction(SIGPIPE, &act, NULL);
182
183 act.sa_handler = SegvHandler;
184 sigaction(SIGSEGV, &act, &old_act);
185 OldSegvHandler = old_act.sa_handler;
186
187 act.sa_handler = ExitHandler;
188 sigaction(SIGTERM, &act, NULL);
189 sigaction(SIGHUP, &act, NULL);
190 sigaction(SIGQUIT, &act, NULL);
191
192 /* we want to avoid race conditions */
193 sigaddset(&act.sa_mask, SIGTSTP);
194
195 act.sa_handler = SigHandler;
196
197 /* we want SIGALRM to abort the current syscall, so we do this before
198 * setting the SA_RESTART flag below. currently this is only used to
199 * timeout on a connect() call in a reasonable amount of time. */
200 sigaction(SIGALRM, &act, NULL);
201
202/* we also don't want to mess with interrupted system calls */
203#ifdef SA_RESTART
204 act.sa_flags = SA_RESTART;
205#endif
206
207 sigaction(SIGCONT, &act, NULL);
208 sigaction(SIGTSTP, &act, NULL);
209 sigaction(SIGINT, &act, NULL);
210 sigaction(SIGWINCH, &act, NULL);
211
212 /* POSIX doesn't allow us to ignore SIGCHLD,
213 * so we just install a dummy handler for it */
214 act.sa_handler = mutt_sig_empty_handler;
215 /* don't need to block any other signals here */
216 sigemptyset(&act.sa_mask);
217 /* we don't want to mess with stopped children */
218 act.sa_flags |= SA_NOCLDSTOP;
219 sigaction(SIGCHLD, &act, NULL);
220}
static sig_handler_t ExitHandler
Function to handle SIGTERM (15), SIGHUP (1), SIGQUIT (3) signals.
Definition: signal.c:62
void mutt_sig_empty_handler(int sig)
Dummy signal handler.
Definition: signal.c:131
sig_handler_t OldSegvHandler
Keep the old SEGV handler, it could have been set by ASAN.
Definition: signal.c:67
static sig_handler_t SegvHandler
Function to handle SIGSEGV (11) signals.
Definition: signal.c:64
+ Here is the call graph for this function:
+ Here is the caller graph for this function:

◆ mutt_sig_reset_child_signals()

void mutt_sig_reset_child_signals ( void  )

Reset ignored signals back to the default.

See sigaction(2): A child created via fork(2) inherits a copy of its parent's signal dispositions. During an execve(2), the dispositions of handled signals are reset to the default; the dispositions of ignored signals are left unchanged.

Definition at line 337 of file signal.c.

338{
339 struct sigaction sa = { 0 };
340
341 sa.sa_handler = SIG_DFL;
342 sa.sa_flags = 0;
343 sigemptyset(&sa.sa_mask);
344
345 /* These signals are set to SIG_IGN and must be reset */
346 sigaction(SIGPIPE, &sa, NULL);
347
348 /* These technically don't need to be reset, but the code has been
349 * doing so for a long time. */
350 sigaction(SIGTERM, &sa, NULL);
351 sigaction(SIGTSTP, &sa, NULL);
352 sigaction(SIGCONT, &sa, NULL);
353}
+ Here is the caller graph for this function:

◆ mutt_sig_unblock()

void mutt_sig_unblock ( void  )

Restore previously blocked signals.

Definition at line 246 of file signal.c.

247{
248 if (!SignalsBlocked)
249 return;
250
251 sigprocmask(SIG_UNBLOCK, &Sigset, 0);
252 SignalsBlocked = false;
253}
+ Here is the caller graph for this function:

◆ mutt_sig_unblock_system()

void mutt_sig_unblock_system ( bool  restore)

Restore previously blocked signals.

Parameters
restoreIf true, restore previous SIGINT, SIGQUIT behaviour

Definition at line 285 of file signal.c.

286{
288 return;
289
290 sigprocmask(SIG_UNBLOCK, &SigsetSys, NULL);
291 if (restore)
292 {
293 sigaction(SIGQUIT, &SysOldQuit, NULL);
294 sigaction(SIGINT, &SysOldInt, NULL);
295 }
296 else
297 {
298 struct sigaction sa = { 0 };
299
300 sa.sa_handler = SIG_DFL;
301 sigemptyset(&sa.sa_mask);
302 sa.sa_flags = 0;
303 sigaction(SIGQUIT, &sa, NULL);
304 sigaction(SIGINT, &sa, NULL);
305 }
306
307 SysSignalsBlocked = false;
308}
+ Here is the caller graph for this function:

Variable Documentation

◆ SigInt

volatile sig_atomic_t SigInt
extern

true after SIGINT is received

Definition at line 69 of file signal.c.

◆ SigWinch

volatile sig_atomic_t SigWinch
extern

true after SIGWINCH is received

Definition at line 70 of file signal.c.

◆ OldSegvHandler

sig_handler_t OldSegvHandler
extern

Old SEGV handler, it could have been set by ASAN.

Old SEGV handler, it could have been set by ASAN.

Definition at line 67 of file signal.c.