From cb8d1bec11c856c7ebe6f1680d32930e25bf4c6c Mon Sep 17 00:00:00 2001 From: Adrian Reber Date: Tue, 17 Mar 2026 12:20:03 +0000 Subject: [PATCH] zdtm: retry pthread_create on EAGAIN in thread-bomb MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The thread-bomb test frequently fails during setup with pthread_create() returning EAGAIN (errno 11). The test creates 1024 threads in a tight loop from main(), and each of those threads immediately spawns another thread that joins its predecessor, resulting in a burst of ~2048 simultaneous thread creations with 64KB stacks. This burst causes transient EAGAIN errors from clone() due to kernel resource pressure (VMA allocator contention, temporary memory fragmentation, etc.). The failure is not related to hard resource limits — ulimit, threads-max, max_map_count and cgroup pids limits are all well above the required values. The failure occurs both inside and outside containers and is worse on hosts with fewer resources. Measured failure rates on a 16GB / 9-CPU host: Before fix: 65% failure rate (13/20 outside container) After fix: ~2.5% failure rate (1/40), and that failure was a C/R issue, not a pthread_create EAGAIN Fix this by adding a pthread_create_retry() wrapper that retries pthread_create() up to 50 times with a 10ms delay when it returns EAGAIN. This gives the kernel time to reclaim resources between attempts while keeping the total worst-case retry time under one second per thread creation. Assisted-by: Claude:claude-opus-4-6 Signed-off-by: Adrian Reber --- test/zdtm/transition/thread-bomb.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/test/zdtm/transition/thread-bomb.c b/test/zdtm/transition/thread-bomb.c index c101f85d4..999495232 100644 --- a/test/zdtm/transition/thread-bomb.c +++ b/test/zdtm/transition/thread-bomb.c @@ -14,6 +14,29 @@ static pthread_attr_t attr; /* Having in mind setup with 64 Kb large pages */ static const size_t stack_size = 64 * 1024; +#define EAGAIN_RETRIES 50 +#define EAGAIN_DELAY_US 10000 + +/* + * Wrapper around pthread_create() that retries on EAGAIN. The test + * creates ~2048 threads in a burst and clone() can transiently fail + * with EAGAIN due to kernel resource pressure (VMA allocator + * contention, memory fragmentation, etc.) even when hard limits + * are not reached. + */ +static int pthread_create_retry(pthread_t *t, const pthread_attr_t *a, + void *(*fn)(void *), void *arg) +{ + int err, retries = 0; + + while (1) { + err = pthread_create(t, a, fn, arg); + if (err != EAGAIN || ++retries > EAGAIN_RETRIES) + return err; + usleep(EAGAIN_DELAY_US); + } +} + static void *thread_fn(void *arg) { pthread_t t, p, *self; @@ -37,7 +60,7 @@ static void *thread_fn(void *arg) *self = pthread_self(); - err = pthread_create(&t, &attr, thread_fn, self); + err = pthread_create_retry(&t, &attr, thread_fn, self); if (err) { pr_err("pthread_create(): %d\n", err); free(self); @@ -73,7 +96,7 @@ int main(int argc, char **argv) for (i = 0; i < max_nr; i++) { pthread_t p; - err = pthread_create(&p, &attr, thread_fn, NULL); + err = pthread_create_retry(&p, &attr, thread_fn, NULL); if (err) { pr_err("pthread_create(): %d\n", err); exit(1);