Unix signal

Also known as: SIGTERM · SIGKILL

On this page 7

A Unix signal is a small, asynchronous notification that the kernel delivers to a process or thread to report an event: a request to terminate, a keyboard interrupt, a child that has exited or a fault such as an invalid memory access. In Linux, signals are the most basic form of interprocess communication for controlling processes, and well-known examples are SIGTERM, the polite request to shut down, and SIGKILL, the forced termination that a process cannot refuse.

A signal carries almost no data, essentially just its number. Its meaning comes from convention and from how the receiving program has chosen to react, which makes correct signal handling a core skill for anyone who writes daemons or manages services.

How signals are generated and delivered

Signals arise from three sources: the kernel (for example SIGSEGV after an invalid memory access or SIGPIPE when writing to a closed pipe), the terminal (Ctrl+C sends SIGINT, Ctrl+Z sends SIGTSTP) and other processes through the kill system call, which the kill, pkill and killall commands use.

Once generated, a signal becomes pending for the target. The kernel delivers it the next time the process returns to user mode, unless the signal is blocked by the process or thread signal mask, in which case it waits. Standard signals are recorded as a single bit, so several identical pending signals collapse into one; real-time signals from SIGRTMIN to SIGRTMAX are queued instead and can carry a small integer value.

For each signal a process has a disposition: the default action, ignore, or a custom signal handler installed with sigaction. The default actions fall into five groups.

Default actionWhat happensExample signals
TerminateProcess endsSIGTERM, SIGHUP, SIGINT, SIGUSR1
Terminate with core dumpProcess ends and may write a core fileSIGQUIT, SIGSEGV, SIGABRT, SIGFPE
IgnoreNothing happensSIGCHLD, SIGWINCH, SIGURG
StopProcess is suspendedSIGSTOP, SIGTSTP, SIGTTIN
ContinueStopped process resumesSIGCONT
Default actions for Unix signals

The most important signals

Linux defines 31 standard signals plus a range of real-time signals. Numbers differ slightly between architectures, so scripts should use names rather than numbers, with SIGKILL and SIGTERM as the commonly cited exceptions whose numbers 9 and 15 are universal.

SignalNumberTypical triggerCommon meaning
SIGHUP1Terminal closed or admin requestReload configuration in many daemons
SIGINT2Ctrl+C in the terminalInterrupt from the user
SIGQUIT3Ctrl+backslashQuit with core dump
SIGKILL9kill -9Immediate, uncatchable termination
SIGSEGV11Invalid memory accessProgram bug, crash
SIGTERM15kill default, service stopGraceful shutdown request
SIGCHLD17Child exited or stoppedParent should reap the child
SIGSTOP19kill -STOPUncatchable pause
Frequently used signals on x86 Linux

Two signals are special: SIGKILL and SIGSTOP cannot be caught, blocked or ignored. They guarantee that an administrator can always end or freeze a process, at least once it leaves kernel code.

SIGTERM compared with SIGKILL

Choosing between SIGTERM and SIGKILL is the most common practical signal decision. SIGTERM asks, SIGKILL forces, and the difference decides whether data is saved cleanly.

AspectSIGTERMSIGKILL
Can be handledYes, by a custom handlerNo
CleanupProgram can flush buffers, close connections, remove lock filesNone; memory and descriptors are released by the kernel
Child processesProgram may stop them in orderChildren are orphaned and adopted by init or a subreaper
RiskA hung program may ignore itPossible data loss or corrupted files
Shell exit status143137
SIGTERM against SIGKILL

The standard pattern, used by systemd and by container runtimes, is to send SIGTERM, wait for a grace period and only then send SIGKILL. systemd waits 90 seconds by default before escalating, and many container platforms use a grace period of 10 to 30 seconds. A shell reports a signal death as exit status 128 plus the signal number.

Writing correct signal handlers

A handler interrupts the program at an arbitrary point, so it may only call async-signal-safe functions such as write and _exit. Calling printf, malloc or most library functions inside a handler can deadlock or corrupt state. The robust approach is to set a flag of type volatile sig_atomic_t in the handler and act on it in the main loop.

  • Use sigaction, not signal: its behavior is precisely defined across systems.
  • Handle EINTR: a blocking system call can return early with EINTR when a signal arrives, unless SA_RESTART is set.
  • Consider signalfd: on Linux it turns signals into readable file descriptor events for event loops.
  • Mind threads: masks are per thread, so many programs block signals everywhere and handle them in one dedicated thread.

Pitfalls when sending and handling signals

A frequent surprise appears in containers: a program running as PID 1 gets no default terminate action for signals it does not handle, so it may ignore SIGTERM and be killed only when the grace period ends. Running a minimal init process or adding an explicit handler solves this.

Other pitfalls include reaching for kill -9 as a first resort, which skips cleanup and can leave stale lock files; expecting SIGKILL to end a process in uninterruptible sleep, shown as state D, which only dies after its kernel operation completes; and forgetting that a parent must handle SIGCHLD and call wait, otherwise finished children remain as zombie processes.

In plain words

A Unix signal is a short message the system sends to a running program. It might say please stop, pause, carry on, or something went wrong. Most programs can decide how to react to these messages.

SIGTERM is like a manager saying it is time to close the shop: staff can finish serving, lock the till and switch off the lights. SIGKILL is like cutting the power to the building. It always works, but nobody gets to tidy up first.

A real-world example

An operations engineer deploys a new version of a web application managed by systemd. Running systemctl restart sends SIGTERM to the old process. The application’s handler stops accepting new connections, finishes requests already in progress, closes its database pool and exits within about three seconds, well inside the 90-second timeout.

Later the same day a background worker hangs on a stuck network call and ignores SIGTERM. After the timeout, systemd escalates to SIGKILL, the worker disappears, and the service manager starts a fresh instance. The logs show exit status 137 for the worker, which tells the engineer that it was force-killed rather than shut down cleanly, and leads to a fix that adds a timeout to the network call.