NeoMutt  2025-09-05-55-g97fc89
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.

60#define ASSERT(COND) \
61 do \
62 { \
63 if (!(COND)) \
64 { \
65 assertion_dump(__FILE__, __LINE__, __func__, #COND); \
66 ASSERT_STOP; \
67 } \
68 } while (false);

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 361 of file signal.c.

362{
363 endwin();
365 printf("%s:%d:%s() -- assertion failed (%s)\n", file, line, func, cond);
366}
void show_backtrace(void)
Log the program's call stack.
Definition backtrace.c:40
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 315 of file signal.c.

316{
317 struct sigaction sa = { 0 };
318
319 sa.sa_handler = SigHandler;
320#ifdef SA_RESTART
321 if (!allow)
322 sa.sa_flags |= SA_RESTART;
323#endif
324 sigaction(SIGINT, &sa, NULL);
325}
static sig_handler_t SigHandler
Function to handle other signals, e.g. SIGINT (2)
Definition signal.c:59
+ 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 227 of file signal.c.

228{
229 if (SignalsBlocked)
230 return;
231
232 sigemptyset(&Sigset);
233 sigaddset(&Sigset, SIGTERM);
234 sigaddset(&Sigset, SIGHUP);
235 sigaddset(&Sigset, SIGTSTP);
236 sigaddset(&Sigset, SIGINT);
237 sigaddset(&Sigset, SIGWINCH);
238 sigprocmask(SIG_BLOCK, &Sigset, 0);
239 SignalsBlocked = true;
240}
static sigset_t Sigset
A set of signals used by mutt_sig_block(), mutt_sig_unblock()
Definition signal.c:41
static bool SignalsBlocked
true when signals are blocked, e.g.
Definition signal.c:52
+ 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 260 of file signal.c.

261{
263 return;
264
265 struct sigaction sa = { 0 };
266
267 /* POSIX: ignore SIGINT and SIGQUIT & block SIGCHLD before exec */
268 sa.sa_handler = SIG_IGN;
269 sa.sa_flags = 0;
270 sigemptyset(&sa.sa_mask);
271 sigaction(SIGINT, &sa, &SysOldInt);
272 sigaction(SIGQUIT, &sa, &SysOldQuit);
273
274 sigemptyset(&SigsetSys);
275 sigaddset(&SigsetSys, SIGCHLD);
276 sigprocmask(SIG_BLOCK, &SigsetSys, 0);
277 SysSignalsBlocked = true;
278}
static bool SysSignalsBlocked
true when system signals are blocked, e.g.
Definition signal.c:56
static struct sigaction SysOldQuit
Backup of SIGQUIT handler, when mutt_sig_block_system() is called.
Definition signal.c:48
static sigset_t SigsetSys
A set of signals used by mutt_sig_block_system(), mutt_sig_unblock_system()
Definition signal.c:43
static struct sigaction SysOldInt
Backup of SIGINT handler, when mutt_sig_block_system() is called.
Definition signal.c:46
+ 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 130 of file signal.c.

131{
132}
+ 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 138 of file signal.c.

139{
140 exit_print_string("Caught signal ");
141 exit_print_int(sig);
143#ifdef HAVE_DECL_SYS_SIGLIST
144 exit_print_string(sys_siglist[sig]);
145#elif (defined(__sun__) && defined(__svr4__))
146 exit_print_string(_sys_siglist[sig]);
147#elif (defined(__alpha) && defined(__osf__))
148 exit_print_string(__sys_siglist[sig]);
149#endif
150 exit_print_string("... Exiting\n");
151 exit(0);
152}
static void exit_print_int(int n)
AS-safe version of printf("%d", n)
Definition signal.c:94
static void exit_print_string(const char *str)
AS-safe version of printf("%s", str)
Definition signal.c:112
+ 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 163 of file signal.c.

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

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

◆ mutt_sig_unblock()

void mutt_sig_unblock ( void )

Restore previously blocked signals.

Definition at line 245 of file signal.c.

246{
247 if (!SignalsBlocked)
248 return;
249
250 sigprocmask(SIG_UNBLOCK, &Sigset, 0);
251 SignalsBlocked = false;
252}
+ 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 284 of file signal.c.

285{
287 return;
288
289 sigprocmask(SIG_UNBLOCK, &SigsetSys, NULL);
290 if (restore)
291 {
292 sigaction(SIGQUIT, &SysOldQuit, NULL);
293 sigaction(SIGINT, &SysOldInt, NULL);
294 }
295 else
296 {
297 struct sigaction sa = { 0 };
298
299 sa.sa_handler = SIG_DFL;
300 sigemptyset(&sa.sa_mask);
301 sa.sa_flags = 0;
302 sigaction(SIGQUIT, &sa, NULL);
303 sigaction(SIGINT, &sa, NULL);
304 }
305
306 SysSignalsBlocked = false;
307}
+ 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 68 of file signal.c.

◆ SigWinch

volatile sig_atomic_t SigWinch
extern

true after SIGWINCH is received

Definition at line 69 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 66 of file signal.c.