$did > 0 or die "BUG: $repo_ctx->{repo}->{git_dir}: docid=$did";
my ($c, $p) = PublicInbox::PktOp->pair;
$c->{ops}->{shard_done} = [ $self, $repo_ctx,
- PublicInbox::OnDestroy->new(\&next_repos, $repo_ctx, $drs)];
+ on_destroy(\&next_repos, $repo_ctx, $drs)];
# shard_done fires when all shards are committed
my @active = keys %{$repo_ctx->{active}};
$IDX_SHARDS[$_]->wq_io_do('shard_commit', [ $p->{op_p} ]) for @active;
open my $refs, '+>', undef;
$git->{-repo}->{refs} = $refs;
my ($c, $p) = PublicInbox::PktOp->pair;
- my $next_on_err = PublicInbox::OnDestroy->new(\&index_next, $self);
+ my $next_on_err = on_destroy \&index_next, $self;
$c->{ops}->{fp_done} = [ $self, $git, $next_on_err ];
$IDX_SHARDS[++$ANY_SHARD % scalar(@IDX_SHARDS)]->wq_io_do('fp_async',
[ $p->{op_p}, $refs ], $git->{git_dir})
my $repo_ctx = $REPO_CTX = { self => $self, repo => $repo };
delete $git->{-cidx_gits_fini}; # may fire gits_fini
my $drs = delete $git->{-cidx_dump_roots_start};
- my $index_done = PublicInbox::OnDestroy->new(\&index_done,
- $repo_ctx, $drs);
+ my $index_done = on_destroy \&index_done, $repo_ctx, $drs;
my ($c, $p) = PublicInbox::PktOp->pair;
$c->{ops}->{shard_done} = [ $self, $repo_ctx, $index_done ];
for my $n (0..$#shard_in) {
sub prep_repo ($$) {
my ($self, $git) = @_;
return if $DO_QUIT;
- my $index_repo = PublicInbox::OnDestroy->new(\&index_repo, $self, $git);
+ my $index_repo = on_destroy \&index_repo, $self, $git;
my $refs = $git->{-repo}->{refs} // die 'BUG: no {-repo}->{refs}';
sysseek($refs, 0, SEEK_SET);
open my $roots_fh, '+>', undef;
my ($self) = @_;
@$SCANQ = () unless $self->{-opt}->{scan};
$GITS_NR = @$SCANQ or return;
- my $gits_fini = PublicInbox::OnDestroy->new(\&gits_fini);
+ my $gits_fini = on_destroy \&gits_fini;
$_->{-cidx_gits_fini} = $gits_fini for @$SCANQ;
if (my $drs = $TODO{dump_roots_start}) {
$_->{-cidx_dump_roots_start} = $drs for @$SCANQ;
umask == $um or progress($self, 'using umask from ',
$self->{cidx_dir}, ': ',
sprintf('0%03o', $um));
- PublicInbox::OnDestroy->new(\&CORE::umask, umask($um));
+ on_destroy \&CORE::umask, umask($um);
} else {
$self->{umask} = umask; # for SearchIdx->with_umask
undef;
($JOIN_DT[1]) = ($QRY_STR =~ /\.\.([0-9]{14})\z/); # YYYYmmddHHMMSS
($JOIN_DT[0]) = ($QRY_STR =~ /\Adt:([0-9]{14})/); # YYYYmmddHHMMSS
$JOIN_DT[0] //= '19700101'.'000000'; # git uses unsigned times
- $TODO{do_join} = PublicInbox::OnDestroy->new(\&do_join, $self);
+ $TODO{do_join} = on_destroy \&do_join, $self;
$TODO{joining} = 1; # keep shards_active() happy
- $TODO{dump_ibx_start} = PublicInbox::OnDestroy->new(\&dump_ibx_start,
- $self, $TODO{do_join});
- $TODO{dump_roots_start} = PublicInbox::OnDestroy->new(
- \&dump_roots_start, $self, $TODO{do_join});
+ $TODO{dump_ibx_start} = on_destroy \&dump_ibx_start,
+ $self, $TODO{do_join};
+ $TODO{dump_roots_start} = on_destroy \&dump_roots_start,
+ $self, $TODO{do_join};
progress($self, "will join in $QRY_STR date range...");
my $id = -1;
@IBXQ = map { ++$id } @IBX;
require_progs('prune', 'xapian-delve' => \@delve, sed => \@sed,
comm => \@COMM, awk => \@AWK);
for (0..$#IDX_SHARDS) { push @delve, "$self->{xpfx}/$_" }
- my $run_prune = PublicInbox::OnDestroy->new(\&run_prune, $self,
- $TODO{dump_roots_start});
+ my $run_prune = on_destroy \&run_prune, $self, $TODO{dump_roots_start};
my ($sort_opt, $sed_opt, $delve_opt);
pipe(local $sed_opt->{0}, local $delve_opt->{1});
pipe(local $sort_opt->{0}, local $sed_opt->{1});
my $restore_umask = prep_umask($self);
local $SIGSET = PublicInbox::DS::block_signals(
POSIX::SIGTSTP, POSIX::SIGCONT);
- my $restore = PublicInbox::OnDestroy->new($$,
- \&PublicInbox::DS::sig_setmask, $SIGSET);
+ my $restore = on_destroy \&PublicInbox::DS::sig_setmask, $SIGSET;
local $PRUNE_DONE = [];
local $IDXQ = [];
local $SCANQ = [];
EPOLLIN EPOLLOUT EPOLLONESHOT EPOLLEXCLUSIVE);
use PublicInbox::Tmpfile;
use PublicInbox::Select;
+use PublicInbox::OnDestroy;
use Errno qw(EAGAIN EINVAL ECHILD);
use Carp qw(carp croak);
-use autodie qw(fork);
our @EXPORT_OK = qw(now msg_more awaitpid add_timer add_uniq_timer);
my $nextq; # queue for next_tick
}
}
-sub do_fork () {
+# for persistent child process
+sub fork_persist () {
my $seed = rand(0xffffffff);
- my $pid = fork;
+ my $pid = PublicInbox::OnDestroy::fork_tmp;
if ($pid == 0) {
srand($seed);
- eval { Net::SSLeay::randomize() };
+ eval { Net::SSLeay::randomize() }; # may not be loaded
Reset();
}
$pid;
use PublicInbox::GitAsyncCat;
use PublicInbox::Eml;
use PublicInbox::Config;
+use PublicInbox::OnDestroy;
our $SO_ACCEPTFILTER = 0x1000;
my @CMD;
my ($set_user, $oldset);
};
if ($daemonize) {
- my $pid = fork // die "fork: $!";
+ my $pid = PublicInbox::OnDestroy::fork_tmp;
exit if $pid;
-
open(STDIN, '+<', '/dev/null') or
die "redirect stdin failed: $!\n";
open STDOUT, '>&STDIN' or die "redirect stdout failed: $!\n";
open STDERR, '>&STDIN' or die "redirect stderr failed: $!\n";
POSIX::setsid();
- $pid = fork // die "fork: $!";
+ $pid = PublicInbox::OnDestroy::fork_tmp;
exit if $pid;
}
return unless defined $pid_file;
$pid_file .= '.oldbin';
write_pid($pid_file);
}
- my $pid = fork;
+ my $pid = eval { PublicInbox::OnDestroy::fork_tmp };
if (!defined($pid)) {
- warn "fork failed: $!\n";
+ warn "fork failed: $! $@\n";
} elsif ($pid == 0) {
$ENV{LISTEN_FDS} = scalar @listeners;
$ENV{LISTEN_PID} = $$;
sub start_worker ($) {
my ($nr) = @_;
return unless @listeners;
- my $pid = PublicInbox::DS::do_fork;
+ my $pid = PublicInbox::DS::fork_persist;
if ($pid == 0) {
undef %WORKERS;
local $PublicInbox::DS::Poller; # allow epoll/kqueue
package PublicInbox::IPC;
use v5.12;
use parent qw(Exporter);
-use autodie qw(close fork pipe read socketpair sysread);
+use autodie qw(close pipe read socketpair sysread);
use Carp qw(croak);
use PublicInbox::DS qw(awaitpid);
use PublicInbox::Spawn;
}
}
+sub exit_exception { exit(!!$@) }
+
# starts a worker if Sereal or Storable is installed
sub ipc_worker_spawn {
my ($self, $ident, $oldset, $fields, @cb_args) = @_;
pipe(my $r_res, my $w_res);
my $sigset = $oldset // PublicInbox::DS::block_signals();
$self->ipc_atfork_prepare;
- my $pid = PublicInbox::DS::do_fork;
+ my $pid = PublicInbox::DS::fork_persist;
if ($pid == 0) {
delete @$self{qw(-wq_s1 -wq_s2 -wq_workers -wq_ppid)};
$w_req = $r_res = undef;
$SIG{$_} = 'IGNORE' for (qw(TERM INT QUIT));
local $0 = $ident;
# ensure we properly exit even if warn() dies:
- my $end = PublicInbox::OnDestroy->new($$, sub { exit(!!$@) });
+ my $end = on_destroy \&exit_exception;
eval {
$fields //= {};
local @$self{keys %$fields} = values(%$fields);
my ($self, $oldset, $fields, $one, @cb_args) = @_;
my ($bcast1, $bcast2);
$one or socketpair($bcast1, $bcast2, AF_UNIX, SOCK_SEQPACKET, 0);
- my $pid = PublicInbox::DS::do_fork;
+ my $pid = PublicInbox::DS::fork_persist;
if ($pid == 0) {
undef $bcast1;
delete @$self{qw(-wq_s1 -wq_ppid)};
local $0 = $one ? $self->{-wq_ident} :
"$self->{-wq_ident} $self->{-wq_worker_nr}";
# ensure we properly exit even if warn() dies:
- my $end = PublicInbox::OnDestroy->new($$, sub { exit(!!$@) });
+ my $end = on_destroy \&exit_exception;
eval {
$fields //= {};
local @$self{keys %$fields} = values(%$fields);
use v5.12;
use parent qw(PublicInbox::DS PublicInbox::LeiExternal
PublicInbox::LeiQuery);
-use autodie qw(bind chdir fork open pipe socket socketpair syswrite unlink);
+use autodie qw(bind chdir open pipe socket socketpair syswrite unlink);
use Getopt::Long ();
use Socket qw(AF_UNIX SOCK_SEQPACKET pack_sockaddr_un);
use Errno qw(EPIPE EAGAIN ECONNREFUSED ENOENT ECONNRESET);
use PublicInbox::Eml;
use PublicInbox::Import;
use PublicInbox::ContentHash qw(git_sha);
+use PublicInbox::OnDestroy;
use PublicInbox::IPC;
use Time::HiRes qw(stat); # ctime comparisons for config cache
use File::Path ();
sub pkt_op_pair {
my ($self) = @_;
- require PublicInbox::OnDestroy;
require PublicInbox::PktOp;
- my $end = PublicInbox::OnDestroy->new($$, \&_delete_pkt_op, $self);
+ my $end = on_destroy \&_delete_pkt_op, $self;
@$self{qw(pkt_op_c pkt_op_p)} = PublicInbox::PktOp->pair;
$end;
}
STDIN->autoflush(1);
dump_and_clear_log();
POSIX::setsid() > 0 or die "setsid: $!";
- my $pid = fork;
+ my $pid = PublicInbox::OnDestroy::fork_tmp;
return if $pid;
$0 = "lei-daemon $path";
local (%PATH2CFG, $MDIR2CFGPATH);
pipe(my $r, my $w);
my $cmd = [ 'git', "--git-dir=$fgrp->{cur_dst}",
qw(update-ref --stdin -z) ];
- my $pack = PublicInbox::OnDestroy->new($$, \&satellite_done, $fgrp);
+ my $pack = on_destroy \&satellite_done, $fgrp;
start_cmd($fgrp, $cmd, { 0 => $r, 2 => $fgrp->{lei}->{2} }, $pack);
close $r;
$fgrp->{dry_run} ? undef : $w;
for my $fgrp (@$fgrpv) {
my $rn = $fgrp->{-remote};
my %opt = ( 2 => $fgrp->{lei}->{2} );
-
- my $update_ref = PublicInbox::OnDestroy->new($$,
- \&fgrp_update, $fgrp);
-
+ my $update_ref = on_destroy \&fgrp_update, $fgrp;
my $src = [ 'git', "--git-dir=$fgrp->{-osdir}", 'for-each-ref',
"--format=refs/%(refname:lstrip=3)%00%(objectname)",
"refs/remotes/$rn/" ];
}
$cmd = [ @git, "--git-dir=$osdir", @fetch, $grp ];
push @$old, @$new;
- my $end = PublicInbox::OnDestroy->new($$, \&fgrpv_done, $old);
+ my $end = on_destroy \&fgrpv_done, $old;
start_cmd($self, $cmd, $opt, $end);
}
}
my $cmd = [ @{$self->{-torsocks}}, @git,
fetch_args($self->{lei}, $opt), $rn ];
push @$cmd, '-P' if $self->{lei}->{prune}; # --prune-tags implied
- my $run_puh = PublicInbox::OnDestroy->new($$, \&run_puh, $self, $fini);
+ my $run_puh = on_destroy \&run_puh, $self, $fini;
++$self->{chg}->{nr_chg};
start_cmd($self, $cmd, $opt, $run_puh);
}
return;
}
}
- my $fini = PublicInbox::OnDestroy->new($$, \&v1_done, $self);
+ my $fini = on_destroy \&v1_done, $self;
if (my $fgrp = forkgroup_prep($self, $uri)) {
$fgrp->{-fini} = $fini;
if ($resume) {
}
}
++$self->{chg}->{nr_chg};
- start_cmd($self, $cmd, $opt, PublicInbox::OnDestroy->new($$,
- \&run_puh, $self, $fini));
+ start_cmd($self, $cmd, $opt,
+ on_destroy(\&run_puh, $self, $fini));
}
if (!$self->{-is_epoch} && $lei->{opt}->{'inbox-config'} =~
/\A(?:always|v1)\z/s &&
sub run_next_puh {
my ($self) = @_;
my $puh = shift @{$self->{-puh_todo}} // return delete($self->{-fini});
- my $fini = PublicInbox::OnDestroy->new($$, \&run_next_puh, $self);
+ my $fini = on_destroy \&run_next_puh, $self;
my $cmd = [ @$puh, ($self->{cur_dst} // $self->{dst}) ];
my $opt = +{ map { $_ => $self->{lei}->{$_} } (0..2) };
start_cmd($self, $cmd, undef, $opt, $fini);
my $opt = { 2 => $self->{lei}->{2} };
open($opt->{1}, '+>', undef);
$self->{-show_ref_up} = $opt->{1};
- my $done = PublicInbox::OnDestroy->new($$, \&up_fp_done, $self);
+ my $done = on_destroy \&up_fp_done, $self;
start_cmd($self, $cmd, $opt, $done);
}
$new = $self->{-ent}->{head};
my $want = parse_epochs($lei->{opt}->{epoch}, $v2_epochs);
my $task = $m ? bless { %$self }, __PACKAGE__ : $self;
my (@skip, $desc);
- my $fini = PublicInbox::OnDestroy->new($$, \&v2_done, $task);
+ my $fini = on_destroy \&v2_done, $task;
for my $nr (sort { $a <=> $b } keys %$v2_epochs) {
my ($uri, $key) = @{$v2_epochs->{$nr}};
my $src = $uri->as_string;
my ($self, $m) = @_;
my $todo = $TODO;
$TODO = \'BUG on further use';
- my $end = PublicInbox::OnDestroy->new($$, \&fgrp_fetch_all, $self);
+ my $end = on_destroy \&fgrp_fetch_all, $self;
{
my $nodep = delete $todo->{''};
sub ipc_atfork_child {
my ($self) = @_;
PublicInbox::LeiInput::input_only_atfork_child($self);
- PublicInbox::OnDestroy->new($$, \&emit_query, $self);
+ on_destroy \&emit_query, $self;
}
no warnings 'once';
use PublicInbox::MdirReader;
use PublicInbox::LeiToMail;
use PublicInbox::Compat qw(uniqstr);
+use PublicInbox::OnDestroy;
use File::Temp qw(tmpnam);
use POSIX ();
use IO::Handle (); # ->autoflush
my ($self) = @_;
my $eidx = $self->{priv_eidx};
my $tl = wantarray && $self->{-err_wr} ?
- PublicInbox::OnDestroy->new($$, \&_tail_err, $self) :
+ on_destroy(\&_tail_err, $self) :
undef;
$eidx->idx_init({-private => 1}); # acquires lock
wantarray ? ($eidx, $tl) : $eidx;
-# Copyright (C) 2021 all contributors <meta@public-inbox.org>
+# Copyright (C) all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
# handles "lei tag" command
package PublicInbox::LeiTag;
-use strict;
-use v5.10.1;
+use v5.12;
use parent qw(PublicInbox::IPC PublicInbox::LeiInput);
use PublicInbox::InboxWritable qw(eml_from_path);
+use PublicInbox::OnDestroy;
sub input_eml_cb { # used by PublicInbox::LeiInput::input_fh
my ($self, $eml) = @_;
PublicInbox::LeiInput::input_only_atfork_child($self);
$self->{lse} = $self->{lei}->{sto}->search;
# this goes out-of-scope at worker process exit:
- PublicInbox::OnDestroy->new($$, \¬e_unimported, $self);
+ on_destroy \¬e_unimported, $self;
}
# Workaround bash word-splitting s to ['kw', ':', 'keyword' ...]
sub lock_for_scope {
my ($self) = @_;
lock_acquire($self) or return; # lock_path not set
- PublicInbox::OnDestroy->new(\&lock_release, $self);
+ on_destroy \&lock_release, $self;
}
sub lock_acquire_fast {
sub lock_for_scope_fast {
my ($self) = @_;
lock_acquire_fast($self) or return; # lock_path not set
- PublicInbox::OnDestroy->new(\&lock_release_fast, $self);
+ on_destroy \&lock_release_fast, $self;
}
1;
sub mh_each_file {
my ($self, $efcb, @arg) = @_;
opendir(my $dh, my $dir = $self->{dir});
- my $restore = PublicInbox::OnDestroy->new($$, \&chdir, $self->{cwdfh});
+ my $restore = on_destroy \&chdir, $self->{cwdfh};
chdir($dh);
my $sort = $self->{sort};
if (defined $sort && "@$sort" ne 'none') {
sub mh_read_one {
my ($self, $n, $ucb, @arg) = @_;
- my $restore = PublicInbox::OnDestroy->new($$, \&chdir, $self->{cwdfh});
+ my $restore = on_destroy \&chdir, $self->{cwdfh};
chdir(my $dir = $self->{dir});
_file2eml($dir, $n, $self, $ucb, @arg);
}
# Various mbox locking methods
package PublicInbox::MboxLock;
use v5.12;
-use PublicInbox::OnDestroy;
+use PublicInbox::OnDestroy ();
use Fcntl qw(:flock F_SETLK F_SETLKW F_RDLCK F_WRLCK
O_CREAT O_EXCL O_WRONLY SEEK_SET);
use Carp qw(croak);
sub DESTROY {
my ($self) = @_;
my $f = $self->{".lock$$"} or return;
- my $x;
+ my $od;
if (my $dh = delete $self->{dh}) {
opendir my $c, '.';
- $x = PublicInbox::OnDestroy->new(\&chdir, $c);
+ $od = PublicInbox::OnDestroy::all \&chdir, $c;
chdir($dh);
}
CORE::unlink($f) or die "unlink($f): $! (lock stolen?)";
package PublicInbox::OnDestroy;
use v5.12;
+use parent qw(Exporter);
+use autodie qw(fork);
+our @EXPORT = qw(on_destroy);
+our $fork_gen = 0;
-sub new {
- shift; # ($class, $cb, @args)
- bless [ @_ ], __PACKAGE__;
+# either parent or child is expected to exit or exec shortly after this:
+sub fork_tmp () {
+ my $pid = fork;
+ ++$fork_gen if $pid == 0;
+ $pid;
}
+# all children
+sub all (@) { bless [ undef, @_ ], __PACKAGE__ }
+
+# same process
+sub on_destroy (@) { bless [ $fork_gen, @_ ], __PACKAGE__ }
+
sub cancel { @{$_[0]} = () }
sub DESTROY {
- my ($cb, @args) = @{$_[0]};
- if (!ref($cb) && $cb) {
- my $pid = $cb;
- return if $pid != $$;
- $cb = shift @args;
- }
- $cb->(@args) if $cb;
+ my ($fgen, $cb, @args) = @{$_[0]};
+ $cb->(@args) if ($cb && ($fgen // $fork_gen) == $fork_gen);
}
1;
$v2w->{current_info} = "[$self->{shard}]"; # for $SIG{__WARN__}
$self->begin_txn_lazy;
# caller (ipc_worker_spawn) must capture this:
- PublicInbox::OnDestroy->new($$, \&_worker_done, $self);
+ on_destroy \&_worker_done, $self;
}
sub index_eml {
package PublicInbox::SpawnPP;
use v5.12;
use POSIX qw(dup2 _exit setpgid :signal_h);
-use autodie qw(chdir close fork pipe);
+use autodie qw(chdir close pipe);
+use PublicInbox::OnDestroy;
# this is loaded by PublicInbox::Spawn, so we can't use/require it, here
# Pure Perl implementation for folks that do not use Inline::C
}
sigprocmask(SIG_SETMASK, $set, $old) or die "SIG_SETMASK(set): $!";
pipe(my $r, my $w);
- my $pid = fork;
+ my $pid = PublicInbox::OnDestroy::fork_tmp;
if ($pid == 0) {
close $r;
$SIG{__DIE__} = sub {
require PublicInbox::DS;
my $oset = PublicInbox::DS::block_signals();
require PublicInbox::OnDestroy;
- my $tmp_mask = PublicInbox::OnDestroy->new(
+ my $tmp_mask = PublicInbox::OnDestroy::all(
\&PublicInbox::DS::sig_setmask, $oset);
- my $pid = PublicInbox::DS::do_fork();
+ my $pid = PublicInbox::DS::fork_persist();
if ($pid == 0) {
close($_) for (@{delete($opt->{-CLOFORK}) // []});
# pretend to be systemd (cf. sd_listen_fds(3))
sub with_umask {
my ($self, $cb, @arg) = @_;
my $old = umask($self->{umask} //= umask_prepare($self));
- my $restore = PublicInbox::OnDestroy->new($$, \&CORE::umask, $old);
+ my $restore = on_destroy \&CORE::umask, $old;
$cb ? $cb->(@arg) : $restore;
}
use PublicInbox::ViewDiff qw(flush_diff uri_escape_path);
use PublicInbox::View;
use PublicInbox::Eml;
+use PublicInbox::OnDestroy;
use Text::Wrap qw(wrap);
use PublicInbox::Hval qw(ascii_html to_filename prurl utf8_maybe);
use POSIX qw(strftime);
qw(--encoding=UTF-8 -z --no-notes --no-patch), $oid),
undef, { 1 => $ctx->{patch_fh} });
$qsp_h->{qsp_err} = \($ctx->{-qsp_err_h} = '');
- my $cmt_fin = PublicInbox::OnDestroy->new($$, \&cmt_fin, $ctx);
+ my $cmt_fin = on_destroy \&cmt_fin, $ctx;
$ctx->{git} = $git;
$ctx->{oid} = $oid;
$qsp_h->psgi_qx($ctx->{env}, undef, \&cmt_hdr_prep, $ctx, $cmt_fin);
my $v = $ctx->{qp}->{$from} // next;
$ctx->{hints}->{$to} = $v if $v ne '';
}
- $ctx->{-next_solver} = PublicInbox::OnDestroy->new($$, \&next_solver);
+ $ctx->{-next_solver} = on_destroy \&next_solver;
++$solver_nr;
$ctx->{-tmp} = File::Temp->newdir("solver.$ctx->{oid_b}-XXXX",
TMPDIR => 1);
sub imap_idle_fork {
my ($self, $uri, $intvl) = @_;
return if $self->{quit};
- my $pid = PublicInbox::DS::do_fork;
+ my $pid = PublicInbox::DS::fork_persist;
if ($pid == 0) {
watch_atfork_child($self);
watch_imap_idle_1($self, $uri, $intvl);
my @imap = grep { # push() always returns > 0
$_->scheme =~ m!\Aimaps?!i ? 1 : (push(@nntp, $_) < 0)
} @$uris;
- my $pid = PublicInbox::DS::do_fork;
+ my $pid = PublicInbox::DS::fork_persist;
if ($pid == 0) {
watch_atfork_child($self);
watch_imap_fetch_all($self, \@imap) if @imap;
push(@log, $tip) if defined $tip;
# limit scope for MockHTTP test (t/solver_git.t)
- my $END = PublicInbox::OnDestroy->new($$, \&summary_END, $ctx);
+ my $END = on_destroy \&summary_END, $ctx;
for (['log', \@log],
[ 'heads', [@EACH_REF, "--count=$nb", 'refs/heads'] ],
[ 'tags', [@EACH_REF, "--count=$nt", 'refs/tags'] ]) {
use PublicInbox::Spawn qw(spawn);
use Socket qw(AF_UNIX SOCK_SEQPACKET);
use PublicInbox::IPC;
-use autodie qw(fork pipe socketpair);
+use autodie qw(pipe socketpair);
sub mkreq {
my ($self, $ios, @arg) = @_;
sub start_worker ($) {
my ($nr) = @_;
- my $pid = eval { PublicInbox::DS::do_fork } // return(warn($@));
+ my $pid = eval { PublicInbox::DS::fork_persist } // return(warn($@));
if ($pid == 0) {
undef %WORKERS;
$SIG{TTIN} = $SIG{TTOU} = 'IGNORE';
sub cb_spawn {
my ($cb, $args, $opt) = @_; # $cb = cpdb() or compact()
- my $pid = PublicInbox::DS::do_fork;
+ my $pid = PublicInbox::DS::fork_persist;
return $pid if $pid > 0;
$SIG{__DIE__} = sub { warn @_; _exit(1) }; # don't jump up stack
$cb->($args, $opt);
exit(255);
};
require PublicInbox::OnDestroy;
-my $auto_unlink = PublicInbox::OnDestroy->new($$, sub { unlink $lockfile });
+my $auto_unlink = PublicInbox::OnDestroy::on_destroy(sub { unlink $lockfile });
my $perm = 0644 & ~umask;
my %seen;
if (-e $pi_config) {
# https://public-inbox.org/meta/20220227080422.gyqowrxomzu6gyin@sourcephile.fr/
my $oldSIGPIPE = $SIG{PIPE};
$SIG{PIPE} = 'DEFAULT';
-my $cleanup = PublicInbox::OnDestroy->new($$, sub {
- $SIG{PIPE} = $oldSIGPIPE;
-});
+my $cleanup = on_destroy(sub { $SIG{PIPE} = $oldSIGPIPE });
test_lei(sub {
my $f = "$ENV{HOME}/big.eml";
# Copyright (C) 2021 all contributors <meta@public-inbox.org>
# License: AGPL-3.0+ <https://www.gnu.org/licenses/agpl-3.0.txt>
use strict; use v5.10.1; use PublicInbox::TestCommon;
+use autodie qw(chdir);
use POSIX qw(_exit);
use PublicInbox::DS qw(now);
use Errno qw(EAGAIN);
undef $mbl;
{
opendir my $cur, '.' or BAIL_OUT $!;
- my $od = PublicInbox::OnDestroy->new(sub { chdir $cur });
- chdir $tmpdir or BAIL_OUT;
+ my $od = on_destroy \&chdir, $cur;
+ chdir $tmpdir;
my $abs = "$tmpdir/rel.lock";
my $rel = PublicInbox::MboxLock->acq('rel', 1, ['dotlock']);
- chdir '/' or BAIL_OUT;
+ chdir '/';
ok(-f $abs, 'lock with abs path created');
undef $rel;
ok(!-f $abs, 'lock gone despite being in the wrong dir');
require_ok 'PublicInbox::MHreader';
use PublicInbox::IO qw(write_file);
use PublicInbox::Lock;
-use PublicInbox::OnDestroy;
use PublicInbox::Eml;
use File::Path qw(remove_tree);
use autodie;
#!perl -w
use v5.12;
use Test::More;
-require_ok 'PublicInbox::OnDestroy';
+use PublicInbox::OnDestroy;
+use POSIX qw(_exit);
my @x;
-my $od = PublicInbox::OnDestroy->new(sub { push @x, 'hi' });
+my $od = on_destroy sub { push @x, 'hi' };
is_deeply(\@x, [], 'not called, yet');
undef $od;
is_deeply(\@x, [ 'hi' ], 'no args works');
-$od = PublicInbox::OnDestroy->new(sub { $x[0] = $_[0] }, 'bye');
+$od = on_destroy sub { $x[0] = $_[0] }, 'bye';
is_deeply(\@x, [ 'hi' ], 'nothing changed while alive');
undef $od;
is_deeply(\@x, [ 'bye' ], 'arg passed');
-$od = PublicInbox::OnDestroy->new(sub { @x = @_ }, qw(x y));
+$od = on_destroy sub { @x = @_ }, qw(x y);
undef $od;
is_deeply(\@x, [ 'x', 'y' ], '2 args passed');
open my $tmp, '+>>', undef or BAIL_OUT $!;
$tmp->autoflush(1);
-$od = PublicInbox::OnDestroy->new(1, sub { print $tmp "$$ DESTROY\n" });
-undef $od;
+$od = on_destroy sub { print $tmp "$$ DESTROY\n" };
+my $pid = PublicInbox::OnDestroy::fork_tmp;
+if ($pid == 0) { undef $od; _exit 0; };
+waitpid($pid, 0);
+is $?, 0, 'test process exited';
is(-s $tmp, 0, '$tmp is empty on pid mismatch');
-$od = PublicInbox::OnDestroy->new($$, sub { $tmp = $$ });
+$od->cancel;
+undef $od;
+is(-s $tmp, 0, '$tmp is empty after ->cancel');
+$od = on_destroy sub { $tmp = $$ };
undef $od;
is($tmp, $$, '$tmp set to $$ by callback');
-$od = PublicInbox::OnDestroy->new($$, sub { $tmp = 'foo' });
+$od = on_destroy sub { $tmp = 'foo' };
$od->cancel;
$od = undef;
isnt($tmp, 'foo', '->cancel');
if (my $nr = $ENV{TEST_LEAK_NR}) {
for (0..$nr) {
- $od = PublicInbox::OnDestroy->new(sub { @x = @_ }, qw(x y));
+ $od = on_destroy sub { @x = @_ }, qw(x y);
}
}
$nwr->imap_common_init;
};
my $mic = (values %$mics)[0];
-my $cleanup = PublicInbox::OnDestroy->new($$, sub {
+my $cleanup = on_destroy sub {
if (defined($folder)) {
my $mic = $nwr->mic_get($uri);
$mic->delete($folder) or
local $ENV{HOME} = $tmpdir;
system(qw(git credential-cache exit));
}
-});
+};
my $imap_append = $nwr->can('imap_append');
my $smsg = bless { kw => [ 'seen' ] }, 'PublicInbox::Smsg';
$imap_append->($mic, $folder, undef, $smsg, eml_load('t/plack-qp.eml'));