From 96dad96ae5bc82a99c63c67463872782d0882e52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Mon, 4 Aug 2025 17:03:42 +0200 Subject: [PATCH] Add support for setting thread stack size When running the isc_quota unit test with less than usual amount of RAM (e.g. in a CI for architectures with 32 bits of address space), the pthread_create() function fails with the "Resource temporarily unavailable (11):" error code. Add functions to get and set the thread stack size (if requested), and use these to set the thread stack size to smaller value in the isc_quota unit test. --- lib/isc/include/isc/thread.h | 5 ++++ lib/isc/os.c | 10 +++++++- lib/isc/thread.c | 49 ++++++++++++++++++------------------ lib/isc/thread_p.h | 6 +++++ tests/isc/mem_test.c | 3 +++ tests/isc/mutex_test.c | 4 +++ tests/isc/quota_test.c | 5 +++- tests/isc/rwlock_test.c | 4 +++ tests/isc/spinlock_test.c | 4 +++ 9 files changed, 63 insertions(+), 27 deletions(-) diff --git a/lib/isc/include/isc/thread.h b/lib/isc/include/isc/thread.h index 17c0fff9b1..1a9b0917f0 100644 --- a/lib/isc/include/isc/thread.h +++ b/lib/isc/include/isc/thread.h @@ -52,3 +52,8 @@ void isc_thread_setname(isc_thread_t thread, const char *name); #define isc_thread_self (uintptr_t)pthread_self + +size_t +isc_thread_getstacksize(void); +void +isc_thread_setstacksize(size_t stacksize); diff --git a/lib/isc/os.c b/lib/isc/os.c index b50248d591..8c3ced67c4 100644 --- a/lib/isc/os.c +++ b/lib/isc/os.c @@ -20,6 +20,7 @@ #include #include "os_p.h" +#include "thread_p.h" static unsigned int isc__os_ncpus = 0; static unsigned long isc__os_cacheline = ISC_OS_CACHELINE_SIZE; @@ -201,9 +202,16 @@ isc__os_initialize(void) { isc__os_cacheline = s; } #endif + + pthread_attr_init(&isc__thread_attr); + + size_t stacksize = isc_thread_getstacksize(); + if (stacksize != 0 && stacksize < THREAD_MINSTACKSIZE) { + isc_thread_setstacksize(THREAD_MINSTACKSIZE); + } } void isc__os_shutdown(void) { - /* empty, but defined for completeness */; + pthread_attr_destroy(&isc__thread_attr); } diff --git a/lib/isc/thread.c b/lib/isc/thread.c index 5841a467fe..ea9e1fb028 100644 --- a/lib/isc/thread.c +++ b/lib/isc/thread.c @@ -40,12 +40,10 @@ #include "thread_p.h" -#ifndef THREAD_MINSTACKSIZE -#define THREAD_MINSTACKSIZE (1024U * 1024) -#endif /* ifndef THREAD_MINSTACKSIZE */ - static struct call_rcu_data *isc__thread_call_rcu_data = NULL; +pthread_attr_t isc__thread_attr; + /* * We can't use isc_mem API here, because it's called too early and the * memory debugging flags can be changed later causing mismatch between flags @@ -126,28 +124,9 @@ isc_thread_main(isc_threadfunc_t func, void *arg) { void isc_thread_create(isc_threadfunc_t func, void *arg, isc_thread_t *thread) { - int ret; - pthread_attr_t attr; - - pthread_attr_init(&attr); - -#if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \ - defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) - size_t stacksize; - ret = pthread_attr_getstacksize(&attr, &stacksize); - PTHREADS_RUNTIME_CHECK(pthread_attr_getstacksize, ret); - - if (stacksize < THREAD_MINSTACKSIZE) { - ret = pthread_attr_setstacksize(&attr, THREAD_MINSTACKSIZE); - PTHREADS_RUNTIME_CHECK(pthread_attr_setstacksize, ret); - } -#endif /* if defined(HAVE_PTHREAD_ATTR_GETSTACKSIZE) && \ - * defined(HAVE_PTHREAD_ATTR_SETSTACKSIZE) */ - - ret = pthread_create(thread, &attr, thread_run, thread_wrap(func, arg)); + int ret = pthread_create(thread, &isc__thread_attr, thread_run, + thread_wrap(func, arg)); PTHREADS_RUNTIME_CHECK(pthread_create, ret); - - pthread_attr_destroy(&attr); } void @@ -188,6 +167,26 @@ isc_thread_yield(void) { #endif /* if defined(HAVE_SCHED_YIELD) */ } +size_t +isc_thread_getstacksize(void) { + size_t stacksize = 0; + +#if HAVE_PTHREAD_ATTR_GETSTACKSIZE + int ret = pthread_attr_getstacksize(&isc__thread_attr, &stacksize); + PTHREADS_RUNTIME_CHECK(pthread_attr_getstacksize, ret); +#endif /* HAVE_PTHREAD_ATTR_GETSTACKSIZE */ + + return stacksize; +} + +void +isc_thread_setstacksize(size_t stacksize ISC_ATTR_UNUSED) { +#if HAVE_PTHREAD_ATTR_SETSTACKSIZE + int ret = pthread_attr_setstacksize(&isc__thread_attr, stacksize); + PTHREADS_RUNTIME_CHECK(pthread_attr_setstacksize, ret); +#endif /* HAVE_PTHREAD_ATTR_SETSTACKSIZE */ +} + void isc__thread_initialize(void) { isc__thread_call_rcu_data = create_call_rcu_data(0, -1); diff --git a/lib/isc/thread_p.h b/lib/isc/thread_p.h index 6ed32cd984..0fd02a9684 100644 --- a/lib/isc/thread_p.h +++ b/lib/isc/thread_p.h @@ -17,6 +17,12 @@ /*! \file */ +#ifndef THREAD_MINSTACKSIZE +#define THREAD_MINSTACKSIZE (1U * 1024 * 1024) +#endif /* ifndef THREAD_MINSTACKSIZE */ + +extern pthread_attr_t isc__thread_attr; + void isc__thread_initialize(void); diff --git a/tests/isc/mem_test.c b/tests/isc/mem_test.c index a19a8ee964..7cb7e06a8d 100644 --- a/tests/isc/mem_test.c +++ b/tests/isc/mem_test.c @@ -37,6 +37,7 @@ #include #include "mem_p.h" +#include "thread_p.h" #include @@ -516,6 +517,8 @@ ISC_RUN_TEST_IMPL(isc_mem_benchmark) { isc_time_t ts1, ts2; double t; + isc_thread_setstacksize(THREAD_MINSTACKSIZE); + atomic_init(&mem_size, ITEM_SIZE); ts1 = isc_time_now(); diff --git a/tests/isc/mutex_test.c b/tests/isc/mutex_test.c index eb09ce0443..44c4b0ef29 100644 --- a/tests/isc/mutex_test.c +++ b/tests/isc/mutex_test.c @@ -36,6 +36,8 @@ #include #include +#include "thread_p.h" + #include static unsigned int loops = 100; @@ -124,6 +126,8 @@ ISC_RUN_TEST_IMPL(isc_mutex_benchmark) { size_t cont; int r; + isc_thread_setstacksize(THREAD_MINSTACKSIZE); + memset(threads, 0, sizeof(*threads) * workers); expected_counter = ITERS * workers * loops * diff --git a/tests/isc/quota_test.c b/tests/isc/quota_test.c index 6b9677978d..dbc28015e4 100644 --- a/tests/isc/quota_test.c +++ b/tests/isc/quota_test.c @@ -32,6 +32,8 @@ #include #include +#include "thread_p.h" + #include isc_quota_t quota; @@ -268,9 +270,10 @@ quota_thread(void *qtip) { } ISC_RUN_TEST_IMPL(isc_quota_callback_mt) { - UNUSED(state); int i; + isc_thread_setstacksize(THREAD_MINSTACKSIZE); + isc_quota_init("a, 100); static qthreadinfo_t qtis[10]; isc_thread_t threads[10]; diff --git a/tests/isc/rwlock_test.c b/tests/isc/rwlock_test.c index efc9827c2f..a26334c92a 100644 --- a/tests/isc/rwlock_test.c +++ b/tests/isc/rwlock_test.c @@ -37,6 +37,8 @@ #include #include +#include "thread_p.h" + #include static unsigned int loops = 100; @@ -255,6 +257,8 @@ isc__rwlock_benchmark(isc_thread_t *threads, unsigned int nthreads, int dc; size_t cont; + isc_thread_setstacksize(THREAD_MINSTACKSIZE); + expected_counter = ITERS * nthreads * loops * ((CNT_MAX - CNT_MIN) / DC + 1); diff --git a/tests/isc/spinlock_test.c b/tests/isc/spinlock_test.c index 6c739a713d..bd9fc37d0d 100644 --- a/tests/isc/spinlock_test.c +++ b/tests/isc/spinlock_test.c @@ -42,6 +42,8 @@ #include #include +#include "thread_p.h" + #include static unsigned int loops = 100; @@ -133,6 +135,8 @@ ISC_RUN_TEST_IMPL(isc_spinlock_benchmark) { int dc; size_t cont; + isc_thread_setstacksize(THREAD_MINSTACKSIZE); + memset(threads, 0, sizeof(*threads) * workers); expected_counter = ITERS * workers * loops *