]> Sergey Matveev's repositories - public-inbox.git/commitdiff
ds: avoid excessive queueing when reaping PIDs
authorEric Wong <e@80x24.org>
Mon, 31 Aug 2020 04:41:37 +0000 (04:41 +0000)
committerEric Wong <e@80x24.org>
Tue, 1 Sep 2020 00:19:19 +0000 (00:19 +0000)
We should not enqueue reap_pids() to run more than once per
EventLoop iteration.  We'll start reformatting reap_pids
to tabs, too, since we're no longer Danga::Socket.

We should also be able to remove timer usage for reaping
down-the-line once we stop abusing dwaitpid() in -watch.

lib/PublicInbox/DS.pm

index a3f2e76c16afcfd84901ca38492ad4eebbd1d6a5..b252ea3c141f326aa7c53c3dd8b98322df1d67d8 100644 (file)
@@ -40,7 +40,7 @@ my $wait_pids; # list of [ pid, callback, callback_arg ]
 my $later_queue; # list of callbacks to run at some later interval
 my $EXPMAP; # fd -> idle_time
 our $EXPTIME = 180; # 3 minutes
-my ($later_timer, $reap_timer, $exp_timer);
+my ($later_timer, $reap_armed, $reap_timer, $exp_timer);
 my $ToClose; # sockets to close when event loop is done
 our (
      %DescriptorMap,             # fd (num) -> PublicInbox::DS object
@@ -68,7 +68,7 @@ Reset all state
 =cut
 sub Reset {
     %DescriptorMap = ();
-    $in_loop = $wait_pids = $later_queue = undef;
+    $in_loop = $wait_pids = $later_queue = $reap_armed = undef;
     $EXPMAP = {};
     $nextq = $ToClose = $reap_timer = $later_timer = $exp_timer = undef;
     $LoopTimeout = -1;  # no timeout by default
@@ -225,24 +225,33 @@ sub RunTimers {
 # and other things.  So we scan the $wait_pids list, which is hopefully
 # not too big.  We keep $wait_pids small by not calling dwaitpid()
 # until we've hit EOF when reading the stdout of the child.
+
 sub reap_pids {
-    my $tmp = $wait_pids or return;
-    $wait_pids = $reap_timer = undef;
-    foreach my $ary (@$tmp) {
-        my ($pid, $cb, $arg) = @$ary;
-        my $ret = waitpid($pid, WNOHANG);
-        if ($ret == 0) {
-            push @$wait_pids, $ary; # autovivifies @$wait_pids
-        } elsif ($cb) {
-            eval { $cb->($arg, $pid) };
-        }
-    }
-    # we may not be done, yet, and could've missed/masked a SIGCHLD:
-    $reap_timer = add_timer(1, \&reap_pids) if $wait_pids;
+       $reap_armed = undef;
+       my $tmp = $wait_pids or return;
+       $wait_pids = undef;
+       foreach my $ary (@$tmp) {
+               my ($pid, $cb, $arg) = @$ary;
+               my $ret = waitpid($pid, WNOHANG);
+               if ($ret == 0) {
+                       push @$wait_pids, $ary; # autovivifies @$wait_pids
+               } elsif ($cb) {
+                       eval { $cb->($arg, $pid) };
+               }
+       }
+       # we may not be done, yet, and could've missed/masked a SIGCHLD:
+       if ($wait_pids && !$reap_armed) {
+               $reap_timer //= add_timer(1, \&reap_pids_timed);
+       }
+}
+
+sub reap_pids_timed {
+       $reap_timer = undef;
+       goto \&reap_pids;
 }
 
 # reentrant SIGCHLD handler (since reap_pids is not reentrant)
-sub enqueue_reap ($) { push @$nextq, \&reap_pids }; # autovivifies
+sub enqueue_reap { $reap_armed //= requeue(\&reap_pids) }
 
 sub in_loop () { $in_loop }
 
@@ -627,7 +636,7 @@ sub dwaitpid ($$$) {
        push @$wait_pids, [ @_ ]; # [ $pid, $cb, $arg ]
 
        # We could've just missed our SIGCHLD, cover it, here:
-       requeue(\&reap_pids);
+       goto &enqueue_reap; # tail recursion
 }
 
 sub _run_later () {