The name is misleading. The command sends a signal, and in most cases the receiving process decides how to respond. Termination is the default for several signals rather than the purpose of the mechanism.
Understanding that distinction explains why a process sometimes ignores the command entirely, and why a different one cannot be ignored yet still fails to remove the process.
What a signal actually is
A signal is an asynchronous notification delivered by the kernel that interrupts a process at whatever it was doing. The process may have registered a handler, in which case that function runs before normal execution resumes.
If no handler is registered, the kernel applies a default action defined per signal, which may be to terminate, to stop, or to ignore. This is why the same signal produces different outcomes against different programs.
The signals worth knowing
| Signal | Number | Default | Can be caught |
|---|---|---|---|
| SIGHUP | 1 | Terminate | Yes |
| SIGINT | 2 | Terminate | Yes |
| SIGQUIT | 3 | Terminate and dump core | Yes |
| SIGKILL | 9 | Terminate | No |
| SIGTERM | 15 | Terminate | Yes |
| SIGSTOP | 19 | Suspend | No |
| SIGCONT | 18 | Resume | Yes |
The default sent by the command is the polite one, number fifteen, which asks a process to shut down and allows it to flush buffers, close files, and release locks first.
Two signals cannot be caught, blocked, or ignored, and are handled entirely by the kernel. That property is what makes them a last resort rather than a first choice.
Why the uncatchable one sometimes fails
A process that will not disappear despite the strongest signal is almost always in uninterruptible sleep, waiting on a kernel operation that has not returned. Signals are delivered when a process next runs, and a process blocked in the kernel is not running.
The usual cause is storage or a network filesystem that has stopped responding. The process is not stuck in the sense of a loop, it is waiting correctly for something that will never arrive, and it will terminate the moment the operation completes or times out.
Rebooting is frequently the only remedy, which is unsatisfying and accurate. The problem is below the process, so nothing done to the process will resolve it.
Why forcing termination has a cost
A process terminated by the uncatchable signal runs no cleanup. Buffered writes are lost, temporary files remain, locks are not released, and child processes are orphaned.
The correct sequence is to send the polite signal, wait, and escalate only if nothing happens. Skipping straight to the forceful one is how databases end up needing recovery on start and how stale lock files accumulate.
Zombies and orphans
A terminated process remains in the table until its parent collects the exit status. Until then it holds no memory and no file handles, only an entry, and it is described as a zombie.
Zombies indicate a parent that is not collecting results rather than a problem with the child, so signalling the zombie accomplishes nothing. Terminating the parent transfers the child to the init process, which collects it immediately.
An orphan is the opposite case, a running process whose parent has exited. It is reparented to init and continues normally, which is the mechanism behind processes that survive the shell that started them.
Why one interrupt stops a whole pipeline
Processes are grouped, and a terminal sends signals to the group in the foreground rather than to a single process. That is why an interrupt at the keyboard stops every stage of a pipeline at once.
It also explains why a background job can be terminated when its terminal closes, because a hangup is delivered to the group, and why tools that detach a process from its terminal exist to prevent exactly that.
Note: if a process ignores the polite signal it has a handler that is failing or is deliberately trapping it. If it ignores the forceful one it is not ignoring anything, it is blocked in the kernel and cannot be scheduled to receive it.