File Coverage

blib/lib/AnyEvent/Fork/Serve.pm
Criterion Covered Total %
statement 30 46 65.2
branch 11 22 50.0
condition 3 4 75.0
subroutine 1 4 25.0
pod 0 2 0.0
total 45 78 57.6


line stmt bran cond sub pod time code
1             package AnyEvent::Fork::Serve;
2              
3             our $OWNER; # pid of process "owning" us
4              
5             # commands understood:
6             # e_val perlcode string...
7             # f_ork
8             # h_andle + fd
9             # a_rgs string...
10             # r_un func
11              
12             # the goal here is to keep this simple, small and efficient
13             sub serve {
14 3     3 0 43 local $^W = 0; # avoid spurious warnings
15              
16 3         58 undef &me; # free a tiny bit of memory
17              
18 3         15 my $master = shift;
19              
20 3         9 my @arg;
21              
22 3         12 my ($cmd, $fd);
23              
24 3         106 local $SIG{CHLD} = 'IGNORE';
25              
26             my $error = sub {
27 0     0   0 warn "[$0] ERROR: $_[0]\n";
28 0         0 last;
29 3         24 };
30              
31             local *run_args = sub () { # AnyEvent::Fork::Serve::run_args
32 0     0   0 my (@ret, @arg) = @arg; # copy and clear @arg
33             @ret
34 3         39 };
  0         0  
35              
36 3         6 while () {
37             # we must not ever read "too much" data, as we might accidentally read
38             # an IO::FDPass::send request.
39              
40 7         14 my $len;
41 7   100     727220 sysread $master, $len, 5 - length $len, length $len or last
42             while 5 > length $len;
43 6         141 ($cmd, $len) = unpack "a L", $len;
44              
45 6         20 my $buf;
46 6   50     88 sysread $master, $buf, $len - length $buf, length $buf or last
47             while $len > length $buf;
48              
49 6 100       79 if ($cmd eq "h") {
    50          
    100          
    50          
    0          
50 2         32 require IO::FDPass;
51 2         50 $fd = IO::FDPass::recv (fileno $master);
52 2 50       18 $fd >= 0 or $error->("AnyEvent::Fork::Serve: fd_recv() failed: $!");
53 2 50       64 open my $fh, "+<&=$fd" or $error->("AnyEvent::Fork::Serve: open (fd_recv) failed: $!");
54 2         8 push @arg, $fh;
55              
56             } elsif ($cmd eq "a") {
57 0         0 push @arg, unpack "(w/a*)*", $buf;
58              
59             } elsif ($cmd eq "f") {
60 2         2671 my $pid = fork;
61              
62 2 100       120 if ($pid eq 0) {
63 1         93 $0 = "$OWNER AnyEvent::Fork";
64 1         27 $master = pop @arg;
65              
66             } else {
67 1         14 pop @arg;
68              
69 1 50       57 $pid
70             or $error->("AnyEvent::Fork::Serve: fork() failed: $!");
71             }
72              
73             } elsif ($cmd eq "e") {
74 2         49 ($cmd, @_) = unpack "(w/a*)*", $buf;
75              
76             # $cmd is allowed to access @_ and nothing else
77             package main;
78 2         696 eval $cmd;
79 0 0       0 $error->("$@") if $@;
80            
81             } elsif ($cmd eq "r") {
82             # we could free &serve etc., but this might just unshare
83             # memory that could be shared otherwise.
84 0         0 @_ = ($master, @arg);
85 0         0 $0 = "$OWNER $buf";
86             package main;
87 0         0 goto &$buf;
88              
89             } else {
90 0         0 $error->("AnyEvent::Fork::Serve received unknown request '$cmd' - stream corrupted?");
91             }
92             }
93              
94 1         43 shutdown $master, 1;
95 1         154064 exit; # work around broken win32 perls
96             }
97              
98             # the entry point for new_exec
99             sub me {
100             #$^F = 2; # should always be the case
101              
102 0 0   0 0   open my $fh, "+<&=$ARGV[0]"
103             or die "AnyEvent::Fork::Serve::me unable to open communication socket: $!\n";
104              
105 0           $OWNER = $ARGV[1];
106              
107 0           $0 = "$OWNER AnyEvent::Fork/exec";
108              
109 0           @ARGV = ();
110 0           @_ = $fh;
111 0           goto &serve;
112             }
113              
114             1
115