File Coverage

blib/lib/Test/MultiProcess.pm
Criterion Covered Total %
statement 10 12 83.3
branch n/a
condition n/a
subroutine 4 4 100.0
pod n/a
total 14 16 87.5


line stmt bran cond sub pod time code
1             package Test::MultiProcess;
2              
3 1     1   65736 use strict;
  1         2  
  1         37  
4 1     1   5 use warnings;
  1         3  
  1         30  
5              
6 1     1   878 use POSIX;
  1         8613  
  1         6  
7 1     1   9659 use Cache::FastMmap;
  0            
  0            
8              
9             our @ISA = qw(Exporter);
10              
11             our %EXPORT_TAGS = ( 'all' => [ qw(
12            
13             ) ] );
14              
15             our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } );
16              
17             our @EXPORT = qw(
18             run_forked
19             );
20              
21             our $VERSION = '0.01';
22              
23             our $RESULT_CACHE_FILE = '/tmp/mu1tiproc.tmp';
24              
25             our $children;
26             our %children;
27              
28             $SIG{CHLD} = \&WAITER;
29             $SIG{INT} = \&HUNTSMAN;
30             $SIG{ALRM} = sub { die "server timeout" };
31              
32             sub run_forked {
33             my %params = @_;
34             my $code = $params{code};
35             my $forks = $params{forks} || 1;
36            
37             my $cache = Cache::FastMmap->new( share_file => $RESULT_CACHE_FILE, expire_time => 0, unlink_on_exit => 0, init_file => 1 );
38              
39             for (1 .. $forks) {
40             make_new_child($code);
41             }
42            
43             for my $pid (keys %children) {
44             while (waitpid($pid,0) != -1) {}
45             }
46              
47             my $results = $cache->get('results');
48            
49             return $results;
50             }
51              
52             sub WAITER {
53             $SIG{CHLD} = \&WAITER;
54             my $pid = wait;
55             $children--;
56             delete $children{$pid};
57             #1 until (-1 == waitpid(-1, WNOHANG));
58             }
59            
60             # SIGINT handler
61             sub HUNTSMAN {
62             local($SIG{CHLD}) = 'IGNORE';
63             kill 'INT' => keys %children;
64             exit;
65             }
66              
67             sub make_new_child {
68             my $code = shift;
69            
70             my $pid;
71             my $sigset;
72            
73             # block sig for fork
74             $sigset = POSIX::SigSet->new(SIGINT);
75             sigprocmask(SIG_BLOCK, $sigset) or die "Can't block SIGINT for fork: $!\n";
76             die "fork: $!" unless defined ($pid = fork);
77              
78             if ($pid)
79             {
80             sigprocmask(SIG_UNBLOCK, $sigset) or die "Can't unblock SIGINT for fork: $!\n";
81             $children{$pid} = 1;
82             $children++;
83             return;
84             } else {
85             $SIG{INT} = 'DEFAULT';
86             sigprocmask(SIG_UNBLOCK, $sigset) or die "Can't unblock SIGINT for fork: $!\n";
87            
88             my $cachel = Cache::FastMmap->new( share_file => $RESULT_CACHE_FILE, expire_time => 0, unlink_on_exit => 0 );
89             my $returned = &$code;
90             $cachel->get_and_set('results', sub { ++${$_[1]}{$returned}; return $_[1]; });
91              
92             exit;
93             }
94             }
95              
96              
97             1;
98             __END__