xref: /xnu-8792.81.2/tests/proc_info_list_kthreads.c (revision 19c3b8c28c31cb8130e034cfb5df6bf9ba342d90)
1*19c3b8c2SApple OSS Distributions /*
2*19c3b8c2SApple OSS Distributions  * proc_info_list_kthreads
3*19c3b8c2SApple OSS Distributions  *
4*19c3b8c2SApple OSS Distributions  * list 64 bit thread ids of kernel_task
5*19c3b8c2SApple OSS Distributions  */
6*19c3b8c2SApple OSS Distributions 
7*19c3b8c2SApple OSS Distributions #include <stdio.h>
8*19c3b8c2SApple OSS Distributions #include <stdlib.h>
9*19c3b8c2SApple OSS Distributions #include <assert.h>
10*19c3b8c2SApple OSS Distributions #include <err.h>
11*19c3b8c2SApple OSS Distributions 
12*19c3b8c2SApple OSS Distributions #include <libproc.h>
13*19c3b8c2SApple OSS Distributions #include <strings.h>
14*19c3b8c2SApple OSS Distributions #include <darwintest.h>
15*19c3b8c2SApple OSS Distributions #include <TargetConditionals.h>
16*19c3b8c2SApple OSS Distributions 
17*19c3b8c2SApple OSS Distributions T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
18*19c3b8c2SApple OSS Distributions 
19*19c3b8c2SApple OSS Distributions #define MAX_TRIES 20
20*19c3b8c2SApple OSS Distributions #define EXTRA_THREADS 15
21*19c3b8c2SApple OSS Distributions 
22*19c3b8c2SApple OSS Distributions #if TARGET_OS_OSX
23*19c3b8c2SApple OSS Distributions T_DECL(proc_info_list_kthreads,
24*19c3b8c2SApple OSS Distributions     "Test to verify PROC_PIDLISTTHREADIDS returns kernel thread IDs for pid 0",
25*19c3b8c2SApple OSS Distributions     T_META_ASROOT(true),
26*19c3b8c2SApple OSS Distributions     T_META_CHECK_LEAKS(false))
27*19c3b8c2SApple OSS Distributions #else
28*19c3b8c2SApple OSS Distributions T_DECL(proc_info_list_kthreads,
29*19c3b8c2SApple OSS Distributions     "Test to verify PROC_PIDLISTTHREADIDS returns kernel thread IDs for pid 0",
30*19c3b8c2SApple OSS Distributions     T_META_ASROOT(false),
31*19c3b8c2SApple OSS Distributions     T_META_CHECK_LEAKS(false))
32*19c3b8c2SApple OSS Distributions #endif /* TARGET_OS_OSX */
33*19c3b8c2SApple OSS Distributions {
34*19c3b8c2SApple OSS Distributions 	int buf_used = 0;
35*19c3b8c2SApple OSS Distributions 
36*19c3b8c2SApple OSS Distributions 	int thread_count = 0;
37*19c3b8c2SApple OSS Distributions 	uint64_t *thread_list = NULL;
38*19c3b8c2SApple OSS Distributions 
39*19c3b8c2SApple OSS Distributions 	/*
40*19c3b8c2SApple OSS Distributions 	 * To use PROC_PIDLISTTHREADIDS, we must pass a buffer of uint64_t's for each thread ID.
41*19c3b8c2SApple OSS Distributions 	 * However, there is a TOCTOU race between asking for the thread count
42*19c3b8c2SApple OSS Distributions 	 * and asking for the array of identifiers.
43*19c3b8c2SApple OSS Distributions 	 *
44*19c3b8c2SApple OSS Distributions 	 * Because the process could have allocated more threads since last we asked
45*19c3b8c2SApple OSS Distributions 	 * how many threads there are, we instead pass an extra slot in the array,
46*19c3b8c2SApple OSS Distributions 	 * and try again if it used that slot.
47*19c3b8c2SApple OSS Distributions 	 */
48*19c3b8c2SApple OSS Distributions 
49*19c3b8c2SApple OSS Distributions 	int attempt = 1;
50*19c3b8c2SApple OSS Distributions 	while (!thread_count && (attempt < MAX_TRIES)) {
51*19c3b8c2SApple OSS Distributions 		struct proc_taskinfo ti;
52*19c3b8c2SApple OSS Distributions 
53*19c3b8c2SApple OSS Distributions 		buf_used = proc_pidinfo(0, PROC_PIDTASKINFO, 0, &ti, sizeof(ti));
54*19c3b8c2SApple OSS Distributions 
55*19c3b8c2SApple OSS Distributions 		T_QUIET; T_WITH_ERRNO; T_ASSERT_GT(buf_used, 0, "proc_pidinfo(PROC_PIDTASKINFO) returned a value > 0");
56*19c3b8c2SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(buf_used, (int)sizeof(ti), "proc_pidinfo(PROC_PIDTASKINFO) returned size %d == %lu", buf_used, sizeof(ti));
57*19c3b8c2SApple OSS Distributions 
58*19c3b8c2SApple OSS Distributions 		T_LOG("The kernel says it has %d threads", ti.pti_threadnum);
59*19c3b8c2SApple OSS Distributions 
60*19c3b8c2SApple OSS Distributions 		int expected_size  = ti.pti_threadnum * (int)sizeof(uint64_t);
61*19c3b8c2SApple OSS Distributions 		/* tack on five extra to detect newly allocated threads */
62*19c3b8c2SApple OSS Distributions 		int allocated_size = expected_size + EXTRA_THREADS * (int)sizeof(uint64_t);
63*19c3b8c2SApple OSS Distributions 		uint64_t *thread_list_tmp = malloc((size_t)allocated_size);
64*19c3b8c2SApple OSS Distributions 		T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(thread_list_tmp, "malloc(size = %d) failed", allocated_size);
65*19c3b8c2SApple OSS Distributions 
66*19c3b8c2SApple OSS Distributions 		buf_used = proc_pidinfo(0, PROC_PIDLISTTHREADIDS, 0, thread_list_tmp, (int)allocated_size);
67*19c3b8c2SApple OSS Distributions 		T_LOG("proc_pidinfo(PROC_PIDLISTTHREADIDS) buf_used = %d, expected_size = %d", buf_used, expected_size);
68*19c3b8c2SApple OSS Distributions 
69*19c3b8c2SApple OSS Distributions 		if (buf_used == 0) {
70*19c3b8c2SApple OSS Distributions 			T_WITH_ERRNO; T_ASSERT_FAIL("proc_pidinfo(PROC_PIDLISTTHREADIDS) failed");
71*19c3b8c2SApple OSS Distributions 		}
72*19c3b8c2SApple OSS Distributions 		if (buf_used == expected_size) {
73*19c3b8c2SApple OSS Distributions 			/* success, we found the expected number of threads */
74*19c3b8c2SApple OSS Distributions 			thread_list = thread_list_tmp;
75*19c3b8c2SApple OSS Distributions 			thread_count = expected_size / (int)sizeof(uint64_t);
76*19c3b8c2SApple OSS Distributions 		} else if (buf_used < expected_size) {
77*19c3b8c2SApple OSS Distributions 			/* there were fewer threads than we expected, fix up the allocation */
78*19c3b8c2SApple OSS Distributions 			thread_list = realloc(thread_list_tmp, (size_t)buf_used);
79*19c3b8c2SApple OSS Distributions 			thread_count = buf_used / (int)sizeof(uint64_t);
80*19c3b8c2SApple OSS Distributions 			T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(thread_list, "realloc(size = %d) failed", buf_used);
81*19c3b8c2SApple OSS Distributions 		} else if (buf_used > expected_size) {
82*19c3b8c2SApple OSS Distributions 			if (buf_used < allocated_size) {
83*19c3b8c2SApple OSS Distributions 				thread_list = realloc(thread_list_tmp, (size_t)buf_used);
84*19c3b8c2SApple OSS Distributions 				thread_count = buf_used / (int)sizeof(uint64_t);
85*19c3b8c2SApple OSS Distributions 				T_QUIET; T_WITH_ERRNO; T_ASSERT_NOTNULL(thread_list, "realloc(size = %d) failed", buf_used);
86*19c3b8c2SApple OSS Distributions 			} else {
87*19c3b8c2SApple OSS Distributions 				/*
88*19c3b8c2SApple OSS Distributions 				 * it used all the extra slots, meaning there are more
89*19c3b8c2SApple OSS Distributions 				 * threads than we thought, try again!
90*19c3b8c2SApple OSS Distributions 				 */
91*19c3b8c2SApple OSS Distributions 				T_LOG("expected %d threads, but saw an extra thread: %d",
92*19c3b8c2SApple OSS Distributions 				    expected_size / (int)sizeof(uint64_t), buf_used / (int)sizeof(uint64_t));
93*19c3b8c2SApple OSS Distributions 				free(thread_list_tmp);
94*19c3b8c2SApple OSS Distributions 			}
95*19c3b8c2SApple OSS Distributions 		}
96*19c3b8c2SApple OSS Distributions 		attempt++;
97*19c3b8c2SApple OSS Distributions 	}
98*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_LE(attempt, MAX_TRIES, "attempt <= MAX_TRIES");
99*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_NOTNULL(thread_list, "thread_list != NULL");
100*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_GT(thread_count, 0, "thread_count > 0");
101*19c3b8c2SApple OSS Distributions 
102*19c3b8c2SApple OSS Distributions 	struct proc_threadinfo pthinfo_64;
103*19c3b8c2SApple OSS Distributions 	for (int i = 0; i < thread_count; i++) {
104*19c3b8c2SApple OSS Distributions 		bzero(&pthinfo_64, sizeof(struct proc_threadinfo));
105*19c3b8c2SApple OSS Distributions 		int retval = proc_pidinfo(0, PROC_PIDTHREADID64INFO, thread_list[i],
106*19c3b8c2SApple OSS Distributions 		    (void *)&pthinfo_64, (uint32_t)sizeof(pthinfo_64));
107*19c3b8c2SApple OSS Distributions 		T_QUIET; T_WITH_ERRNO; T_EXPECT_GT(retval, 0, "proc_pidinfo(PROC_PIDTASKINFO) returned %d", retval);
108*19c3b8c2SApple OSS Distributions 		T_QUIET; T_EXPECT_EQ(retval, (int)sizeof(pthinfo_64), "proc_pidinfo(PROC_PIDTASKINFO) returned size %d == %lu",
109*19c3b8c2SApple OSS Distributions 		    retval, sizeof(pthinfo_64));
110*19c3b8c2SApple OSS Distributions 	}
111*19c3b8c2SApple OSS Distributions }
112