Linux signals are an essential concept for anyone looking to understand how processes communicate and interact within a Unix-like operating system. Signals are a form of inter-process communication (IPC) used to notify a process that a specific event has occurred. This blog post will explore signals, the tools kill
, pkill
, and pidof
, and how to create a Python script that reacts differently to various signals sent using the kill
command.
What Are Linux Signals?
A signal is a limited form of message that can be sent to a process. It informs the process to perform some action, such as termination or reloading its configuration. Each signal has a unique integer number and a symbolic name, such as:
- SIGHUP (1): Hangup detected on controlling terminal or death of controlling process.
- SIGINT (2): Interrupt from keyboard (Ctrl+C).
- SIGTERM (15): Termination signal.
- SIGKILL (9): Kill signal, cannot be caught or ignored.
- SIGUSR1 (10) and SIGUSR2 (12): User-defined signals for custom purposes.
Processes can handle some signals programmatically, while others (like SIGKILL
) are not catchable.
List of Standard Linux Signals
You can list all signals with the following command:
bashkill -L
But here is the organized list of signals with their descriptions:
Signal Number | Signal Name | Description |
---|---|---|
1 | SIGHUP | Hangup detected on controlling terminal or death of controlling process. |
2 | SIGINT | Interrupt from keyboard (Ctrl+C). |
3 | SIGQUIT | Quit from keyboard. |
4 | SIGILL | Illegal instruction. |
5 | SIGTRAP | Trace/breakpoint trap. |
6 | SIGABRT | Abort signal from abort(3). |
7 | SIGBUS | Bus error (bad memory access). |
8 | SIGFPE | Floating-point exception. |
9 | SIGKILL | Kill signal, cannot be caught or ignored. |
10 | SIGUSR1 | User-defined signals for custom purposes. |
11 | SIGSEGV | Invalid memory reference. |
12 | SIGUSR2 | User-defined signals for custom purposes. |
13 | SIGPIPE | Broken pipe: write to pipe with no readers. |
14 | SIGALRM | Timer signal from alarm(2). |
15 | SIGTERM | Termination signal. |
16 | SIGSTKFLT | Stack fault on coprocessor (unused on most systems). |
17 | SIGCHLD | Child process terminated, stopped, or continued. |
18 | SIGCONT | Continue if stopped. |
19 | SIGSTOP | Stop process. |
20 | SIGTSTP | Stop typed at terminal. |
21 | SIGTTIN | Terminal input for background process. |
22 | SIGTTOU | Terminal output for background process. |
23 | SIGURG | Urgent condition on socket. |
24 | SIGXCPU | CPU time limit exceeded. |
25 | SIGXFSZ | File size limit exceeded. |
26 | SIGVTALRM | Virtual alarm clock. |
27 | SIGPROF | Profiling alarm clock. |
28 | SIGWINCH | Window size change. |
29 | SIGIO | I/O now possible. |
30 | SIGPWR | Power failure. |
31 | SIGSYS | Bad system call. |
34 | SIGRTMIN | Real-time. |
35 | SIGRTMIN+1 | Real-time plus one. |
36 | SIGRTMIN+2 | Real-time plus two. |
37 | SIGRTMIN+3 | Real-time plus three. |
38 | SIGRTMIN+4 | Real-time plus four. |
39 | SIGRTMIN+5 | Real-time plus five. |
40 | SIGRTMIN+6 | Real-time plus six. |
41 | SIGRTMIN+7 | Real-time plus seven. |
42 | SIGRTMIN+8 | Real-time plus eight. |
43 | SIGRTMIN+9 | Real-time plus nine. |
44 | SIGRTMIN+10 | Real-time plus ten. |
45 | SIGRTMIN+11 | Real-time plus eleven. |
46 | SIGRTMIN+12 | Real-time plus twelve. |
47 | SIGRTMIN+13 | Real-time plus thirteen. |
48 | SIGRTMIN+14 | Real-time plus fourteen. |
49 | SIGRTMIN+15 | Real-time plus fifteen. |
50 | SIGRTMAX-14 | Real-time minus fourteen. |
51 | SIGRTMAX-13 | Real-time minus thirteen. |
52 | SIGRTMAX-12 | Real-time minus twelve. |
53 | SIGRTMAX-11 | Real-time minus eleven. |
54 | SIGRTMAX-10 | Real-time minus ten. |
55 | SIGRTMAX-9 | Real-time minus nine. |
56 | SIGRTMAX-8 | Real-time minus eight. |
57 | SIGRTMAX-7 | Real-time minus seven. |
58 | SIGRTMAX-6 | Real-time minus six. |
59 | SIGRTMAX-5 | Real-time minus five. |
60 | SIGRTMAX-4 | Real-time minus four. |
61 | SIGRTMAX-3 | Real-time minus three. |
62 | SIGRTMAX-2 | Real-time minus two. |
63 | SIGRTMAX-1 | Real-time minus one. |
64 | SIGRTMAX | Real-time maximum. |
Commands for Managing Signals
-
kill
The kill
command sends a signal to a process. By default, it sends the SIGTERM
signal. To specify a signal:
bashkill -SIGKILL <pid>
kill -9 <pid> # You can use number as well
-
pkill
The pkill
command allows you to send signals to processes by name:
bashpkill -SIGUSR1 python
pkill -10 python
-
pidof
The pidof
command retrieves the PID(s) of a process by name:
bashpidof python
Combine it with kill
to send a signal:
bashkill -9 $(pidof python)
Exit Codes
This blog is not about exit codes. But we must mention that when a process is terminated by a signal, it will exit with a specific exit code unless the program is designed to handle with another exit code. The exit code is calculated as 128 + signal number
. For example:
-
SIGINT
means2
and it will exit with128 + 2 = 130
-
SIGKILL
means9
and it will exit with128 + 9 = 137
-
SIGTERM
means15
and it will exit with128 + 15 = 143
Reacting to Signals in Python
Python provides the signal
module, which allows a script to handle signals programmatically. Here is an example script that handles SIGINT
, SIGTERM
, and SIGUSR1
differently:
pythonimport signal
import os
import time
def handle_signal(signum, frame):
if signum == signal.SIGINT:
print("Received SIGINT (Ctrl+C). I don't want to exit.")
elif signum == signal.SIGTERM:
print("Received SIGTERM. Cleaning up before termination.")
countdown = 5
while countdown > 0:
print(f"Exiting in {countdown} seconds...")
time.sleep(1)
countdown -= 1
exit(128 + signum)
elif signum == signal.SIGUSR1:
print("Received SIGUSR1. Performing user-defined action.")
print("I'm doing something...")
time.sleep(3)
print("I'm done.")
exit(128 + signum)
else:
print(f"Received unknown signal: {signum}")
# Register signal handlers
signal.signal(signal.SIGINT, handle_signal)
signal.signal(signal.SIGTERM, handle_signal)
signal.signal(signal.SIGUSR1, handle_signal)
print(f"Process PID: {os.getpid()}")
print("Waiting for signals. Use kill or pkill to send signals to this process.")
try:
while True:
time.sleep(1) # Keep the program running to receive signals
except KeyboardInterrupt:
print("Program interrupted. Exiting.")
How to Test the Script
-
Save the script to a file, e.g.,
signal_handler.py
. - Run the script:
bashpython3 signal_handler.py
- Send signals to the process using its PID:
bashkill -2 <pid>
kill -15 <pid>
kill -10 <pid>
You can also use pkill
or combine pidof
with kill
to achieve the same.
Conclusion
Linux signals are a powerful tool for managing processes and enabling inter-process communication. Commands like kill
, pkill
, and pidof
make it easier to work with signals in practice. By writing scripts that handle signals, you can add resilience and customization to your applications, allowing them to respond intelligently to system events. Experiment with the provided Python script to deepen your understanding of Linux signals!