System-Level Interrupts and Events
In Unix-based environments, processes communicate asynchronous events via signals. These serve as software interrupts generated by hardware faults or kernel requests. Unlike hardware interrupts, signals allow user-space programs to register handlers for specific events like termination requests or segmentation violations.
Core Terminology
Signals function as software equivalents to hardware interruptions. Upon receipt, a process can execute a predefined routine. Common scenarios include division errors (SIGFPE), invalid memory access (SIGSEGV), or user-initiated termination (SIGINT). The legacy signal range (1-31) lacks queue support, potentially dropping duplicates, whereas real-time signals (34+) guarantee delivery order and quantity.
Configuring Handlers
A handler is a user-defined routine accepting an integer representing the signal ID. It operates under strict constraints regarding function safety.
Legacy Interface
The signal() interface simplifies registration but exhibits inconsistent behavior across platforms regarding resumption after interruption.
#include <stdio.h>
#include <signal.h>
void my_handler(int sig_num) {
fprintf(stdout, "Received signal %d\n", sig_num);
}
int main(void) {
if (signal(SIGINT, my_handler) == SIG_ERR) {
perror("Failed to set trap");
return 1;
}
while (1) {
// Main execution loop
}
return 0;
}
Modern Interface (sigaction)
For robust production code, sigaction() provides granular control over mask behaviors and restart semantics.
#include <string.h>
#include <unistd.h>
void handler_fn(int sig, siginfo_t *info, void *ctx) {
// Enhanced error logging
}
int configure_signal(int signum) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = handler_fn;
sa.sa_flags = SA_SIGINFO | SA_RESTART;
sigemptyset(&sa.sa_mask);
return sigaction(signum, &sa, NULL);
}
Delivery Mechanisms
Signals reach processes through multiple vectors:
- Input Devices: Key combinations like Ctrl+C (interrupt) or Ctrl+Z (suspend).
- Runtime Faults: Arithmetic overflow or illegal pointer dereferencing.
- CLI Tools: The
killcommand targets PIDs, whilekillalladdresses process names. - System Calls: Programmatic generation uses
kill(pid, sig)for external targets,raise(sig)for self-signaling, orabort()to trigger abnormal termination. Timers utilizealarm(seconds)to dispatch SIGALRM.
Masking and State Management
Processes maintain a bit-mask of pending or blocked signals using sigset_t. Operations include adding, deleting, or testing specific bits within the set.
Blocking prevetns delivery until explicitly unblocked via sigprocmask(). This mechanism ensures atomicity during critical sections.
sigset_t current_mask, block_set;
// Retrieve active mask
sigprocmask(SIG_SETMASK, NULL, ¤t_mask);
// Block a set of signals
sigaddset(&block_set, SIGINT);
sigprocmask(SIG_BLOCK, &block_set, NULL);
Process State Pausing
To halt execution synchronously, kernels offer suspension primitives. pause() indefinitely suspends the caller until any signal is received, returning -1 upon wake-up. Conversely, sleep() suspends for a defined duration, interruptible by asynchronous signals which cause premature return of remaining seconds.