aboutsummaryrefslogtreecommitdiff
path: root/cddl/lib/libtpool
diff options
context:
space:
mode:
Diffstat (limited to 'cddl/lib/libtpool')
-rw-r--r--cddl/lib/libtpool/Makefile15
-rw-r--r--cddl/lib/libtpool/Makefile.depend16
-rw-r--r--cddl/lib/libtpool/tests/Makefile13
-rw-r--r--cddl/lib/libtpool/tests/libtpool_test.c82
4 files changed, 121 insertions, 5 deletions
diff --git a/cddl/lib/libtpool/Makefile b/cddl/lib/libtpool/Makefile
index 637385bc842e..3a50a21bf62c 100644
--- a/cddl/lib/libtpool/Makefile
+++ b/cddl/lib/libtpool/Makefile
@@ -1,12 +1,12 @@
-# $FreeBSD$
-
.PATH: ${SRCTOP}/sys/contrib/openzfs/lib/libtpool
.PATH: ${SRCTOP}/sys/contrib/openzfs/include
+PACKAGE= zfs
+LIB_PACKAGE=
-LIB= tpool
-LIBADD= spl
-PACKAGE= runtime
+LIB= tpool
+SHLIBDIR?= /lib
+LIBADD= spl
INCS= thread_pool_impl.h
SRCS= thread_pool.c
@@ -24,4 +24,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/Makefile.depend b/cddl/lib/libtpool/Makefile.depend
new file mode 100644
index 000000000000..409c3c86cc20
--- /dev/null
+++ b/cddl/lib/libtpool/Makefile.depend
@@ -0,0 +1,16 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ cddl/lib/libspl \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/cddl/lib/libtpool/tests/Makefile b/cddl/lib/libtpool/tests/Makefile
new file mode 100644
index 000000000000..19e43cc18821
--- /dev/null
+++ b/cddl/lib/libtpool/tests/Makefile
@@ -0,0 +1,13 @@
+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 "${SRCTOP}/cddl/Makefile.inc"
+.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..42bce269cb23
--- /dev/null
+++ b/cddl/lib/libtpool/tests/libtpool_test.c
@@ -0,0 +1,82 @@
+#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;
+ int r;
+
+ /* Block this task until all thread pool workers have been created. */
+ r = pthread_barrier_wait(barrier);
+ ATF_REQUIRE_MSG(r == 0 || r == PTHREAD_BARRIER_SERIAL_THREAD,
+ "pthread_barrier_wait failed: %s", strerror(r));
+}
+
+/*
+ * 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 */
+ r = pthread_barrier_wait(&barrier);
+ ATF_REQUIRE_MSG(r == 0 || r == PTHREAD_BARRIER_SERIAL_THREAD,
+ "pthread_barrier_wait failed: %s", strerror(r));
+ tpool_wait(tp1);
+ tpool_wait(tp0);
+}
+
+ATF_TP_ADD_TCS(tp)
+{
+ ATF_TP_ADD_TC(tp, complete_exhaustion);
+
+ return (atf_no_error());
+}