# Signal handling — `%SIG` `%SIG` is the hash where Perl exposes signal handlers. Setting `$SIG{NAME}` installs a handler for signal `NAME`; deleting it restores the default action. Two pseudo-signals — `__WARN__` and `__DIE__` — are not real OS signals at all but interpreter hooks into [`warn`](../perlfunc/warn.md) and [`die`](../perlfunc/die.md). ## The signal table Real OS signals come from the `POSIX` and `signal.h` lists. The common ones — keys you will actually use: | Key | Signal | Default action | When you handle it | |---------|----------|------------------|-----------------------------------------| | `INT` | SIGINT | terminate | Ctrl-C: graceful shutdown | | `TERM` | SIGTERM | terminate | `kill `: graceful shutdown | | `HUP` | SIGHUP | terminate | terminal hangup; daemons reload config | | `QUIT` | SIGQUIT | terminate + core | Ctrl-: like INT but with a core dump | | `PIPE` | SIGPIPE | terminate | wrote to a closed pipe; usually ignored | | `CHLD` | SIGCHLD | ignore | a child process died (`waitpid` here) | | `USR1` | SIGUSR1 | terminate | application-defined event | | `USR2` | SIGUSR2 | terminate | application-defined event | | `ALRM` | SIGALRM | terminate | `alarm()` timer expired | | `WINCH` | SIGWINCH | ignore | terminal window resized | | `IO` | SIGIO | terminate | async I/O ready | The full list — including signals you cannot catch (`KILL`, `STOP`) and platform-specific signals — comes from the [`POSIX`](../../POSIX.md) module, which exports the numeric constants (`SIGINT`, `SIGTERM`, …) and the `WIFEXITED`-family `wait` macros. ## Installing a handler Three handler-value forms are accepted: ```perl $SIG{INT} = \&handler; # code reference — preferred $SIG{INT} = sub { ... }; # anonymous sub — also fine $SIG{INT} = 'IGNORE'; # ignore the signal $SIG{INT} = 'DEFAULT'; # restore default action $SIG{INT} = ''; # same as DEFAULT $SIG{INT} = undef; # same as DEFAULT ``` Don’t use a *bareword* (`$SIG{INT} = 'handler'`) — that references a *name* in the `main::` package, which Perl looks up each time the signal arrives. If you rename `handler`, the bareword form silently keeps targeting the old name. The handler receives one argument — the signal name as a string: ```perl sub handler { my ($signame) = @_; print "received SIG$signame\n"; } $SIG{INT} = \&handler; $SIG{TERM} = \&handler; ``` ## Safe signals — the deferred-delivery rule Since Perl 5.8, signal delivery is **deferred**. When a signal arrives, the OS sets a flag in the interpreter; the actual Perl handler runs only at the next *safe point* — typically between op-code executions. This means: - A handler **cannot** interrupt a `read`, `open`, `connect`, or any other syscall mid-call. Slow syscalls return early with `EINTR` in `$!` and the handler runs after. - A handler **cannot** interrupt a regex match in progress. A long-running regex on a malicious input will not be cut short by SIGINT. - The handler runs in regular Perl context. It can call any Perl code, allocate memory, throw exceptions — none of the re-entrancy hazards of C signal handlers. This is the right trade-off for almost every program. If you genuinely need pre-5.8 *unsafe* signal handling — handlers that run synchronously in the signal context, with all the re-entrancy hazards — set the `PERL_SIGNALS=unsafe` environment variable before starting Perl. Do not do this casually. PetaPerl implements deferred-delivery signal handling. ## The graceful-shutdown pattern The standard shape: a flag set by the handler, checked by the main loop: ```perl my $shutting_down = 0; $SIG{INT} = sub { $shutting_down = 1 }; $SIG{TERM} = sub { $shutting_down = 1 }; while (my $job = $queue->next) { last if $shutting_down; # check at a safe point process($job); } if ($shutting_down) { log_and_close(); exit 0; } ``` The main loop polls the flag at a place where it is safe to unwind cleanly. The handler does *only* ”set the flag“ — no logging, no I/O — minimising the time it spends running. For applications that block on a long syscall (`accept`, `read`, `select`), the loop has to be structured to retry on `EINTR`: ```perl my $shutting_down = 0; $SIG{INT} = sub { $shutting_down = 1 }; while (!$shutting_down) { my $client = accept($srv, $sock); unless (defined $client) { next if $!{EINTR}; # signal woke us up — re-check flag die "accept: $!"; } handle($client); } ``` `$!{EINTR}` (see [error variables](error.md)) tells you the syscall exited because a signal arrived. The flag was set by the handler; the main loop sees the wake-up, re-checks `$shutting_down`, and exits cleanly. ## Reaping child processes — SIGCHLD When a child process exits, the parent gets SIGCHLD. The handler must call [`waitpid`](../perlfunc/waitpid.md) to *reap* the zombie: ```perl $SIG{CHLD} = sub { while ((my $kid = waitpid(-1, WNOHANG)) > 0) { my $status = $?; log_child_death($kid, $status); } }; ``` The `while` loop with `WNOHANG` (from [`POSIX`](../../POSIX.md) `:sys_wait_h`) handles the case where two children exit close together — only one SIGCHLD is delivered (it is not queued), so the handler must drain *all* pending exits each time it runs. `$SIG{CHLD} = 'IGNORE'` is a special case: it does not just ignore the signal, it tells the kernel to auto-reap children. Use this when your script forks children whose exit status you do not care about. ## SIGPIPE — the closed-pipe case When you `print` to a pipe whose reader has gone away, the kernel sends SIGPIPE. The default action is to terminate the process — which is rarely what you want. Most filter programs should ignore SIGPIPE and check the `print` return value instead: ```perl local $SIG{PIPE} = 'IGNORE'; print {$child_pipe} $data or die "write to pipe: $!"; # $! will be EPIPE if the reader closed ``` With the handler ignored, the syscall returns failure with `EPIPE` rather than killing the program. ## Timeouts via SIGALRM Combined with [`alarm`](../perlfunc/alarm.md) and an `eval` block, SIGALRM provides a portable timeout for any blocking operation: ```perl sub with_timeout { my ($seconds, $code) = @_; my $result; eval { local $SIG{ALRM} = sub { die "TIMEOUT\n" }; alarm $seconds; $result = $code->(); alarm 0; # cancel the timer 1; } or do { die $@ unless $@ eq "TIMEOUT\n"; return undef; }; return $result; } my $line = with_timeout(5, sub { <$slow_socket> }); ``` The pattern: 1. `local $SIG{ALRM}` — handler is in scope only for this call. 2. `alarm $seconds` — schedule the signal. 3. Perform the blocking work. 4. `alarm 0` — cancel the timer if work succeeded. 5. Inside the handler, `die "TIMEOUT\n"` — the trailing `\n` suppresses the ”at line N“ suffix and makes the error value easy to test against. ## `__WARN__` and `__DIE__` — interpreter hooks These two keys in `%SIG` are *not* OS signals. They are called when the interpreter is about to emit a warning ([`warn`](../perlfunc/warn.md)) or throw a fatal exception ([`die`](../perlfunc/die.md)). ### `$SIG{__WARN__}` — warning interception ```perl my @warnings; { local $SIG{__WARN__} = sub { my ($msg) = @_; push @warnings, $msg; }; do_thing_that_might_warn(); } # Now @warnings holds every warning that fired inside the block, # without anything having printed to STDERR. ``` A `__WARN__` handler that does nothing silences the warning entirely. A handler that calls `die` upgrades warnings into exceptions: ```perl local $SIG{__WARN__} = sub { die $_[0] }; eval { something_warny() }; # warns become catchable ``` The lexical pragma `use warnings FATAL => 'all'` is a more targeted way to do this — it makes warnings fatal only in the lexical scope where the pragma is active. Use it instead of `__WARN__` for ”treat warnings as errors“ requirements. ### `$SIG{__DIE__}` — die interception A `__DIE__` handler runs when `die` is about to throw — both for uncaught exceptions and inside `eval`. Inside an `eval`, the handler runs *before* the exception is caught, which is the classic source of confusion: a global `__DIE__` handler that logs every ”death“ will fire on every `eval { ... }` that calls `die` for ordinary control flow. ```perl $SIG{__DIE__} = sub { print STDERR "dying: $_[0]" }; eval { die "expected error" }; # the handler still runs! ``` If you want a global death logger, gate it on [`$^S`](interpreter.md): ```perl $SIG{__DIE__} = sub { return if $^S; # inside eval — let it be caught print STDERR "uncaught: $_[0]"; }; ``` Realistically, **avoid `$SIG{__DIE__}` for new code**. The pragma [`use warnings`](../perlfunc/use.md) and the [error variables](error.md) cover what you need without the surprise. The modern [`try`/`catch`](../perlfunc/try.md) feature handles exceptions explicitly without the action-at-a-distance of `$SIG{__DIE__}`. ## Listing available signals ```perl use Config; my @signals = split / /, $Config{sig_name}; print "available signals: @signals\n"; # HUP INT QUIT ILL TRAP ABRT BUS FPE KILL ... ``` Or, for the numeric→name mapping: ```perl use Config; my @names = split / /, $Config{sig_name}; my @nums = split / /, $Config{sig_num}; my %sig_num = map { $names[$_] => $nums[$_] } 0..$#names; my %sig_name = map { $nums[$_] => $names[$_] } 0..$#names; ``` This is what most signal-listing utilities do internally. ## See also - [`POSIX`](../../POSIX.md) — the canonical source of `SIG*` numeric constants and the `WIFEXITED`/`WEXITSTATUS` macros for decoding child status in a SIGCHLD handler. - [`kill`](../perlfunc/kill.md) — the partner of `%SIG`: send a signal to a process (typically to test your own handler). - [`alarm`](../perlfunc/alarm.md) — schedule a SIGALRM; the basis of timeout patterns. - [`waitpid`](../perlfunc/waitpid.md) — reap a child after SIGCHLD. - [`fork`](../perlfunc/fork.md) — produces the children whose deaths SIGCHLD reports. - [Error variables](error.md) — `$!` after `EINTR`, `$?` after `waitpid`, `$@` after `die` from inside a handler. - [Interpreter introspection](interpreter.md) — `$^S` for the `__DIE__` ”are we inside `eval`“ check. - [`try`/`catch`](../perlfunc/try.md) — the modern alternative to `$SIG{__DIE__}`-based exception handling.