Notice: This page requires JavaScript to function properly.
Please enable JavaScript in your browser settings or update your browser.
Oppiskele Signal Handling | Practical System Call Usage
Linux System Calls with C

bookSignal Handling

Signals in Linux are a fundamental mechanism for handling asynchronous events. A signal is a limited form of inter-process communication used to notify a process that a specific event has occurred. Signals can be sent by the kernel or by other processes, and are often used for events such as segmentation faults (SIGSEGV), illegal instructions (SIGILL), or external interrupts like pressing Ctrl+C in a terminal (SIGINT).

When a signal is delivered to a process, the process can respond in one of several ways: it can ignore the signal, use the default action (such as terminating the process), or catch the signal by installing a custom signal handler. Signal handlers are functions written in C that execute in response to specific signals, allowing you to perform cleanup, log information, or otherwise manage the event before the process continues or terminates.

Signal handling is crucial for building robust Linux programs. For example, you might want your program to clean up temporary files or save state before exiting when interrupted by a user. To do this, you must understand how to register signal handlers and ensure your code is safe to execute in the asynchronous context of a signal.

signal_handler_demo.c

signal_handler_demo.c

copy
12345678910111213141516171819202122232425262728293031
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> void handle_sigint(int sig) { // Print a message when SIGINT is received write(STDOUT_FILENO, "Caught SIGINT! Exiting gracefully.\n", 34); _exit(0); // Use _exit() to avoid unsafe operations in handler } int main() { // Register handle_sigint as the handler for SIGINT (Ctrl+C) struct sigaction sa; sa.sa_handler = handle_sigint; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); if (sigaction(SIGINT, &sa, NULL) == -1) { perror("sigaction"); return 1; } printf("Running. Press Ctrl+C to trigger SIGINT...\n"); // Loop forever, waiting for signals while (1) { pause(); // Wait for a signal to arrive } return 0; }

In the provided program, you install a custom signal handler for SIGINT (triggered by pressing Ctrl+C). The handler function, handle_sigint, uses the write system call to print a message, then calls _exit(0) to terminate the process immediately. This approach avoids calling functions that are not safe within a signal handler.

When a signal handler is invoked, it interrupts the normal flow of your program at an unpredictable point. This raises concerns about reentrancy—if your handler calls functions that are not reentrant (that is, not safe to be interrupted and called again before a previous invocation is complete), you may encounter undefined behavior or data corruption. For this reason, only a small set of system calls and library functions are considered signal-safe; these include _exit, write, and a few others.

Best practices for writing signal handlers in C include:

  • Keep the handler as short and simple as possible;
  • Avoid calling non-reentrant or unsafe functions such as printf, malloc, or most standard library functions;
  • Use only async-signal-safe functions within the handler;
  • If complex cleanup or communication is needed, set a flag in the handler and perform the work in the main program flow.

By following these guidelines, you ensure your program responds to signals reliably and safely, minimizing the risk of subtle bugs or crashes.

question mark

Which of the following statements about signal handlers in C on Linux are correct?

Select all correct answers

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 2. Luku 3

Kysy tekoälyä

expand

Kysy tekoälyä

ChatGPT

Kysy mitä tahansa tai kokeile jotakin ehdotetuista kysymyksistä aloittaaksesi keskustelumme

bookSignal Handling

Pyyhkäise näyttääksesi valikon

Signals in Linux are a fundamental mechanism for handling asynchronous events. A signal is a limited form of inter-process communication used to notify a process that a specific event has occurred. Signals can be sent by the kernel or by other processes, and are often used for events such as segmentation faults (SIGSEGV), illegal instructions (SIGILL), or external interrupts like pressing Ctrl+C in a terminal (SIGINT).

When a signal is delivered to a process, the process can respond in one of several ways: it can ignore the signal, use the default action (such as terminating the process), or catch the signal by installing a custom signal handler. Signal handlers are functions written in C that execute in response to specific signals, allowing you to perform cleanup, log information, or otherwise manage the event before the process continues or terminates.

Signal handling is crucial for building robust Linux programs. For example, you might want your program to clean up temporary files or save state before exiting when interrupted by a user. To do this, you must understand how to register signal handlers and ensure your code is safe to execute in the asynchronous context of a signal.

signal_handler_demo.c

signal_handler_demo.c

copy
12345678910111213141516171819202122232425262728293031
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> void handle_sigint(int sig) { // Print a message when SIGINT is received write(STDOUT_FILENO, "Caught SIGINT! Exiting gracefully.\n", 34); _exit(0); // Use _exit() to avoid unsafe operations in handler } int main() { // Register handle_sigint as the handler for SIGINT (Ctrl+C) struct sigaction sa; sa.sa_handler = handle_sigint; sa.sa_flags = 0; sigemptyset(&sa.sa_mask); if (sigaction(SIGINT, &sa, NULL) == -1) { perror("sigaction"); return 1; } printf("Running. Press Ctrl+C to trigger SIGINT...\n"); // Loop forever, waiting for signals while (1) { pause(); // Wait for a signal to arrive } return 0; }

In the provided program, you install a custom signal handler for SIGINT (triggered by pressing Ctrl+C). The handler function, handle_sigint, uses the write system call to print a message, then calls _exit(0) to terminate the process immediately. This approach avoids calling functions that are not safe within a signal handler.

When a signal handler is invoked, it interrupts the normal flow of your program at an unpredictable point. This raises concerns about reentrancy—if your handler calls functions that are not reentrant (that is, not safe to be interrupted and called again before a previous invocation is complete), you may encounter undefined behavior or data corruption. For this reason, only a small set of system calls and library functions are considered signal-safe; these include _exit, write, and a few others.

Best practices for writing signal handlers in C include:

  • Keep the handler as short and simple as possible;
  • Avoid calling non-reentrant or unsafe functions such as printf, malloc, or most standard library functions;
  • Use only async-signal-safe functions within the handler;
  • If complex cleanup or communication is needed, set a flag in the handler and perform the work in the main program flow.

By following these guidelines, you ensure your program responds to signals reliably and safely, minimizing the risk of subtle bugs or crashes.

question mark

Which of the following statements about signal handlers in C on Linux are correct?

Select all correct answers

Oliko kaikki selvää?

Miten voimme parantaa sitä?

Kiitos palautteestasi!

Osio 2. Luku 3
some-alt