2 * proc_info_list_kthreads
4 * list 64 bit thread ids of kernel_task
14 #include <darwintest.h>
15 #include <TargetConditionals.h>
17 T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
20 #define EXTRA_THREADS 15
23 T_DECL(proc_info_list_kthreads
,
24 "Test to verify PROC_PIDLISTTHREADIDS returns kernel thread IDs for pid 0",
26 T_META_CHECK_LEAKS(false))
28 T_DECL(proc_info_list_kthreads
,
29 "Test to verify PROC_PIDLISTTHREADIDS returns kernel thread IDs for pid 0",
31 T_META_CHECK_LEAKS(false))
32 #endif /* TARGET_OS_OSX */
37 uint64_t *thread_list
= NULL
;
40 * To use PROC_PIDLISTTHREADIDS, we must pass a buffer of uint64_t's for each thread ID.
41 * However, there is a TOCTOU race between asking for the thread count
42 * and asking for the array of identifiers.
44 * Because the process could have allocated more threads since last we asked
45 * how many threads there are, we instead pass an extra slot in the array,
46 * and try again if it used that slot.
50 while (!thread_count
&& (attempt
< MAX_TRIES
)) {
51 struct proc_taskinfo ti
;
53 buf_used
= proc_pidinfo(0, PROC_PIDTASKINFO
, 0, &ti
, sizeof(ti
));
55 T_QUIET
; T_WITH_ERRNO
; T_ASSERT_GT(buf_used
, 0, "proc_pidinfo(PROC_PIDTASKINFO) returned a value > 0");
56 T_QUIET
; T_ASSERT_EQ(buf_used
, (int)sizeof(ti
), "proc_pidinfo(PROC_PIDTASKINFO) returned size %d == %lu", buf_used
, sizeof(ti
));
58 T_LOG("The kernel says it has %d threads", ti
.pti_threadnum
);
60 int expected_size
= ti
.pti_threadnum
* (int)sizeof(uint64_t);
61 /* tack on five extra to detect newly allocated threads */
62 int allocated_size
= expected_size
+ EXTRA_THREADS
* (int)sizeof(uint64_t);
63 uint64_t *thread_list_tmp
= malloc((size_t)allocated_size
);
64 T_QUIET
; T_WITH_ERRNO
; T_ASSERT_NOTNULL(thread_list_tmp
, "malloc(size = %d) failed", allocated_size
);
66 buf_used
= proc_pidinfo(0, PROC_PIDLISTTHREADIDS
, 0, thread_list_tmp
, (int)allocated_size
);
67 T_LOG("proc_pidinfo(PROC_PIDLISTTHREADIDS) buf_used = %d, expected_size = %d", buf_used
, expected_size
);
70 T_WITH_ERRNO
; T_ASSERT_FAIL("proc_pidinfo(PROC_PIDLISTTHREADIDS) failed");
72 if (buf_used
== expected_size
) {
73 /* success, we found the expected number of threads */
74 thread_list
= thread_list_tmp
;
75 thread_count
= expected_size
/ (int)sizeof(uint64_t);
76 } else if (buf_used
< expected_size
) {
77 /* there were fewer threads than we expected, fix up the allocation */
78 thread_list
= realloc(thread_list_tmp
, (size_t)buf_used
);
79 thread_count
= buf_used
/ (int)sizeof(uint64_t);
80 T_QUIET
; T_WITH_ERRNO
; T_ASSERT_NOTNULL(thread_list
, "realloc(size = %d) failed", buf_used
);
81 } else if (buf_used
> expected_size
) {
82 if (buf_used
< allocated_size
) {
83 thread_list
= realloc(thread_list_tmp
, (size_t)buf_used
);
84 thread_count
= buf_used
/ (int)sizeof(uint64_t);
85 T_QUIET
; T_WITH_ERRNO
; T_ASSERT_NOTNULL(thread_list
, "realloc(size = %d) failed", buf_used
);
88 * it used all the extra slots, meaning there are more
89 * threads than we thought, try again!
91 T_LOG("expected %d threads, but saw an extra thread: %d",
92 expected_size
/ (int)sizeof(uint64_t), buf_used
/ (int)sizeof(uint64_t));
93 free(thread_list_tmp
);
98 T_QUIET
; T_ASSERT_LE(attempt
, MAX_TRIES
, "attempt <= MAX_TRIES");
99 T_QUIET
; T_ASSERT_NOTNULL(thread_list
, "thread_list != NULL");
100 T_QUIET
; T_ASSERT_GT(thread_count
, 0, "thread_count > 0");
102 struct proc_threadinfo pthinfo_64
;
103 for (int i
= 0; i
< thread_count
; i
++) {
104 bzero(&pthinfo_64
, sizeof(struct proc_threadinfo
));
105 int retval
= proc_pidinfo(0, PROC_PIDTHREADID64INFO
, thread_list
[i
],
106 (void *)&pthinfo_64
, (uint32_t)sizeof(pthinfo_64
));
107 T_QUIET
; T_WITH_ERRNO
; T_EXPECT_GT(retval
, 0, "proc_pidinfo(PROC_PIDTASKINFO) returned %d", retval
);
108 T_QUIET
; T_EXPECT_EQ(retval
, (int)sizeof(pthinfo_64
), "proc_pidinfo(PROC_PIDTASKINFO) returned size %d == %lu",
109 retval
, sizeof(pthinfo_64
));