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