]> Sergey Matveev's repositories - public-inbox.git/commitdiff
qspawn: shorten lifetime of circular references
authorEric Wong <e@80x24.org>
Tue, 17 Sep 2019 08:31:20 +0000 (08:31 +0000)
committerEric Wong <e@80x24.org>
Tue, 17 Sep 2019 08:31:44 +0000 (08:31 +0000)
All of these circular references are designed to clear
themselves, but these will make actual errors from Devel::Cycle
easier-to-spot.

The circular reference in the limiter {run_queue} is not a real
problem, but we can avoid storing the circular reference until
we actually need to spawn the child, reducing the size of the
Qspawn object while it's in the queue, slightly.

We also do not need to have redundant checks to spawn new
processes, we should only spawn new processes when they're
->start-ed or after waitpid reaps them.

lib/PublicInbox/Qspawn.pm

index 844d50f7cdeedb6775df8183df8a2d3f9bb83c18..10fe534112b5d29e5c75ada28fa9b337f9d1e176 100644 (file)
@@ -44,11 +44,11 @@ sub new ($$$;) {
 }
 
 sub _do_spawn {
-       my ($self, $cb) = @_;
+       my ($self, $cb, $limiter) = @_;
        my $err;
        my ($cmd, $env, $opts) = @{$self->{args}};
        my %opts = %{$opts || {}};
-       my $limiter = $self->{limiter};
+       $self->{limiter} = $limiter;
        foreach my $k (PublicInbox::Spawn::RLIMITS()) {
                if (defined(my $rlimit = $limiter->{$k})) {
                        $opts{$k} = $rlimit;
@@ -94,21 +94,21 @@ sub waitpid_err ($$) {
                $err = "W: waitpid($xpid, 0) => $pid: $!";
        } # else should not be called with pid == 0
 
+       my $env = delete $self->{env};
+
        # done, spawn whatever's in the queue
        my $limiter = $self->{limiter};
        my $running = --$limiter->{running};
 
-       # limiter->{max} may change dynamically
-       if (($running || $limiter->{running}) < $limiter->{max}) {
-               if (my $next = shift @{$limiter->{run_queue}}) {
-                       _do_spawn(@$next);
+       if ($running < $limiter->{max}) {
+               if (my $next = shift(@{$limiter->{run_queue}})) {
+                       _do_spawn(@$next, $limiter);
                }
        }
 
        return unless $err;
        $self->{err} = $err;
-       my $env = $self->{env} or return;
-       if (!$env->{'qspawn.quiet'}) {
+       if ($env && !$env->{'qspawn.quiet'}) {
                log_err($env, join(' ', @{$self->{args}}) . ": $err");
        }
 }
@@ -132,22 +132,12 @@ sub finish ($;$) {
        if (delete $self->{rpipe}) {
                do_waitpid($self, $env);
        }
-
-       # limiter->{max} may change dynamically
-       my $limiter = $self->{limiter};
-       if ($limiter->{running} < $limiter->{max}) {
-               if (my $next = shift @{$limiter->{run_queue}}) {
-                       _do_spawn(@$next);
-               }
-       }
 }
 
 sub start {
        my ($self, $limiter, $cb) = @_;
-       $self->{limiter} = $limiter;
-
        if ($limiter->{running} < $limiter->{max}) {
-               _do_spawn($self, $cb);
+               _do_spawn($self, $cb, $limiter);
        } else {
                push @{$limiter->{run_queue}}, [ $self, $cb ];
        }