about summary refs log tree commit homepage
diff options
context:
space:
mode:
authorEric Wong <e@80x24.org>2024-01-30 07:22:21 +0000
committerEric Wong <e@80x24.org>2024-01-30 08:28:55 +0000
commit53eafcd90a3179200192263807cf3df7c869b500 (patch)
tree254a2f9cf1efc98f87b4ac453f69a4356ebac7cb
parent6b8bcf8bb0afc843e563862ae50a02d41aaba129 (diff)
downloadpublic-inbox-53eafcd90a3179200192263807cf3df7c869b500.tar.gz
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.
-rw-r--r--lib/PublicInbox/ExtSearchIdx.pm1
-rw-r--r--lib/PublicInbox/Limiter.pm15
-rw-r--r--lib/PublicInbox/Spawn.pm31
-rw-r--r--t/spawn.t21
4 files changed, 47 insertions, 21 deletions
diff --git a/lib/PublicInbox/ExtSearchIdx.pm b/lib/PublicInbox/ExtSearchIdx.pm
index 53078124..ebbffffc 100644
--- a/lib/PublicInbox/ExtSearchIdx.pm
+++ b/lib/PublicInbox/ExtSearchIdx.pm
@@ -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;
diff --git a/lib/PublicInbox/Limiter.pm b/lib/PublicInbox/Limiter.pm
index 48a2b6a3..a8d08fc3 100644
--- a/lib/PublicInbox/Limiter.pm
+++ b/lib/PublicInbox/Limiter.pm
@@ -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;
         }
diff --git a/lib/PublicInbox/Spawn.pm b/lib/PublicInbox/Spawn.pm
index e6b12994..e36659ce 100644
--- a/lib/PublicInbox/Spawn.pm
+++ b/lib/PublicInbox/Spawn.pm
@@ -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?
diff --git a/t/spawn.t b/t/spawn.t
index 48f541b8..5b17ed38 100644
--- 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;
         }
 }