Signals are types of messages sent by an operating system or a process to the other process. A simple example is when running a command line program pressing Ctrl-C will send the interrupt signal('SIGINT') to the program by default terminating it.

To be noted is that unexpected signals can leave your perl program or data in an unfinished state.

How does perl catch and handle signals ?

Here is is an example:

#!/usr/bin/perl
use warnings;
use strict;

$SIG{'USR1'} = \&handle_stop;
$SIG{'USR2'} = \&handle_gracestop;

my $ppid      = $$;
my $child_pid = fork();

sub handle_stop {
    print "$$: caught usr1 signal\n";
    exit;
}

sub handle_gracestop {
    print "$$: caught usr2 signal\n";
    sleep 2;
    kill 'USR1', $child_pid;
}

if ($child_pid) {
    print "$ppid ( parent ) waiting\n";
    sleep 500;
} else {
    print "$$: (child) waiting\n";
    sleep 3;
    print "$$: Child signalling $ppid\n";
    kill 'USR2', $ppid;
    sleep 15;
    print "$$ Hey, Im alone\n";
}

Outcome:

$ ./signaltest.pl 
29684 ( parent ) waiting
29685: (child) waiting
29685: Child signalling 29684
29684: caught usr2 signal
29685: caught usr1 signal

So, in above run, the main program(parent) forked a child process, parent wait for 500 secs, while child send a signal('SIGUSR2') signal to parent, caused parent process interrupted to sub routine handle_gracestop, in gracestop, the parent process send a signal('SIGUSR1') to child process. Both parent and child processes exited through signal handling.

Isn't it simple?

Basically there are two methods in perl you can catch and handle signals.

Method 1: The %SIG Hash

All Perl programs have the global variable %SIG hash which contains keys corresponding to each signal type. When a signal is sent to a Perl program, the value of the matching key name in %SIG is automatically de-referenced. This makes it possible to assign code references to handle specific signals by adding a coderef to the signal’s key value in %SIG. Let’s use an example Perl script called sleeper.pl to demonstrate. All sleeper.pl does is sleep for 20 seconds:

use strict;
use warnings;

sleep(20);

Now let’s update sleeper.pl to handle an interrupt signal using %SIG:

use strict;
use warnings;

$SIG{INT} = sub { die "Caught a sigint $!" };

sleep(20);

If we run sleeper.pl on the command line and press control-c to send a SIGINT to it, we can see the our code ref was executed:

perl sleeper.pl
^CCaught a sig int Interrupted system call at projects/scripts/sleeper.pl line 4.

By updating the various key-value pairs in %SIG it’s possible to handle specific signals, for example we can update sleeper.pl to handle a terminate signal:

use strict;
use warnings;

$SIG{INT} = sub { die "Caught a sigint $!" };
$SIG{TERM} = sub { die "Caught a sigterm $!" };

sleep(20);

It’s often easier to define a signal handling subroutine rather than using anonymous subroutines for every signal you wish to catch. Let’s update sleeper.pl accordingly:

use strict;
use warnings;

$SIG{INT}  = \&signal_handler;
$SIG{TERM} = \&signal_handler;

sleep(20);

sub signal_handler {
    die "Caught a signal $!";
}

Now the signal_handler subroutine will be called everytime sleeper.pl receives a SIGINT or SIGTERM signal. Using these techniques it’s possible to extend signal-handling behavior for all signals that you wish to be handled.

Method 2: sigtrap

sigtrap is a useful Perl pragma that makes handling signals easier than manipulating %SIG directly. The sigtrap pragma recognizes three groups of signals: normal-signals (HUP, PIPE, INT, TERM), error-signals (ABRT, BUS, EMT, FPE, ILL, QUIT, SEGV, SYS and TRAP) and old-interface-signals (ABRT, BUS, EMT, FPE, ILL, PIPE, QUIT, SEGV, SYS, TERM, and TRAP). Using sigtrap we can update sleeper.pl to die when any of the normal-signals are received:

use strict;
use warnings;
use sigtrap qw/die normal-signals/;

sleep(20);

Instead of calling die we can have sigtrap call the signal_handler routine that we defined previously:

use strict;
use warnings;
use sigtrap qw/handler signal_handler normal-signals/;

sleep(20);

sub signal_handler {
    die "Caught a signal $!";
}

There is a lot more to sigtrap, check out the sigtrap perldoc entry for more details about its functionality.

Useful signal handling behavior

It’s common to call die when handling SIGINT and SIGTERM. die is useful because it will ensure that Perl stops correctly: for example Perl will execute a destructor method if present when die is called, but the destructor method will not be called if a SIGINT or SIGTERM is received and no signal handler calls die. Additional behaviors that are useful in a signal handling subroutine are stack tracing, event logging, thread termination and temporary file clean up. The correct behavior to define will depend on the type of signal received and the type of Perl program.

POSIX signals

Not every signal can be handled: on POSIX compliant systems (such as BSD, Linux and OSX) SIGSTOP and SIGKILL cannot be caught, blocked or ignored. See the signal man page for further details. Not every signal needs to be handled - each signal has a default program behavior (disposition) which may not affect the running of the program (also defined on the man page). You can find a list of signals Perl recognizes by printing %SIG at the command line:

perl -e 'foreach (keys %SIG) { print "$_\t" }'

Output from RHEL7
$ perl -e 'foreach (keys %SIG) { print "$_\t" }'
NUM63    TRAP    NUM42    URG    STOP    NUM39    NUM62    NUM43    USR2    NUM57    NUM56    RTMAX 
NUM59    VTALRM    CONT    NUM45    NUM61    TERM    NUM44    NUM36NUM32    BUS    NUM40    NUM51    
IOT    STKFLT    NUM41    KILL    QUIT    NUM37    NUM50    ABRT    NUM48    CLD    NUM35    NUM38  
TTOU    IO    TSTP    PROF    NUM53    NUM58    SEGV    RTMIN    POLL    PIPE    SYS    NUM46    PWR  
CHLD    HUP    FPE    NUM54    XCPU    TTIN    NUM52    NUM55    XFSZ    NUM33    INT    NUM49    
UNUSED    WINCH    USR1    ILL    ALRM    NUM47    NUM60   

Check OS singals

$ kill -l
 1) SIGHUP     2) SIGINT     3) SIGQUIT     4) SIGILL     5) SIGTRAP
 6) SIGABRT     7) SIGBUS     8) SIGFPE     9) SIGKILL    10) SIGUSR1
11) SIGSEGV    12) SIGUSR2    13) SIGPIPE    14) SIGALRM    15) SIGTERM
16) SIGSTKFLT    17) SIGCHLD    18) SIGCONT    19) SIGSTOP    20) SIGTSTP
21) SIGTTIN    22) SIGTTOU    23) SIGURG    24) SIGXCPU    25) SIGXFSZ
26) SIGVTALRM    27) SIGPROF    28) SIGWINCH    29) SIGIO    30) SIGPWR
31) SIGSYS    34) SIGRTMIN    35) SIGRTMIN+1    36) SIGRTMIN+2    37) SIGRTMIN+3
38) SIGRTMIN+4    39) SIGRTMIN+5    40) SIGRTMIN+6    41) SIGRTMIN+7    42) SIGRTMIN+8
43) SIGRTMIN+9    44) SIGRTMIN+10    45) SIGRTMIN+11    46) SIGRTMIN+12    47) SIGRTMIN+13
48) SIGRTMIN+14    49) SIGRTMIN+15    50) SIGRTMAX-14    51) SIGRTMAX-13    52) SIGRTMAX-12
53) SIGRTMAX-11    54) SIGRTMAX-10    55) SIGRTMAX-9    56) SIGRTMAX-8    57) SIGRTMAX-7
58) SIGRTMAX-6    59) SIGRTMAX-5    60) SIGRTMAX-4    61) SIGRTMAX-3    62) SIGRTMAX-2
63) SIGRTMAX-1    64) SIGRTMAX    

Ref:

http://perltricks.com/article/37/2013/8/18/Catch-and-Handle-Signals-in-Perl
https://www.perl.com/doc/FMTEYEWTK/IPC/signals.html