Skip to content

Commit 5c1ba99

Browse files
committed
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. openzfs/zfs#16172 MFC after: 2 weeks Sponsored by: Axcient Differential Revision: https://reviews.freebsd.org/D45587
1 parent ece617c commit 5c1ba99

4 files changed

Lines changed: 97 additions & 0 deletions

File tree

cddl/lib/libtpool/Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,9 @@ CFLAGS+= -include ${SRCTOP}/sys/contrib/openzfs/include/os/freebsd/spl/sys/ccomp
2222
CFLAGS+= -DHAVE_ISSETUGID
2323
CFLAGS+= -include ${SRCTOP}/sys/modules/zfs/zfs_config.h
2424

25+
.include <src.opts.mk>
26+
27+
HAS_TESTS=
28+
SUBDIR.${MK_TESTS}+= tests
29+
2530
.include <bsd.lib.mk>

cddl/lib/libtpool/tests/Makefile

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
ZFSTOP= ${SRCTOP}/sys/contrib/openzfs
2+
3+
ATF_TESTS_C+= libtpool_test
4+
5+
TEST_METADATA+= timeout="10"
6+
7+
CFLAGS+= -I${ZFSTOP}/include \
8+
-I${ZFSTOP}/lib/libspl/include
9+
10+
LIBADD+= pthread tpool
11+
12+
.include <bsd.test.mk>
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#include <sys/stdtypes.h>
2+
#include <sys/sysctl.h>
3+
#include <errno.h>
4+
#include <pthread.h>
5+
6+
#include <thread_pool.h>
7+
8+
#include <atf-c.h>
9+
10+
static void
11+
tp_delay(void *arg)
12+
{
13+
pthread_barrier_t *barrier = arg;
14+
15+
/* Block this task until all thread pool workers have been created. */
16+
pthread_barrier_wait(barrier);
17+
}
18+
19+
/*
20+
* NB: we could reduce the test's resource cost by using rctl(4). But that
21+
* isn't enabled by default. And even with a thread limit of 1500, it takes <
22+
* 0.1s to run on my machine. So I don't think it's worth optimizing for the
23+
* case where rctl is available.
24+
*/
25+
ATF_TC(complete_exhaustion);
26+
ATF_TC_HEAD(complete_exhaustion, tc)
27+
{
28+
atf_tc_set_md_var(tc, "descr",
29+
"A thread pool should fail to schedule tasks if it is completely impossible to spawn any threads.");
30+
}
31+
32+
ATF_TC_BODY(complete_exhaustion, tc)
33+
{
34+
pthread_barrier_t barrier;
35+
tpool_t *tp0, *tp1;
36+
size_t len;
37+
int max_threads_per_proc = 0;
38+
int nworkers;
39+
int r, i;
40+
41+
42+
len = sizeof(max_threads_per_proc);
43+
r = sysctlbyname("kern.threads.max_threads_per_proc",
44+
&max_threads_per_proc, &len, NULL, 0);
45+
ATF_REQUIRE_EQ_MSG(r, 0, "sysctlbyname: %s", strerror(errno));
46+
nworkers = max_threads_per_proc - 1;
47+
pthread_barrier_init(&barrier, NULL, max_threads_per_proc);
48+
49+
/*
50+
* Create the first thread pool and spawn the maximum allowed number of
51+
* processes.
52+
*/
53+
tp0 = tpool_create(nworkers, nworkers, 1, NULL);
54+
ATF_REQUIRE(tp0 != NULL);
55+
for (i = 0; i < nworkers; i++) {
56+
ATF_REQUIRE_EQ(tpool_dispatch(tp0, tp_delay, &barrier), 0);
57+
}
58+
59+
/*
60+
* Now create a second thread pool. Unable to create new threads, the
61+
* dispatch function should return an error.
62+
*/
63+
tp1 = tpool_create(nworkers, 2 * nworkers, 1, NULL);
64+
ATF_REQUIRE(tp1 != NULL);
65+
ATF_REQUIRE_EQ(tpool_dispatch(tp1, tp_delay, NULL), -1);
66+
67+
/* Cleanup */
68+
ATF_REQUIRE_EQ(pthread_barrier_wait(&barrier), 0);
69+
tpool_wait(tp1);
70+
tpool_wait(tp0);
71+
}
72+
73+
ATF_TP_ADD_TCS(tp)
74+
{
75+
ATF_TP_ADD_TC(tp, complete_exhaustion);
76+
77+
return (atf_no_error());
78+
}

etc/mtree/BSD.tests.dist

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@
8080
..
8181
cddl
8282
lib
83+
libtpool
84+
..
8385
..
8486
sbin
8587
..

0 commit comments

Comments
 (0)