if (my $pr = $opt->{-progress}) {
                $pr->("indexing $ibx->{inboxdir} ...\n");
        }
-       local %SIG = %SIG;
+       local @SIG{keys %SIG} = values %SIG;
        setup_signals(\&index_terminate, $ibx);
        my $idx = { current_info => $ibx->{inboxdir} };
        local $SIG{__WARN__} = sub {
 
 
 sub eidx_watch { # public-inbox-extindex --watch main loop
        my ($self, $opt) = @_;
-       local %SIG = %SIG;
+       local @SIG{keys %SIG} = values %SIG;
        for my $sig (qw(HUP USR1 TSTP QUIT INT TERM)) {
                $SIG{$sig} = sub { warn "SIG$sig ignored while scanning\n" };
        }
        $sig->{QUIT} = $sig->{INT} = $sig->{TERM} = $quit;
        my $sigfd = PublicInbox::Sigfd->new($sig,
                                        $PublicInbox::Syscall::SFD_NONBLOCK);
-       %SIG = (%SIG, %$sig) if !$sigfd;
+       @SIG{keys %$sig} = values(%$sig) if !$sigfd;
        local $self->{-watch_sync} = $sync; # for ->on_inbox_unlock
        if (!$sigfd) {
                # wake up every second to accept signals if we don't
 
                        $fields //= {};
                        local @$self{keys %$fields} = values(%$fields);
                        my $on_destroy = $self->ipc_atfork_child;
-                       local %SIG = %SIG;
+                       local @SIG{keys %SIG} = values %SIG;
                        PublicInbox::DS::sig_setmask($sigset);
                        ipc_worker_loop($self, $r_req, $w_res);
                };
                        $fields //= {};
                        local @$self{keys %$fields} = values(%$fields);
                        my $on_destroy = $self->ipc_atfork_child;
-                       local %SIG = %SIG;
+                       local @SIG{keys %SIG} = values %SIG;
                        PublicInbox::DS::sig_setmask($oldset);
                        wq_worker_loop($self, $bcast2);
                };
 
                # note: "local *STDIN = *STDIN;" and so forth did not work in
                # old versions of perl
                local %ENV = $env ? (%ENV, %$env) : %ENV;
-               local %SIG = %SIG;
+               local @SIG{keys %SIG} = map { undef } values %SIG;
+               local $SIG{FPE} = 'IGNORE'; # Perl default
                local $0 = join(' ', @$cmd);
                my $orig_io = _prepare_redirects($fhref);
                my $cwdfh = $lei_cwdfh;
 
        delete $self->{poll_pids};
        delete $self->{opendirs};
        PublicInbox::DS->Reset;
-       %SIG = (%SIG, %{$self->{sig}}, CHLD => 'DEFAULT');
+       my $sig = delete $self->{sig};
+       $sig->{CHLD} = 'DEFAULT';
+       @SIG{keys %$sig} = values %$sig;
        PublicInbox::DS::sig_setmask($self->{oldset});
 }
 
 
 
        # run in parallel:
        my %pids;
-       local %SIG = %SIG;
+       local @SIG{keys %SIG} = values %SIG;
        setup_signals(\&kill_pids, \%pids);
        while (@$queue) {
                while (scalar(keys(%pids)) < $max && scalar(@$queue)) {
                PublicInbox::SearchIdx::load_xapian_writable();
        }
 
-       local %SIG = %SIG;
+       local @SIG{keys %SIG} = values %SIG;
        setup_signals();
        $ibx->with_umask(\&_run, $ibx, $cb, $opt);
 }
        $pr->("$pfx `".join(' ', @$cmd)."'\n") if $pr;
        push @$cmd, $src, $dst;
        my ($rd, $pid);
-       local %SIG = %SIG;
+       local @SIG{keys %SIG} = values %SIG;
        setup_signals(\&kill_compact, \$pid);
        ($rd, $pid) = popen_rd($cmd, undef, $rdr);
        while (<$rd>) {
        }
 
        my ($tmp, $ft);
-       local %SIG = %SIG;
+       local @SIG{keys %SIG} = values %SIG;
        if ($opt->{compact}) {
                my ($dir) = ($new =~ m!(.*?/)[^/]+/*\z!);
                same_fs_or_die($dir, $new);
 
        my $pid = fork // DIE "fork: $!";
        if ($pid == 0) {
                close $wr if $wr;
+               $SIG{USR1} = undef; # undo parent $SIG{USR1}
                $worker = $$;
                while (1) {
                        my $r = sysread($rd, my $buf, UINT_SIZE);