From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-Status: No, score=-4.0 required=3.0 tests=ALL_TRUSTED,BAYES_00, URIBL_BLOCKED shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from localhost (dcvr.yhbt.net [127.0.0.1]) by dcvr.yhbt.net (Postfix) with ESMTP id 22DDB1FA18 for ; Mon, 31 Aug 2020 04:41:42 +0000 (UTC) From: Eric Wong To: meta@public-inbox.org Subject: [PATCH 08/11] ds: avoid excessive queueing when reaping PIDs Date: Mon, 31 Aug 2020 04:41:37 +0000 Message-Id: <20200831044140.17027-9-e@80x24.org> In-Reply-To: <20200831044140.17027-1-e@80x24.org> References: <20200831044140.17027-1-e@80x24.org> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit List-Id: 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 | 43 ++++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/lib/PublicInbox/DS.pm b/lib/PublicInbox/DS.pm index a3f2e76c..b252ea3c 100644 --- a/lib/PublicInbox/DS.pm +++ b/lib/PublicInbox/DS.pm @@ -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 () {