Linux - Linux Signals and Inter-Process Process Control
Linux signals are a fundamental mechanism used by the operating system to notify processes that a particular event has occurred. They allow processes to communicate with the kernel and with other processes without requiring them to continuously check for changes. Signals are commonly used to terminate processes, pause and resume execution, handle errors, reload configurations, and coordinate activities between processes.
1. What Is a Signal in Linux?
A signal is an asynchronous notification delivered to a process or thread. When a process receives a signal, Linux can take a predefined action, or the program can provide its own signal-handling function.
For example, suppose a program is running continuously in the terminal. Pressing Ctrl+C normally sends the SIGINT signal to that process. The default behavior of SIGINT is to terminate the process.
Signals are identified by names and numbers. Some commonly used signals include:
| Signal | Number | Purpose |
|---|---|---|
| SIGHUP | 1 | Hangup or request configuration reload |
| SIGINT | 2 | Interrupt from the keyboard |
| SIGQUIT | 3 | Quit and produce a core dump |
| SIGKILL | 9 | Immediately terminate a process |
| SIGTERM | 15 | Request graceful termination |
| SIGSTOP | 19 | Stop or pause a process |
| SIGCONT | 18 | Continue a stopped process |
| SIGCHLD | 17 | Notify a parent when a child process changes state |
| SIGUSR1 | 10 | User-defined signal |
| SIGUSR2 | 12 | User-defined signal |
The exact numbering can vary on some architectures, so signal names are generally preferred in scripts and programs.
2. How Signals Work
A simplified signal lifecycle is:
Event occurs → Signal is generated → Signal is delivered → Process handles the signal
For example:
User presses Ctrl+C
|
v
SIGINT is generated
|
v
Signal is delivered to the foreground process
|
v
Process performs its SIGINT action
|
v
Process terminates or handles the interruption
A signal can be generated by several sources. The kernel can generate signals when certain events occur. One process can send a signal to another process, and a user can indirectly generate signals through terminal operations.
For example:
kill -TERM 2456
This sends SIGTERM to process ID 2456.
Despite its name, the kill command does not necessarily mean "forcefully terminate." It is a general command for sending signals to processes.
3. SIGTERM: Graceful Process Termination
SIGTERM is one of the most important signals for process management.
When a process receives SIGTERM, it is being asked to terminate. The application has an opportunity to perform cleanup operations before exiting.
For example:
kill -TERM 2456
A well-designed application might respond by:
-
Stopping new work.
-
Finishing currently running operations.
-
Closing files.
-
Closing network connections.
-
Saving necessary information.
-
Releasing resources.
-
Exiting normally.
This is why SIGTERM is normally preferred over SIGKILL when stopping an application.
4. SIGKILL: Immediate Termination
SIGKILL forcibly terminates a process:
kill -KILL 2456
or:
kill -9 2456
Unlike SIGTERM, a process cannot catch, ignore, or handle SIGKILL.
This makes SIGKILL powerful but potentially disruptive. The application does not get an opportunity to perform its normal cleanup.
For example, if an application is writing data when it receives SIGKILL, it may not get an opportunity to complete its operation cleanly.
A good general practice is:
SIGTERM → wait → SIGKILL if necessary
rather than immediately using kill -9.
5. SIGINT and Ctrl+C
When a user presses:
Ctrl+C
the terminal normally sends SIGINT to the foreground process group.
For example:
ping example.com
If the command is running continuously, pressing Ctrl+C interrupts it.
Applications can handle SIGINT differently depending on their design. A command-line application might terminate immediately, while another program might use the signal to initiate a controlled shutdown.
6. SIGSTOP and SIGCONT
Linux provides signals for stopping and continuing processes.
SIGSTOP suspends a process:
kill -STOP 2456
The process remains in memory but stops executing.
To resume it:
kill -CONT 2456
SIGCONT tells the stopped process to continue execution.
These signals are useful for temporarily suspending a process without terminating it.
For example:
Running
|
| SIGSTOP
v
Stopped
|
| SIGCONT
v
Running
SIGSTOP, like SIGKILL, cannot be caught or ignored by the target process.
7. SIGHUP and Configuration Reloading
Historically, SIGHUP represented a terminal hangup. Today, many Linux services use it for another purpose: requesting that a service reload its configuration.
For example:
kill -HUP 2456
However, the exact behavior depends on the application. Not every program treats SIGHUP as a configuration-reload request.
This is important when administering servers. The correct signal should always be verified from the application's documentation.
8. SIGCHLD and Parent-Child Processes
SIGCHLD is particularly important when working with parent and child processes.
When a child process terminates or changes state, the kernel can notify its parent using SIGCHLD.
Consider:
Parent Process
|
| creates
v
Child Process
|
| finishes
v
SIGCHLD sent to parent
The parent can then collect information about the child process.
This mechanism is closely related to the concept of process reaping. A parent normally uses system calls such as wait() or waitpid() to collect the child's termination status.
If a parent fails to properly reap terminated children, zombie processes can accumulate.
9. Sending Signals with the kill Command
The basic syntax is:
kill [signal] PID
For example:
kill -TERM 2456
Another form is:
kill -15 2456
To send SIGKILL:
kill -9 2456
To send SIGSTOP:
kill -STOP 2456
To send SIGCONT:
kill -CONT 2456
You can see available signals with:
kill -l
This displays the signals supported by the system.
10. Finding a Process ID
Before sending a signal, you often need the process ID.
You can use:
ps aux
For a particular process, tools such as:
pgrep nginx
can be useful.
For example:
pgrep nginx
might return:
2456
2510
2534
You could then send a signal to one of those processes.
Another useful command is:
pidof nginx
which can return the process IDs associated with the specified program.
11. Signal Handling by Applications
A Linux application can define how it responds to many signals.
For example, a server might receive SIGTERM and execute a cleanup routine before exiting.
Conceptually:
SIGTERM received
|
v
Signal handler
|
+--> Stop accepting new connections
|
+--> Finish current operations
|
+--> Close resources
|
+--> Exit
Programming languages and libraries provide mechanisms for registering signal handlers.
In C, modern applications commonly use sigaction() rather than the older signal() interface because sigaction() provides more predictable and flexible behavior.
12. Signals That Cannot Be Caught
Most signals can be handled or ignored by an application, but there are important exceptions.
Two particularly important signals are:
SIGKILL
SIGSTOP
A program cannot install a handler for SIGKILL or SIGSTOP.
This design gives administrators and the operating system reliable mechanisms for terminating or stopping a process even if the process is malfunctioning.
For example, if a program is stuck and does not respond to SIGTERM, an administrator can eventually use:
kill -9 PID
13. Signal Masks
A process can temporarily block certain signals.
A signal mask specifies which signals are currently blocked from normal delivery.
Blocking does not necessarily mean the signal disappears. Depending on the signal type, a pending signal can remain until it becomes unblocked.
Conceptually:
Signal generated
|
v
Is signal blocked?
/ \
Yes No
| |
v v
Pending Delivered
|
v
Unblocked later
|
v
Delivered
Signal masks are particularly important in multithreaded applications because threads can have different signal masks.
14. Pending Signals
A signal is considered pending when it has been generated but has not yet been delivered to the process or thread.
This can happen when a signal is temporarily blocked.
For example:
SIGTERM generated
|
v
Signal blocked
|
v
Signal becomes pending
|
v
Signal is unblocked
|
v
Signal is delivered
Understanding pending signals is useful when troubleshooting applications that appear not to respond immediately to administrative commands.
15. Signals and Process Groups
Signals are not limited to individual processes.
Linux also supports process groups. This is especially important for terminal applications and job control.
For example, a shell may create a group containing several related processes:
Shell
|
+-- Process A
|
+-- Process B
|
+-- Process C
A signal can be directed toward a process group rather than only one process.
This allows related processes to be controlled together.
For example, terminal-generated signals such as SIGINT are normally delivered to the foreground process group.
16. Signals and Inter-Process Communication
Signals are one form of inter-process communication, commonly called IPC.
IPC allows separate processes to exchange information or coordinate actions.
Signals are particularly useful for notification rather than transferring large amounts of data.
For example:
Process A
|
| SIGUSR1
v
Process B
Process A can notify Process B that an event occurred.
For more substantial data exchange, other IPC mechanisms are generally more appropriate, such as:
-
Pipes
-
UNIX domain sockets
-
Message queues
-
Shared memory
-
Semaphores
Therefore, signals are best viewed as lightweight event notifications rather than a general-purpose data-transfer mechanism.
17. User-Defined Signals
Linux provides:
SIGUSR1
SIGUSR2
for application-specific purposes.
A developer can assign their own meaning to these signals.
For example, an application might define:
SIGUSR1 → Reload application settings
SIGUSR2 → Produce diagnostic information
The meaning is determined by the application, not by Linux itself.
These signals can be sent using:
kill -USR1 PID
or:
kill -USR2 PID
18. The kill Command and Permissions
A user cannot necessarily send arbitrary signals to every process on the system.
Linux uses process ownership and permissions to control signal delivery. In general, users can signal processes they have appropriate permission to control, while privileged users can manage a much broader range of processes.
For example:
kill -TERM 2456
may fail if the current user does not have permission to signal process 2456.
An administrator may need appropriate privileges to control a system service owned by another user.
19. The pkill and killall Commands
When many processes share the same name, identifying individual PIDs can be inconvenient.
pkill allows signals to be sent based on process attributes.
For example:
pkill -TERM nginx
This can send SIGTERM to matching processes.
Another command commonly available on Linux systems is:
killall nginx
The exact behavior and matching rules should be checked on the particular Linux distribution because implementations can differ.
For administrative scripts, precise process selection is important to avoid accidentally signaling unrelated processes.
20. Practical Example: Graceful Shutdown
Suppose a web server has PID 2456.
First, request a graceful shutdown:
kill -TERM 2456
Then check whether it is still running:
ps -p 2456
If the application has stopped, no further action is needed.
If it remains stuck and there is a legitimate reason to force termination:
kill -KILL 2456
The process-management sequence is therefore:
Identify process
|
v
Send SIGTERM
|
v
Allow cleanup
|
v
Check process status
|
+---- Stopped ----> Done
|
+---- Still running
|
v
SIGKILL if required
21. Signals in Shell Scripts
Signals are also important when writing shell scripts.
A script can use the trap command to specify actions when certain signals are received.
For example:
trap 'echo "Termination requested"; exit 0' TERM
This tells the shell to execute the specified action when it receives SIGTERM.
A more practical script might use trap to remove temporary files before exiting:
cleanup() {
rm -f /tmp/myfile
}
trap cleanup EXIT
This allows cleanup logic to be centralized rather than duplicated throughout the script.
22. Signal Safety
Signal handling has important programming constraints.
A signal can arrive asynchronously, meaning it can interrupt a program while the program is performing another operation.
Therefore, signal handlers should generally perform only safe and limited operations.
For example, complex operations inside a signal handler can introduce race conditions or inconsistent program state.
For sophisticated applications, developers often use signals only to record that an event occurred and then perform the actual work in the application's normal execution flow.
23. Signals in Multithreaded Programs
Signals become more complicated when an application contains multiple threads.
A process may contain:
Process
|
+-- Thread 1
|
+-- Thread 2
|
+-- Thread 3
Some signals are directed toward a specific thread, while others are directed toward the process and may be delivered to an appropriate thread according to Linux's signal rules.
Applications therefore need to carefully design signal handling when using multiple threads.
Linux provides mechanisms such as pthread_sigmask() for managing signal masks in threaded programs.
24. Signals and Job Control
Signals are fundamental to shell job control.
When you execute a command in a terminal, the shell can control whether it runs in the foreground or background.
For example:
sleep 100
Pressing Ctrl+Z normally causes the terminal to send SIGTSTP, which suspends the foreground job.
You can then use:
fg
to bring the job back to the foreground, or:
bg
to continue the stopped job in the background.
This demonstrates how signals, process groups, terminals, and shells work together.
25. Important Differences Between Common Signals
The most important distinctions are:
| Signal | Main Purpose | Can Application Handle It? |
|---|---|---|
| SIGINT | Interrupt a process | Yes |
| SIGTERM | Request graceful termination | Yes |
| SIGKILL | Force termination | No |
| SIGSTOP | Force process to stop | No |
| SIGCONT | Resume stopped process | Yes, subject to process state |
| SIGHUP | Terminal hangup or application-defined action | Yes |
| SIGUSR1 | Application-defined notification | Yes |
| SIGUSR2 | Application-defined notification | Yes |
| SIGCHLD | Child-process state notification | Yes |
| SIGTSTP | Terminal-generated stop request | Yes |
26. Best Practices for Signal-Based Process Control
When administering Linux systems, several practices are important.
First, prefer SIGTERM for normal process termination:
kill -TERM PID
Second, use SIGKILL only when a process cannot be terminated appropriately through normal mechanisms.
Third, verify the target process before sending a signal, particularly when using commands such as pkill or killall.
Fourth, understand that the same signal can have application-specific behavior. SIGHUP, for example, does not universally mean "reload configuration."
Fifth, avoid assuming that a successful kill command means the process has already exited. The command primarily requests signal delivery; the process may take time to respond.
Finally, applications should be designed to handle termination signals gracefully whenever possible.
Conclusion
Linux signals provide a lightweight and powerful mechanism for controlling processes and enabling communication between processes. Signals such as SIGTERM, SIGINT, SIGKILL, SIGSTOP, SIGCONT, and SIGCHLD have important roles in process management, while SIGUSR1 and SIGUSR2 allow applications to implement their own notification mechanisms.
Understanding signals is particularly valuable for Linux administrators, developers, DevOps engineers, and anyone working with server applications. The key distinction to remember is that SIGTERM requests a process to terminate gracefully, whereas SIGKILL forces immediate termination. Signals also form an important part of Linux job control, parent-child process management, service administration, and inter-process communication.