File Coverage

blib/lib/Signals/XSIG/Default.pm
Criterion Covered Total %
statement 51 115 44.3
branch 17 60 28.3
condition 3 6 50.0
subroutine 11 15 73.3
pod 0 5 0.0
total 82 201 40.8


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 12     12   115 use strict;
  12         20  
  12         293  
8 12     12   50 use warnings;
  12         15  
  12         331  
9 12     12   55 use Config;
  12         19  
  12         630  
10 12     12   67 use Carp;
  12         28  
  12         901  
11 12     12   4935 use POSIX ();
  12         76827  
  12         283  
12 12     12   59 use Exporter;
  12         18  
  12         4004  
13              
14             our @ISA = qw(Exporter);
15             our @EXPORT = qw(%DEFAULT_BEHAVIOR);
16              
17             our %DEFAULT_BEHAVIOR;
18             our $VERSION = '0.16';
19              
20             my @snam = split ' ', $Config{sig_name};
21             my @snum = split ' ', $Config{sig_num};
22              
23             sub import {
24 12     12   20 my $ignore = 1;
25 12         56 while () {
26 3480 100       5242 next if /^#/;
27 3408 100       6316 next unless /\S/;
28 3228 100       8914 if (/^\[(.+)\]/) {
    50          
    100          
29 192 100 100     1013 if ($1 eq 'default' || $1 eq $^O) {
30 24         137 $ignore = 0;
31             } else {
32 168         434 $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 984         1143 s/^\d+\. //;
42 984         988 s/^SIG//;
43 984         2934 my ($sig, $num, $behavior) = /^(\w+)\s+\[(\d*)\]\s+=>\s+(.+)/;
44 984 50       1560 if (defined $sig) {
45 984         2457 $DEFAULT_BEHAVIOR{$sig} = $behavior;
46             }
47             }
48             }
49 12 50       54 if ($ENV{SIGNALS_XSIG_DUMP}) {
50 12     12   6118 use Data::Dumper;
  12         66998  
  12         1404  
51 0         0 print STDERR Dumper(\%DEFAULT_BEHAVIOR),"\n";
52             }
53 12         293 return;
54             }
55              
56             sub perform_default_behavior {
57 4     4 0 8 my ($signal, @args) = @_;
58              
59 4         8 my $funcname = 'default_SIG' . $signal;
60 4 50       20 if (defined &$funcname) {
61 12     12   73 no strict 'refs'; ## no critic (NoStrict)
  12         20  
  12         5727  
62 0 0       0 return if $funcname->($signal, @args);
63             }
64              
65 4         8 my $behavior = $DEFAULT_BEHAVIOR{$signal};
66 4 50       8 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       20 if (ref($behavior) eq 'CODE') {
79 4 50       10 if (defined &$behavior) {
80 4         14 $behavior->($signal);
81 4         17 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 0 0         if ($behavior =~ /^ABORT/) {
100 0           untie %SIG;
101 0           %SIG = ();
102 0           $SIG{$signal} = $SIG{"ABRT"} = "DEFAULT";
103 0           killprog_with_signal("ABRT");
104 0           POSIX::abort();
105 0           croak "Abort\n";
106             }
107 0 0         if ($behavior =~ /^SIGSEGV/) {
108 0           killprog_with_signal('SEGV');
109 0           croak "Abort\n";
110             }
111              
112 0 0         if ($behavior =~ /^EXIT (\d+)/) {
113 0           my $exit_code = $1;
114 0           exit($exit_code);
115             }
116              
117 0 0         if ($behavior =~ /^TERMINATE/) {
118 0           my $number;
119 0           for (my $i=0; $i<@snum; $i++) {
120 0 0         $number = $snum[$i] if $signal eq $snam[$i];
121             }
122              
123 0           killprog_with_signal($signal, $number);
124 0           croak "default behavior for SIG$signal should have killed script ",
125             "but for some reason it didn't :-(\n";
126             }
127              
128 0           croak "Signals::XSIG: unknown behavior \"$behavior\" ",
129             "for SIG$signal. Terminating this program.\n";
130             }
131              
132             sub killprog_with_signal {
133 0     0 0   my ($sig,$sig_no) = @_;
134 0           untie %SIG;
135 0           %SIG = ();
136 0           $SIG{$sig} = 'DEFAULT';
137              
138 0 0         unless ($sig_no) {
139 0           my @sig_name = split ' ', $Config{sig_name};
140 0           ($sig_no) = grep { $sig eq $sig_name[$_] } split ' ',$Config{sig_num};
  0            
141             }
142              
143 0           kill $sig, $$;
144 0 0         sleep 1 if $^O eq 'MSWin32';
145 0 0         eval {
146 12     12   75 use POSIX ();
  12         21  
  12         2694  
147 0 0         if ($sig_no) {
148             # this is needed for Linux
149 0           POSIX::sigaction($sig_no, &POSIX::SIG_DFL);
150 0           POSIX::sigprocmask(&POSIX::SIG_UNBLOCK,
151             POSIX::SigSet->new($sig_no));
152             }
153             } or ();
154 0           kill $sig, $$;
155 0 0         sleep 1 if $^O eq 'MSWin32';
156              
157 0           my $miniprog = q[$SIG{'__SIGNAL__'}='DEFAULT';sleep 4;
158             kill '__SIGNAL__',$$;sleep 1+"MSWin32"eq$^O;die];
159 0           $miniprog =~ s/__SIGNAL__/$sig/g;
160 0           exec($^X, "-e", $miniprog);
161             }
162              
163             # in principle, SIGSTOP cannot be trapped.
164             sub suspend {
165 0 0   0 0   if ($^O eq 'MSWin32') {
166             # MSWin32 doesn't have signals as such.
167             # Win32::API->SuspendProcess / SuspendThread ?
168             # Win32::Process->suspend ?
169             # Win32::Thread->suspend ?
170 0 0         if ($$ > 0) {
171             # suspend process
172             # enumerate all threads in process
173             # suspend each thread
174             } else {
175             # suspend thread
176             }
177             }
178 0           return kill 'STOP', $$;
179             }
180              
181             ##################################################################
182              
183             # system specific and other special behaviors.
184             # Signals that don't fall into the terminate/suspend/ignore
185             # paradigm or that have other special needs can be implemented
186             # below.
187             # Return true if the signal is "handled" and no further
188             # processing is necessary.
189              
190             sub default_SIG__WARN__ { ## no critic (Unpacking)
191 0     0 0   CORE::warn @_;
192 0           return 1;
193             }
194              
195             sub default_SIG__DIE__ { ## no critic (Unpacking)
196 0     0 0   CORE::die @_;
197 0           return 1;
198             }
199              
200             1;
201              
202             =head1 NAME
203              
204             Signals::XSIG::Default - enumerate/implement default unhandled signal behavior
205              
206             =head1 DESCRIPTION
207              
208             Module for emulating the default behavior for all
209             signals in your system. The emulator is used when you have
210             used L to register more than one
211             handler for a signal, and at least one of those
212             handlers is C.
213              
214             See L for much more information.
215              
216             =cut
217              
218              
219              
220             # see spike/analyze_default_signal_behavior.pl
221              
222             # for each new system that is available to us, run
223             # spike/analyze_default_signal_behavior.pl
224             # and include that data at the end of this file ...
225             #
226             # we can also infer behavior from CPAN tester results,
227             # see t/20-defaults.t
228             #
229             __DATA__