our @EXPORT_OK = qw(now msg_more);
use warnings;
use 5.010_001;
+use Scalar::Util qw(blessed);
use PublicInbox::Syscall qw(:epoll);
use PublicInbox::Tmpfile;
use Carp qw(croak confess carp);
require File::Spec;
-my $nextq = []; # queue for next_tick
-my $WaitPids = []; # list of [ pid, callback, callback_arg ]
-my $reap_timer;
+my $nextq; # queue for next_tick
+my $WaitPids; # list of [ pid, callback, callback_arg ]
+my $later_queue; # callbacks
+my ($later_timer, $reap_timer);
our (
%DescriptorMap, # fd (num) -> PublicInbox::DS object
$Epoll, # Global epoll fd (or DSKQXS ref)
$LoopTimeout, # timeout of event loop in milliseconds
$DoneInit, # if we've done the one-time module init yet
@Timers, # timers
+ $in_loop,
);
Reset();
=cut
sub Reset {
%DescriptorMap = ();
+ $nextq = [];
$WaitPids = [];
- $reap_timer = undef;
+ $later_queue = [];
+ $reap_timer = $later_timer = undef;
@ToClose = ();
$LoopTimeout = -1; # no timeout by default
@Timers = ();
my $q = $nextq;
$nextq = [];
for (@$q) {
- if (ref($_) eq 'CODE') {
- $_->();
- } else {
+ # we avoid "ref" on blessed refs to workaround a Perl 5.16.3 leak:
+ # https://rt.perl.org/Public/Bug/Display.html?id=114340
+ if (blessed($_)) {
$_->event_step;
+ } else {
+ $_->();
}
}
}
# reentrant SIGCHLD handler (since reap_pids is not reentrant)
sub enqueue_reap ($) { push @$nextq, \&reap_pids };
+sub running () { ($SIG{CHLD} // '') eq \&enqueue_reap }
+
sub EpollEventLoop {
- local $SIG{CHLD} = \&enqueue_reap;
- while (1) {
+ local $in_loop = 1;
+ do {
my @events;
my $i;
my $timeout = RunTimers();
# in that event.
$DescriptorMap{$events[$i]->[0]}->event_step;
}
- return unless PostEventLoop();
- }
+ } while (PostEventLoop());
+ _run_later();
}
=head2 C<< CLASS->SetPostLoopCallback( CODEREF ) >>
# must be called with eval, PublicInbox::DS may not be loaded (see t/qspawn.t)
sub dwaitpid ($$$) {
my ($pid, $cb, $arg) = @_;
- my $chld = $SIG{CHLD};
- if (defined($chld) && $chld eq \&enqueue_reap) {
+ if ($in_loop) {
push @$WaitPids, [ $pid, $cb, $arg ];
# We could've just missed our SIGCHLD, cover it, here:
}
}
+sub _run_later () {
+ my $run = $later_queue;
+ $later_timer = undef;
+ $later_queue = [];
+ $_->() for @$run;
+}
+
+sub later ($) {
+ my ($cb) = @_;
+ push @$later_queue, $cb;
+ $later_timer //= AddTimer(undef, 60, \&_run_later);
+}
+
package PublicInbox::DS::Timer;
# [$abs_float_firetime, $coderef];
sub cancel {