Linux Signals and Process Management Tools

Linux Signals and Process Management Tools

Learn how to handle Linux signals in Python, including SIGINT, SIGTERM and SIGUSR1, with practical examples of process management and signal handling.

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:

kill -L

But here is the organized list of signals with their descriptions:

Signal NumberSignal NameDescription
1SIGHUPHangup detected on controlling terminal or death of controlling process.
2SIGINTInterrupt from keyboard (Ctrl+C).
3SIGQUITQuit from keyboard.
4SIGILLIllegal instruction.
5SIGTRAPTrace/breakpoint trap.
6SIGABRTAbort signal from abort(3).
7SIGBUSBus error (bad memory access).
8SIGFPEFloating-point exception.
9SIGKILLKill signal, cannot be caught or ignored.
10SIGUSR1User-defined signals for custom purposes.
11SIGSEGVInvalid memory reference.
12SIGUSR2User-defined signals for custom purposes.
13SIGPIPEBroken pipe: write to pipe with no readers.
14SIGALRMTimer signal from alarm(2).
15SIGTERMTermination signal.
16SIGSTKFLTStack fault on coprocessor (unused on most systems).
17SIGCHLDChild process terminated, stopped, or continued.
18SIGCONTContinue if stopped.
19SIGSTOPStop process.
20SIGTSTPStop typed at terminal.
21SIGTTINTerminal input for background process.
22SIGTTOUTerminal output for background process.
23SIGURGUrgent condition on socket.
24SIGXCPUCPU time limit exceeded.
25SIGXFSZFile size limit exceeded.
26SIGVTALRMVirtual alarm clock.
27SIGPROFProfiling alarm clock.
28SIGWINCHWindow size change.
29SIGIOI/O now possible.
30SIGPWRPower failure.
31SIGSYSBad system call.
34SIGRTMINReal-time.
35SIGRTMIN+1Real-time plus one.
36SIGRTMIN+2Real-time plus two.
37SIGRTMIN+3Real-time plus three.
38SIGRTMIN+4Real-time plus four.
39SIGRTMIN+5Real-time plus five.
40SIGRTMIN+6Real-time plus six.
41SIGRTMIN+7Real-time plus seven.
42SIGRTMIN+8Real-time plus eight.
43SIGRTMIN+9Real-time plus nine.
44SIGRTMIN+10Real-time plus ten.
45SIGRTMIN+11Real-time plus eleven.
46SIGRTMIN+12Real-time plus twelve.
47SIGRTMIN+13Real-time plus thirteen.
48SIGRTMIN+14Real-time plus fourteen.
49SIGRTMIN+15Real-time plus fifteen.
50SIGRTMAX-14Real-time minus fourteen.
51SIGRTMAX-13Real-time minus thirteen.
52SIGRTMAX-12Real-time minus twelve.
53SIGRTMAX-11Real-time minus eleven.
54SIGRTMAX-10Real-time minus ten.
55SIGRTMAX-9Real-time minus nine.
56SIGRTMAX-8Real-time minus eight.
57SIGRTMAX-7Real-time minus seven.
58SIGRTMAX-6Real-time minus six.
59SIGRTMAX-5Real-time minus five.
60SIGRTMAX-4Real-time minus four.
61SIGRTMAX-3Real-time minus three.
62SIGRTMAX-2Real-time minus two.
63SIGRTMAX-1Real-time minus one.
64SIGRTMAXReal-time maximum.

Commands for Managing Signals

  1. kill

The kill command sends a signal to a process. By default, it sends the SIGTERM signal. To specify a signal:

kill -SIGKILL <pid>
kill -9 <pid> # You can use number as well
  1. pkill

The pkill command allows you to send signals to processes by name:

pkill -SIGUSR1 python
pkill -10 python
  1. pidof

The pidof command retrieves the PID(s) of a process by name:

pidof python

Combine it with kill to send a signal:

kill -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 means 2 and it will exit with 128 + 2 = 130
  • SIGKILL means 9 and it will exit with 128 + 9 = 137
  • SIGTERM means 15 and it will exit with 128 + 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:

import 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

  1. Save the script to a file, e.g., signal_handler.py.

  2. Run the script:

python3 signal_handler.py
  1. Send signals to the process using its PID:
kill -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!