diff options
Diffstat (limited to 'cddl/lib/libtpool')
-rw-r--r-- | cddl/lib/libtpool/Makefile | 15 | ||||
-rw-r--r-- | cddl/lib/libtpool/Makefile.depend | 16 | ||||
-rw-r--r-- | cddl/lib/libtpool/tests/Makefile | 13 | ||||
-rw-r--r-- | cddl/lib/libtpool/tests/libtpool_test.c | 82 |
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()); +} |