Skip to content

Understanding Signals


You have already seen processes being inspected and monitored. The next step is controlling them, but before using kill, pkill, or killall, it helps to understand what those commands actually send.

They send signals.

A signal is a small notification delivered by the kernel to a process. Different signals request different actions: some ask a process to terminate gracefully, some stop or continue it, and one can force it to disappear immediately.

What Is A Signal?

A signal is an asynchronous event sent to a process.

Conceptually:

Process
   ▲
   │ signal
   │
Kernel / another process

For example:

kill -TERM 1234

does not mean “destroy PID 1234.”

It means:

Send signal SIGTERM to PID 1234.

The process then receives that signal and, depending on the signal and its own signal-handling behavior, takes an appropriate action.

This distinction matters because kill is really a signal-sending command, despite its name.

Why Does Linux Use Signals?

Signals provide a simple mechanism for communicating important events to processes.

For example:

SIGTERM
    → Please terminate.

SIGKILL
    → Terminate immediately; no handling.

SIGSTOP
    → Stop executing.

SIGCONT
    → Continue a stopped process.

SIGHUP
    → Traditionally associated with a terminal disconnect;
      commonly also used by services to request a reload.

There are more signals, but these are enough to understand most everyday process management.

SIGTERM: Ask The Process To Stop

The signal you’ll generally want first when terminating a process is:

SIGTERM

You can send it explicitly:

kill -TERM 1234

or using its signal number:

kill -15 1234

The important idea is that SIGTERM is a request. A process can catch it and perform cleanup before exiting. For example, a server might receive SIGTERM and:

stop accepting new connections
        ↓
finish existing work
        ↓
close files
        ↓
flush data
        ↓
exit

This is why graceful termination is normally preferable to immediately killing a process.

A Process Can Handle SIGTERM

Unlike SIGKILL, a program can catch SIGTERM and decide what to do.

A simple Python example makes the idea concrete:

import os
import signal
import time


def handle_term(signum, frame):
    print("Received SIGTERM, cleaning up...")
    raise SystemExit


signal.signal(signal.SIGTERM, handle_term)

print("Running. PID:", os.getpid())

while True:
    time.sleep(1)

Run it:

python3 signal-demo.py

From another terminal, send:

kill -TERM <PID>

The program receives the signal and runs its handler before exiting.

The point of this example isn’t Python signal programming. It demonstrates why SIGTERM is useful: the application gets an opportunity to shut itself down properly.

SIGKILL: Force The Process To Die

SIGKILL is fundamentally different:

kill -KILL 1234

or:

kill -9 1234

The kernel terminates the process immediately. The process cannot catch, ignore, or handle SIGKILL. There is no graceful cleanup opportunity. That makes it powerful, but also dangerous.

The stackoverflow Q/A answers beautifully:

You cannot, at least not for the process being killed.

What you can do is arrange for the parent process to watch for the child process’s death, and act accordingly. Any decent process supervision system, such as daemontools, has such a facility built in.

The usual escalation is therefore:

SIGTERM
   ↓
wait
   ↓
check whether it exited
   ↓
SIGKILL only if necessary

Warning

kill -9 should not be your default way of stopping processes. It is the emergency option for a process that refuses to terminate normally or is otherwise stuck.

Why kill -9 Is So Common?

You will often see:

kill -9 <PID>

used as if -9 simply means “kill harder.”

Technically, it means:

send signal number 9 = SIGKILL

The command isn’t asking the process to cooperate. The kernel terminates it directly.

This is useful when a process is genuinely refusing to terminate, but using it immediately can hide the actual reason a process isn’t shutting down cleanly.

SIGHUP: More Than A Terminal Hangup

Historically, SIGHUP means hangup.

It originated from terminal connections: when a terminal disappeared, processes associated with it could receive SIGHUP.

But many Unix/Linux services also use SIGHUP for:

reload configuration

For example, a daemon may document:

kill -HUP <PID>

as a request to re-read its configuration without completely restarting.

This is application-specific behavior. SIGHUP does not universally mean “reload configuration.”

The important lesson is:

A signal has a defined operating-system meaning, but a program may implement its own useful response to a catchable signal.

SIGSTOP And SIGCONT

Signals aren’t only about termination.

SIGSTOP tells the kernel to stop a process:

kill -STOP 1234

The process remains present, but it stops executing.

You can inspect its state with:

ps -p 1234 -o pid,stat,cmd

Then resume it:

kill -CONT 1234

Now the process can continue executing.

This is the same basic mechanism behind shell job control, which you’ll use later.

Some Signals Cannot Be Handled

Most signals can be caught, ignored, or handled by the process.

Two important exceptions are:

SIGKILL
SIGSTOP

A process cannot catch or ignore either one.

This gives the kernel a guaranteed mechanism to:

terminate a process

or:

stop a process

even if that process is badly behaved.

Signal Names And Numbers

Linux provides both names and numbers.

For example:

SIGHUP  = 1
SIGKILL = 9
SIGTERM = 15
SIGSTOP = 19
SIGCONT = 18

So these are equivalent:

kill -TERM 1234
kill -15 1234

and:

kill -KILL 1234
kill -9 1234

Using the signal name is often clearer because it communicates intent directly.

How Does kill Actually Fit In?

The relationship is:

kill
  │
  │ requests
  ▼
Kernel
  │
  │ delivers
  ▼
Signal
  │
  ▼
Process

So:

kill -TERM 1234

means:

Find PID 1234
       ↓
Ask the kernel to send SIGTERM
       ↓
Process receives SIGTERM
       ↓
Process handles it or follows its default action

kill does not directly reach into the process and terminate it. It asks the kernel to deliver a signal.

The Default Action Matters

Every signal has a default action defined by the operating system. For many signals, that action is termination. But a process can change its behavior for many signals by installing a signal handler or otherwise ignoring the signal.

For example:

SIGTERM
   ↓
default: terminate
   ↓
program may catch it
   ↓
program can perform cleanup
   ↓
program exits

Whereas:

SIGKILL
   ↓
kernel terminates process
   ↓
no handler
   ↓
no cleanup handler

This difference is the reason SIGTERM and SIGKILL should not be treated as interchangeable.

What About A Zombie?

If a process is already a zombie, sending it:

kill -TERM <PID>

doesn’t make the zombie disappear.

A zombie has already terminated. What remains is a small process-table entry containing its exit status until its parent collects it.

The parent needs to perform the appropriate wait() operation.

So:

Running process
    ↓ SIGTERM
Process exits
    ↓
Zombie temporarily exists
    ↓
Parent reaps it
    ↓
Zombie disappears

This is another reason not to think of signals simply as “ways to delete processes.”

Choosing The Right Signal

SignalMeaningTypical Use
SIGTERMRequest terminationNormal shutdown
SIGKILLImmediate terminationLast resort
SIGHUPHangup; application may use it for reloadTerminal/session events or service reloads
SIGSTOPStop executionTemporarily pause a process
SIGCONTContinue executionResume a stopped process

You don’t need to memorize every signal.

You need to understand that signals are different requests, and the signal you choose determines how the process is expected to react.

A Safe Escalation Pattern

When a process needs to stop, think:

Do I know the correct PID?
        ↓
Send SIGTERM
        ↓
Wait and check
        ↓
Did it exit?
   │
   ├── Yes → done
   │
   └── No
        ↓
Investigate why
        ↓
SIGKILL if genuinely necessary

The important part is that SIGKILL comes after SIGTERM, not before it.

What You Should Remember

The most important distinction is simple:

SIGTERM
    → "Please shut down."

SIGKILL
    → "The kernel will terminate you now."

SIGSTOP
    → "Stop executing."

SIGCONT
    → "Continue executing."

SIGHUP
    → "Hangup" at the OS level;
      applications may give it additional meaning such as reload.

And remember what kill really does:

kill
  ↓
send a signal
  ↓
kernel
  ↓
process

Once you understand signals, commands such as kill, pkill, and killall become much easier to reason about. They are primarily different ways of selecting processes and sending signals to them.

What’s Next

The next lesson puts this knowledge into practice: safely killing processes with kill, pkill, and killall, including how to verify your target before sending a signal and how to avoid broad process-matching mistakes.

Last updated on