diff options
author | Eric Wong <e@80x24.org> | 2023-08-29 17:20:16 +0000 |
---|---|---|
committer | Eric Wong <e@80x24.org> | 2023-08-29 21:57:13 +0000 |
commit | 1ea097fe25d3717ad0b8e232268a6d55d8ed7225 (patch) | |
tree | 2c8fd60178fe124e050ba880e412fb3bc6a8674e /t/spawn.t | |
parent | bd0dc6ad0391f811f5248d83538a2eef8f74de95 (diff) | |
download | public-inbox-1ea097fe25d3717ad0b8e232268a6d55d8ed7225.tar.gz |
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
Diffstat (limited to 't/spawn.t')
-rw-r--r-- | t/spawn.t | 34 |
1 files changed, 29 insertions, 5 deletions
@@ -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: { |