Ch. 21 · Operating Systems

Operating Systems: Signals

Use SIGTERM for graceful shutdown, respect the limits of signal handlers, and know which signals cannot be caught.

~2 min readintermediateupdated Oct 5, 2026

A signal is an asynchronous notification delivered to a process, used for control such as termination, interrupts and timers. Handlers must be careful because a signal can arrive between any two instructions, and some signals cannot be caught at all.

Before you start

You should understand processes and basic control flow. This article covers common signals and handler safety.

Step-by-step walkthrough

Step 1: Catch SIGTERM for graceful shutdown

SIGTERM is the standard request to stop, sent by orchestrators before force-killing. Handling it lets the process stop accepting new work, drain in-flight requests and exit cleanly. Ignoring it forces the platform to escalate to a hard kill.

Step 2: Know what cannot be caught

SIGKILL cannot be caught or ignored, which is what makes it the guaranteed kill. SIGSTOP cannot be caught either. So graceful shutdown depends on SIGTERM; a process that ignores it will eventually be SIGKILLed with no chance to clean up.

Step 3: Keep handlers minimal and async-safe

A handler can run between instructions, so it may interrupt code that is partway through allocating or modifying shared state. Do only async-signal-safe work, such as setting a flag or writing to a pipe, and let the main loop perform the real cleanup. Heavy work in a handler risks deadlock and corruption.

Worked scenario

The process sets a flag on SIGTERM and shuts down in the main loop.

let shuttingDown = false;
process.on('SIGTERM', () => { shuttingDown = true; });
setInterval(() => { if (shuttingDown) process.exit(0); }, 100);
JavaScript

Walk through the example

The handler does the minimum: it flips a flag. The main loop checks the flag and performs an orderly exit, so cleanup happens outside the signal context where it is safe. This is the pattern behind graceful shutdown in servers, though most runtimes provide a cleaner shutdown hook.

Common mistake

Doing complex work such as logging, locking or allocating inside the handler, which can deadlock if the signal interrupted the code holding the lock. Another is ignoring SIGTERM and being killed abruptly, losing in-flight work.

Verify the behavior

Send SIGTERM and confirm the process drains and exits with code 0. Send SIGKILL and confirm it cannot be caught. Log from the handler and observe the interrupted state if the handler does too much.

Interview exercise

Why must a signal handler avoid doing much work?

Answer and reasoning

Because the handler runs at an arbitrary point, possibly interrupting code that holds a lock or is mid-update of shared state. If the handler then calls the same lock or the same non-reentrant function, it can deadlock or corrupt data. Restricting the handler to async-signal-safe operations and deferring real work to the main flow avoids that.

Continue learning

Compare shutdown behavior in Graceful shutdown and IPC in IPC mechanisms. Read the Linux signal documentation and try the Operating systems interview questions.

More in Operating Systems

read ✓Operating Systems · hard

Operating Systems: CPU Cache Locality

Improve performance with spatial and temporal locality, avoid pointer chasing, and understand false sharing between threads.

~2 min readread →
read ✓Operating Systems · hard

Copy-on-Write Memory and fork

How copy-on-write lets fork share pages until a write, why RSS can be misleading, and the implications for memory and latency.

~2 min readread →
read ✓Operating Systems · hard

Operating Systems: epoll and select

How select, poll and epoll report I/O readiness, and the difference between level- and edge-triggered notifications.

~2 min readread →
esc