Background
Unix/Linux allows a user to have control over a program that they are running by sending what are called signals. These signals are then normally handled by the program in a way that is compliant with Unix/Linux standards. Two of the most important signals that are commonly sent to a program are called SIGTERM and SIGKILL. Those and a couple of others will be explored in this tutorial.
Basics
Send SIGTERM
The default signal sent by kill is signal 15 also known as SIGTERM. This is a friendly shutdown signal, which allows the process to get it’s things in order before exiting.
This can also be sent by explicitly telling kill what signal to send
Send SIGKILL
The next most common signal is 9 also known as SIGKILL. This is a stronger signal which does not allow the process to get it’s things in order before stopping it.
Send arbitrary signal
There are many other signals that can be registered and handled by a process. In my kernel they were found here: /usr/src/kernels/2.6.18-8.el5-i686/include/asm They can also be found here online. The following will send SIGUSR1
Experiment
Register SIGTERM
The following Python code will register a function called a signal handler to catch the SIGTERM signal.
import signal
import sys
def signal_handler_term(signal, frame):
print "Caught SIGTERM signal"
sys.exit(0)
#signal.signal(signal.SIGTERM, signal_handler_term)
while True:
pass
When we run this script, it will remain in memory until we issue the SIGTERM signal with the kill command
On a different terminal, let’s find the correct process
Notice that the process is still running
smccarty 8181 4753 86 14:48 pts/7 00:00:12 python ./signal-catcher.py
smccarty 8183 4476 0 14:48 pts/6 00:00:00 grep signal-catcher.py
Now issue the default signal for kill, SIGTERM
The process will display the message we set and exit
Try it again with SIGKILL and notice the difference. Python was not allowed to handle the signal, instead it was killed by the OS (Linux)
The operating system displays a default message, but our process is never given a chance to catch the SIGKILL
Register SIGKILL
Now let’s create a quick script to try and catch the SIGKILL signal.
import signal
import sys
def signal_handler_kill(signal, frame):
print "Caught SIGKILL signal"
sys.exit(0)
signal.signal(signal.SIGKILL, signal_handler_kill)
while True:
pass
Notice after trying to run this code, it will exit with an error
Python will not allow us to register SIGKILL
File "./signal-catcher.py", line 22, in <module>
signal.signal(signal.SIGKILL, signal_handler_kill)
RuntimeError: (22, 'Invalid argument')
The standard C library does not allow a handler to be registered for the SIGKILL signal. The following C code from the Python source checks for SIG_ERR and propagates RuntimeError up the python stack. This code can be found under Modules/signalmodule.c if you are interested
PyErr_SetFromErrno(PyExc_RuntimeError);
return NULL;
}
Also, from the documentation
to the :func:`signal.signal` function. For example, you can't set a handler on
the :const:`SIGKILL` signal; previous versions of Python would quietly accept
this, but 2.4 will raise a :exc:`RuntimeError` exception.
Register SIGSTOP
As a fiinal experiment, try and register SIGSTOP. It has the same restriction that SIGKILL has. A process is not permitted to catch SIGSTOP. This is because SIGSTOP and SIGCONT are reserved for use by the operating system for job control.
