File Coverage

lib/Fork/Utils.pm
Criterion Covered Total %
statement 46 47 97.8
branch 7 14 50.0
condition 2 6 33.3
subroutine 7 7 100.0
pod 1 1 100.0
total 63 75 84.0


line stmt bran cond sub pod time code
1             package Fork::Utils;
2              
3 1     1   79163 use 5.012;
  1         4  
4 1     1   5 use warnings;
  1         2  
  1         37  
5 1     1   5 use base qw/ Exporter /;
  1         2  
  1         110  
6 1     1   7 use Config ();
  1         2  
  1         15  
7 1     1   591 use POSIX ();
  1         7396  
  1         37  
8 1     1   9 use Carp qw/ croak /;
  1         2  
  1         438  
9              
10             our $VERSION = '0.01';
11             our @EXPORT_OK = qw/ safe_exec /;
12              
13             sub safe_exec {
14              
15 2     2 1 1899 my ( %options ) = @_;
16 2         9 my ( $code, $args, $sigset, $replace_mask ) = @options{ qw/code args sigset replace_mask/ };
17              
18 2 50       10 croak( 'Argument $code must be a CODE reference.' ) if ( ref( $code ) ne 'CODE' );
19 2 50 33     7 croak( 'Argument $args must be an ARRAY reference.' ) if ( $args && ref( $args ) ne 'ARRAY' );
20 2 50 33     16 croak( 'Argument $sigset must be an ARRAY reference.' ) if ( $sigset && ref( $sigset ) ne 'ARRAY' );
21              
22 2         137 state $sig_nums = [ split( /\s+/, $Config::Config{'sig_num'} ) ];
23 2         103 state $sig_names = [ split( /\s+/, $Config::Config{'sig_name'} ) ];
24 2         10 my %signame2signum = ();
25              
26 2         4 for my $i ( 0 .. $#{$sig_nums} ) {
  2         11  
27 138         244 $signame2signum{ $sig_names->[ $i ] } = $sig_nums->[ $i ];
28             }
29              
30 2         19 my $new_sig_set = new POSIX::SigSet ();
31 2         8 my $old_sig_set = new POSIX::SigSet ();
32              
33 2         31 $new_sig_set->emptyset();
34 2         8 $old_sig_set->emptyset();
35              
36 2 50       7 $sigset = [] if ( ! $sigset ); # let's use empty mask by default
37              
38 2         3 foreach my $sig_name ( grep { $_ } @{ $sigset } ) {
  2         6  
  2         7  
39 2 50       15 $new_sig_set->addset( $signame2signum{ $sig_name } ) if ( $signame2signum{ $sig_name } );
40             }
41              
42 2 50       5 if ( ! $replace_mask ) { # add signals into the current mask
43 2         26 POSIX::sigprocmask( POSIX::SIG_BLOCK, $new_sig_set, $old_sig_set );
44             } else { # replace the current signla mask
45 0         0 POSIX::sigprocmask( POSIX::SIG_SETMASK, $new_sig_set, $old_sig_set );
46             }
47              
48 2 50       5 my $result = eval{ $code->( @{ $args || [] } ); };
  2         4  
  2         15  
49 2         3000375 my $error = $@;
50              
51             # we don't use POSIX::SIG_UNBLOCK because we can occasionally unblock some signals that were blocked previously
52 2         35 POSIX::sigprocmask( POSIX::SIG_SETMASK, $old_sig_set );
53              
54 2         6 $@ = $error; # restore the error if it was replaced by POSIX::sigprocmask
55              
56 2         86 return( $result );
57             }
58              
59             1;
60             __END__