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
         ..

Reply via email to