]> git.ipfire.org Git - thirdparty/public-inbox.git/commitdiff
ds: introduce and use do_fork helper
authorEric Wong <e@80x24.org>
Tue, 17 Oct 2023 23:37:59 +0000 (23:37 +0000)
committerEric Wong <e@80x24.org>
Wed, 18 Oct 2023 20:50:30 +0000 (20:50 +0000)
This ensures we handle RNG reseeding and resetting the event
loop properly in child processes after forking.

lib/PublicInbox/DS.pm
lib/PublicInbox/Daemon.pm
lib/PublicInbox/IPC.pm
lib/PublicInbox/TestCommon.pm
lib/PublicInbox/Watch.pm
lib/PublicInbox/Xapcmd.pm

index eefbdcc3ec0716cfb341e2d11854ec4fc40003d1..9960937dcd2cf3dfd4517db7f62f43aa32c08884 100644 (file)
@@ -34,6 +34,7 @@ use PublicInbox::Tmpfile;
 use PublicInbox::Select;
 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
@@ -737,6 +738,17 @@ sub awaitpid {
        }
 }
 
+sub do_fork () {
+       my $seed = rand(0xffffffff);
+       my $pid = fork;
+       if ($pid == 0) {
+               srand($seed);
+               eval { Net::SSLeay::randomize() };
+               Reset();
+       }
+       $pid;
+}
+
 package PublicInbox::DummyPoller; # only used during Reset
 use v5.12;
 
index 520cef72916e3f63d10ffb7f2bf136022e271f06..f33f6f173ff292fec69371046f93bbdd83352496 100644 (file)
@@ -541,17 +541,11 @@ sub reap_worker { # awaitpid CB
 
 sub start_worker ($) {
        my ($nr) = @_;
-       my $seed = rand(0xffffffff);
        return unless @listeners;
-       my $pid = fork;
-       if (!defined($pid)) {
-               warn "fork: $!";
-       } elsif ($pid == 0) {
+       my $pid = PublicInbox::DS::do_fork;
+       if ($pid == 0) {
                undef %WORKERS;
-               PublicInbox::DS::Reset();
                local $PublicInbox::DS::Poller; # allow epoll/kqueue
-               srand($seed);
-               eval { Net::SSLeay::randomize() };
                $set_user->() if $set_user;
                PublicInbox::EOFpipe->new($parent_pipe, \&worker_quit);
                worker_loop();
@@ -563,9 +557,9 @@ sub start_worker ($) {
 }
 
 sub start_workers {
-       for my $nr (grep { !defined($WORKERS{$_}) } (0..($nworker - 1))) {
-               start_worker($nr);
-       }
+       my @idx = grep { !defined($WORKERS{$_}) } (0..($nworker - 1)) or return;
+       eval { start_worker($_) for @idx };
+       warn "E: $@\n" if $@;
 }
 
 sub trim_workers {
index 5964645e589e69e7ea15f138c5b36cb7c7323829..3292d960409cae7677018928fd40e544a295c048 100644 (file)
@@ -102,12 +102,8 @@ sub ipc_worker_spawn {
        pipe(my $r_res, my $w_res);
        my $sigset = $oldset // PublicInbox::DS::block_signals();
        $self->ipc_atfork_prepare;
-       my $seed = rand(0xffffffff);
-       my $pid = fork;
+       my $pid = PublicInbox::DS::do_fork;
        if ($pid == 0) {
-               srand($seed);
-               eval { Net::SSLeay::randomize() };
-               eval { PublicInbox::DS->Reset };
                delete @$self{qw(-wq_s1 -wq_s2 -wq_workers -wq_ppid)};
                $w_req = $r_res = undef;
                $w_res->autoflush(1);
@@ -341,13 +337,9 @@ sub _wq_worker_start {
        my ($self, $oldset, $fields, $one, @cb_args) = @_;
        my ($bcast1, $bcast2);
        $one or socketpair($bcast1, $bcast2, AF_UNIX, SOCK_SEQPACKET, 0);
-       my $seed = rand(0xffffffff);
-       my $pid = fork;
+       my $pid = PublicInbox::DS::do_fork;
        if ($pid == 0) {
-               srand($seed);
-               eval { Net::SSLeay::randomize() };
                undef $bcast1;
-               eval { PublicInbox::DS->Reset };
                delete @$self{qw(-wq_s1 -wq_ppid)};
                $self->{-wq_worker_nr} =
                                keys %{delete($self->{-wq_workers}) // {}};
index 323152b44f057669c568b5064ce88cf178af54ef..77da822bbaeccc533fa0ae9e2f3c3ac18745faee 100644 (file)
@@ -549,9 +549,8 @@ sub start_script {
        require PublicInbox::OnDestroy;
        my $tmp_mask = PublicInbox::OnDestroy->new(
                                        \&PublicInbox::DS::sig_setmask, $oset);
-       my $pid = fork // die "fork: $!";
+       my $pid = PublicInbox::DS::do_fork();
        if ($pid == 0) {
-               eval { PublicInbox::DS->Reset };
                for (@{delete($opt->{-CLOFORK}) // []}) {
                        close($_) or die "close $!";
                }
index 3426d4a7f7c02ad4f7a0dc7149f15cf5d486f29f..41b77dc1e482a0e65f2725d8658312fea2550b6b 100644 (file)
@@ -385,7 +385,6 @@ sub watch_atfork_child ($) {
        my ($self) = @_;
        delete $self->{pids};
        delete $self->{opendirs};
-       PublicInbox::DS->Reset;
        my $sig = delete $self->{sig};
        $sig->{CHLD} = $sig->{HUP} = $sig->{USR1} = 'DEFAULT';
        # TERM/QUIT/INT call ->quit, which works in both parent+child
@@ -413,11 +412,8 @@ sub imap_idle_reap { # awaitpid callback
 sub imap_idle_fork {
        my ($self, $uri, $intvl) = @_;
        return if $self->{quit};
-       my $seed = rand(0xffffffff);
-       my $pid = fork // die "fork: $!";
+       my $pid = PublicInbox::DS::do_fork;
        if ($pid == 0) {
-               srand($seed);
-               eval { Net::SSLeay::randomize() };
                watch_atfork_child($self);
                watch_imap_idle_1($self, $uri, $intvl);
                _exit(0);
@@ -477,11 +473,8 @@ sub poll_fetch_fork { # DS::add_timer callback
        my @imap = grep { # push() always returns > 0
                $_->scheme =~ m!\Aimaps?!i ? 1 : (push(@nntp, $_) < 0)
        } @$uris;
-       my $seed = rand(0xffffffff);
-       my $pid = fork // die "fork: $!";
+       my $pid = PublicInbox::DS::do_fork;
        if ($pid == 0) {
-               srand($seed);
-               eval { Net::SSLeay::randomize() };
                watch_atfork_child($self);
                watch_imap_fetch_all($self, \@imap) if @imap;
                watch_nntp_fetch_all($self, \@nntp) if @nntp;
index 4e055acf956732631822ca90db20f6763fab5e38..c2b66e69dccef1ee85f34ae9325f02887f173963 100644 (file)
@@ -11,6 +11,7 @@ use PublicInbox::SearchIdx;
 use File::Temp 0.19 (); # ->newdir
 use File::Path qw(remove_tree);
 use POSIX qw(WNOHANG _exit);
+use PublicInbox::DS;
 
 # support testing with dev versions of Xapian which installs
 # commands with a version number suffix (e.g. "xapian-compact-1.5")
@@ -102,10 +103,8 @@ sub commit_changes ($$$$) {
 
 sub cb_spawn {
        my ($cb, $args, $opt) = @_; # $cb = cpdb() or compact()
-       my $seed = rand(0xffffffff);
-       my $pid = fork // die "fork: $!";
+       my $pid = PublicInbox::DS::do_fork;
        return $pid if $pid > 0;
-       srand($seed);
        $SIG{__DIE__} = sub { warn @_; _exit(1) }; # don't jump up stack
        $cb->($args, $opt);
        _exit(0);