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