File Coverage

blib/lib/Parallel/Simple.pm
Criterion Covered Total %
statement 12 60 20.0
branch 0 40 0.0
condition 0 6 0.0
subroutine 4 8 50.0
pod 4 4 100.0
total 20 118 16.9


line stmt bran cond sub pod time code
1             package Parallel::Simple;
2              
3 1     1   21689 use strict;
  1         3  
  1         31  
4 1     1   5 use warnings;
  1         2  
  1         24  
5              
6 1     1   5 use Exporter ();
  1         5  
  1         27  
7 1     1   5 use vars qw( $VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS );
  1         2  
  1         1009  
8             $VERSION = '0.01';
9              
10             @ISA = qw( Exporter );
11             @EXPORT = qw();
12             @EXPORT_OK = qw( prun );
13              
14             my $error;
15             my $return_values;
16              
17 0     0 1   sub err { $error }
18 0     0 1   sub rv { $return_values }
19              
20             sub errplus {
21 0 0   0 1   return unless ( defined $error );
22 0           "$error\n" . ( ref($return_values) =~ /HASH/ ?
23 0           join( '', map { "\t$_ => $return_values->{$_}\n" } sort keys %$return_values ) :
24 0 0         join( '', map { "\t$_ => $return_values->[$_]\n" } 0..$#$return_values )
25             );
26             }
27              
28             sub prun {
29 0     0 1   ( $error, $return_values ) = ( undef, undef ); # reset globals
30 0 0         return 1 unless ( @_ ); # return true if 0 args passed
31 0 0         my %options = %{pop @_} if ( ref($_[-1]) =~ /HASH/ ); # grab options, if specified
  0            
32 0 0         return 1 unless ( @_ ); # return true if 0 code blocks passed
33              
34             # normalize named and unnamed blocks into similar structure to simplify main loop
35 0 0         my $named = ref($_[0]) ? 0 : 1; # if first element is a subref, they're not named
36 0           my $i = 0; # used to turn array into hash with array-like keys
37 0 0         my %blocks = $named ? @_ : map { $i++ => $_ } @_;
  0            
38              
39             # fork children
40 0           my %child_registry; # pid => { name => $name, return_value => $return_value }
41 0           while ( my ( $name, $block ) = each %blocks ) {
42 0           my $child = fork();
43 0 0         unless ( defined $child ) {
44 0           $error = "$!";
45 0           last; # something's wrong; stop trying to fork
46             }
47 0 0         if ( $child == 0 ) { # child
48 0 0         my ( $subref, @args ) = ref($block) =~ /ARRAY/ ? @$block : ( $block );
49 0           my $return_value = eval { $subref->( @args ) };
  0            
50 0 0         warn( $@ ) if ( $@ ); # print death message, because eval doesn't
51 0 0         exit( $@ ? 255 : $options{use_return} ? $return_value : 0 );
    0          
52             }
53 0           $child_registry{$child} = { name => $name, return_value => undef };
54             }
55              
56             # wait for children to finish
57 0           my $successes = 0;
58 0           my $child;
59 0           do {
60 0           $child = waitpid( -1, 0 );
61 0 0 0       if ( $child > 0 and exists $child_registry{$child} ) {
62 0 0         $child_registry{$child}{return_value} = $? unless ( defined $child_registry{$child}{return_value} );
63 0 0         $successes++ if ( $? == 0 );
64 0 0 0       if ( $? > 0 and $options{abort_on_error} ) {
65 0           while ( my ( $pid, $child ) = each %child_registry ) {
66 0 0         unless ( defined $child->{return_value} ) {
67 0           kill( 9, $pid );
68 0           $child->{return_value} = -1;
69             }
70             }
71             }
72             }
73             } while ( $child > 0 );
74              
75             # store return values using appropriate data type
76 0           $return_values = $named
77 0           ? { map { $_->{name} => $_->{return_value} } values %child_registry }
78 0 0         : [ map { $_->{return_value} } sort { $a->{name} <=> $b->{name} } values %child_registry ];
  0            
79              
80 0           my $num_blocks = keys %blocks;
81 0 0         return 1 if ( $successes == $num_blocks ); # all good!
82              
83 0           $error = "only $successes of $num_blocks blocks completed successfully";
84 0           return 0; # sorry... better luck next time
85             }
86              
87             1;
88              
89             __END__