Unix/Linux Signals 101

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.
kill 1234

 

This can also be sent by explicitly telling kill what signal to send
kill -15 1235

 

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.
kill -9 1236

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
kill -10 1237

 

Experiment

Register SIGTERM

The following Python code will register a function called a signal handler to catch the SIGTERM signal.
#!/usr/bin/env python

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
./signal-catcher.py

 

On a different terminal, let’s find the correct process
ps -af | grep signal-catcher.py

 

Notice that the process is still running
ps -ef | grep signal-catcher.py
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
kill 8181

 

The process will display the message we set and exit
Caught SIGTERM signal

 

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)
kill -9 8267

 

The operating system displays a default message, but our process is never given a chance to catch the SIGKILL
Killed

 

Register SIGKILL

Now let’s create a quick script to try and catch the SIGKILL signal.
#!/usr/bin/env python

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
./signal-catcher.py

 

Python will not allow us to register SIGKILL
Traceback (most recent call last):
File "./signal-catcher.py", line 22, in
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
if (PyOS_setsig(sig_num, func) == SIG_ERR) {
PyErr_SetFromErrno(PyExc_RuntimeError);
return NULL;
}

 

Also, from the documentation
* The :mod:`signal` module now performs tighter error-checking on the parameters
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.

 

Leave a Reply

Your email address will not be published. Required fields are marked *