Understanding Linux Signals: A Comprehensive Guide
1. Signal Fundamentals
Signals in Linux are software interrupts delivered to a process by the operating system or other processes. They serve as notifications that a particular event has occurred, requiring attention or action from the receiving process.
When a process receives a signal, it can:
- Execute the default action associated with that signal
- Handle the signal with a custom function (signal handler)
- Ignore the signal (if permitted)
2. Purpose of Signals
Signals serve several important purposes in Linux systems:
- Inter-Process Communication (IPC): Processes can send signals to each other to communicate events. For example, a parent process might send a signal to a child process to instruct it to terminate.
- Exception Handling: When a process performs an illegal operation (such as accessing invalid memory or dividing by zero), the kernel sends an appropriate signal to notify the process of the error.
- System Management: System administrators use signals to control process behavior, such as terminating unresponsive processes.
3. Types of Signals
Linux defines two categories of signals:
- Standard Signals: These are numbered from 1 to 31 and represent the traditional Unix signals. They are supported by all Unix-like systems.
- Real-time Signals: Numbered from 32 to 64, these are Linux-specific extensions that provide additional funcsionality for real-time applications.
To view all available signals on your system, execute:
kill -l
4. Common Signals and Their Meanings
Below are some of the most frequently encountered signals in Linux programming:
Key actions include:
- Term: Terminate the process
- Core: Terminate the process and generate a core dump for debugging
- Ignore: Ignore the signal
- Cont: Continue the process if it was stopped
- Stop: Stop the process (pause execution without terminating)
5. Signal Handling in Programming
In C programming, the signal() functon is used to define how a process should handle a specific signal:
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
void handle_sigint(int sig) {
printf("Caught signal %d (SIGINT)\n", sig);
// Perform cleanup or other actions here
}
int main() {
// Register the signal handler
signal(SIGINT, handle_sigint);
printf("Waiting for SIGINT (Ctrl+C)...\n");
while(1) {
sleep(1); // Infinite loop waiting for signal
}
return 0;
}
For more robust signal handling, especially in complex applications, consider using the sigaction() system call, which provides more control and reliability than the simpler signal() function.