File Coverage

blib/lib/Signals/XSIG/Default.pm
Criterion Covered Total %
statement 47 110 42.7
branch 16 58 27.5
condition 3 6 50.0
subroutine 10 14 71.4
pod 0 5 0.0
total 76 193 39.3


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