ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-Fork-RPC/RPC/Async.pm
Revision: 1.18
Committed: Sun Sep 15 20:18:14 2019 UTC (6 years, 9 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.17: +20 -0 lines
Log Message:
2.0

File Contents

# Content
1 package AnyEvent::Fork::RPC::Async;
2
3 use common::sense; # actually required to avoid spurious warnings...
4
5 our $VERSION = 2; # protocol version
6
7 use Errno ();
8
9 use AnyEvent;
10
11 # declare only
12 sub AnyEvent::Fork::RPC::event;
13 sub AnyEvent::Fork::RPC::flush;
14
15 sub do_exit { exit } # workaround for perl 5.14 and below
16
17 sub run {
18 my %kv = splice @_, pop;
19
20 my $rfh = shift;
21 my $wfh = fileno $rfh ? $rfh : *STDOUT;
22
23 my $function = delete $kv{function};
24 my $serialiser = delete $kv{serialiser};
25 my $rlen = delete $kv{rlen};
26 my $done = delete $kv{done};
27
28 $0 =~ s/^(\d+).*$/$1 $function/s;
29
30 {
31 package main;
32 my $init = delete $kv{init};
33 &$init if length $init;
34 $function = \&$function; # resolve function early for extra speed
35 }
36
37 %kv = (); # save some very small amount of memory
38
39 my $busy = 1; # exit when == 0
40
41 my ($f, $t) = eval $serialiser; AE::log fatal => $@ if $@;
42 my ($wbuf, $ww);
43
44 my $wcb = sub {
45 my $len = syswrite $wfh, $wbuf;
46
47 unless (defined $len) {
48 if ($! != Errno::EAGAIN && $! != Errno::EWOULDBLOCK) {
49 undef $ww;
50 AE::log fatal => "AnyEvent::Fork::RPC: write error ($!), parent gone?";
51 }
52 }
53
54 substr $wbuf, 0, $len, "";
55
56 unless (length $wbuf) {
57 undef $ww;
58 unless ($busy) {
59 shutdown $wfh, 1;
60 @_ = (); goto &$done;
61 }
62 }
63 };
64
65 my $write = sub {
66 $wbuf .= $_[0];
67 $ww ||= AE::io $wfh, 1, $wcb;
68 };
69
70 *AnyEvent::Fork::RPC::flush = sub {
71 while (length $wbuf) {
72 my $len = syswrite $wfh, $wbuf;
73
74 if (defined $len) {
75 substr $wbuf, 0, $len, "";
76 } elsif ($! == Errno::EAGAIN || $! == Errno::EWOULDBLOCK) {
77 my $fdset;
78 (vec $fdset, fileno $wfh, 1) = 1;
79 # buggy windows often sets exceptfds instead of wfds
80 select undef, my $wset = $fdset, my $eset = $fdset, undef;
81 } else {
82 return 0;
83 }
84 }
85
86 1
87 };
88
89 *AnyEvent::Fork::RPC::event = sub {
90 $write->(pack "NN/a*", 0, &$f);
91 };
92
93 my ($rbuf, $rw);
94
95 my $len;
96
97 $rw = AE::io $rfh, 0, sub {
98 $rlen = $rlen * 2 + 16 if $rlen - 128 < length $rbuf;
99 $len = sysread $rfh, $rbuf, $rlen - length $rbuf, length $rbuf;
100
101 if ($len) {
102 while (8 <= length $rbuf) {
103 (my $id, $len) = unpack "NN", $rbuf;
104 8 + $len <= length $rbuf
105 or last;
106
107 my @r = $t->(substr $rbuf, 8, $len);
108 substr $rbuf, 0, 8 + $len, "";
109
110 ++$busy;
111 $function->(sub {
112 --$busy;
113 $write->(pack "NN/a*", $id, &$f);
114 }, @r);
115 }
116 } elsif (defined $len or $! == Errno::EINVAL) { # EINVAL is for microshit windoze
117 undef $rw;
118 --$busy;
119 $ww ||= AE::io $wfh, 1, $wcb;
120 } elsif ($! != Errno::EAGAIN && $! != Errno::EWOULDBLOCK) {
121 undef $rw;
122 AE::log fatal => "AnyEvent::Fork::RPC: read error in child: $!";
123 }
124 };
125
126 $AnyEvent::MODEL eq "AnyEvent::Impl::EV"
127 ? EV::run ()
128 : AE::cv->recv;
129 }
130
131 1
132