Permalink
Browse files

Polish Proc methods that expect the Proc to be done

Affects methods .status, .Numeric, .Bool, .exitcode, and .sink.
Fixes module build installation failures and RT#125757:
https://rt.perl.org/Ticket/Display.html?id=125757#ticket-history

Even before Proc refactor, we had some issues where users would call, say,
.exitcode, and expect the exitcode, but .out/.err pipes were still open,
so the .exitcode was wrong.

The Proc refactor exacerbated the issue, as now the user had to ensure the
opened pipes were closed when a call to one of the affected methods listed
above were made or a Proc was sunk.

Fix by waiting for the proc to finish up when any of the affected methods
are called. The one extra thing we can do is also close .stdin of the proc,
but I'm not 100% sure if we should. Also, the current method is a bit fragile,
in that setting $exitcode when instantiating the Proc to anything but -1
will not await for proc to be completed and won't update the exitcode...
  • Loading branch information...
zoffixznet committed Jun 15, 2017
1 parent 14d7571 commit e4468c610c1565be267dc6688d050c985e056afc
Showing with 36 additions and 19 deletions.
  1. +36 −19 src/core/Proc.pm
@@ -108,49 +108,66 @@ my class Proc {
}

method !await-if-last-handle(--> Nil) {
$!active-handles--;
if $!active-handles == 0 {
self.status(await($!finished).status);
CATCH { default { self.status(0x100) } }
}
self!wait-for-finish unless --$!active-handles;
}

method spawn(*@args where .so, :$cwd = $*CWD, :$env) {
method !wait-for-finish {
CATCH { default { self.status(0x100) } }
self.status(await($!finished).status) if $!exitcode == -1;
}

method spawn(*@args where .so, :$cwd = $*CWD, :$env --> Bool:D) {
@!command = @args;
my %env := $env ?? $env.hash !! %*ENV;
self!spawn-internal(@args, $cwd, %env)
self!spawn-internal(@args, $cwd, $env)
}

method shell($cmd, :$cwd = $*CWD, :$env) {
method shell($cmd, :$cwd = $*CWD, :$env --> Bool:D) {
@!command = $cmd;
my %env := $env ?? $env.hash !! %*ENV;
my @args := Rakudo::Internals.IS-WIN
?? (%*ENV<ComSpec>, '/c', $cmd)
!! ('/bin/sh', '-c', $cmd);
self!spawn-internal(@args, $cwd, %env)
self!spawn-internal(@args, $cwd, $env)
}

method !spawn-internal(@args, $cwd, %ENV) {
method !spawn-internal(@args, $cwd, $env --> Bool:D) {
my %ENV := $env ?? $env.hash !! %*ENV;
$!proc := Proc::Async.new(|@args, :$!w);
.() for @!pre-spawn;
$!finished = $!proc.start(:$cwd, :%ENV, scheduler => $PROCESS::SCHEDULER);
unless $!in || $!out || $!err {
self.status(await($!finished).status);
my $is-spawned := do {
CATCH { default { self.status(0x100) } }
}
self.Bool
await $!proc.ready;
True
} // False;
.() for @!post-spawn;
self!wait-for-finish unless $!out || $!err || $!in;
$is-spawned
}

proto method status(|) { * }
multi method status($new_status) {
$!exitcode = $new_status +> 8;
$!signal = $new_status +& 0xFF;
}
multi method status(Proc:D:) { ($!exitcode +< 8) +| $!signal }
multi method Numeric(Proc:D:) { $!exitcode }
multi method Bool(Proc:D:) { $!exitcode == 0 }
multi method status(Proc:D:) {
self!wait-for-finish;
($!exitcode +< 8) +| $!signal
}
multi method Numeric(Proc:D:) {
self!wait-for-finish;
$!exitcode
}
multi method Bool(Proc:D:) {
self!wait-for-finish;
$!exitcode == 0
}
method exitcode {
self!wait-for-finish;
$!exitcode
}

method sink(--> Nil) {
self!wait-for-finish;
X::Proc::Unsuccessful.new(:proc(self)).throw if $!exitcode > 0;
}
}

0 comments on commit e4468c6

Please sign in to comment.