ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/AnyEvent-Fork/Fork/Serve.pm
Revision: 1.31
Committed: Wed Jan 26 16:44:16 2022 UTC (2 years, 5 months ago) by root
Branch: MAIN
CVS Tags: rel-1_32, HEAD
Changes since 1.30: +4 -2 lines
Log Message:
1.32

File Contents

# Content
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 local $^W = 0; # avoid spurious warnings
15
16 undef &me; # free a tiny bit of memory
17
18 my $master = shift;
19
20 my @arg;
21
22 my ($cmd, $fd);
23
24 my $error = sub {
25 warn "[$0] ERROR: $_[0]\n";
26 last;
27 };
28
29 local *run_args = sub () { # AnyEvent::Fork::Serve::run_args
30 my (@ret, @arg) = @arg; # copy and clear @arg
31 @ret
32 };
33
34 while () {
35 # we manually reap child processes before we sleep, as local $SIG...
36 # will destroy existing child handlers instead of restoring them.
37 1 while 0 < waitpid -1, 1; # WNOHANG is portably 1. prove me wrong.
38
39 # we must not ever read "too much" data, as we might accidentally read
40 # an IO::FDPass::send request.
41
42 my $len;
43 sysread $master, $len, 5 - length $len, length $len or last
44 while 5 > length $len;
45 ($cmd, $len) = unpack "a L", $len;
46
47 my $buf;
48 sysread $master, $buf, $len - length $buf, length $buf or last
49 while $len > length $buf;
50
51 if ($cmd eq "h") {
52 require IO::FDPass;
53 $fd = IO::FDPass::recv (fileno $master);
54 $fd >= 0 or $error->("AnyEvent::Fork::Serve: fd_recv() failed: $!");
55 open my $fh, "+<&=$fd" or $error->("AnyEvent::Fork::Serve: open (fd_recv) failed: $!");
56 push @arg, $fh;
57
58 } elsif ($cmd eq "a") {
59 push @arg, unpack "(w/a*)*", $buf;
60
61 } elsif ($cmd eq "f") {
62 my $pid = fork;
63
64 if ($pid eq 0) {
65 $0 = "$OWNER AnyEvent::Fork";
66 $master = pop @arg;
67
68 } else {
69 pop @arg;
70
71 $pid
72 or $error->("AnyEvent::Fork::Serve: fork() failed: $!");
73 }
74
75 } elsif ($cmd eq "e") {
76 ($cmd, @_) = unpack "(w/a*)*", $buf;
77
78 # $cmd is allowed to access @_ and nothing else
79 package main;
80 eval $cmd;
81 $error->("$@") if $@;
82
83 } elsif ($cmd eq "r") {
84 # we could free &serve etc., but this might just unshare
85 # memory that could be shared otherwise.
86 @_ = ($master, @arg);
87 $0 = "$OWNER $buf";
88 package main;
89 goto &$buf;
90
91 } else {
92 $error->("AnyEvent::Fork::Serve received unknown request '$cmd' - stream corrupted?");
93 }
94 }
95
96 shutdown $master, 1;
97 exit; # work around broken win32 perls
98 }
99
100 # the entry point for new_exec
101 sub me {
102 #$^F = 2; # should always be the case
103
104 open my $fh, "+<&=$ARGV[0]"
105 or die "AnyEvent::Fork::Serve::me unable to open communication socket: $!\n";
106
107 $OWNER = $ARGV[1];
108
109 $0 = "$OWNER AnyEvent::Fork/exec";
110
111 @ARGV = ();
112 @_ = $fh;
113 goto &serve;
114 }
115
116 1
117