1
0
mirror of git://git.sv.gnu.org/coreutils.git synced 2026-02-12 02:12:06 +02:00

tests: nproc: fix false failure on some systems

* tests/nproc/nproc-quota.sh: Also simulate sched_getscheduler()
as this will not be called on older or non linux, or
may return ENOSYS on Alpine.
Fixes https://bugs.gnu.org/79299
This commit is contained in:
Pádraig Brady
2025-08-24 11:41:01 +01:00
parent 11a31296fa
commit 4bfcf62f74

View File

@@ -19,6 +19,53 @@
. "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
print_ver_ nproc
require_root_
require_gcc_shared_
# Replace sched_getscheduler()
cat > k.c <<'EOF' || framework_failure_
#include <stdio.h>
#include <errno.h>
#define __USE_GNU /* For SCHED_DEADLINE. */
#include <sched.h>
int
sched_getscheduler (pid_t pid)
{
fclose (fopen ("preloaded","w")); /* marker for preloaded interception */
FILE* policyf = fopen ("/proc/self/sched", "r");
int policy;
#define fscanfmt fscanf /* Avoid syntax check. */
if (pid == 0 && fscanfmt (policyf, "policy : %d", &policy) == 1)
{
switch (policy)
{
case 0: return SCHED_OTHER;
case 1: return SCHED_FIFO;
case 2: return SCHED_RR;
case 6: return SCHED_DEADLINE;
case -1: errno = EINVAL; return -1;
default: return SCHED_OTHER;
}
}
else
{
errno = ENOSYS;
return -1;
}
}
EOF
# compile/link the interception shared library:
gcc_shared_ k.c k.so \
|| skip_ 'failed to build sched_getscheduler shared library'
(export LD_PRELOAD=$LD_PRELOAD:./k.so
nproc) || fail=1
# Ensure our wrapper is in place and is called
# I.e., this test is restricted to new enough Linux systems
# as otherwise cpu_quota() will not call sched_getscheduler()
test -e preloaded || skip_ 'LD_PRELOAD interception failed'
# We could look for modifiable cgroup quotas on the current system,
# but that would be dangerous to modify and restore robustly.
@@ -32,6 +79,7 @@ ROOT=cgroup
mkdir -p $ROOT/sys/fs/cgroup/foo &&
touch $ROOT/sys/fs/cgroup/cgroup.controllers &&
echo '0::/foo' > $ROOT/proc/self/cgroup &&
echo 'policy : 0' > $ROOT/proc/self/sched &&
echo 'max 100000' > $ROOT/sys/fs/cgroup/foo/cpu.max # ignored
} || framework_failure_
@@ -39,7 +87,10 @@ nproc=$abs_top_builddir/src/nproc$EXEEXT
cp --parents $(ldd $nproc | grep -o '/[^ ]*') $ROOT ||
skip_ 'Failed to copy nproc libs to chroot'
cp $nproc $ROOT || framework_failure_
chroot $ROOT /nproc --version ||
cp k.so $ROOT || framework_failure_
NPROC() { LD_PRELOAD=$LD_PRELOAD:./k.so chroot $ROOT /nproc "$@"; }
NPROC --version ||
skip_ 'Failed to execute nproc in chroot'
unset OMP_NUM_THEADS
@@ -52,34 +103,45 @@ ncpus=$(nproc) || fail=1
# would then not match $ncpus
if test "$ncpus" = "$(nproc --all)"; then
echo 'max 100000' > $ROOT/sys/fs/cgroup/cpu.max &&
test $(chroot $ROOT /nproc) -eq $ncpus || fail=1
test $(NPROC) -eq $ncpus || fail=1
# Note Linux won't allow values > 1,000,000 (i.e., micro seconds)
# so no point testing above that threshold ( for e.g $((1<<53)) )
echo "1000000 1" > $ROOT/sys/fs/cgroup/cpu.max &&
test $(chroot $ROOT /nproc) -eq $ncpus || fail=1
test $(NPROC) -eq $ncpus || fail=1
# Can't happen in real cgroup, but ensure we avoid divide by zero
echo '100000 0' > $ROOT/sys/fs/cgroup/cpu.max &&
test $(chroot $ROOT /nproc) -eq $ncpus || fail=1
test $(NPROC) -eq $ncpus || fail=1
echo '100000 100000' > $ROOT/sys/fs/cgroup/cpu.max &&
test $(OMP_NUM_THREADS=$ncpus chroot $ROOT /nproc) -eq $ncpus || fail=1
test $(OMP_NUM_THREADS=$ncpus NPROC) -eq $ncpus || fail=1
echo '100000 100000' > $ROOT/sys/fs/cgroup/cpu.max &&
echo 'policy : 1' > $ROOT/proc/self/sched && # No quota for SCHED_FIFO
test $(NPROC) -eq $ncpus || fail=1
echo 'policy : 2' > $ROOT/proc/self/sched && # No quota for SCHED_RR
test $(NPROC) -eq $ncpus || fail=1
echo 'policy : 6' > $ROOT/proc/self/sched && # No quota for SCHED_DEADLINE
test $(NPROC) -eq $ncpus || fail=1
echo 'policy : -1' > $ROOT/proc/self/sched && # Unsupported
test $(NPROC) -eq $ncpus || fail=1
echo 'policy : 0' > $ROOT/proc/self/sched # reset to SCHED_OTHER
fi
echo '40000 100000' > $ROOT/sys/fs/cgroup/cpu.max &&
test $(chroot $ROOT /nproc) -eq 1 || fail=1
test $(NPROC) -eq 1 || fail=1
echo '50000 100000' > $ROOT/sys/fs/cgroup/cpu.max &&
test $(chroot $ROOT /nproc) -eq 1 || fail=1
test $(NPROC) -eq 1 || fail=1
echo '100000 100000' > $ROOT/sys/fs/cgroup/cpu.max &&
test $(chroot $ROOT /nproc) -eq 1 || fail=1
test $(NPROC) -eq 1 || fail=1
echo '140000 100000' > $ROOT/sys/fs/cgroup/cpu.max &&
test $(chroot $ROOT /nproc) -eq 1 || fail=1
test $(NPROC) -eq 1 || fail=1
echo '1 1000000' > $ROOT/sys/fs/cgroup/cpu.max &&
test $(chroot $ROOT /nproc) -eq 1 || fail=1
test $(NPROC) -eq 1 || fail=1
if test $ncpus -gt 1; then
echo '150000 100000' > $ROOT/sys/fs/cgroup/cpu.max &&
test $(chroot $ROOT /nproc) -eq 2 || fail=1
test $(NPROC) -eq 2 || fail=1
echo '150000 100000' > $ROOT/sys/fs/cgroup/cpu.max &&
test $(OMP_THREAD_LIMIT=10 chroot $ROOT /nproc) -eq 2 || fail=1
test $(OMP_THREAD_LIMIT=10 NPROC) -eq 2 || fail=1
fi
Exit $fail