File Coverage

blib/lib/Signals/XSIG/Default.pm
Criterion Covered Total %
statement 48 116 41.3
branch 17 64 26.5
condition 3 6 50.0
subroutine 10 14 71.4
pod 0 5 0.0
total 78 205 38.0


line stmt bran cond sub pod time code
1             # emulate default behaviors for the various signals.
2              
3             package Signals::XSIG::Default;
4              
5             ## no critic (RequireLocalizedPunctuationVars)
6              
7 13     13   122 use strict;
  13         19  
  13         278  
8 13     13   47 use warnings;
  13         18  
  13         341  
9 13     13   51 use Config;
  13         34  
  13         577  
10 13     13   113 use Carp;
  13         40  
  13         919  
11 13     13   4562 use POSIX ();
  13         75344  
  13         283  
12 13     13   67 use Exporter;
  13         20  
  13         3943  
13              
14             our @ISA = qw(Exporter);
15             our @EXPORT = qw(%DEFAULT_BEHAVIOR);
16              
17             our %DEFAULT_BEHAVIOR;
18             our $VERSION = '1.00';
19              
20             my @snam = split ' ', $Config{sig_name};
21             my @snum = split ' ', $Config{sig_num};
22              
23             sub import {
24 13     13   33 my $ignore = 1;
25 13         61 while () {
26 3796 100       5107 next if /^#/;
27 3718 100       6150 next unless /\S/;
28 3523 100       9391 if (/^\[(.+)\]/) {
    50          
    100          
29 208 100 100     660 if ($1 eq 'default' || $1 eq $^O) {
30 26         94 $ignore = 0;
31             } else {
32 182         378 $ignore = 1;
33             }
34             } elsif (/\{(.+)\/(\d+)\}/) {
35 0 0 0     0 if ($1 eq $^O && $2 <= int($] * 1000)) {
36 0         0 $ignore = 0;
37             } else {
38 0         0 $ignore = 1;
39             }
40             } elsif (!$ignore) {
41 1066         1113 s/^\d+\. //;
42 1066         989 s/^SIG//;
43 1066         2876 my ($sig, $num, $behavior) = /^(\w+)\s+\[(\d*)\]\s+=>\s+(.+)/;
44 1066 50       1552 if (defined $sig) {
45 1066         2389 $DEFAULT_BEHAVIOR{$sig} = $behavior;
46             }
47             }
48             }
49 13 50       71 if ($ENV{SIGNALS_XSIG_DUMP}) {
50 13     13   5546 use Data::Dumper;
  13         65070  
  13         1580  
51 0         0 print STDERR Dumper(\%DEFAULT_BEHAVIOR),"\n";
52             }
53 13         329 return;
54             }
55              
56             sub perform_default_behavior {
57 4     4 0 7 my ($signal, @args) = @_;
58              
59 4         7 my $funcname = 'default_SIG' . $signal;
60 4 50       24 if (defined &$funcname) {
61 13     13   84 no strict 'refs'; ## no critic (NoStrict)
  13         18  
  13         8223  
62 0 0       0 return if $funcname->($signal, @args);
63             }
64              
65 4         7 my $behavior = $DEFAULT_BEHAVIOR{$signal};
66 4 50       10 if (!defined $behavior) {
67 0 0       0 if ($signal =~ /^NUM(\d+)/) {
68 0         0 my $signum = 0 + $1;
69 0         0 $behavior = $DEFAULT_BEHAVIOR{"NUMxx"};
70 0         0 $behavior =~ s/xx/$signum/;
71             }
72 0 0       0 if (!defined $behavior) {
73 0         0 croak "Signals::XSIG: no default behavior is specified ",
74             "for SIG$signal. Terminating this program.\n";
75             }
76             }
77              
78 4 50       9 if (ref($behavior) eq 'CODE') {
79 4 50       6 if (defined &$behavior) {
80 4         9 $behavior->($signal);
81 4         21 return;
82             } else {
83 0           carp "Signals::XSIG: Default behavior for SIG$signal ",
84             "is not set to a valid subroutine.";
85 0           return;
86             }
87             }
88              
89 0 0         if ($behavior eq 'IGNORE') {
90 0           return;
91             }
92              
93 0 0         if ($behavior eq 'SUSPEND') {
94 0           suspend($signal);
95             # ... then wait for the SIGCONT ...
96 0           return;
97             }
98              
99             # remaining default behaviors should terminate the program
100 0           unimport Signals::XSIG;
101 0           %SIG = ();
102              
103 0 0         if ($behavior =~ /^ABORT/) {
104 0           end_prog_with_signal("ABRT"); # 1st try
105 0           POSIX::abort(); # 2nd try
106 0           croak "Abort\n"; # 3rd try
107             }
108 0 0         if ($behavior =~ /^SIGSEGV/) {
109 0           end_prog_with_signal('SEGV'); # 1st try
110 0           croak "Abort\n"; # 2nd try
111             }
112 0 0         if ($behavior =~ /^EXIT (\d+)/) {
113 0           my $exit_code = $1;
114 0 0         if ($^O eq 'MSWin32') {
115 0           close STDOUT;
116 0           close STDERR;
117             }
118 0           exit($exit_code);
119             }
120 0 0         if ($behavior =~ /^TERMINATE/) {
121 0           my $number;
122 0           for (my $i=0; $i<@snum; $i++) {
123 0 0         $number = $snum[$i] if $signal eq $snam[$i];
124             }
125              
126 0           end_prog_with_signal($signal, $number);
127 0           end_prog_with_signal('TERM', $number);
128 0           end_prog_with_signal('KILL', $number);
129 0           croak "default behavior for SIG$signal should have killed script ",
130             "but for some reason it didn't :-(\n";
131             }
132              
133 0           croak "Signals::XSIG: unknown behavior \"$behavior\" ",
134             "for SIG$signal. Terminating this program.\n";
135             }
136              
137             sub end_prog_with_signal {
138 0     0 0   my ($sig, $sig_no) = @_;
139             # $SIG{$sig} = 'DEFAULT';
140              
141 0 0         if ($^O eq 'MSWin32') {
142             # to flush
143 0           close STDOUT;
144 0           close STDERR;
145             }
146              
147 0 0         unless ($sig_no) {
148 0           my @sig_name = split ' ', $Config{sig_name};
149 0           ($sig_no) = grep { $sig eq $sig_name[$_] } split ' ',$Config{sig_num};
  0            
150             }
151              
152 0           kill $sig, $$;
153 0 0         sleep 1 if $^O eq 'MSWin32';
154              
155             # still here? Try setting POSIX signal handling functions
156 0 0         eval {
157 0 0         if ($sig_no) {
158             # this is needed for Linux
159 0           POSIX::sigaction($sig_no, &POSIX::SIG_DFL);
160 0           POSIX::sigprocmask(&POSIX::SIG_UNBLOCK,
161             POSIX::SigSet->new($sig_no));
162             }
163             } or ();
164 0           kill $sig, $$;
165 0 0         sleep 1 if $^O eq 'MSWin32';
166              
167             # still here? replacing process with simple perl script that terminates with signal
168 0           my $miniprog = q[$SIG{'__SIGNAL__'}='DEFAULT';sleep 2;
169             kill '__SIGNAL__',$$;sleep 1+"MSWin32"eq$^O;die];
170 0           $miniprog =~ s/__SIGNAL__/$sig/g;
171 0           exec($^X, "-e", $miniprog);
172             }
173              
174             # SIGSTOP cannot be trapped.
175             sub suspend {
176 0 0   0 0   if ($^O eq 'MSWin32') {
177             # MSWin32 doesn't have signals as such.
178             # Win32::API->SuspendProcess / SuspendThread ?
179             # Win32::Process->suspend ?
180             # Win32::Thread->suspend ?
181 0 0         if ($$ > 0) {
182             # suspend process
183             # enumerate all threads in process
184             # suspend each thread
185             } else {
186             # suspend thread
187             }
188             }
189 0           return kill 'STOP', $$;
190             }
191              
192             ##################################################################
193              
194             # system specific and other special behaviors.
195             # Signals that don't fall into the terminate/suspend/ignore
196             # paradigm or that have other special needs can be implemented
197             # below.
198             # Return true if the signal is "handled" and no further
199             # processing is necessary.
200              
201             sub default_SIG__WARN__ { ## no critic (Unpacking)
202 0     0 0   CORE::warn @_;
203 0           return 1;
204             }
205              
206             sub default_SIG__DIE__ { ## no critic (Unpacking)
207 0     0 0   CORE::die @_;
208 0           return 1;
209             }
210              
211             1;
212              
213             =head1 NAME
214              
215             Signals::XSIG::Default - enumerate/implement default unhandled signal behavior
216              
217             =head1 DESCRIPTION
218              
219             Module for emulating the default behavior for all
220             signals in your system. The emulator is used when you have
221             used L to register more than one
222             handler for a signal, and at least one of those
223             handlers is C.
224              
225             See L for much more information.
226              
227             =cut
228              
229              
230              
231             # see spike/analyze_default_signal_behavior.pl
232              
233             # for each new system that is available to us, run
234             # spike/analyze_default_signal_behavior.pl
235             # and include that data at the end of this file ...
236             #
237             # we can also infer behavior from CPAN tester results,
238             # see t/20-defaults.t
239             #
240             __DATA__