What is a Signal

A signal is an asynchronous notification delivered to a process. When you press Ctrl+C in your terminal, the kernel sends SIGINT to the foreground process. When you run kill 1234, you're sending SIGTERM to PID 1234. Signals are the kernel's way of tapping a process on the shoulder — or forcefully shutting it down.

How it works

Each signal is identified by a number and a name. The most important ones:

  • SIGINT (2) — interrupt. Sent when you press Ctrl+C. Default action: terminate.
  • SIGTERM (15) — termination request. The polite way to ask a process to exit. The process can catch this and clean up.
  • SIGKILL (9) — kill immediately. Cannot be caught or ignored. The kernel terminates the process with no cleanup.
  • SIGSTOP — pause the process. Cannot be caught. Sent by Ctrl+Z (via SIGTSTP, which can be caught).
  • SIGSEGV (11) — segmentation fault. The process tried to access memory it shouldn't. Default action: terminate with a core dump.

When a signal arrives, the process can:

  1. Handle it — run a custom signal handler function, then resume.
  2. Ignore it — explicitly discard the signal (not possible for SIGKILL and SIGSTOP).
  3. Take the default action — usually terminate or stop.

Signal handling is tricky because signals are asynchronous. They can arrive at any point during execution, even in the middle of a library call. Signal handlers must be careful about what functions they call — only async-signal-safe functions are guaranteed to work correctly inside a handler.

Why it matters

Signals are how processes are managed at the OS level. Graceful shutdown (SIGTERM), forced kill (SIGKILL), crash diagnosis (SIGSEGV), and job control (Ctrl+C, Ctrl+Z) all work through signals. Every daemon, container runtime, and init system must handle signals correctly. Mishandling them leads to zombie processes, data corruption on shutdown, or services that ignore kill commands.

See How Processes Work for how signals fit into the process lifecycle.