ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/AnyEvent-Fork-Remote/Remote.pm
(Generate patch)

Comparing AnyEvent-Fork-Remote/Remote.pm (file contents):
Revision 1.2 by root, Sat Apr 27 23:59:04 2013 UTC vs.
Revision 1.6 by root, Sun Jul 13 00:14:58 2014 UTC

8 8
9 use AnyEvent; 9 use AnyEvent;
10 use AnyEvent::Fork::Remote; 10 use AnyEvent::Fork::Remote;
11 11
12 my $rpc = AnyEvent::Fork::Remote 12 my $rpc = AnyEvent::Fork::Remote
13 ->new 13 ->new_execp ("ssh", "ssh", "othermachine", "perl")
14 ->require ("MyModule") 14 ->require ("MyModule")
15 ->run ("MyModule::run", my $cv = AE::cv); 15 ->run ("MyModule::run", my $cv = AE::cv);
16 16
17 my $fh = $cv->recv; 17 my $fh = $cv->recv;
18 18
19=head1 DESCRIPTION 19=head1 DESCRIPTION
20 20
21Despite what the name of this module might suggest, it doesn't actualyl 21Despite what the name of this module might suggest, it doesn't actually
22create remote processes for you. But it does make it easy to use them, 22create remote processes for you. But it does make it easy to use them,
23once you have started them. 23once you have started them.
24 24
25This module implements a very similar API as L<AnyEvent::Fork>. In fact, 25This module implements a very similar API as L<AnyEvent::Fork>. In fact,
26similar enough to require at most minor modifications to support both 26similar enough to require at most minor modifications to support both
43 43
44=item * C<fork> does not actually fork, but will create a new process 44=item * C<fork> does not actually fork, but will create a new process
45 45
46=back 46=back
47 47
48=head1 EXAMPLES 48=head1 EXAMPLE
49
50This example uses a local perl (because that is likely going to work
51without further setup) and the L<AnyEvent::Fork::RPC> to create simple
52worker process.
53
54First load the modules we are going to use:
55
56 use AnyEvent;
57 use AnyEvent::Fork::Remote;
58 use AnyEvent::Fork::RPC;
59
60Then create, configure and run the process:
61
62 my $rpc = AnyEvent::Fork::Remote
63 ->new_execp ("perl", "perl")
64 ->eval ('
65 sub myrun {
66 "this is process $$, and you passed <@_>"
67 }
68 ')
69 ->AnyEvent::Fork::RPC::run ("myrun");
70
71We use C<new_execp> to execute the first F<perl> found in the PATH. You'll
72have to make sure there is one for this to work. The perl does not
73actually have to be the same perl as the one running the example, and it
74doesn't need to have any modules installed.
75
76The reason we have to specify C<perl> twice is that the first argument to
77C<new_execp> (and also C<new_exec>) is the program name or path, while
78the remaining ones are the arguments, and the first argument passed to a
79program is the program name, so it has to be specified twice.
80
81Finally, the standard example, send some numbers to the remote function,
82and print whatever it returns:
83
84 my $cv = AE::cv;
85
86 for (1..10) {
87 $cv->begin;
88 $rpc->($_, sub {
89 print "remote function returned: $_[0]\n";
90 $cv->end;
91 });
92 }
93
94 $cv->recv;
95
96Now, executing F<perl> in the PATH isn't very interesting - you could have
97done the same with L<AnyEvent::Fork>, and it might even be more efficient.
98
99The power of this module is that the F<perl> doesn't need to run on the
100local box, you could simply substitute another command, such as F<ssh
101remotebox perl>:
102
103 my $rpc = AnyEvent::Fork::Remote
104 ->new_execp ("ssh", "ssh", "remotebox", "perl")
105
106And if you want to use a specific path for ssh, use C<new_exec>:
107
108 my $rpc = AnyEvent::Fork::Remote
109 ->new_exec ("/usr/bin/ssh", "ssh", "remotebox", "perl")
110
111Of course, it doesn't really matter to this module how you construct your
112perl processes, what matters is that somehow, you give it a file handle
113connected to the new perls STDIN and STDOUT.
49 114
50=head1 PARENT PROCESS USAGE 115=head1 PARENT PROCESS USAGE
51 116
52=over 4 117=over 4
53 118
59 124
60use Carp (); 125use Carp ();
61use Errno (); 126use Errno ();
62 127
63use AnyEvent (); 128use AnyEvent ();
64use AnyEvent::Util ();
65 129
66our $VERSION = 0.1; 130our $VERSION = 0.2;
67 131
68# xored together must start and and with \n 132# xored together must start and and with \n
69my $magic0 = "Pdk{6y[_zZ"; 133my $magic0 = "Pdk{6y[_zZ";
70my $magic1 = "Z^yZ7~i=oP"; 134my $magic1 = "Z^yZ7~i=oP";
71 135
77 141
78Each time a new process is needed, it executes C<$path> with the given 142Each time a new process is needed, it executes C<$path> with the given
79arguments (the first array member must be the program name, as with 143arguments (the first array member must be the program name, as with
80the C<exec> function with explicit PROGRAM argument) and both C<STDIN> 144the C<exec> function with explicit PROGRAM argument) and both C<STDIN>
81and C<STDOUT> connected to a communications socket. No input must be 145and C<STDOUT> connected to a communications socket. No input must be
82consumed by the comamnd before F<perl> is started, and no output should be 146consumed by the command before F<perl> is started, and no output should be
83generated. 147generated.
84 148
85The program I<must> invoke F<perl> somehow, with STDIN and STDOUT intact, 149The program I<must> invoke F<perl> somehow, with STDIN and STDOUT intact,
86without specifying anything to execute (no script file name, no C<-e> 150without specifying anything to execute (no script file name, no C<-e>
87switch etc.). 151switch etc.).
103 -oCheckHostIP=no -oTCPKeepAlive=yes -oStrictHostKeyChecking=no 167 -oCheckHostIP=no -oTCPKeepAlive=yes -oStrictHostKeyChecking=no
104 -oGlobalKnownHostsFile=/dev/null -oUserKnownHostsFile=/dev/null 168 -oGlobalKnownHostsFile=/dev/null -oUserKnownHostsFile=/dev/null
105 otherhost 169 otherhost
106 exec perl); 170 exec perl);
107 171
172=item my $proc = new_execp AnyEvent::Fork::Remote $file, @args...
173
174Just like C<new_exec>, except that the program is searched in the
175C<$ENV{PATH}> first, similarly to how the shell does it. This makes it easier
176to find e.g. C<ssh>:
177
178 $proc = new_execp AnyEvent::Fork::Remote "ssh", "ssh", "otherhost", "perl";
179
108=item my $proc = new AnyEvent::Fork::Remote $create_callback 180=item my $proc = new AnyEvent::Fork::Remote $create_callback
109 181
110Basically the same as C<new_exec>, but instead of a hardcoded command 182Basically the same as C<new_exec>, but instead of a command to execute,
111path, it expects a callback which is invoked each time a process needs to 183it expects a callback which is invoked each time a process needs to be
112be created. 184created.
113 185
114The C<$create_callback> is called with another callback as argument, 186The C<$create_callback> is called with another callback as argument,
115and should call this callback with the file handle that is connected 187and should call this callback with the file handle that is connected
116to a F<perl> process. This callback can be invoked even after the 188to a F<perl> process. This callback can be invoked even after the
117C<$create_callback> returns. 189C<$create_callback> returns.
164 236
165sub new_from_fh { 237sub new_from_fh {
166 my ($class, @fh) = @_; 238 my ($class, @fh) = @_;
167 239
168 $class->new (sub { 240 $class->new (sub {
169 shift @fh 241 my $fh = shift @fh
170 or Carp::croak "AnyEvent::Fork::Remote::new_from_fh does not support fork"; 242 or Carp::croak "AnyEvent::Fork::Remote::new_from_fh does not support fork";
243
244 $_[0]($fh);
171 }); 245 });
172} 246}
173 247
174sub new_exec { 248sub _new_exec {
249 my $p = pop;
250
175 my ($class, $program, @argv) = @_; 251 my ($class, $program, @argv) = @_;
176 252
177 require AnyEvent::Util; 253 require AnyEvent::Util;
178 require Proc::FastSpawn; 254 require Proc::FastSpawn;
179 255
187 open my $oldout, ">&1" or die; 263 open my $oldout, ">&1" or die;
188 264
189 open STDIN , "<&" . fileno $b or die; 265 open STDIN , "<&" . fileno $b or die;
190 open STDOUT, ">&" . fileno $b or die; 266 open STDOUT, ">&" . fileno $b or die;
191 267
268 $p ? Proc::FastSpawn::spawnp ($program, \@argv)
192 Proc::FastSpawn::spawn ($program, \@argv); 269 : Proc::FastSpawn::spawn ($program, \@argv);
193 270
194 open STDIN , "<&" . fileno $oldin ; 271 open STDIN , "<&" . fileno $oldin ;
195 open STDOUT, ">&" . fileno $oldout; 272 open STDOUT, ">&" . fileno $oldout;
196 273
197 $done->($a); 274 $done->($a);
198 }) 275 })
276}
277
278sub new_exec {
279 push @_, 0;
280 &_new_exec
281}
282
283sub new_execp {
284 push @_, 1;
285 &_new_exec
199} 286}
200 287
201=item $new_proc = $proc->fork 288=item $new_proc = $proc->fork
202 289
203Quite the same as the same method of L<AnyEvent::Fork>, except that it 290Quite the same as the same method of L<AnyEvent::Fork>, except that it
265 $linecode =~ s/\s+/ /g; # takes care of \n 352 $linecode =~ s/\s+/ /g; # takes care of \n
266 $linecode =~ s/"/''/g; 353 $linecode =~ s/"/''/g;
267 substr $linecode, 70, length $linecode, "..." if length $linecode > 70; 354 substr $linecode, 70, length $linecode, "..." if length $linecode > 70;
268 355
269 $self->[1] .= '{ local @_ = ' . (aq @args) . ";\n#line 1 \"'$linecode'\"\n$perlcode;\n}\n"; 356 $self->[1] .= '{ local @_ = ' . (aq @args) . ";\n#line 1 \"'$linecode'\"\n$perlcode;\n}\n";
357
358 $self
270} 359}
271 360
272=item $proc = $proc->require ($module, ...) 361=item $proc = $proc->require ($module, ...)
273 362
274Quite the same as the same method of L<AnyEvent::Fork>. 363Quite the same as the same method of L<AnyEvent::Fork>.
301=item $proc->run ($func, $cb->($fh)) 390=item $proc->run ($func, $cb->($fh))
302 391
303Very similar to the run method of L<AnyEvent::Fork>. 392Very similar to the run method of L<AnyEvent::Fork>.
304 393
305On the parent side, the API is identical, except that a C<$cb> argument of 394On the parent side, the API is identical, except that a C<$cb> argument of
306C<undef> instad of a valid file handle signals an error. 395C<undef> instead of a valid file handle signals an error.
307 396
308On the child side, the "communications socket" is in fact just C<*STDIN>, 397On the child side, the "communications socket" is in fact just C<*STDIN>,
309and typically can only be read from (this highly depends on how the 398and typically can only be read from (this highly depends on how the
310program is created - if you just run F<perl> locally, it will work for 399program is created - if you just run F<perl> locally, it will work for
311both reading and writing, but commands such as F<rsh> or F<ssh> typically 400both reading and writing, but commands such as F<rsh> or F<ssh> typically
335 424
336 $self->[0](sub { 425 $self->[0](sub {
337 my $fh = shift 426 my $fh = shift
338 or die "AnyEvent::Fork::Remote: create callback failed"; 427 or die "AnyEvent::Fork::Remote: create callback failed";
339 428
340 my $code = 'BEGIN {' . $self->[1] . "}\n" 429 my $owner = length $ENV{HOSTNAME} ? "$ENV{HOSTNAME}:$$" : "*:$$";
430
431 my $code = 'BEGIN { $0 = ' . (sq "$func of $owner") . '; ' . $self->[1] . "}\n"
341 . 'syswrite STDOUT, ' . (sq $magic0) . '^' . (sq $magic1) . ';' 432 . 'syswrite STDOUT, ' . (sq $magic0) . '^' . (sq $magic1) . ';'
342 . '{ sysread STDIN, my $dummy, 1 }' 433 . '{ sysread STDIN, my $dummy, 1 }'
343 . "\n$func*STDIN," . (aq @{ $self->[2] }) . ';' 434 . "\n$func*STDIN," . (aq @{ $self->[2] }) . ';'
344 . "\n__END__\n"; 435 . "\n__END__\n";
345
346 warn $code;#d#
347 436
348 AnyEvent::Util::fh_nonblocking $fh, 1; 437 AnyEvent::Util::fh_nonblocking $fh, 1;
349 438
350 my ($rw, $ww); 439 my ($rw, $ww);
351 440

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines