git: 5c1ba994a8bc - main - Add a regression test for a libtpool bug
Date: Sun, 15 Jun 2025 16:02:28 UTC
The branch main has been updated by asomers:
URL: https://cgit.FreeBSD.org/src/commit/?id=5c1ba994a8bcb6676ea3d1bb21b072b90e2d3ae9
commit 5c1ba994a8bcb6676ea3d1bb21b072b90e2d3ae9
Author: Alan Somers <asomers@FreeBSD.org>
AuthorDate: 2024-05-07 17:48:33 +0000
Commit: Alan Somers <asomers@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
..