The branch main has been updated by asomers: URL: https://cgit.FreeBSD.org/src/commit/?id=5c1ba994a8bcb6676ea3d1bb21b072b90e2d3ae9
commit 5c1ba994a8bcb6676ea3d1bb21b072b90e2d3ae9 Author: Alan Somers <asom...@freebsd.org> AuthorDate: 2024-05-07 17:48:33 +0000 Commit: Alan Somers <asom...@freebsd.org> CommitDate: 2025-06-15 16:01:37 +0000 Add a regression test for a libtpool bug Test that tpool_dispatch returns an error if it cannot start even one worker. Previously, it would hang. The test must reside here rather than in the OpenZFS repo because the latter has no infrastructure for writing libtpool tests. https://github.com/openzfs/zfs/issues/16172 MFC after: 2 weeks Sponsored by: Axcient Differential Revision: https://reviews.freebsd.org/D45587 --- cddl/lib/libtpool/Makefile | 5 +++ cddl/lib/libtpool/tests/Makefile | 12 +++++ cddl/lib/libtpool/tests/libtpool_test.c | 78 +++++++++++++++++++++++++++++++++ etc/mtree/BSD.tests.dist | 2 + 4 files changed, 97 insertions(+) diff --git a/cddl/lib/libtpool/Makefile b/cddl/lib/libtpool/Makefile index 2afaf0c417e9..3ab625dd306b 100644 --- a/cddl/lib/libtpool/Makefile +++ b/cddl/lib/libtpool/Makefile @@ -22,4 +22,9 @@ CFLAGS+= -include ${SRCTOP}/sys/contrib/openzfs/include/os/freebsd/spl/sys/ccomp CFLAGS+= -DHAVE_ISSETUGID CFLAGS+= -include ${SRCTOP}/sys/modules/zfs/zfs_config.h +.include <src.opts.mk> + +HAS_TESTS= +SUBDIR.${MK_TESTS}+= tests + .include <bsd.lib.mk> diff --git a/cddl/lib/libtpool/tests/Makefile b/cddl/lib/libtpool/tests/Makefile new file mode 100644 index 000000000000..d87f5fc86789 --- /dev/null +++ b/cddl/lib/libtpool/tests/Makefile @@ -0,0 +1,12 @@ +ZFSTOP= ${SRCTOP}/sys/contrib/openzfs + +ATF_TESTS_C+= libtpool_test + +TEST_METADATA+= timeout="10" + +CFLAGS+= -I${ZFSTOP}/include \ + -I${ZFSTOP}/lib/libspl/include + +LIBADD+= pthread tpool + +.include <bsd.test.mk> diff --git a/cddl/lib/libtpool/tests/libtpool_test.c b/cddl/lib/libtpool/tests/libtpool_test.c new file mode 100644 index 000000000000..42726a13420c --- /dev/null +++ b/cddl/lib/libtpool/tests/libtpool_test.c @@ -0,0 +1,78 @@ +#include <sys/stdtypes.h> +#include <sys/sysctl.h> +#include <errno.h> +#include <pthread.h> + +#include <thread_pool.h> + +#include <atf-c.h> + +static void +tp_delay(void *arg) +{ + pthread_barrier_t *barrier = arg; + + /* Block this task until all thread pool workers have been created. */ + pthread_barrier_wait(barrier); +} + +/* + * NB: we could reduce the test's resource cost by using rctl(4). But that + * isn't enabled by default. And even with a thread limit of 1500, it takes < + * 0.1s to run on my machine. So I don't think it's worth optimizing for the + * case where rctl is available. + */ +ATF_TC(complete_exhaustion); +ATF_TC_HEAD(complete_exhaustion, tc) +{ + atf_tc_set_md_var(tc, "descr", + "A thread pool should fail to schedule tasks if it is completely impossible to spawn any threads."); +} + +ATF_TC_BODY(complete_exhaustion, tc) +{ + pthread_barrier_t barrier; + tpool_t *tp0, *tp1; + size_t len; + int max_threads_per_proc = 0; + int nworkers; + int r, i; + + + len = sizeof(max_threads_per_proc); + r = sysctlbyname("kern.threads.max_threads_per_proc", + &max_threads_per_proc, &len, NULL, 0); + ATF_REQUIRE_EQ_MSG(r, 0, "sysctlbyname: %s", strerror(errno)); + nworkers = max_threads_per_proc - 1; + pthread_barrier_init(&barrier, NULL, max_threads_per_proc); + + /* + * Create the first thread pool and spawn the maximum allowed number of + * processes. + */ + tp0 = tpool_create(nworkers, nworkers, 1, NULL); + ATF_REQUIRE(tp0 != NULL); + for (i = 0; i < nworkers; i++) { + ATF_REQUIRE_EQ(tpool_dispatch(tp0, tp_delay, &barrier), 0); + } + + /* + * Now create a second thread pool. Unable to create new threads, the + * dispatch function should return an error. + */ + tp1 = tpool_create(nworkers, 2 * nworkers, 1, NULL); + ATF_REQUIRE(tp1 != NULL); + ATF_REQUIRE_EQ(tpool_dispatch(tp1, tp_delay, NULL), -1); + + /* Cleanup */ + ATF_REQUIRE_EQ(pthread_barrier_wait(&barrier), 0); + tpool_wait(tp1); + tpool_wait(tp0); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, complete_exhaustion); + + return (atf_no_error()); +} diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index bfd21607ed4d..7d21dcbd2cbf 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -80,6 +80,8 @@ .. cddl lib + libtpool + .. .. sbin ..