Notes on UNIX signals
- Signal handlers
- Working with signals
- Blocking operations
Signals are asynchronous notifications sent to processes by the kernel, potentially in response to a hardware exception or interrupt. The kernel interrupts the flow of execution of a process during any non-atomic instruction to deliver the signal.
Signals are not queued. Processes have binary flags to represent whether a signal is pending. When a signal is delivered, the corresponding binary flag will be set to true. The signal will be delivered as soon as the signal is not blocked and the binary flag will be reset to false. If a signal is delivered multiple times, the corresponding binary flag is set to true, and the signal is delivered once unless the binary flag is set to false before the new instance of the signal is delivered.
Signal handlers are only executed when transitioning from kernel mode to user mode. The kernel checks the pending signals when deciding to schedule a process to run. When delivering a signal, the kernel stores the current execution context into the user-space stack, creates a stack frame for the signal handler, and jumps into the signal handler in user mode. After a signal handler executes, the kernel takes over control in order to restore the execution context.
A process may specify signal handlers to respond to,
ignore, or block signals other than
SIGSTOP. If not handled,
the default signal handlers are executed (documented in
Programs may setup signal handlers using
sigaction(2), or its easier-to-use wrapper
signal(3). The handler functions receive the signal
number as an argument.
Signals may be delivered while a signal handler is running. For this reason, it is recommended for signal handlers to be reentrant (it can safely be executed by multiple threads in parallel) and/or not be interruptible by signal handlers.
Linux maintains a list of “async-signal-safe” functions that
are safe to use in signal handlers in
POSIX defines an integer type
is safe to use as a global variable shared between a program and
its signal handlers. Read and write to
variables are atomic operations, but
-- are not. It is recommended to declare
sig_atomic_t variables as
prevent optimizer tricks.
Signal handlers typically use the process’ stack, but they
can be configured to use a custom stack with
sigaltstack(2). This can be useful when handling
SIGSEGV signal, which can occur when the
process stack space is exhausted.
A signal may be delivered while its own signal handler is
running. The signal that triggered the handler is blocked by
default when the handler runs, unless the
SA_NODEFER is set, in which case the new instance
of the signal will be set to pending and will be delivered once
the running signal handler exits.
A process may send a signal along with a piece of data (an
integer or a pointer) by using
corresponding handler can access this data if it was setup with
SA_SIGINFO flag of
Working with signals
Processes may send signals using
process only has permission to send a signal if the real or
effective user ID match, or the user has super-user privileges.
As an exception, the
SIGCONT can always be sent to
any descendant of the process.
kill(2) will fail if
the sender is configured to ignore the signal.
kill(2) function allows a process to send a
signal to a specific process (ignoring its descendants), to all
the processes that belong to the sender’s process group ID, or
(given super-user privileges) to all the processes excluding
The shell sends interrup signals, like
to the foregroung process group.
Blocking (masking) signals
Signals, other than
SIGSTOP, can be blocked with
sigprocmask(2). Blocked signals are delivered when
the signal is unblocked. The list of pending signals can be
sigpending(2). Blocking signals is
useful to prevent interrupts during critical code paths. Signal
masks are per thread, and not per process.
SIGCONTsignal can’t be blocked on Linux
sigaction(2) function accepts a set of
signals that must be blocked when executing a particular signal
handler. Also, the signal that executed the current signal
handler will be blocked unless the
If a signal handler is updated while a signal is pending, then the updated handler will be executed. The operating system only checks how a process wants to react to a handler when delivering the signal, and not when setting the signal’s binary flag.
Signals, other than
SIGSTOP, can be ignored using
signal(3) along with
Processes may reset a signal handler to its default by using
signal(3) along with
sigaction(2) function also supports a
SA_RESETHAND flag to implement one-shot signal
handlers where the handler is reset after the first handler
Waiting for signals
A process may wait for a signal to occur with the
(which supports a timeout argument) functions.
Pausing and resuming processes
A process may be paused with
SIGSTOP (sent when
Ctrl-Z on a shell) and then resumed with
Terminating a process
There are many signals to terminate a process.
SIGTERM allows a process to gracefully terminate.
SIGKILL inconditionally aborts the process and can
be used as a last resort.
SIGQUIT terminates a
process, potentially creating a core dump.
A forked process inherits the signal mask and all signal
execve(2) resets all signal handlers
but keeps the set of ignored and blocked signals.
A parent process receives
SIGCHLD when a child
exits, unless the
SA_NOCLDSTOP flag of
sigaction(2) is set. Handling
is not a reliable way to wait for more than one
children to exit, as multiple children might exit while
SIGCHLD is being handled, but
would only be delivered once.
If a process has more than one thread, then the signal
handler is sent to only one of its threads. This decision is
implementation-specific. Programs may send a signal to a
specific thread using
Some signals generated a result of an specific instruction,
always be sent to the thread that executed such instruction.
If a signal is delivered while a blocking system call (like
read(2)) is running, then the system call will fail
EINTR. The calling program may deal with
EINTR by manually restarting the system call.
Affected system calls may also be automatically restarted after
signal interruption if the signal is setup with the
The full list of affected system calls is documented in
The affected system calls include open(2), read(2), write(2), sendto(2), recvfrom(2), sendmsg(2) and recvmsg(2)