A signal is a software-generated interrupt sent to a process by the operating system or another process to notify it about an event.
- C provides a fixed set of signals, each identified by an integer value. For example, SIGINT has the value 2.
- Signals can be generated by user actions, such as pressing Ctrl+C, or sent by another process.
Signal Handling
Signal handling in C allows a program to control how it responds when a signal is received, instead of relying only on its default behavior.
- A signal handler function can be defined to perform a custom action when a specific signal occurs.
- It provides flexibility to handle events such as errors, interruptions, or user actions like pressing Ctrl+C.
Default Signal Handlers
There are several default signal handler functions. Each signal is associated with one of these default handler routines. The different default handler routines typically have one of the following actions:
- Ign: Ignore the signal, i.e., do nothing just return.
- Term: Terminate the process.
- Cont: Unblock a stopped process.
- Stop: Block the process.
#include <stdio.h>
#include <signal.h>
int main() {
while (1) {
printf("hello world\n");
}
return 0;
}
Output
hello world
hello world
hello world
. .
. .
Above program prints "hello world" infinitely. When the user presses Ctrl + C, the SIGINT signal is sent, and the default handler terminates the process.
User Defined Signal Handlers
A process can replace the default signal handler for most signals (except SIGKILL) with its own custom handler function.
- A signal handler can have any name, but it must return void and accept one int parameter representing the signal number.
- The signal() function from the <signal.h> header is used to register the custom handler for a specific signal.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void signalHandler(int sig) {
const char msg[] = "Caught SIGINT\n";
write(STDOUT_FILENO, msg, sizeof(msg) - 1);
_exit(sig);
}
int main() {
signal(SIGINT, signalHandler);
while (1) {
printf("Hello World!\n");
sleep(1);
}
return 0;
}
Output
Hello World!
Hello World!
Hello World!
....
Ctrl+C (Enter by user)
Caught SIGINT
In the above code, the program prints "Hello World!" continuously. When the user presses Ctrl+C, the OS sends a SIGINT signal to the process. The registered signalHandler function is invoked, which safely prints "Caught SIGINT" and terminates the program.
Syntax
signal(type, signalHandler);
where,
- type: Type of signal.
- signalHandler: Function that handle type signal.
Generate Signals Manually
In the above example, you can see that the signal is automatically generated when the user presses Ctrl+C. There are functions available that provide the functionality to generate signals manually.
raise() Function
The raise() function in C is used to send a signal to the current process. It takes the signal type as an argument and triggers that signal within the same process.
- It is defined in the <signal.h> header file and can be used to manually generate signals such as SIGINT
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
// Signal handler function
void signalHandler(int sig) {
printf("Interrupt handled: %d", sig);
// Optionally exit the program after handling
exit(sig);
}
int main() {
// Handle signal
signal(SIGINT, signalHandler);
// Automatically generate a signal
raise(SIGINT);
return 0;
}
Output
Interrupt handled: 2
Syntax
raise(signal_type);
It returns 0 on success, or a non-zero value on failure.
kill() Function
The kill() function in C is used to send a signal to another process or a group of processes using their process ID (PID).
- It is defined in the <signal.h> header file and can send signals such as SIGTERM or SIGKILL.
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
void handle_signal(int signal_num) {
printf("Received signal: %d\n", signal_num);
}
int main() {
// Handle signal
signal(SIGINT, handle_signal);
// Get current process ID
pid_t pid = getpid();
// Generate signal using kill()
kill(pid, SIGINT);
return 0;
}
Output:
Received Signal: 2Syntax
kill(pid, signal_type);
where, pid: The process ID of the target process to which the signal should be sent.
Signal Types in C
C offers various types of interruptions, which are listed below:
Signal Name | Description | Default Behaviour |
|---|---|---|
SIGABRT | Abnormal termination (abort) by the program. | Program terminates |
SIGFPE | Floating-point exception (e.g., division by zero or overflow). | Program terminates |
SIGILL | Illegal instruction (e.g., invalid opcode). | Program terminates |
SIGINT | Interrupt signal (sent when Ctrl+C is pressed by the user). | Program terminates |
SIGSEGV | Segmentation fault (invalid memory access). | Program terminates |
SIGTERM | Termination signal (request to terminate the process). | Program terminates |
SIGKILL | Kill signal (forceful termination of a process). | Program terminates |
SIGBUS | Bus error (e.g., misaligned memory access). | Program terminates |
SIGQUIT | Quit signal (similar to SIGINT but causes core dump). | Program terminates (Core dump) |
SIGCHLD | Child process terminated or stopped. | No action (handled by parent) |
SIGCONT | Continue a stopped process. | Process resumed |
SIGTSTP | Terminal stop signal (sent by pressing Ctrl+Z). | Process Stop |