File Coverage

blib/lib/Sys/SigAction.pm
Criterion Covered Total %
statement 78 89 87.6
branch 22 40 55.0
condition 4 12 33.3
subroutine 18 18 100.0
pod 5 8 62.5
total 127 167 76.0


line stmt bran cond sub pod time code
1             #
2             # Copyright (c) 2004-2016 Lincoln A. Baxter
3             #
4             # You may distribute under the terms of either the GNU General Public
5             # License or the Artistic License, as specified in the Perl README file,
6              
7             package Sys::SigAction;
8             require 5.005;
9 8     8   138812 use strict;
  8         13  
  8         218  
10 8     8   32 use warnings;
  8         11  
  8         224  
11 8     8   2544 use POSIX qw( :signal_h ceil INT_MAX ) ;
  8         32816  
  8         46  
12             require Exporter;
13 8     8   7986 use vars qw( $VERSION @ISA @EXPORT_OK %EXPORT_TAGS );
  8         13  
  8         604  
14              
15             #support high resolution time transparently in timeout_call by defining
16             #the function sig_alarm() which calls Time::HiRes::alarm if available
17             #or core alarm with the ceil of the value passed otherwise.
18             #timeout_call uses sig_alarm()
19              
20             #replacement for alarm, factional second arg in floating point format:
21 8     8   2966 use Sys::SigAction::Alarm qw( ssa_alarm );
  8         16  
  8         833  
22             sub sig_alarm
23             {
24 14     14 1 23 my $secs = shift;
25 14         54 ssa_alarm( $secs );
26             }
27              
28             #use Data::Dumper;
29              
30             @ISA = qw( Exporter );
31             @EXPORT_OK = qw( set_sig_handler timeout_call sig_name sig_number sig_alarm );
32             $VERSION = '0.23';
33              
34 8     8   37 use Config;
  8         8  
  8         4980  
35             my %signame = ();
36             my %signo = ();
37             {
38             defined $Config{sig_name} or die "This OS does not support signals?";
39             my $i = 0; # Config prepends fake 0 signal called "ZERO".
40             my @numbers = split( ' ' ,$Config{sig_num} );
41             foreach my $name (split(' ', $Config{sig_name}))
42             {
43             $signo{$name} = $numbers[$i];
44             $signame{$signo{$name}} = $name;
45             #print "name=$name num=" .$numbers[$i] ."\n" ;
46             $i++;
47             }
48             }
49              
50             sub sig_name {
51 2     2 1 8 my ($sig) = @_;
52 2 50       14 return $sig if $sig !~ m/^\d+$/ ;
53 2         13 return $signame{$sig} ;
54             }
55             sub sig_number {
56 118     118 1 109 my ($sig) = @_;
57 118 100       486 return $sig if $sig =~ m/^\d+$/;
58 16         49 return $signo{$sig} ;
59             }
60             #if ( $] < 5008 ) {
61             # #over write definitions of sig_name and sig_number
62             # sub sig_name { warn "sig_name() not supported on perl versions < 5.8.0"; }
63             # sub sig_number { warn "sig_number() not supported on perl versions < 5.8.0"; }
64             #}
65              
66             my $use_sigaction = ( $] >= 5.008 and $Config{d_sigaction} );
67              
68             sub _attrs_warning($)
69             {
70 39     39   38 my ( $attrs ) = @_ ;
71             #my $act = POSIX::SigAction->new( $handler ,$mask ,$attrs->{flags} ,$attrs->{safe} );
72             #steve ( SPURKIS@cpan.org submitted http://rt.cpan.org/Ticket/Display.html?id=19916
73             # puts out the above line is a mis-interpretation of the API for POSIX::SigAcation
74             # so here is the fix (per his suggestion)... lab:
75             #
76             #http://rt.cpan.org/Public/Bug/Display.html?id=21777
77             #2006-09-29: in perl 5.8.0 (RH) $act->safe() is broken
78             # safe is not available until 5.8.2
79             # DAMN... it was in my docs too...
80 39 50       85 if ( exists( $attrs->{safe} ) )
81             {
82 0 0 0     0 if ( ( $] < 5.008002 ) && defined($attrs->{safe}) && $attrs->{safe} )
      0        
83             {
84 0         0 warn "safe mode is not supported in perl versions less than 5.8.2";
85 0         0 delete $attrs->{safe};
86             }
87             }
88              
89             }
90             sub set_sig_handler( $$;$$ )
91             {
92 39     39 1 2015088 my ( $sig ,$handler ,$attrs ) = @_;
93 39 100       96 $attrs = {} if not defined $attrs;
94 39         60 _attrs_warning($attrs);
95 39 50       61 if ( not $use_sigaction )
96             {
97             #warn '$flags not supported in perl versions < 5.8' if $] < 5.008 and defined $flags;
98 0         0 $sig = sig_name( $sig );
99 0         0 my $ohandler = $SIG{$sig};
100 0         0 $SIG{$sig} = $handler;
101 0 0       0 return if not defined wantarray;
102 0         0 return Sys::SigAction->new( $sig ,$ohandler );
103             }
104 39         62 my $act = mk_sig_action( $handler ,$attrs );
105 39         62 return set_sigaction( sig_number($sig) ,$act );
106             }
107             sub mk_sig_action($$)
108             {
109 39     39 0 47 my ( $handler ,$attrs ) = @_;
110 39 50       74 die 'mk_sig_action requires perl 5.8.0 or later' if $] < 5.008;
111 39 50       101 $attrs->{flags} = 0 if not defined $attrs->{flags};
112 39 100       81 $attrs->{mask} = [] if not defined $attrs->{mask};
113             #die '$sig is not defined' if not defined $sig;
114             #$sig = sig_number( $sig );
115 39         49 my @siglist = ();
116 39         33 foreach (@{$attrs->{mask}}) { push( @siglist ,sig_number($_)); };
  39         89  
  4         8  
117 39         192 my $mask = POSIX::SigSet->new( @siglist );
118              
119 39         131 my $act = POSIX::SigAction->new( $handler ,$mask ,$attrs->{flags} );
120              
121             #apply patch suggested by CPAN bugs
122             # http://rt.cpan.org/Ticket/Display.html?id=39599
123             # http://rt.cpan.org/Ticket/Display.html?id=39946 (these are dups)
124             #using safe mode with masking signals still breaks the masking of signals!
125 39 50       220 $act->safe($attrs->{safe}) if defined $attrs->{safe};
126 39         47 return $act;
127             }
128              
129              
130             sub set_sigaction($$)
131             {
132 72     72 0 84 my ( $sig ,$action ) = @_;
133 72 50       129 die 'set_sigaction() requires perl 5.8.0 or later' if $] < 5.008;
134 72 50       105 die '$sig is not defined' if not defined $sig;
135 72 50       215 die '$action is not a POSIX::SigAction' if not UNIVERSAL::isa( $action ,'POSIX::SigAction' );
136 72         89 $sig = sig_number( $sig );
137 72 100       123 if ( defined wantarray )
138             {
139 33         63 my $oact = POSIX::SigAction->new();
140 33         419 sigaction( $sig ,$action ,$oact );
141 33         81 return Sys::SigAction->new( $sig ,$oact );
142             }
143             else
144             {
145 39         450 sigaction( $sig ,$action );
146             }
147             }
148              
149 8     8   40 use constant TIMEDOUT => {};
  8         20  
  8         2734  
150             sub timeout_call( $$@ )
151             {
152 7     7 1 5667 my ( $timeout, $code, @args ) = @_;
153              
154 7 50       22 if (!$timeout) {
155 0         0 &$code(@args);
156 0         0 return 0;
157             }
158              
159 7         11 my $timed_out = 0;
160 7         8 eval {
161 7     4   35 my $sa = set_sig_handler( SIGALRM ,sub { $timed_out = 1; die TIMEDOUT; } );
  4         3100377  
  4         66  
162 7         11 eval {
163 7         14 sig_alarm( $timeout );
164 7         18 &$code(@args);
165             };
166 7         1000177 sig_alarm(0);
167 7 50       60 die $@ if $@;
168             };
169 7 100 100     77 die $@ if $@ and (not ref $@ or $@ != TIMEDOUT);
      33        
170              
171 4         25 return $timed_out;
172             }
173             sub new {
174 33     33 0 41 my ($class,$sig,$act) = @_;
175 33         180 bless { SIG=>$sig ,ACT => $act } ,$class ;
176             }
177             sub DESTROY
178             {
179 33 50   33   4357 if ( $use_sigaction )
180             {
181 33         105 set_sigaction( $_[0]->{'SIG'} ,$_[0]->{'ACT'} );
182             }
183             else
184             {
185             #set it to default if not defined (suppress undefined warning)
186 0 0       0 $SIG{$_[0]->{'SIG'}} = defined $_[0]->{'ACT'} ? $_[0]->{'ACT'} : 'DEFAULT' ;
187             }
188 33         166 return;
189             }
190              
191             1;
192              
193             __END__