kill -9 and POSIX signals?!
— October 6, 2018It’s 3:30AM on a Saturday, and I’m currently working on a shell in Go. I’m trying to recall how to trap signals in Go, and kill -9
came to my mind. All I knew was that the command “terminates a program”, but why is it actually the case? I don’t understand it well, so I’m going to explore how the kill
command and signal actually works.
Here’s what man kill
shows:
SYNOPSIS
kill [-s signal_name] pid ...
kill -l [exit_status]
kill -signal_name pid ...
kill -signal_number pid ...
I didn’t know 9 is actually the signal number! Interesting. So, a signal is actually used for sending information between processes or between the kernel and a process.
Here is a high level overview on how I think signals are used:
- Doing
kill -9 <pid>
gets thekill
utility to make a syscall to generate a SIGKILL signal in the kernel, and this terminates the process pid. - Whenever an invalid memory address is accessed, the kernel generates a SIGSEGV signal, and this results in the termination of the process with a segmentation fault.
- Whenever the user presses Ctrl + C on the keyboard, the kernel sends the SIGINT signal to the shell process, which then sends it to the process.
There are many different signal types, and we can list all of them through kill -l
or man signal
.
bash-3.2$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGEMT 8) SIGFPE
9) SIGKILL 10) SIGBUS 11) SIGSEGV 12) SIGSYS
13) SIGPIPE 14) SIGALRM 15) SIGTERM 16) SIGURG
17) SIGSTOP 18) SIGTSTP 19) SIGCONT 20) SIGCHLD
21) SIGTTIN 22) SIGTTOU 23) SIGIO 24) SIGXCPU
25) SIGXFSZ 26) SIGVTALRM 27) SIGPROF 28) SIGWINCH
29) SIGINFO 30) SIGUSR1 31) SIGUSR2
The common ones are SIGHUP(1)
, SIGINT(2)
(Ctrl + C), SIGQUIT(3)
(Ctrl + D), SIGKILL(9)
and SIGTERM(15)
. By default, kill
without the signal name will use SIGTERM. This will ask the process to terminate as soon as it possibly can (i.e. graceful shutdown).
So, how can we actually get the shell process to send it to the inner process? We need traps. Traps allow us to trap some or all of these signals that the kernel sends to the process, and the process could then perform operations on the trapped signal.
We can create a trap for specific signals in our shell process, and when it receives those signals, it can act accordingly, such as forwarding it to the inner process or terminating it, in the case of a SIGINT.
Also, a quick look at the linux kernel source code shows the following fact:
SIGKILL and SIGSTOP cannot be caught, blocked, or ignored.
Takeaways
-
kill -9 <pid>
can be translated into:
- Don’t run
kill -9
just becausekill
doesn’t work. Only do this as a last resort. - You cannot SIGKILL pid 1 (
init
on Linux /launchd
on Mac OSX). This is done to assure that the system is not brought down accidentally.
I should probably play with strace
someday. I wonder what shows up for these kill
syscalls.