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 int r; 15 16 /* Block this task until all thread pool workers have been created. */ 17 r = pthread_barrier_wait(barrier); 18 ATF_REQUIRE_MSG(r == 0 || r == PTHREAD_BARRIER_SERIAL_THREAD, 19 "pthread_barrier_wait failed: %s", strerror(r)); 20 } 21 22 /* 23 * NB: we could reduce the test's resource cost by using rctl(4). But that 24 * isn't enabled by default. And even with a thread limit of 1500, it takes < 25 * 0.1s to run on my machine. So I don't think it's worth optimizing for the 26 * case where rctl is available. 27 */ 28 ATF_TC(complete_exhaustion); 29 ATF_TC_HEAD(complete_exhaustion, tc) 30 { 31 atf_tc_set_md_var(tc, "descr", 32 "A thread pool should fail to schedule tasks if it is completely impossible to spawn any threads."); 33 } 34 35 ATF_TC_BODY(complete_exhaustion, tc) 36 { 37 pthread_barrier_t barrier; 38 tpool_t *tp0, *tp1; 39 size_t len; 40 int max_threads_per_proc = 0; 41 int nworkers; 42 int r, i; 43 44 len = sizeof(max_threads_per_proc); 45 r = sysctlbyname("kern.threads.max_threads_per_proc", 46 &max_threads_per_proc, &len, NULL, 0); 47 ATF_REQUIRE_EQ_MSG(r, 0, "sysctlbyname: %s", strerror(errno)); 48 nworkers = max_threads_per_proc - 1; 49 pthread_barrier_init(&barrier, NULL, max_threads_per_proc); 50 51 /* 52 * Create the first thread pool and spawn the maximum allowed number of 53 * processes. 54 */ 55 tp0 = tpool_create(nworkers, nworkers, 1, NULL); 56 ATF_REQUIRE(tp0 != NULL); 57 for (i = 0; i < nworkers; i++) { 58 ATF_REQUIRE_EQ(tpool_dispatch(tp0, tp_delay, &barrier), 0); 59 } 60 61 /* 62 * Now create a second thread pool. Unable to create new threads, the 63 * dispatch function should return an error. 64 */ 65 tp1 = tpool_create(nworkers, 2 * nworkers, 1, NULL); 66 ATF_REQUIRE(tp1 != NULL); 67 ATF_REQUIRE_EQ(tpool_dispatch(tp1, tp_delay, NULL), -1); 68 69 /* Cleanup */ 70 r = pthread_barrier_wait(&barrier); 71 ATF_REQUIRE_MSG(r == 0 || r == PTHREAD_BARRIER_SERIAL_THREAD, 72 "pthread_barrier_wait failed: %s", strerror(r)); 73 tpool_wait(tp1); 74 tpool_wait(tp0); 75 } 76 77 ATF_TP_ADD_TCS(tp) 78 { 79 ATF_TP_ADD_TC(tp, complete_exhaustion); 80 81 return (atf_no_error()); 82 } 83