File Coverage

blib/lib/IO/Lambda/Fork.pm
Criterion Covered Total %
statement 82 104 78.8
branch 18 50 36.0
condition 1 3 33.3
subroutine 16 19 84.2
pod 4 4 100.0
total 121 180 67.2


line stmt bran cond sub pod time code
1             # $Id: Fork.pm,v 1.12 2010/02/09 08:40:41 dk Exp $
2              
3             package IO::Lambda::Fork;
4              
5 9     9   8190 use base qw(IO::Lambda);
  9         18  
  9         1044  
6              
7             our $DEBUG = $IO::Lambda::DEBUG{fork} || 0;
8            
9 9     9   45 use strict;
  9         18  
  9         207  
10 9     9   36 use warnings;
  9         18  
  9         216  
11 9     9   36 use Exporter;
  9         162  
  9         306  
12 9     9   7965 use Socket;
  9         34704  
  9         6318  
13 9     9   7101 use POSIX;
  9         61200  
  9         54  
14 9     9   41292 use Storable qw(thaw freeze);
  9         30942  
  9         675  
15 9     9   8073 use IO::Handle;
  9         69525  
  9         567  
16 9     9   72 use IO::Lambda qw(:all :dev);
  9         27  
  9         4581  
17 9     9   6570 use IO::Lambda::Signal qw(pid);
  9         27  
  9         9855  
18              
19             our @ISA = qw(Exporter);
20             our @EXPORT_OK = qw(new_process process new_forked forked);
21             our %EXPORT_TAGS = (all => \@EXPORT_OK);
22              
23 0     0   0 sub _d { "forked(" . _o($_[0]) . ")" }
24              
25             # return pid and socket
26             sub new_process(&)
27             {
28 44     44 1 56 my $cb = shift;
29            
30 44         654 my $r = IO::Handle-> new;
31 44         1837 my $w = IO::Handle-> new;
32 44         2361 socketpair( $r, $w, AF_UNIX, SOCK_STREAM, PF_UNSPEC);
33 44         336 $w-> blocking(0);
34              
35 44         53464 my $pid = fork;
36 44 50       1835 unless ( defined $pid) {
37 0 0       0 warn "fork() failed:$!\n" if $DEBUG;
38 0         0 close($w);
39 0         0 close($r);
40 0         0 return ( undef, $! );
41             }
42              
43 44 100       496 if ( $pid == 0) {
44 8         1139 close($w);
45 8 50       517 warn "process($$) started\n" if $DEBUG;
46 8 50       397 eval { $cb-> ($r) if $cb; };
  8         455  
47 8 50       2281 warn "process($$) ended\n" if $DEBUG;
48 8 50       54 warn $@ if $@;
49 8         3228 close($r);
50 8 50       923 POSIX::exit($@ ? 1 : 0);
51             }
52            
53 36 50       217 warn "forked pid=$pid\n" if $DEBUG;
54              
55 36         1342 close($r);
56              
57 36         3201 return ($pid, $w);
58             }
59              
60             # simple fork, return only $? and $!
61             sub process(&)
62             {
63 0     0 1 0 my $cb = shift;
64              
65             lambda {
66 0     0   0 my $pid = fork;
67 0 0       0 return undef, $! unless defined $pid;
68 0 0       0 unless ( $pid) {
69 0 0       0 warn "process($$) started\n" if $DEBUG;
70 0         0 eval { $cb->(); };
  0         0  
71 0 0       0 warn "process($$) ended\n" if $DEBUG;
72 0 0       0 warn $@ if $@;
73 0 0       0 POSIX::exit($@ ? 1 : 0);
74             }
75              
76 0 0       0 warn "forked pid=$pid\n" if $DEBUG;
77 0         0 context $pid;
78 0         0 &pid();
79             }
80            
81 0         0 }
82              
83             # return output from a subprocess
84             sub new_forked(&)
85             {
86 44     44 1 67 my $cb = shift;
87              
88             my ( $pid, $r) = new_process {
89 8     8   173 my @ret;
90 8         154 my $socket = shift;
91 8 50       185 eval { @ret = $cb-> () if $cb };
  8         489  
92 8 50       1702510 my $msg = $@ ? [ 0, $@ ] : [ 1, @ret ];
93 8 50       215 warn "process($$) ended: [@$msg]\n" if $DEBUG > 1;
94 8         493 print $socket freeze($msg);
95 44         271 };
96              
97             lambda {
98 36 50   36   81 return undef, undef, $r unless defined $pid;
99            
100 36         107 my $buf = '';
101 36         679 context readbuf, $r, \ $buf, undef;
102             tail {
103 32         67 my ( $ok, $error) = @_;
104 32         53 my @ret;
105              
106 32 50       555 ($ok,$error) = (0,$!) unless close($r);
107              
108 32 50       93 unless ( $ok) {
109 0         0 @ret = ( undef, $error);
110             } else {
111 32         40 my $msg;
112 32         130 eval { $msg = thaw $buf };
  32         449  
113 32 50 33     1254 unless ( $msg and ref($msg) and ref($msg) eq 'ARRAY') {
    50          
114 0         0 @ret = ( undef, $@);
115             } elsif ( 0 == shift @$msg) {
116 0         0 @ret = ( undef, @$msg);
117             } else {
118 32         114 @ret = ( 1, @$msg);
119             }
120             }
121              
122 32         127 context $pid;
123             pid {
124 31 50       137 warn "pid($pid): exitcode=$?, [@ret]\n" if $DEBUG > 1;
125 31         102 return shift, @ret;
126 36         629 }}}
  32         1000  
127 36         4486 }
128              
129             # simpler version of new_forked
130             sub forked(&)
131             {
132 48     48 1 2037 my $cb = shift;
133             lambda {
134 44     44   133 context &new_forked($cb);
135             tail {
136 31         75 my ( $pid, $ok, @ret) = @_;
137 31         87 return @ret;
138 36         1754 }}
139 48         329 }
140              
141             1;
142              
143             __DATA__