user/dev discussion of public-inbox itself
 help / color / mirror / code / Atom feed
Search results ordered by [date|relevance]  view[summary|nested|Atom feed]
thread overview below | download mbox.gz: |
* [PATCH v2] t/spawn.t: workaround OpenBSD RLIMIT_CPU delays
       [not found]     <20230829165521.41372-1-e@80x24.org>
@ 2023-08-29 17:20 14% ` Eric Wong
  0 siblings, 0 replies; 2+ results
From: Eric Wong @ 2023-08-29 17:20 UTC (permalink / raw)
  To: meta

RLIMIT_CPU on OpenBSD doesn't work reliably with few syscalls or
on mostly idle systems.  Even at its most accurate, it takes an
extra second to fire compared to FreeBSD or Linux due to
internal accounting differences, but worst case even the SIGKILL
can be 50s delayed.

So rewrite the CPU burner script in Perl where we can unblock
SIGXCPU and reliably use more syscalls.

Link: https://marc.info/?i=20230829010110.M269767@dcvr
---
 v2:
 - only enable Perl warnings in subprocess if enabled in parent
 - gettimeofday(2) instead of time(2) for resolution and accuracy
 - increase warn delay to quiet non-OpenBSD systems
 - avoid $tot accumulation since times(2) is already cumulative
 - update comment based on feedback from OpenBSD bug report
 - stricter check exit status check
 - quiet readline result on success

Range-diff:
1:  61dd1ad5 ! 1:  d3d732dc t/spawn.t: workaround OpenBSD RLIMIT_CPU delays
    @@ t/spawn.t: SKIP: {
     -	my ($r, $w);
     -	pipe($r, $w) or die "pipe: $!";
     -	my $cmd = ['sh', '-c', 'while true; do :; done'];
    -+	my $cmd = [$^X, '-w', '-e', <<'EOM' ];
    ++	my $cmd = [ $^X, ($^W ? ('-w') : ()), '-e', <<'EOM' ];
     +use POSIX qw(:signal_h);
     +use BSD::Resource qw(times);
    ++use Time::HiRes qw(time); # gettimeofday
     +my $set = POSIX::SigSet->new;
     +$set->emptyset; # spawn() defaults to blocking all signals
     +sigprocmask(SIG_SETMASK, $set) or die "SIG_SETMASK: $!";
     +my $tot = 0;
     +$SIG{XCPU} = sub { print "SIGXCPU $tot\n"; exit(1) };
    -+my $next = time + 1;
    ++my $next = time + 1.1;
     +while (1) {
    -+	# OpenBSD needs both `times' and `write' (via Perl warn) syscalls
    -+	# here are both required to trigger RLIMIT_CPU; not sure why.
    -+	# Even the hard limit seems ignored unless we make those syscalls.
    -+	# Staying entirely in userspace had no effect, and neither did
    -+	# some other syscalls tried.  Neither fstat, nor sigprocmask were
    -+	# able to cause either SIGXCPU or SIGKILL.
    -+	# to fire on respective soft and hard rlimits being exceeded.
    ++	# OpenBSD needs some syscalls (e.g. `times', `gettimeofday'
    ++	# 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;
    -+	$tot += $_ for ($t[0], $t[1]);
    ++	$tot = $t[0] + $t[1];
     +	if (time > $next) {
     +		warn "# T: @t (utime, ctime, cutime, cstime)\n";
    -+		$next = time + 1;
    ++		$next = time + 1.1;
     +	}
     +}
     +EOM
    @@ t/spawn.t: SKIP: {
      	vec($rset, fileno($r), 1) = 1;
      	ok(select($rset, undef, undef, 5), 'child died before timeout');
      	is(waitpid($pid, 0), $pid, 'XCPU child process reaped');
    -+	like(my $line = readline($r), qr/SIGXCPU/, 'SIGXCPU handled');
    -+	diag "line=$line";
    - 	isnt($?, 0, 'non-zero exit status');
    +-	isnt($?, 0, 'non-zero exit status');
    ++	my $line;
    ++	like($line = readline($r), qr/SIGXCPU/, 'SIGXCPU handled') or
    ++		diag explain($line);
    ++	is($? >> 8, 1, 'non-zero exit status');
      }
      
    + SKIP: {

 t/spawn.t | 34 +++++++++++++++++++++++++++++-----
 1 file changed, 29 insertions(+), 5 deletions(-)

diff --git a/t/spawn.t b/t/spawn.t
index ff95ae8e..9ed3be36 100644
--- a/t/spawn.t
+++ b/t/spawn.t
@@ -185,18 +185,42 @@ SKIP: {
 		require BSD::Resource;
 		defined(BSD::Resource::RLIMIT_CPU())
 	} or skip 'BSD::Resource::RLIMIT_CPU missing', 3;
-	my ($r, $w);
-	pipe($r, $w) or die "pipe: $!";
-	my $cmd = ['sh', '-c', 'while true; do :; done'];
+	my $cmd = [ $^X, ($^W ? ('-w') : ()), '-e', <<'EOM' ];
+use POSIX qw(:signal_h);
+use BSD::Resource qw(times);
+use Time::HiRes qw(time); # gettimeofday
+my $set = POSIX::SigSet->new;
+$set->emptyset; # spawn() defaults to blocking all signals
+sigprocmask(SIG_SETMASK, $set) or die "SIG_SETMASK: $!";
+my $tot = 0;
+$SIG{XCPU} = sub { print "SIGXCPU $tot\n"; exit(1) };
+my $next = time + 1.1;
+while (1) {
+	# OpenBSD needs some syscalls (e.g. `times', `gettimeofday'
+	# 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;
+	$tot = $t[0] + $t[1];
+	if (time > $next) {
+		warn "# T: @t (utime, ctime, cutime, cstime)\n";
+		$next = time + 1.1;
+	}
+}
+EOM
+	pipe(my($r, $w)) or die "pipe: $!";
 	my $fd = fileno($w);
-	my $opt = { RLIMIT_CPU => [ 1, 1 ], RLIMIT_CORE => [ 0, 0 ], 1 => $fd };
+	my $opt = { RLIMIT_CPU => [ 1, 9 ], RLIMIT_CORE => [ 0, 0 ], 1 => $fd };
 	my $pid = spawn($cmd, undef, $opt);
 	close $w or die "close(w): $!";
 	my $rset = '';
 	vec($rset, fileno($r), 1) = 1;
 	ok(select($rset, undef, undef, 5), 'child died before timeout');
 	is(waitpid($pid, 0), $pid, 'XCPU child process reaped');
-	isnt($?, 0, 'non-zero exit status');
+	my $line;
+	like($line = readline($r), qr/SIGXCPU/, 'SIGXCPU handled') or
+		diag explain($line);
+	is($? >> 8, 1, 'non-zero exit status');
 }
 
 SKIP: {

^ permalink raw reply related	[relevance 14%]

* [PATCH] t/spawn.t: workaround OpenBSD RLIMIT_CPU delays
@ 2023-08-29  1:10  8% Eric Wong
  0 siblings, 0 replies; 2+ results
From: Eric Wong @ 2023-08-29  1:10 UTC (permalink / raw)
  To: meta

RLIMIT_CPU on OpenBSD doesn't work reliably with few syscalls or
on mostly idle systems.  Even at its most accurate, it takes an
extra second to fire compared to FreeBSD or Linux due to
internal accounting differences, but worst case even the SIGKILL
can be 50s delayed.

So rewrite the CPU burner script in Perl where we can unblock
SIGXCPU and reliably use more syscalls.

Link: https://marc.info/?i=20230829010110.M269767@dcvr
---
 t/spawn.t | 33 +++++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/t/spawn.t b/t/spawn.t
index ff95ae8e..87800dd6 100644
--- a/t/spawn.t
+++ b/t/spawn.t
@@ -185,17 +185,42 @@ SKIP: {
 		require BSD::Resource;
 		defined(BSD::Resource::RLIMIT_CPU())
 	} or skip 'BSD::Resource::RLIMIT_CPU missing', 3;
-	my ($r, $w);
-	pipe($r, $w) or die "pipe: $!";
-	my $cmd = ['sh', '-c', 'while true; do :; done'];
+	my $cmd = [$^X, '-w', '-e', <<'EOM' ];
+use POSIX qw(:signal_h);
+use BSD::Resource qw(times);
+my $set = POSIX::SigSet->new;
+$set->emptyset; # spawn() defaults to blocking all signals
+sigprocmask(SIG_SETMASK, $set) or die "SIG_SETMASK: $!";
+my $tot = 0;
+$SIG{XCPU} = sub { print "SIGXCPU $tot\n"; exit(1) };
+my $next = time + 1;
+while (1) {
+	# OpenBSD needs both `times' and `write' (via Perl warn) syscalls
+	# here are both required to trigger RLIMIT_CPU; not sure why.
+	# Even the hard limit seems ignored unless we make those syscalls.
+	# Staying entirely in userspace had no effect, and neither did
+	# some other syscalls tried.  Neither fstat, nor sigprocmask were
+	# able to cause either SIGXCPU or SIGKILL.
+	# to fire on respective soft and hard rlimits being exceeded.
+	my @t = times;
+	$tot += $_ for ($t[0], $t[1]);
+	if (time > $next) {
+		warn "# T: @t (utime, ctime, cutime, cstime)\n";
+		$next = time + 1;
+	}
+}
+EOM
+	pipe(my($r, $w)) or die "pipe: $!";
 	my $fd = fileno($w);
-	my $opt = { RLIMIT_CPU => [ 1, 1 ], RLIMIT_CORE => [ 0, 0 ], 1 => $fd };
+	my $opt = { RLIMIT_CPU => [ 1, 9 ], RLIMIT_CORE => [ 0, 0 ], 1 => $fd };
 	my $pid = spawn($cmd, undef, $opt);
 	close $w or die "close(w): $!";
 	my $rset = '';
 	vec($rset, fileno($r), 1) = 1;
 	ok(select($rset, undef, undef, 5), 'child died before timeout');
 	is(waitpid($pid, 0), $pid, 'XCPU child process reaped');
+	like(my $line = readline($r), qr/SIGXCPU/, 'SIGXCPU handled');
+	diag "line=$line";
 	isnt($?, 0, 'non-zero exit status');
 }
 

^ permalink raw reply related	[relevance 8%]

Results 1-2 of 2 | reverse | options above
-- pct% links below jump to the message on this page, permalinks otherwise --
2023-08-29  1:10  8% [PATCH] t/spawn.t: workaround OpenBSD RLIMIT_CPU delays Eric Wong
     [not found]     <20230829165521.41372-1-e@80x24.org>
2023-08-29 17:20 14% ` [PATCH v2] " Eric Wong

Code repositories for project(s) associated with this public inbox

	https://80x24.org/public-inbox.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).