]> git.ipfire.org Git - thirdparty/public-inbox.git/commitdiff
spawn: support some rlimit uses via Inline::C
authorEric Wong <e@80x24.org>
Tue, 30 Jan 2024 07:22:21 +0000 (07:22 +0000)
committerEric Wong <e@80x24.org>
Tue, 30 Jan 2024 08:28:55 +0000 (08:28 +0000)
BSD::Resource isn't packaged for Alpine (as of 3.19), but we
also have optional Inline::C support and already rely on calling
setrlimit(2) directly from the Inline::C version of pi_fork_exec.

lib/PublicInbox/ExtSearchIdx.pm
lib/PublicInbox/Limiter.pm
lib/PublicInbox/Spawn.pm
t/spawn.t

index 53078124dec000ad935440db823a48d0e4daa67e..ebbffffc02e0aa235b5ea9c111b17ab83469d687 100644 (file)
@@ -22,6 +22,7 @@ use Scalar::Util qw(blessed);
 use Sys::Hostname qw(hostname);
 use File::Glob qw(bsd_glob GLOB_NOSORT);
 use PublicInbox::MultiGit;
+use PublicInbox::Spawn ();
 use PublicInbox::Search;
 use PublicInbox::SearchIdx qw(prepare_stack is_ancestor is_bad_blob);
 use PublicInbox::OverIdx;
index 48a2b6a38ba18f40fba46850e6539f11c87ce25f..a8d08fc3f0c86386f22c89b0beeb2e765fe166f3 100644 (file)
@@ -31,14 +31,17 @@ sub setup_rlimit {
                } elsif (scalar(@rlimit) != 2) {
                        warn "could not parse $k: $v\n";
                }
-               eval { require BSD::Resource };
-               if ($@) {
-                       warn "BSD::Resource missing for $rlim";
-                       next;
-               }
+               my $inf = $v =~ /\binfinity\b/i ?
+                       $PublicInbox::Spawn::RLIMITS{RLIM_INFINITY} // eval {
+                               require BSD::Resource;
+                               BSD::Resource::RLIM_INFINITY();
+                       } // do {
+                               warn "BSD::Resource missing for $rlim";
+                               next;
+                       } : undef;
                for my $i (0..$#rlimit) {
                        next if $rlimit[$i] ne 'INFINITY';
-                       $rlimit[$i] = BSD::Resource::RLIM_INFINITY();
+                       $rlimit[$i] = $inf;
                }
                $self->{$rlim} = \@rlimit;
        }
index e6b12994039db3bfd6c268fae62bc7d7bc881863..e36659ce9f1897065963fbd94d4d2a8e5a57e746 100644 (file)
@@ -21,10 +21,11 @@ use IO::Handle ();
 use Carp qw(croak);
 use PublicInbox::IO;
 our @EXPORT_OK = qw(which spawn popen_rd popen_wr run_die run_wait run_qx);
-our @RLIMITS = qw(RLIMIT_CPU RLIMIT_CORE RLIMIT_DATA);
+our (@RLIMITS, %RLIMITS);
 use autodie qw(close open pipe seek sysseek truncate);
 
 BEGIN {
+       @RLIMITS = qw(RLIMIT_CPU RLIMIT_CORE RLIMIT_DATA);
        my $all_libc = <<'ALL_LIBC'; # all *nix systems we support
 #include <sys/resource.h>
 #include <sys/socket.h>
@@ -283,14 +284,28 @@ void recv_cmd4(PerlIO *s, SV *buf, STRLEN n)
        Inline_Stack_Done;
 }
 #endif /* defined(CMSG_SPACE) && defined(CMSG_LEN) */
-ALL_LIBC
 
+void rlimit_map()
+{
+       Inline_Stack_Vars;
+       Inline_Stack_Reset;
+ALL_LIBC
        my $inline_dir = $ENV{PERL_INLINE_DIRECTORY} // (
                        $ENV{XDG_CACHE_HOME} //
                        ( ($ENV{HOME} // '/nonexistent').'/.cache' )
                ).'/public-inbox/inline-c';
        undef $all_libc unless -d $inline_dir;
        if (defined $all_libc) {
+               for (@RLIMITS, 'RLIM_INFINITY') {
+                       $all_libc .= <<EOM;
+       Inline_Stack_Push(sv_2mortal(newSVpvs("$_")));
+       Inline_Stack_Push(sv_2mortal(newSViv($_)));
+EOM
+               }
+               $all_libc .= <<EOM;
+       Inline_Stack_Done;
+} // rlimit_map
+EOM
                local $ENV{PERL_INLINE_DIRECTORY} = $inline_dir;
                # CentOS 7.x ships Inline 0.53, 0.64+ has built-in locking
                my $lk = PublicInbox::Lock->new($inline_dir.
@@ -316,6 +331,7 @@ ALL_LIBC
        }
        if (defined $all_libc) { # set for Gcf2
                $ENV{PERL_INLINE_DIRECTORY} = $inline_dir;
+               %RLIMITS = rlimit_map();
        } else {
                require PublicInbox::SpawnPP;
                *pi_fork_exec = \&PublicInbox::SpawnPP::pi_fork_exec
@@ -361,11 +377,12 @@ sub spawn ($;$$) {
        my $rlim = [];
        foreach my $l (@RLIMITS) {
                my $v = $opt->{$l} // next;
-               my $r = eval "require BSD::Resource; BSD::Resource::$l();";
-               unless (defined $r) {
-                       warn "$l undefined by BSD::Resource: $@\n";
-                       next;
-               }
+               my $r = $RLIMITS{$l} //
+                       eval "require BSD::Resource; BSD::Resource::$l();" //
+                       do {
+                               warn "$l undefined by BSD::Resource: $@\n";
+                               next;
+                       };
                push @$rlim, $r, @$v;
        }
        my $cd = $opt->{'-C'} // ''; # undef => NULL mapping doesn't work?
index 48f541b83678860f4db1a331f071dfb559f193d1..5b17ed38e245b8ca1de82fc8146519de2929d08b 100644 (file)
--- a/t/spawn.t
+++ b/t/spawn.t
@@ -6,7 +6,7 @@ use Test::More;
 use PublicInbox::Spawn qw(which spawn popen_rd run_qx);
 require PublicInbox::Sigfd;
 require PublicInbox::DS;
-
+my $rlimit_map = PublicInbox::Spawn->can('rlimit_map');
 {
        my $true = which('true');
        ok($true, "'true' command found with which()");
@@ -192,14 +192,19 @@ EOF
 }
 
 SKIP: {
-       eval {
-               require BSD::Resource;
-               defined(BSD::Resource::RLIMIT_CPU())
-       } or skip 'BSD::Resource::RLIMIT_CPU missing', 3;
+       if ($rlimit_map) { # Inline::C installed
+               my %rlim = $rlimit_map->();
+               ok defined($rlim{RLIMIT_CPU}), 'RLIMIT_CPU defined';
+       } else {
+               eval {
+                       require BSD::Resource;
+                       defined(BSD::Resource::RLIMIT_CPU())
+               } or skip 'BSD::Resource::RLIMIT_CPU missing', 3;
+       }
        my $cmd = [ $^X, qw(-w -e), <<'EOM' ];
 use POSIX qw(:signal_h);
-use BSD::Resource qw(times);
 use Time::HiRes qw(time); # gettimeofday
+my $have_bsd_resource = eval { require BSD::Resource };
 my $set = POSIX::SigSet->new;
 $set->emptyset; # spawn() defaults to blocking all signals
 sigprocmask(SIG_SETMASK, $set) or die "SIG_SETMASK: $!";
@@ -211,10 +216,10 @@ while (1) {
        # and `write' (via Perl warn)) on otherwise idle systems to
        # hit RLIMIT_CPU and fire signals:
        # https://marc.info/?i=02A4BB8D-313C-464D-845A-845EB6136B35@gmail.com
-       my @t = times;
+       my @t = $have_bsd_resource ? BSD::Resource::times() : (0, 0);
        $tot = $t[0] + $t[1];
        if (time > $next) {
-               warn "# T: @t (utime, ctime, cutime, cstime)\n";
+               warn "# T: @t (utime, ctime, cutime, cstime)\n" if @t;
                $next = time + 1.1;
        }
 }