All about Linux signals
Table of Contents:
- All about Linux signals
- Introduction
- What is signaled, signal handlers
- Handling specific signals: SIGCHLD, SIGBUS, SIGSEGV, SIGABRT
- What happens when a process receives a signal, system call interruption
- Blocking signals
- Waiting for a signal
- Sending signals
- Real-time signals
- Signals and fork()
- Signals and threads
- Other uses of signals
- That's not everything!
Handling SIGCHLD
If you create new processes in your program and don't really want to wait until they exit, and possibly their exist status doesn't matter, just want to cleanup zombie processes you can create a
SIGCHLD handler that does just that and forget about process you've created. This handler can look like this one:
Fragment of example: SIGCHLD handler
static void sigchld_hdl (int sig) { /* Wait for all dead processes. * We use a non-blocking call to be sure this signal handler will not * block if a child was cleaned up in another part of the program. */ while (waitpid(-1, NULL, WNOHANG) > 0) { } }
This way whenever a child exits it will be cleaned-up but information which process was that, why it exited and its exit status is forgotten. You could make the handler more intelligent but remember to not use any function that is not listed as signal-safe.
You must remember that if you make child processes SIGCHLD must have a handler. The behavior of ignoring this signal is undefined, so at least a handler that doesn't do anything is required.
Handling SIGBUS
The
SIGBUS signal is sent to the process when you access mapped memory (with mmap(2)) that doesn't correspond to a file. A common example is that the file you've mapped was later truncated (possible by another program) and you read past it's current end. Accessing files this way doesn't require any system function that could return an error, you just read from memory like if it was on the heap or stack. This is a really bad situation when you don't want your program to terminate after a file read error. Unfortunately handling SIGBUS isn't simple or clean, but it's possible. If you want to continue running your program you have to use longjmp(3). It's something like goto but worse! We have to jump to some other place in the program that the mmap()ed memory is not accessed if we receive SIGBUS. If you place an empty handler for this signal, in case of read error the program will be interrupted, signal handler executed and the control returns to the same place that caused the error. So we need to jump into another place from the signal handler. This sounds low-level, but it's possible using standard POSIX functions.
See the example: SIGBUS handling
You must keep in mind the list of signal-safe functions: In this example we never actually return from the signal handler. The stack is cleaned up, but program is restarted in completely different place, so if you've had, for example, a mutex locked during the operation like:
pthread_mutex_lock (&m); for (l = 0; l < 1000; l++) if (mem[l] == 'd') // BANG! SIGBUS here! j++; pthread_mutex_unlock (&m);
After longjmp(3) the mutex is still held although in every other situation the mutex is released.
So handling SIGBUS is possible but very tricky and can introduce bugs that are very hard to debug. The program's code also becomes ugly.
Handling SIGSEGV
Handling the
SIGSEGV (segmentation fault) signal is also possible. In most cases returning from the signal handler makes no sense since the program will be restarted from the instruction that caused segmentation fault. So if you have no solution on how to fix the state of the program to let it continue running properly at the same moment it crashed, you must end the program. One example of when you may restart the program is when you have memory obtained using mmap(2) that is read-only, you may check if the signal handler that the cause of segmentation fault was writing to this memory (using data from siginfo_t) and use mprotect(2) to change the protection of this memory. How practical is it? I don't know.
Exhausting stack space is one of the causes of segmentation fault. In this case running a signal handler is not possible because it requires space on the stack. To allow handling SIGSEGV in such condition the sigaltstack(2) function exists that sets alternative stack to be used by signal handlers.
Handling SIGABRT
When handling this signal you should keep in mind how the abort(3) function works: it rises the signal twice, but the second time the
SIGABRT handler is restored to the default state, so the program terminates even if you have a handler defined. So you actually have a chance to do something in case of abort(3) before the program termination. It's possible to not terminate the program by not exiting from the signal handler and using longjmp(3) instead as described earlier.


Hi, typo jerk here
Thanks. I don't consider it
I was looking for linux
Great write-up
Signals - That's not everything