File Coverage

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


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   918537 use strict;
  8         17  
  8         314  
10 8     8   57 use warnings;
  8         14  
  8         512  
11 8     8   2819 use POSIX qw( :signal_h ceil INT_MAX ) ;
  8         50655  
  8         46  
12             require Exporter;
13 8     8   11614 use vars qw( $VERSION @ISA @EXPORT_OK %EXPORT_TAGS );
  8         25  
  8         741  
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   3943 use Sys::SigAction::Alarm qw( ssa_alarm );
  8         41  
  8         891  
22             sub sig_alarm
23             {
24 14     14 1 37 my $secs = shift;
25 14         73 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.24';
33              
34 8     8   50 use Config;
  8         12  
  8         8304  
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 225274 my ($sig) = @_;
52 2 50       17 return $sig if $sig !~ m/^\d+$/ ;
53 2         21 return $signame{$sig} ;
54             }
55             sub sig_number {
56 118     118 1 182885 my ($sig) = @_;
57 118 100       743 return $sig if $sig =~ m/^\d+$/;
58 16         86 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   80 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       120 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 2945023 my ( $sig ,$handler ,$attrs ) = @_;
93 39 100       128 $attrs = {} if not defined $attrs;
94 39         123 _attrs_warning($attrs);
95 39 50       105 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         108 my $act = mk_sig_action( $handler ,$attrs );
105 39         178 return set_sigaction( sig_number($sig) ,$act );
106             }
107             sub mk_sig_action($$)
108             {
109 39     39 0 83 my ( $handler ,$attrs ) = @_;
110 39 50       115 die 'mk_sig_action requires perl 5.8.0 or later' if $] < 5.008;
111 39 50       162 $attrs->{flags} = 0 if not defined $attrs->{flags};
112 39 100       133 $attrs->{mask} = [] if not defined $attrs->{mask};
113             #die '$sig is not defined' if not defined $sig;
114             #$sig = sig_number( $sig );
115 39         77 my @siglist = ();
116 39         68 foreach (@{$attrs->{mask}}) { push( @siglist ,sig_number($_)); };
  39         119  
  4         13  
117 39         259 my $mask = POSIX::SigSet->new( @siglist );
118              
119 39         229 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       346 $act->safe($attrs->{safe}) if defined $attrs->{safe};
126 39         91 return $act;
127             }
128              
129              
130             sub set_sigaction($$)
131             {
132 72     72 0 182 my ( $sig ,$action ) = @_;
133 72 50       265 die 'set_sigaction() requires perl 5.8.0 or later' if $] < 5.008;
134 72 50       176 die '$sig is not defined' if not defined $sig;
135 72 50       299 die '$action is not a POSIX::SigAction' if not UNIVERSAL::isa( $action ,'POSIX::SigAction' );
136 72         158 $sig = sig_number( $sig );
137 72 100       192 if ( defined wantarray )
138             {
139 33         94 my $oact = POSIX::SigAction->new();
140 33         1026 sigaction( $sig ,$action ,$oact );
141 33         139 return Sys::SigAction->new( $sig ,$oact );
142             }
143             else
144             {
145 39         922 sigaction( $sig ,$action );
146             }
147             }
148              
149 8     8   104 use constant TIMEDOUT => {};
  8         15  
  8         3609  
150             sub timeout_call( $$@ )
151             {
152 7     7 1 22778 my ( $timeout, $code, @args ) = @_;
153              
154 7 50       34 if (!$timeout) {
155 0         0 &$code(@args);
156 0         0 return 0;
157             }
158              
159 7         13 my $timed_out = 0;
160 7         16 eval {
161 7     4   61 my $sa = set_sig_handler( SIGALRM ,sub { $timed_out = 1; die TIMEDOUT; } );
  4         3102586  
  4         93  
162 7         19 eval {
163 7         26 sig_alarm( $timeout );
164 7         32 &$code(@args);
165             };
166 7         1000378 sig_alarm(0);
167 7 50       75 die $@ if $@;
168             };
169 7 100 100     71 die $@ if $@ and (not ref $@ or $@ != TIMEDOUT);
      66        
170              
171 4         26 return $timed_out;
172             }
173             sub new {
174 33     33 0 98 my ($class,$sig,$act) = @_;
175 33         340 bless { SIG=>$sig ,ACT => $act } ,$class ;
176             }
177             sub DESTROY
178             {
179 33 50   33   2397 if ( $use_sigaction )
180             {
181 33         148 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         298 return;
189             }
190              
191             1;
192              
193             __END__