All about Linux signals
Table of Contents:
- All about Linux signals
- 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!
There are differences in signal handling between a single-threaded program and a multi-threaded program. Since according to POSIX specification a multi-threaded program is one process with one PID, which thread is interrupted to handle the arriving signal? If you use the old (unsupported) LinuxThreads implementation the answer is simple: all threads have separate PIDs, so the signal is delivered to the thread with PID provided to kill(2), so in case of this implementation all threads are treated as separate processes. This fact is not really interesting since this implementation is not used in any modern Linux distribution.
With Native POSIX Threads Library things get more interesting. Since this is the POSIX compliant implementation the behavior described here also applies to other POSIX systems.
This is the most interesting question. There are two cases:
- Process-directed signals (sent to a PID using functions like kill(2)). Threads have their separate signal mask which can be manipulated using pthread_sigmask(2) similary to sigprocmask(2), so such signal is not delivered to a thread that has this signal blocked. It's delivered to one of threads in the process with this signal unblocked. It's unspecified which thread will get it. If all threads have the signal blocked, it's queued in the per-process queue. If there is no signal handler defined for the signal and the default action is to terminate the process with or without dumping the core the whole process is terminated.
- Thread-directed signals. There is a special function to send a signal to a specific thread: pthread_kill(2). It can be used to send a signal from one thread to another (or itself). This way the signal will be delivered or queued for the specific thread. There are also per-thread directed signals generated by the operating system like
SIGSEGV. If there is no signal handler defined for a signal that default's action is to terminate the process, a thread-directed signal terminated the whole process.
As you can see there is a process-wide signal queue and a per-thread queues.
Signal actions are set for the whole process. The behavior of signal(2) is undefined for multi-threaded application, sigaction(2) must be used. Keep in mind that none of pthreads related functions are described as signal safe in signal(7). Especially using mutexes in signal handlers is very bad idea.
To get sigwaitinfo(2) and sigtimedwait(2) functions behave reliable for process-directed signals, all signals you wait for must be blocked for all threads. Especially using pause() for process-directed signals can be a bad idea.
As previously said, both threading implementations (LinuxThreads and NPTL) internally use some number of real-time signals, so it's another good reason to always refer to those signals using