use Symbol qw(gensym);
use IO::KQueue;
use Errno qw(EAGAIN);
+use PublicInbox::OnDestroy;
use PublicInbox::Syscall qw(EPOLLONESHOT EPOLLIN EPOLLOUT EPOLLET);
sub EV_DISPATCH () { 0x0080 }
sub new {
my ($class) = @_;
- bless { kq => IO::KQueue->new, owner_pid => $$ }, $class;
+ my $fgen = $PublicInbox::OnDestroy::fork_gen;
+ bless { kq => IO::KQueue->new, fgen => $fgen }, $class;
}
# returns a new instance which behaves like signalfd on Linux.
sub DESTROY {
my ($self) = @_;
my $kq = delete $self->{kq} or return;
- if (delete($self->{owner_pid}) == $$) {
+ delete($self->{fgen}) == $PublicInbox::OnDestroy::fork_gen and
POSIX::close($$kq);
- }
}
1;
return unless defined $pid_file;
write_pid($pid_file);
- # for ->DESTROY:
- bless { pid => $$, pid_file => \$pid_file }, __PACKAGE__;
+ on_destroy \&unlink_pid_file_safe_ish, \$pid_file;
}
sub has_busy_clients { # post_loop_do CB
warn "BUG: .oldbin suffix exists: $pid_file\n";
return;
}
- unlink_pid_file_safe_ish($$, $pid_file);
+ unlink_pid_file_safe_ish(\$pid_file);
$pid_file .= '.oldbin';
write_pid($pid_file);
}
my $file = $pid_file;
$file =~ s/\.oldbin\z// or die "BUG: no '.oldbin' suffix in $file";
- unlink_pid_file_safe_ish($$, $pid_file);
+ unlink_pid_file_safe_ish(\$pid_file);
$pid_file = $file;
eval { write_pid($pid_file) };
warn $@, "\n" if $@;
}
-sub unlink_pid_file_safe_ish ($$) {
- my ($unlink_pid, $file) = @_;
- return unless defined $unlink_pid && $unlink_pid == $$;
+sub unlink_pid_file_safe_ish ($) {
+ my ($fref) = @_;
- open my $fh, '<', $file or return;
+ open my $fh, '<', $$fref or return;
local $/ = "\n";
defined(my $read_pid = <$fh>) or return;
chomp $read_pid;
- if ($read_pid == $unlink_pid) {
- Net::Server::Daemonize::unlink_pid_file($file);
- }
+ Net::Server::Daemonize::unlink_pid_file($$fref) if $read_pid == $$;
}
sub master_quit ($) {
$nworker = 1;
local (%XNETD, %POST_ACCEPT);
daemon_prepare($default_listen);
- my $for_destroy = daemonize();
+ my $unlink_on_leave = daemonize();
# localize GCF2C for tests:
local $PublicInbox::GitAsyncCat::GCF2C;
local %POST_ACCEPT;
daemon_loop();
- # ->DESTROY runs when $for_destroy goes out-of-scope
+ # $unlink_on_leave runs
}
sub write_pid ($) {
do_chown($path);
}
-sub DESTROY {
- unlink_pid_file_safe_ish($_[0]->{pid}, ${$_[0]->{pid_file}});
-}
-
1;
sub gcf_inflight ($) {
my ($self) = @_;
# FIXME: the first {sock} check can succeed but Perl can complain
- # about calling ->owner_pid on an undefined value. Not sure why or
- # how this happens but t/imapd.t can complain about it, sometimes.
+ # about an undefined value. Not sure why or how this happens but
+ # t/imapd.t can complain about it, sometimes.
if ($self->{sock}) {
- if (eval { $self->{sock}->owner_pid == $$ }) {
+ if (eval { $self->{sock}->can_reap }) {
return $self->{inflight};
} elsif ($@) {
no warnings 'uninitialized';
- warn "E: $self sock=$self->{sock}: owner_pid failed: ".
+ warn "E: $self sock=$self->{sock}: can_reap failed: ".
"$@ (continuing...)";
}
delete @$self{qw(sock inflight)};
use Carp qw(croak);
use IO::Poll qw(POLLIN);
use Errno qw(EINTR EAGAIN);
+use PublicInbox::OnDestroy;
# don't autodie in top-level for Perl 5.16.3 (and maybe newer versions)
# we have our own ->close, so we scope autodie into each sub
my ($io, $pid, @cb_arg) = @_;
bless $io, __PACKAGE__;
# we share $err (and not $self) with awaitpid to avoid a ref cycle
- ${*$io}{pi_io_reap} = [ $$, $pid, \(my $err) ];
+ ${*$io}{pi_io_reap} = [ $PublicInbox::OnDestroy::fork_gen,
+ $pid, \(my $err) ];
awaitpid($pid, \&waitcb, \$err, @cb_arg);
$io;
}
${${*$io}{pi_io_reap} // []}[1];
}
-sub owner_pid {
+sub can_reap {
my ($io) = @_;
- ${${*$io}{pi_io_reap} // [-1]}[0];
+ ${${*$io}{pi_io_reap} // [-1]}[0] == $PublicInbox::OnDestroy::fork_gen;
}
# caller cares about error result if they call close explicitly
my ($io) = @_;
my $ret = $io->SUPER::close;
my $reap = delete ${*$io}{pi_io_reap};
- return $ret unless $reap && $reap->[0] == $$;
+ return $ret if ($reap->[0] // -1) != $PublicInbox::OnDestroy::fork_gen;
if (defined ${$reap->[2]}) { # reap_pids already reaped asynchronously
$? = ${$reap->[2]};
} else { # wait synchronously
sub DESTROY {
my ($io) = @_;
my $reap = delete ${*$io}{pi_io_reap};
- if ($reap && $reap->[0] == $$) {
+ if (($reap->[0] // -1) == $PublicInbox::OnDestroy::fork_gen) {
$io->SUPER::close;
awaitpid($reap->[1]);
}
use PublicInbox::Git;
use autodie qw(close open rename seek truncate);
use PublicInbox::Import;
+use PublicInbox::OnDestroy;
use PublicInbox::LeiXSearch;
use Fcntl qw(SEEK_SET);
sub overs_all { # for xoids_for (called only in lei workers?)
my ($self) = @_;
- my $pid = $$;
- if (($self->{owner_pid} // $pid) != $pid) {
+ my $fgen = $PublicInbox::OnDestroy::fork_gen ;
+ if (($self->{fgen} // $fgen) != $fgen) {
delete($_->{over}) for @{$self->{ibxish}};
}
- $self->{owner_pid} = $pid;
+ $self->{fgen} = $fgen;
grep(defined, map { $_->over } @{$self->{ibxish}});
}
use PublicInbox::Spawn qw(which spawn popen_rd run_qx);
require PublicInbox::Sigfd;
require PublicInbox::DS;
+use PublicInbox::OnDestroy;
my $rlimit_map = PublicInbox::Spawn->can('rlimit_map');
{
my $true = which('true');
my @arg;
my $fh = popen_rd(['cat'], undef, { 0 => $r },
sub { @arg = @_; warn "x=$$\n" }, 'hi');
- my $pid = fork // BAIL_OUT $!;
+ my $pid = PublicInbox::OnDestroy::fork_tmp;
local $SIG{__WARN__} = sub { _exit(1) };
if ($pid == 0) {
local $SIG{__DIE__} = sub { _exit(2) };