[pve-devel] [RFC common 2/2] fork_worker: use separate pipe for status messages
Wolfgang Bumiller
w.bumiller at proxmox.com
Fri Dec 15 12:07:25 CET 2017
Generally the idea is good. Some issues in the code, though.
Plus I wonder if the long stdout/err replacements could just be changed
to use dup2()... (There's more that could be improved, eg. csync+psync
could be one socketpair())
On Fri, Dec 15, 2017 at 09:13:33AM +0100, Thomas Lamprecht wrote:
> We forced line wise flushing of the workers STDOUT and STDERR to
> capture the final status (TASK OK/TASK ERROR).
> Thus, if the code executed in the worker wanted to flush explicitly,
> e.g., when the last output wasn't new line terminated but needed to
> reach the users eyes, the parent just ignored that.
> This leads to confusing results in CLI handlers using fork_workers.
>
> So remove the buffering logic completely and introduce a separate
> pipe for sending the final status.
>
> Signed-off-by: Thomas Lamprecht <t.lamprecht at proxmox.com>
> ---
> src/PVE/RESTEnvironment.pm | 56 +++++++++++++++++++++++++---------------------
> 1 file changed, 30 insertions(+), 26 deletions(-)
>
> diff --git a/src/PVE/RESTEnvironment.pm b/src/PVE/RESTEnvironment.pm
> index 0ad6dba..3a2bf8e 100644
> --- a/src/PVE/RESTEnvironment.pm
> +++ b/src/PVE/RESTEnvironment.pm
> @@ -396,6 +396,7 @@ sub fork_worker {
>
> my @psync = POSIX::pipe();
> my @csync = POSIX::pipe();
> + my @ctrlfd = POSIX::pipe() if $sync;
>
> my $node = $self->{nodename};
>
> @@ -427,9 +428,11 @@ sub fork_worker {
> POSIX::setsid();
>
> POSIX::close ($psync[0]);
> + POSIX::close ($ctrlfd[0]) if $sync;
> POSIX::close ($csync[1]);
>
> $outfh = $sync ? $psync[1] : undef;
> + my $resfh = $sync ? $ctrlfd[1] : undef;
>
> eval {
> PVE::INotify::inotify_close();
> @@ -450,6 +453,7 @@ sub fork_worker {
> if !open(STDIN, "</dev/null");
>
> $outfh = PVE::Tools::upid_open($upid);
> + $resfh = $outfh;
> }
>
>
> @@ -499,10 +503,14 @@ sub fork_worker {
> chomp $err;
> $err =~ s/\n/ /mg;
> syslog('err', $err);
> - print STDERR "TASK ERROR: $err\n";
> + my $msg = "TASK ERROR: $err\n";
> + POSIX::write($resfh, $msg, length($msg));
> + POSIX::close($resfh) if $sync;
> POSIX::_exit(-1);
> } else {
> - print STDERR "TASK OK\n";
> + my $msg = "TASK OK\n";
> + POSIX::write($resfh, $msg, length($msg));
> + POSIX::close($resfh) if $sync;
> POSIX::_exit(0);
> }
> kill(-9, $$);
> @@ -511,6 +519,7 @@ sub fork_worker {
> # parent
>
> POSIX::close ($psync[1]);
> + POSIX::close ($ctrlfd[1]);
Needs to check $sync
pvedaemon[1617]: Use of uninitialized value in subroutine entry at /usr/share/perl5/PVE/RESTEnvironment.pm line 522.
> POSIX::close ($csync[0]);
>
> my $readbuf = '';
> @@ -562,7 +571,6 @@ sub fork_worker {
>
> if ($sync) {
> my $count;
> - my $outbuf = '';
> my $int_count = 0;
> eval {
> local $SIG{INT} = local $SIG{QUIT} = local $SIG{TERM} = sub {
> @@ -591,38 +599,34 @@ sub fork_worker {
> }
> last if $count == 0; # eof
>
> - $outbuf .= $readbuf;
> - while ($outbuf =~ s/^(([^\010\r\n]*)(\r|\n|(\010)+|\r\n))//s) {
> - my $line = $1;
> - my $data = $2;
> - if ($data =~ m/^TASK OK$/) {
> - # skip
> - } elsif ($data =~ m/^TASK ERROR: (.+)$/) {
> - print STDERR "$1\n";
> - } else {
> - print $line;
> - }
> - if ($outfh) {
> - print $outfh $line;
> - $outfh->flush();
> - }
> - }
> + print $readbuf;
> + select->flush();
> +
> + # write always to task log (output and control messages)
But control messages aren't always read here as $ctrlfd isn't in
$select (and doesn't have to be since it's only filled when the client
exits, and read below.)
> + print $outfh $readbuf;
> + $outfh->flush();
> } else {
> # some commands daemonize without closing stdout
> last if !PVE::ProcFSTools::check_process_running($cpid);
> }
> }
> +
> + # get status (error or OK)
> + POSIX::read($ctrlfd[0], $readbuf, 4096);
Again: $ctrlfd validity depends on $sync.
(We could always have a $ctrlfd thoguh?)
> + if ($readbuf =~ m/^TASK OK\n?$/) {
> + print $outfh $readbuf;
> + } elsif ($readbuf =~ m/^TASK ERROR: (.*)\n?$/) {
> + print STDERR "$1\n";
> + print $outfh "\n$readbuf";
> + } else {
> + die "got unexpected control message: $readbuf\n";
> + }
> + $outfh->flush();
> };
> my $err = $@;
>
> POSIX::close($psync[0]);
> -
> - if ($outbuf) { # just to be sure
> - print $outbuf;
> - if ($outfh) {
> - print $outfh $outbuf;
> - }
> - }
> + POSIX::close($ctrlfd[0]);
>
> if ($err) {
> $err =~ s/\n/ /mg;
> --
> 2.11.0
More information about the pve-devel
mailing list