@@ -50,8 +50,9 @@ See L<https://github.com/jhthorsen/mojo-ioloop-readwritefork/tree/master/example
50
50
=cut
51
51
52
52
use Mojo::Base ' Mojo::EventEmitter' ;
53
- use IO::Pty;
54
53
use Mojo::Util ' url_escape' ;
54
+ use Errno qw( EAGAIN ECONNRESET EINTR EPIPE EWOULDBLOCK ) ;
55
+ use IO::Pty;
55
56
use POSIX ' :sys_wait_h' ;
56
57
use Scalar::Util ();
57
58
use constant CHUNK_SIZE => $ENV {MOJO_CHUNK_SIZE } || 131072;
@@ -109,22 +110,10 @@ Close STDIN stream to the child process immediately.
109
110
=cut
110
111
111
112
sub close {
112
- my ($self , $what ) = @_ ;
113
- $self -> {stream }{$what }-> close if ref $self -> {stream }{$what };
114
- $self ;
115
- }
116
-
117
- =head2 close_gracefully
118
-
119
- $self = $self->close_gracefully("stdin");
120
-
121
- Close STDIN to the child process stream gracefully.
122
-
123
- =cut
124
-
125
- sub close_gracefully {
126
- my ($self , $what ) = @_ ;
127
- $self -> {stream }{$what }-> close_gracefully if ref $self -> {stream }{$what };
113
+ my $self = shift ;
114
+ my $what = $_ [0] eq ' stdout' ? ' stdout_read' : ' stdin_write' ; # stdout_read is EXPERIMENTAL
115
+ my $fh = delete $self -> {$what } or return $self ;
116
+ CORE::close ($fh ) or $self -> emit(error => $! );
128
117
$self ;
129
118
}
130
119
@@ -211,10 +200,9 @@ sub _start {
211
200
warn " [$pid ] Child starting ($args ->{program} @{$args ->{program_args}})\n " if DEBUG;
212
201
$self -> {pid } = $pid ;
213
202
$self -> {stdout_read } = $stdout_read ;
203
+ $self -> {stdin_write } = $stdin_write ;
214
204
$stdout_read -> close_slave if defined $stdout_read and UNIVERSAL::isa($stdout_read , ' IO::Pty' );
215
205
216
- $self -> _stdin($stdin_write );
217
-
218
206
Scalar::Util::weaken($self );
219
207
$self -> reactor-> io($stdout_read => sub {
220
208
$self -> {stop } and return ;
@@ -236,6 +224,7 @@ sub _start {
236
224
});
237
225
$self -> reactor-> watch($stdout_read , 1, 0);
238
226
$self -> _setup_recurring_child_alive_check($pid );
227
+ $self -> _write;
239
228
}
240
229
else { # child ===========================================================
241
230
if ($args -> {conduit } eq ' pty' ) {
@@ -308,22 +297,17 @@ Example:
308
297
309
298
$self->write("some data\n", sub {
310
299
my ($self) = @_;
311
- $self->close_gracefully ;
300
+ $self->close ;
312
301
});
313
302
314
303
=cut
315
304
316
305
sub write {
317
- my $self = shift ;
318
-
319
- if ($self -> {stream }{stdin }) {
320
- $self -> {stream }{stdin }-> write (@_ );
321
- warn " [${ \$ self->pid }] Wrote buffer (" .url_escape($_ [0]) ." )\n " if DEBUG;
322
- }
323
- else {
324
- push @{ $self -> {stdin_buffer } }, [@_ ];
325
- }
306
+ my ($self , $chunk , $cb ) = @_ ;
326
307
308
+ $self -> once(drain => $cb ) if $cb ;
309
+ $self -> {stdin_buffer } .= $chunk ;
310
+ $self -> _write if $self -> {stdin_write };
327
311
$self ;
328
312
}
329
313
@@ -345,6 +329,11 @@ sub kill {
345
329
kill $signal , $pid ;
346
330
}
347
331
332
+ sub _error {
333
+ return if $! == EAGAIN || $! == EINTR || $! == EWOULDBLOCK;
334
+ return $_ [0]-> kill if $! == ECONNRESET || $! == EPIPE;
335
+ return $_ [0]-> emit(error => $! )-> kill ;
336
+ }
348
337
349
338
sub _cleanup {
350
339
my $self = shift ;
@@ -353,8 +342,6 @@ sub _cleanup {
353
342
$reactor -> watch($self -> {stdout_read }, 0, 0) if $self -> {stdout_read };
354
343
$reactor -> remove(delete $self -> {stdout_read }) if $self -> {stdout_read };
355
344
$reactor -> remove(delete $self -> {delay }) if $self -> {delay };
356
- $reactor -> remove(delete $self -> {delay }) if $self -> {delay };
357
- delete ($self -> {stream }{stdin })-> close if $self -> {stream }{stdin };
358
345
}
359
346
360
347
sub _read {
@@ -370,18 +357,24 @@ sub _read {
370
357
$self -> emit_safe(read => $buffer );
371
358
}
372
359
373
- sub _stdin {
374
- my ($self , $handle ) = @_ ;
375
- my $stream = Mojo::IOLoop::Stream-> new($handle );
376
-
377
- Scalar::Util::weaken($self );
378
- $stream -> on(error => sub { $! == 9 ? shift -> close : return $self -> emit(error => $_ [1]); });
379
- $stream -> reactor($self -> reactor);
380
- $stream -> timeout(0);
381
- $stream -> start;
360
+ sub _write {
361
+ my $self = shift ;
382
362
383
- $self -> {stream }{stdin } = $stream ;
384
- $self -> write (@$_ ) for @{ delete $self -> {stdin_buffer } || [] };
363
+ return unless length $self -> {stdin_buffer };
364
+ my $stdin_write = $self -> {stdin_write };
365
+ my $written = $stdin_write -> syswrite ($self -> {stdin_buffer });
366
+ return $self -> _error unless defined $written ;
367
+ my $chunk = substr $self -> {stdin_buffer }, 0, $written , ' ' ;
368
+ warn " [${ \$ self->pid }] Wrote buffer (" .url_escape($chunk ) ." )\n " if DEBUG;
369
+
370
+ if (length $self -> {stdin_buffer }) {
371
+ # This is one ugly hack because it does not seem like IO::Pty play
372
+ # nice with Mojo::Reactor(::EV) ->io(...) and ->watch(...)
373
+ $self -> reactor-> timer(0.01 => sub { $self and $self -> _write });
374
+ }
375
+ else {
376
+ $self -> emit_safe(' drain' );
377
+ }
385
378
}
386
379
387
380
sub DESTROY { shift -> _cleanup }
0 commit comments