1*a325d9c4SApple OSS Distributions#ifdef T_NAMESPACE 2*a325d9c4SApple OSS Distributions#undef T_NAMESPACE 3*a325d9c4SApple OSS Distributions#endif 4*a325d9c4SApple OSS Distributions#include <darwintest.h> 5*a325d9c4SApple OSS Distributions 6*a325d9c4SApple OSS Distributions#include <kdd.h> 7*a325d9c4SApple OSS Distributions#include <kern/kcdata.h> 8*a325d9c4SApple OSS Distributions#include <kern/debug.h> 9*a325d9c4SApple OSS Distributions#include <kern/block_hint.h> 10*a325d9c4SApple OSS Distributions#include <mach/mach.h> 11*a325d9c4SApple OSS Distributions#include <mach/mach_init.h> 12*a325d9c4SApple OSS Distributions#include <mach/mach_traps.h> 13*a325d9c4SApple OSS Distributions#include <mach/message.h> 14*a325d9c4SApple OSS Distributions#include <mach/port.h> 15*a325d9c4SApple OSS Distributions#include <mach/semaphore.h> 16*a325d9c4SApple OSS Distributions#include <mach/task.h> 17*a325d9c4SApple OSS Distributions#include <os/lock.h> 18*a325d9c4SApple OSS Distributions#include <pthread.h> 19*a325d9c4SApple OSS Distributions#include <signal.h> 20*a325d9c4SApple OSS Distributions#include <sys/sysctl.h> 21*a325d9c4SApple OSS Distributions#include <sys/stackshot.h> 22*a325d9c4SApple OSS Distributions#include <sys/types.h> 23*a325d9c4SApple OSS Distributions#include <stdlib.h> 24*a325d9c4SApple OSS Distributions#include <unistd.h> 25*a325d9c4SApple OSS Distributions#include <TargetConditionals.h> 26*a325d9c4SApple OSS Distributions 27*a325d9c4SApple OSS Distributions#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) 28*a325d9c4SApple OSS Distributions#include <pcre.h> 29*a325d9c4SApple OSS Distributions#endif 30*a325d9c4SApple OSS Distributions 31*a325d9c4SApple OSS Distributions 32*a325d9c4SApple OSS DistributionsT_GLOBAL_META( 33*a325d9c4SApple OSS Distributions T_META_NAMESPACE("xnu.scheduler"), 34*a325d9c4SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"), 35*a325d9c4SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("stackshot"), 36*a325d9c4SApple OSS Distributions T_META_OWNER("jonathan_w_adams"), 37*a325d9c4SApple OSS Distributions T_META_ASROOT(true) 38*a325d9c4SApple OSS Distributions); 39*a325d9c4SApple OSS Distributions 40*a325d9c4SApple OSS Distributions#include <Foundation/Foundation.h> 41*a325d9c4SApple OSS Distributions 42*a325d9c4SApple OSS Distributions#define SENDS_TO_BLOCK 6 43*a325d9c4SApple OSS Distributions#define NUMRETRIES 5 44*a325d9c4SApple OSS Distributions#define KRWLCK_STORES_EXCL_OWNER 0 45*a325d9c4SApple OSS Distributions 46*a325d9c4SApple OSS Distributions#define KMUTEX_SYSCTL_CHECK_EXISTS 0 47*a325d9c4SApple OSS Distributions#define KMUTEX_SYSCTL_ACQUIRE_WAIT 1 48*a325d9c4SApple OSS Distributions#define KMUTEX_SYSCTL_ACQUIRE_NOWAIT 2 49*a325d9c4SApple OSS Distributions#define KMUTEX_SYSCTL_SIGNAL 3 50*a325d9c4SApple OSS Distributions#define KMUTEX_SYSCTL_TEARDOWN 4 51*a325d9c4SApple OSS Distributions 52*a325d9c4SApple OSS Distributions#define KRWLCK_SYSCTL_CHECK_EXISTS 0 53*a325d9c4SApple OSS Distributions#define KRWLCK_SYSCTL_RACQUIRE_NOWAIT 1 54*a325d9c4SApple OSS Distributions#define KRWLCK_SYSCTL_RACQUIRE_WAIT 2 55*a325d9c4SApple OSS Distributions#define KRWLCK_SYSCTL_WACQUIRE_NOWAIT 3 56*a325d9c4SApple OSS Distributions#define KRWLCK_SYSCTL_WACQUIRE_WAIT 4 57*a325d9c4SApple OSS Distributions#define KRWLCK_SYSCTL_SIGNAL 5 58*a325d9c4SApple OSS Distributions#define KRWLCK_SYSCTL_TEARDOWN 6 59*a325d9c4SApple OSS Distributions 60*a325d9c4SApple OSS Distributionsstatic const char kmutex_ctl[] = "debug.test_MutexOwnerCtl"; 61*a325d9c4SApple OSS Distributionsstatic const char krwlck_ctl[] = "debug.test_RWLockOwnerCtl"; 62*a325d9c4SApple OSS Distributions 63*a325d9c4SApple OSS Distributionsstatic mach_port_t send = MACH_PORT_NULL; 64*a325d9c4SApple OSS Distributionsstatic mach_port_t recv = MACH_PORT_NULL; 65*a325d9c4SApple OSS Distributions 66*a325d9c4SApple OSS Distributionsstatic void * 67*a325d9c4SApple OSS Distributionstake_stackshot(uint32_t extra_flags, uint64_t since_timestamp) 68*a325d9c4SApple OSS Distributions{ 69*a325d9c4SApple OSS Distributions void * stackshot = NULL; 70*a325d9c4SApple OSS Distributions int ret = 0; 71*a325d9c4SApple OSS Distributions uint32_t stackshot_flags = STACKSHOT_SAVE_LOADINFO | 72*a325d9c4SApple OSS Distributions STACKSHOT_GET_GLOBAL_MEM_STATS | 73*a325d9c4SApple OSS Distributions STACKSHOT_SAVE_IMP_DONATION_PIDS | 74*a325d9c4SApple OSS Distributions STACKSHOT_KCDATA_FORMAT; 75*a325d9c4SApple OSS Distributions 76*a325d9c4SApple OSS Distributions if (since_timestamp != 0) 77*a325d9c4SApple OSS Distributions stackshot_flags |= STACKSHOT_COLLECT_DELTA_SNAPSHOT; 78*a325d9c4SApple OSS Distributions 79*a325d9c4SApple OSS Distributions stackshot_flags |= extra_flags; 80*a325d9c4SApple OSS Distributions 81*a325d9c4SApple OSS Distributions stackshot = stackshot_config_create(); 82*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(stackshot, "Allocating stackshot config"); 83*a325d9c4SApple OSS Distributions 84*a325d9c4SApple OSS Distributions ret = stackshot_config_set_flags(stackshot, stackshot_flags); 85*a325d9c4SApple OSS Distributions T_ASSERT_POSIX_ZERO(ret, "Setting flags on stackshot config"); 86*a325d9c4SApple OSS Distributions 87*a325d9c4SApple OSS Distributions ret = stackshot_config_set_pid(stackshot, getpid()); 88*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Setting target pid on stackshot config"); 89*a325d9c4SApple OSS Distributions 90*a325d9c4SApple OSS Distributions if (since_timestamp != 0) { 91*a325d9c4SApple OSS Distributions ret = stackshot_config_set_delta_timestamp(stackshot, since_timestamp); 92*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Setting prev snapshot time on stackshot config"); 93*a325d9c4SApple OSS Distributions } 94*a325d9c4SApple OSS Distributions 95*a325d9c4SApple OSS Distributions for (int retries = NUMRETRIES; retries > 0; retries--) { 96*a325d9c4SApple OSS Distributions ret = stackshot_capture_with_config(stackshot); 97*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(ret == 0 || ret == EBUSY || ret == ETIMEDOUT, 98*a325d9c4SApple OSS Distributions "Attempting to take stackshot (error %d)...", ret); 99*a325d9c4SApple OSS Distributions if (retries == 0 && (ret == EBUSY || ret == ETIMEDOUT)) 100*a325d9c4SApple OSS Distributions T_ASSERT_FAIL("Failed to take stackshot after %d retries: got %d (%s)", NUMRETRIES, ret, strerror(ret)); 101*a325d9c4SApple OSS Distributions if (ret == 0) 102*a325d9c4SApple OSS Distributions break; 103*a325d9c4SApple OSS Distributions } 104*a325d9c4SApple OSS Distributions return stackshot; 105*a325d9c4SApple OSS Distributions} 106*a325d9c4SApple OSS Distributions 107*a325d9c4SApple OSS Distributionsstatic void 108*a325d9c4SApple OSS Distributionssave_stackshot(void *stackshot, const char *filename) 109*a325d9c4SApple OSS Distributions{ 110*a325d9c4SApple OSS Distributions void *buf = stackshot_config_get_stackshot_buffer(stackshot); 111*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(buf, "buf"); 112*a325d9c4SApple OSS Distributions size_t size = stackshot_config_get_stackshot_size(stackshot); 113*a325d9c4SApple OSS Distributions FILE *f = fopen(filename, "w"); 114*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(f, "f"); 115*a325d9c4SApple OSS Distributions fwrite(buf, size, 1, f); 116*a325d9c4SApple OSS Distributions fclose(f); 117*a325d9c4SApple OSS Distributions} 118*a325d9c4SApple OSS Distributions 119*a325d9c4SApple OSS Distributionsstatic 120*a325d9c4SApple OSS Distributionsvoid check_python(void *stackshot, const char *fmt, ...) 121*a325d9c4SApple OSS Distributions{ 122*a325d9c4SApple OSS Distributions save_stackshot(stackshot, "/tmp/ss"); 123*a325d9c4SApple OSS Distributions 124*a325d9c4SApple OSS Distributions#if !(TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR) 125*a325d9c4SApple OSS Distributions va_list args; 126*a325d9c4SApple OSS Distributions va_start(args, fmt); 127*a325d9c4SApple OSS Distributions char *re_string = NULL; 128*a325d9c4SApple OSS Distributions vasprintf(&re_string, fmt, args); 129*a325d9c4SApple OSS Distributions va_end(args); 130*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(re_string, "vasprintf"); 131*a325d9c4SApple OSS Distributions 132*a325d9c4SApple OSS Distributions const char *pcreErrorStr; 133*a325d9c4SApple OSS Distributions int pcreErrorOffset; 134*a325d9c4SApple OSS Distributions pcre *re = pcre_compile(re_string, 0, &pcreErrorStr, &pcreErrorOffset, NULL); 135*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(re, "pcre_compile"); 136*a325d9c4SApple OSS Distributions 137*a325d9c4SApple OSS Distributions bool found = false; 138*a325d9c4SApple OSS Distributions FILE *p = popen("/usr/local/bin/kcdata --pretty /tmp/ss", "r"); 139*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(p, "popen"); 140*a325d9c4SApple OSS Distributions while (1) { 141*a325d9c4SApple OSS Distributions char *line = NULL; 142*a325d9c4SApple OSS Distributions size_t linecap = 0; 143*a325d9c4SApple OSS Distributions ssize_t linesize = getline(&line, &linecap, p); 144*a325d9c4SApple OSS Distributions if (linesize < 0) { 145*a325d9c4SApple OSS Distributions if (line) 146*a325d9c4SApple OSS Distributions free(line); 147*a325d9c4SApple OSS Distributions break; 148*a325d9c4SApple OSS Distributions } 149*a325d9c4SApple OSS Distributions int pcre_ret = pcre_exec(re, NULL, line, strlen(line), 0, 0, NULL, 0); 150*a325d9c4SApple OSS Distributions if (pcre_ret == 0){ 151*a325d9c4SApple OSS Distributions T_LOG("line: %s", line); 152*a325d9c4SApple OSS Distributions found = true; 153*a325d9c4SApple OSS Distributions } 154*a325d9c4SApple OSS Distributions free(line); 155*a325d9c4SApple OSS Distributions } 156*a325d9c4SApple OSS Distributions T_EXPECT_TRUE(found, "found the waitinfo in kcdata.py output"); 157*a325d9c4SApple OSS Distributions pclose(p); 158*a325d9c4SApple OSS Distributions pcre_free(re); 159*a325d9c4SApple OSS Distributions free(re_string); 160*a325d9c4SApple OSS Distributions#endif 161*a325d9c4SApple OSS Distributions} 162*a325d9c4SApple OSS Distributions 163*a325d9c4SApple OSS Distributions 164*a325d9c4SApple OSS Distributions// waitinfo can be NULL, but len must be non-null and point to the length of the waitinfo array. 165*a325d9c4SApple OSS Distributions// when the function returns, len will be set to the number of waitinfo structs found in the stackshot. 166*a325d9c4SApple OSS Distributionsstatic void 167*a325d9c4SApple OSS Distributionsfind_blocking_info(void * stackshot, struct stackshot_thread_waitinfo *waitinfo, int *len) 168*a325d9c4SApple OSS Distributions{ 169*a325d9c4SApple OSS Distributions void *buf = NULL; 170*a325d9c4SApple OSS Distributions uint32_t t = 0; 171*a325d9c4SApple OSS Distributions uint32_t buflen = 0; 172*a325d9c4SApple OSS Distributions NSError *error = nil; 173*a325d9c4SApple OSS Distributions NSMutableDictionary *parsed_container = nil; 174*a325d9c4SApple OSS Distributions NSArray *parsed_waitinfo = nil; 175*a325d9c4SApple OSS Distributions 176*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(len, "Length pointer shouldn't be NULL"); 177*a325d9c4SApple OSS Distributions int oldlen = *len; 178*a325d9c4SApple OSS Distributions *len = 0; 179*a325d9c4SApple OSS Distributions 180*a325d9c4SApple OSS Distributions buf = stackshot_config_get_stackshot_buffer(stackshot); 181*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_NOTNULL(buf, "Getting stackshot buffer"); 182*a325d9c4SApple OSS Distributions buflen = stackshot_config_get_stackshot_size(stackshot); 183*a325d9c4SApple OSS Distributions 184*a325d9c4SApple OSS Distributions kcdata_iter_t iter = kcdata_iter(buf, buflen); 185*a325d9c4SApple OSS Distributions 186*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(kcdata_iter_type(iter) == KCDATA_BUFFER_BEGIN_STACKSHOT || 187*a325d9c4SApple OSS Distributions kcdata_iter_type(iter) == KCDATA_BUFFER_BEGIN_DELTA_STACKSHOT, 188*a325d9c4SApple OSS Distributions "Checking start of stackshot buffer"); 189*a325d9c4SApple OSS Distributions 190*a325d9c4SApple OSS Distributions iter = kcdata_iter_next(iter); 191*a325d9c4SApple OSS Distributions KCDATA_ITER_FOREACH(iter) 192*a325d9c4SApple OSS Distributions { 193*a325d9c4SApple OSS Distributions t = kcdata_iter_type(iter); 194*a325d9c4SApple OSS Distributions 195*a325d9c4SApple OSS Distributions if (t != KCDATA_TYPE_CONTAINER_BEGIN) { 196*a325d9c4SApple OSS Distributions continue; 197*a325d9c4SApple OSS Distributions } 198*a325d9c4SApple OSS Distributions 199*a325d9c4SApple OSS Distributions if (kcdata_iter_container_type(iter) != STACKSHOT_KCCONTAINER_TASK) { 200*a325d9c4SApple OSS Distributions continue; 201*a325d9c4SApple OSS Distributions } 202*a325d9c4SApple OSS Distributions 203*a325d9c4SApple OSS Distributions parsed_container = parseKCDataContainer(&iter, &error); 204*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(!error, "Error while parsing container: %d (%s)", 205*a325d9c4SApple OSS Distributions (int)error.code, [error.domain UTF8String]); 206*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_TRUE(parsed_container && !error, "Parsing container"); 207*a325d9c4SApple OSS Distributions 208*a325d9c4SApple OSS Distributions parsed_waitinfo = parsed_container[@"task_snapshots"][@"thread_waitinfo"]; 209*a325d9c4SApple OSS Distributions for (id elem in parsed_waitinfo) { 210*a325d9c4SApple OSS Distributions /* check to see that tid matches expected idle status */ 211*a325d9c4SApple OSS Distributions uint8_t type = [elem[@"wait_type"] unsignedCharValue]; 212*a325d9c4SApple OSS Distributions if (type != kThreadWaitNone) { 213*a325d9c4SApple OSS Distributions if (waitinfo && *len < oldlen) { 214*a325d9c4SApple OSS Distributions struct stackshot_thread_waitinfo *curr = &waitinfo[*len]; 215*a325d9c4SApple OSS Distributions curr->wait_type = type; 216*a325d9c4SApple OSS Distributions curr->owner = [elem[@"owner"] unsignedLongLongValue]; 217*a325d9c4SApple OSS Distributions curr->waiter = [elem[@"waiter"] unsignedLongLongValue]; 218*a325d9c4SApple OSS Distributions curr->context = [elem[@"context"] unsignedLongLongValue]; 219*a325d9c4SApple OSS Distributions } 220*a325d9c4SApple OSS Distributions (*len)++; 221*a325d9c4SApple OSS Distributions } 222*a325d9c4SApple OSS Distributions } 223*a325d9c4SApple OSS Distributions [parsed_container release]; 224*a325d9c4SApple OSS Distributions } 225*a325d9c4SApple OSS Distributions} 226*a325d9c4SApple OSS Distributions 227*a325d9c4SApple OSS Distributions/* perform various actions with a mutex in kernel memory. note that, since we aren't allowed 228*a325d9c4SApple OSS Distributions * to go to user space while still holding a mutex, the lock-acquiring actions in this kernel 229*a325d9c4SApple OSS Distributions * sysctl will either lock and immediately release the lock, or lock and wait until a semaphore 230*a325d9c4SApple OSS Distributions * is signalled, then unlock. if called with CHECK_EXISTS, returns whether or not the sysctl 231*a325d9c4SApple OSS Distributions * exist in the kernel (to determine if we're running with CONFIG_XNUPOST defined). Else, 232*a325d9c4SApple OSS Distributions * returns 1. */ 233*a325d9c4SApple OSS Distributionsstatic int kmutex_action(int action) 234*a325d9c4SApple OSS Distributions{ 235*a325d9c4SApple OSS Distributions int ret = 0; 236*a325d9c4SApple OSS Distributions if (action == KMUTEX_SYSCTL_CHECK_EXISTS) { 237*a325d9c4SApple OSS Distributions ret = sysctlbyname(krwlck_ctl, NULL, NULL, NULL, 0); 238*a325d9c4SApple OSS Distributions return !(ret == -1); 239*a325d9c4SApple OSS Distributions } 240*a325d9c4SApple OSS Distributions 241*a325d9c4SApple OSS Distributions char * action_name = ""; 242*a325d9c4SApple OSS Distributions switch(action) { 243*a325d9c4SApple OSS Distributions case KMUTEX_SYSCTL_ACQUIRE_WAIT: 244*a325d9c4SApple OSS Distributions action_name = "lock (and wait)"; 245*a325d9c4SApple OSS Distributions break; 246*a325d9c4SApple OSS Distributions case KMUTEX_SYSCTL_ACQUIRE_NOWAIT: 247*a325d9c4SApple OSS Distributions action_name = "lock"; 248*a325d9c4SApple OSS Distributions break; 249*a325d9c4SApple OSS Distributions case KMUTEX_SYSCTL_SIGNAL: 250*a325d9c4SApple OSS Distributions action_name = "signal to holder of"; 251*a325d9c4SApple OSS Distributions break; 252*a325d9c4SApple OSS Distributions case KMUTEX_SYSCTL_TEARDOWN: 253*a325d9c4SApple OSS Distributions action_name = "tear down"; 254*a325d9c4SApple OSS Distributions break; 255*a325d9c4SApple OSS Distributions default: 256*a325d9c4SApple OSS Distributions T_ASSERT_FAIL("Somebody passed the wrong argument to kmutex_action: %d", action); 257*a325d9c4SApple OSS Distributions break; 258*a325d9c4SApple OSS Distributions } 259*a325d9c4SApple OSS Distributions 260*a325d9c4SApple OSS Distributions ret = sysctlbyname(kmutex_ctl, NULL, NULL, &action, sizeof(int)); 261*a325d9c4SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "sysctl: %s kernel mutex", action_name); 262*a325d9c4SApple OSS Distributions return 1; 263*a325d9c4SApple OSS Distributions} 264*a325d9c4SApple OSS Distributions 265*a325d9c4SApple OSS Distributionsstatic void 266*a325d9c4SApple OSS Distributionssysctl_kmutex_test_match(uint64_t context) 267*a325d9c4SApple OSS Distributions{ 268*a325d9c4SApple OSS Distributions int ret = 0; 269*a325d9c4SApple OSS Distributions unsigned long long unslid_kmutex_address = 0; 270*a325d9c4SApple OSS Distributions size_t addrsize = sizeof(unslid_kmutex_address); 271*a325d9c4SApple OSS Distributions 272*a325d9c4SApple OSS Distributions ret = sysctlbyname(kmutex_ctl, &unslid_kmutex_address, &addrsize, NULL, 0); 273*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "Getting unslid location of kernel mutex. Size is %llu", 274*a325d9c4SApple OSS Distributions (unsigned long long)addrsize); 275*a325d9c4SApple OSS Distributions T_EXPECT_EQ(context, unslid_kmutex_address, 276*a325d9c4SApple OSS Distributions "Context should match unslid location of mutex in kernel memory"); 277*a325d9c4SApple OSS Distributions} 278*a325d9c4SApple OSS Distributions 279*a325d9c4SApple OSS Distributions/* We don't really care what goes into these messages, we're just sending something to a port. */ 280*a325d9c4SApple OSS Distributionsstatic void 281*a325d9c4SApple OSS Distributionsmsg_send_helper(mach_port_t remote_port) 282*a325d9c4SApple OSS Distributions{ 283*a325d9c4SApple OSS Distributions int ret; 284*a325d9c4SApple OSS Distributions mach_msg_header_t * msg = NULL; 285*a325d9c4SApple OSS Distributions 286*a325d9c4SApple OSS Distributions ret = vm_allocate(mach_task_self(), 287*a325d9c4SApple OSS Distributions (vm_address_t *)&msg, 288*a325d9c4SApple OSS Distributions PAGE_SIZE, 289*a325d9c4SApple OSS Distributions VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | TRUE); 290*a325d9c4SApple OSS Distributions 291*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Allocating vm page %p", (void*)msg); 292*a325d9c4SApple OSS Distributions msg->msgh_bits = MACH_MSGH_BITS_SET(MACH_MSG_TYPE_COPY_SEND, 0, 0, 0); 293*a325d9c4SApple OSS Distributions msg->msgh_size = PAGE_SIZE; 294*a325d9c4SApple OSS Distributions msg->msgh_remote_port = remote_port; 295*a325d9c4SApple OSS Distributions msg->msgh_local_port = MACH_PORT_NULL; 296*a325d9c4SApple OSS Distributions msg->msgh_voucher_port = MACH_PORT_NULL; 297*a325d9c4SApple OSS Distributions ret = mach_msg(msg, 298*a325d9c4SApple OSS Distributions MACH_SEND_MSG | MACH_MSG_OPTION_NONE, 299*a325d9c4SApple OSS Distributions PAGE_SIZE, 300*a325d9c4SApple OSS Distributions 0, 301*a325d9c4SApple OSS Distributions MACH_PORT_NULL, 302*a325d9c4SApple OSS Distributions MACH_MSG_TIMEOUT_NONE, 303*a325d9c4SApple OSS Distributions MACH_PORT_NULL); 304*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Sending message to port %d", remote_port); 305*a325d9c4SApple OSS Distributions 306*a325d9c4SApple OSS Distributions vm_deallocate(mach_task_self(), (vm_address_t)msg, PAGE_SIZE); 307*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Deallocating vm page %p", (void*)msg); 308*a325d9c4SApple OSS Distributions} 309*a325d9c4SApple OSS Distributions 310*a325d9c4SApple OSS Distributionsstatic void 311*a325d9c4SApple OSS Distributionsmsg_recv_helper(mach_port_t local_port) 312*a325d9c4SApple OSS Distributions{ 313*a325d9c4SApple OSS Distributions int ret = 0; 314*a325d9c4SApple OSS Distributions mach_msg_size_t size = 2*PAGE_SIZE; 315*a325d9c4SApple OSS Distributions mach_msg_header_t * msg = NULL; 316*a325d9c4SApple OSS Distributions ret = vm_allocate(mach_task_self(), 317*a325d9c4SApple OSS Distributions (vm_address_t *)&msg, 318*a325d9c4SApple OSS Distributions size, 319*a325d9c4SApple OSS Distributions VM_MAKE_TAG(VM_MEMORY_MACH_MSG) | TRUE ); 320*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Allocating page %p for message", (void*)msg); 321*a325d9c4SApple OSS Distributions 322*a325d9c4SApple OSS Distributions ret = mach_msg(msg, 323*a325d9c4SApple OSS Distributions MACH_RCV_MSG, 324*a325d9c4SApple OSS Distributions 0, 325*a325d9c4SApple OSS Distributions size, 326*a325d9c4SApple OSS Distributions local_port, 327*a325d9c4SApple OSS Distributions MACH_MSG_TIMEOUT_NONE, 328*a325d9c4SApple OSS Distributions MACH_PORT_NULL); 329*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Received message on port %d", local_port); 330*a325d9c4SApple OSS Distributions ret = vm_deallocate(mach_task_self(), (vm_address_t)msg, PAGE_SIZE); 331*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Deallocating page %p", (void*)msg); 332*a325d9c4SApple OSS Distributions} 333*a325d9c4SApple OSS Distributions 334*a325d9c4SApple OSS Distributions/* perform various actions with a rwlock in kernel memory. note that, since we aren't allowed 335*a325d9c4SApple OSS Distributions * to go to user space while still holding a rwlock, the lock-acquiring actions in this kernel 336*a325d9c4SApple OSS Distributions * sysctl will either lock and immediately release the lock, or lock and wait until a semaphore 337*a325d9c4SApple OSS Distributions * is signalled, then unlock. if called with CHECK_EXISTS, returns whether or not the sysctl 338*a325d9c4SApple OSS Distributions * exist in the kernel (to determine if we're running with CONFIG_XNUPOST defined). Else, 339*a325d9c4SApple OSS Distributions * returns 1. */ 340*a325d9c4SApple OSS Distributionsstatic int 341*a325d9c4SApple OSS Distributionskrwlck_action(int action) 342*a325d9c4SApple OSS Distributions{ 343*a325d9c4SApple OSS Distributions int ret = 0; 344*a325d9c4SApple OSS Distributions if (action == KRWLCK_SYSCTL_CHECK_EXISTS) { 345*a325d9c4SApple OSS Distributions ret = sysctlbyname(krwlck_ctl, NULL, NULL, NULL, 0); 346*a325d9c4SApple OSS Distributions return !(ret == -1); 347*a325d9c4SApple OSS Distributions } 348*a325d9c4SApple OSS Distributions 349*a325d9c4SApple OSS Distributions char * action_name = ""; 350*a325d9c4SApple OSS Distributions switch(action) { 351*a325d9c4SApple OSS Distributions case KRWLCK_SYSCTL_RACQUIRE_NOWAIT: 352*a325d9c4SApple OSS Distributions action_name = "shared lock"; 353*a325d9c4SApple OSS Distributions break; 354*a325d9c4SApple OSS Distributions case KRWLCK_SYSCTL_RACQUIRE_WAIT: 355*a325d9c4SApple OSS Distributions action_name = "shared lock (and wait)"; 356*a325d9c4SApple OSS Distributions break; 357*a325d9c4SApple OSS Distributions case KRWLCK_SYSCTL_WACQUIRE_NOWAIT: 358*a325d9c4SApple OSS Distributions action_name = "exclusive lock"; 359*a325d9c4SApple OSS Distributions break; 360*a325d9c4SApple OSS Distributions case KRWLCK_SYSCTL_WACQUIRE_WAIT: 361*a325d9c4SApple OSS Distributions action_name = "exclusive lock (and wait)"; 362*a325d9c4SApple OSS Distributions break; 363*a325d9c4SApple OSS Distributions case KRWLCK_SYSCTL_SIGNAL: 364*a325d9c4SApple OSS Distributions action_name = "signal to holder of"; 365*a325d9c4SApple OSS Distributions break; 366*a325d9c4SApple OSS Distributions case KRWLCK_SYSCTL_TEARDOWN: 367*a325d9c4SApple OSS Distributions action_name = "tear down"; 368*a325d9c4SApple OSS Distributions break; 369*a325d9c4SApple OSS Distributions default: 370*a325d9c4SApple OSS Distributions T_ASSERT_FAIL("Somebody passed the wrong argument to krwlck_action: %d", action); 371*a325d9c4SApple OSS Distributions break; 372*a325d9c4SApple OSS Distributions } 373*a325d9c4SApple OSS Distributions 374*a325d9c4SApple OSS Distributions ret = sysctlbyname(krwlck_ctl, NULL, NULL, &action, sizeof(int)); 375*a325d9c4SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "sysctl: %s kernel rwlock", action_name); 376*a325d9c4SApple OSS Distributions return 1; 377*a325d9c4SApple OSS Distributions} 378*a325d9c4SApple OSS Distributions 379*a325d9c4SApple OSS Distributionsstatic void 380*a325d9c4SApple OSS Distributionssysctl_krwlck_test_match(uint64_t context) 381*a325d9c4SApple OSS Distributions{ 382*a325d9c4SApple OSS Distributions int ret = 0; 383*a325d9c4SApple OSS Distributions unsigned long long unslid_krwlck_address = 0; 384*a325d9c4SApple OSS Distributions size_t addrsize = sizeof(unslid_krwlck_address); 385*a325d9c4SApple OSS Distributions 386*a325d9c4SApple OSS Distributions ret = sysctlbyname(krwlck_ctl, &unslid_krwlck_address, &addrsize, NULL, 0); 387*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "Getting unslid location of kernel rwlock"); 388*a325d9c4SApple OSS Distributions T_EXPECT_EQ(context, unslid_krwlck_address, "Context should match unslid location of rwlock in kernel memory"); 389*a325d9c4SApple OSS Distributions} 390*a325d9c4SApple OSS Distributions 391*a325d9c4SApple OSS Distributions/* "Grabbing" threads: only purpose is to grab a sync primitive and hang. */ 392*a325d9c4SApple OSS Distributions 393*a325d9c4SApple OSS Distributionsstatic void * 394*a325d9c4SApple OSS Distributionskmutex_grabbing_thread(void * arg) 395*a325d9c4SApple OSS Distributions{ 396*a325d9c4SApple OSS Distributions (void)arg; 397*a325d9c4SApple OSS Distributions kmutex_action(KMUTEX_SYSCTL_ACQUIRE_NOWAIT); 398*a325d9c4SApple OSS Distributions return NULL; 399*a325d9c4SApple OSS Distributions} 400*a325d9c4SApple OSS Distributions 401*a325d9c4SApple OSS Distributionsstatic void * 402*a325d9c4SApple OSS Distributionskmutex_grab_and_wait_thread(void * arg) 403*a325d9c4SApple OSS Distributions{ 404*a325d9c4SApple OSS Distributions (void)arg; 405*a325d9c4SApple OSS Distributions kmutex_action(KMUTEX_SYSCTL_ACQUIRE_WAIT); 406*a325d9c4SApple OSS Distributions return NULL; 407*a325d9c4SApple OSS Distributions} 408*a325d9c4SApple OSS Distributions 409*a325d9c4SApple OSS Distributionsstatic void * 410*a325d9c4SApple OSS Distributionssem_grabbing_thread(void * arg) 411*a325d9c4SApple OSS Distributions{ 412*a325d9c4SApple OSS Distributions semaphore_t *sem = (semaphore_t *)arg; 413*a325d9c4SApple OSS Distributions semaphore_wait(*sem); 414*a325d9c4SApple OSS Distributions return NULL; 415*a325d9c4SApple OSS Distributions} 416*a325d9c4SApple OSS Distributions 417*a325d9c4SApple OSS Distributionsstatic void * 418*a325d9c4SApple OSS Distributionsmsg_blocking_thread(void * arg) 419*a325d9c4SApple OSS Distributions{ 420*a325d9c4SApple OSS Distributions (void)arg; 421*a325d9c4SApple OSS Distributions msg_recv_helper(send); 422*a325d9c4SApple OSS Distributions 423*a325d9c4SApple OSS Distributions for (int i = 0; i < SENDS_TO_BLOCK; i++) 424*a325d9c4SApple OSS Distributions msg_send_helper(recv); // will block on send until message is received 425*a325d9c4SApple OSS Distributions return NULL; 426*a325d9c4SApple OSS Distributions} 427*a325d9c4SApple OSS Distributions 428*a325d9c4SApple OSS Distributionsstatic void * 429*a325d9c4SApple OSS Distributionsulock_blocking_thread(void * arg) 430*a325d9c4SApple OSS Distributions{ 431*a325d9c4SApple OSS Distributions os_unfair_lock_t oul = (os_unfair_lock_t)arg; 432*a325d9c4SApple OSS Distributions os_unfair_lock_lock(oul); 433*a325d9c4SApple OSS Distributions os_unfair_lock_unlock(oul); 434*a325d9c4SApple OSS Distributions return NULL; 435*a325d9c4SApple OSS Distributions} 436*a325d9c4SApple OSS Distributions 437*a325d9c4SApple OSS Distributions// acquires a kernel rwlock for writing, and then waits on a kernel semaphore. 438*a325d9c4SApple OSS Distributionsstatic void * 439*a325d9c4SApple OSS Distributionskrwlck_write_waiting_thread(void * arg) 440*a325d9c4SApple OSS Distributions{ 441*a325d9c4SApple OSS Distributions (void)arg; 442*a325d9c4SApple OSS Distributions krwlck_action(KRWLCK_SYSCTL_WACQUIRE_WAIT); 443*a325d9c4SApple OSS Distributions return NULL; 444*a325d9c4SApple OSS Distributions} 445*a325d9c4SApple OSS Distributions 446*a325d9c4SApple OSS Distributions// attempts to acquire a kernel rwlock for reading, and doesn't wait on a semaphore afterwards. 447*a325d9c4SApple OSS Distributionsstatic void * 448*a325d9c4SApple OSS Distributionskrwlck_read_grabbing_thread(void * arg) 449*a325d9c4SApple OSS Distributions{ 450*a325d9c4SApple OSS Distributions (void)arg; 451*a325d9c4SApple OSS Distributions krwlck_action(KRWLCK_SYSCTL_RACQUIRE_NOWAIT); 452*a325d9c4SApple OSS Distributions return NULL; 453*a325d9c4SApple OSS Distributions} 454*a325d9c4SApple OSS Distributions 455*a325d9c4SApple OSS Distributionsstatic void * 456*a325d9c4SApple OSS Distributionspthread_mutex_blocking_thread(void * arg) 457*a325d9c4SApple OSS Distributions{ 458*a325d9c4SApple OSS Distributions pthread_mutex_t *mtx = (pthread_mutex_t *)arg; 459*a325d9c4SApple OSS Distributions pthread_mutex_lock(mtx); 460*a325d9c4SApple OSS Distributions pthread_mutex_unlock(mtx); 461*a325d9c4SApple OSS Distributions return NULL; 462*a325d9c4SApple OSS Distributions} 463*a325d9c4SApple OSS Distributions 464*a325d9c4SApple OSS Distributionsstatic void * 465*a325d9c4SApple OSS Distributionspthread_rwlck_blocking_thread(void * arg) 466*a325d9c4SApple OSS Distributions{ 467*a325d9c4SApple OSS Distributions pthread_rwlock_t *rwlck = (pthread_rwlock_t *)arg; 468*a325d9c4SApple OSS Distributions pthread_rwlock_rdlock(rwlck); 469*a325d9c4SApple OSS Distributions pthread_rwlock_unlock(rwlck); 470*a325d9c4SApple OSS Distributions return NULL; 471*a325d9c4SApple OSS Distributions} 472*a325d9c4SApple OSS Distributions 473*a325d9c4SApple OSS Distributionsstatic void * 474*a325d9c4SApple OSS Distributionspthread_cond_blocking_thread(void * arg) 475*a325d9c4SApple OSS Distributions{ 476*a325d9c4SApple OSS Distributions pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; 477*a325d9c4SApple OSS Distributions pthread_cond_t *cond = (pthread_cond_t *)arg; 478*a325d9c4SApple OSS Distributions pthread_cond_wait(cond, &mtx); 479*a325d9c4SApple OSS Distributions pthread_mutex_unlock(&mtx); 480*a325d9c4SApple OSS Distributions return NULL; 481*a325d9c4SApple OSS Distributions} 482*a325d9c4SApple OSS Distributions 483*a325d9c4SApple OSS Distributionsstatic void * 484*a325d9c4SApple OSS Distributionswaitpid_blocking_thread(void * arg) 485*a325d9c4SApple OSS Distributions{ 486*a325d9c4SApple OSS Distributions pid_t pid = (pid_t)arg; 487*a325d9c4SApple OSS Distributions 488*a325d9c4SApple OSS Distributions int ret = waitpid(pid, NULL, 0); 489*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "Reaping child."); 490*a325d9c4SApple OSS Distributions return NULL; 491*a325d9c4SApple OSS Distributions} 492*a325d9c4SApple OSS Distributions 493*a325d9c4SApple OSS Distributions/* 494*a325d9c4SApple OSS Distributions * Uses a debug sysctl to initialize a kernel mutex. 495*a325d9c4SApple OSS Distributions * 496*a325d9c4SApple OSS Distributions * The 'waiting' thread grabs this kernel mutex, and immediately waits on a kernel semaphore. 497*a325d9c4SApple OSS Distributions * The 'grabbing' thread just attempts to lock the kernel mutex. 498*a325d9c4SApple OSS Distributions * When the semaphore is signalled, the 'waiting' thread will unlock the kernel mutex, 499*a325d9c4SApple OSS Distributions * giving the opportunity for the 'grabbing' thread to lock it and then immediately unlock it. 500*a325d9c4SApple OSS Distributions * This allows us to create a situation in the kernel where we know a thread to be blocked 501*a325d9c4SApple OSS Distributions * on a kernel mutex. 502*a325d9c4SApple OSS Distributions */ 503*a325d9c4SApple OSS Distributionsstatic void 504*a325d9c4SApple OSS Distributionstest_kmutex_blocking(void) 505*a325d9c4SApple OSS Distributions{ 506*a325d9c4SApple OSS Distributions int ret = 0; 507*a325d9c4SApple OSS Distributions int len = 2; 508*a325d9c4SApple OSS Distributions struct stackshot_thread_waitinfo waitinfo[2] = { { 0 }, { 0 } }; 509*a325d9c4SApple OSS Distributions uint64_t thread_id = 0; 510*a325d9c4SApple OSS Distributions pthread_t grabbing, waiting; 511*a325d9c4SApple OSS Distributions 512*a325d9c4SApple OSS Distributions T_LOG("Starting %s", __FUNCTION__); 513*a325d9c4SApple OSS Distributions ret = pthread_create(&waiting, NULL, kmutex_grab_and_wait_thread, NULL); // thread will block until we signal it 514*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Spawning grab and wait thread"); 515*a325d9c4SApple OSS Distributions sleep(1); // give time for thread to block 516*a325d9c4SApple OSS Distributions ret = pthread_create(&grabbing, NULL, kmutex_grabbing_thread, NULL); // thread should immediately block 517*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Spawning waiting thread"); 518*a325d9c4SApple OSS Distributions sleep(3); // give (lots of) time for thread to give up spinning on lock 519*a325d9c4SApple OSS Distributions 520*a325d9c4SApple OSS Distributions void * stackshot = take_stackshot(STACKSHOT_THREAD_WAITINFO, 0); 521*a325d9c4SApple OSS Distributions 522*a325d9c4SApple OSS Distributions ret = pthread_threadid_np(waiting, &thread_id); // this is the thread that currently holds the kernel mutex 523*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Getting integer value of thread id"); 524*a325d9c4SApple OSS Distributions 525*a325d9c4SApple OSS Distributions check_python(stackshot, "thread \\d+: semaphore port \\w+ with unknown owner"); 526*a325d9c4SApple OSS Distributions 527*a325d9c4SApple OSS Distributions find_blocking_info(stackshot, (struct stackshot_thread_waitinfo *)&waitinfo, &len); 528*a325d9c4SApple OSS Distributions 529*a325d9c4SApple OSS Distributions T_EXPECT_EQ(len, 2, "There should only be two blocking threads"); 530*a325d9c4SApple OSS Distributions for (int i = 0; i < len; i++) { 531*a325d9c4SApple OSS Distributions struct stackshot_thread_waitinfo *curr = &waitinfo[i]; 532*a325d9c4SApple OSS Distributions if (curr->wait_type == kThreadWaitSemaphore) 533*a325d9c4SApple OSS Distributions continue; 534*a325d9c4SApple OSS Distributions T_EXPECT_EQ(curr->wait_type, kThreadWaitKernelMutex, "Wait type should match expected KernelMutex value"); 535*a325d9c4SApple OSS Distributions T_EXPECT_EQ(curr->owner, thread_id, "Thread ID of blocking thread should match 'owner' field in stackshot"); 536*a325d9c4SApple OSS Distributions sysctl_kmutex_test_match(curr->context); 537*a325d9c4SApple OSS Distributions 538*a325d9c4SApple OSS Distributions check_python(stackshot, "thread \\d+: kernel mutex %llx owned by thread %lld", curr->context, thread_id); 539*a325d9c4SApple OSS Distributions } 540*a325d9c4SApple OSS Distributions 541*a325d9c4SApple OSS Distributions kmutex_action(KMUTEX_SYSCTL_SIGNAL); // waiting thread should now unblock. 542*a325d9c4SApple OSS Distributions ret = pthread_join(waiting, NULL); 543*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Joining on waiting thread"); 544*a325d9c4SApple OSS Distributions ret = pthread_join(grabbing, NULL); 545*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Joining on grabber thread"); 546*a325d9c4SApple OSS Distributions kmutex_action(KMUTEX_SYSCTL_TEARDOWN); 547*a325d9c4SApple OSS Distributions stackshot_config_dealloc(stackshot); 548*a325d9c4SApple OSS Distributions} 549*a325d9c4SApple OSS Distributions 550*a325d9c4SApple OSS Distributions/* Initialize a userspace semaphore, and spawn a thread to block on it. */ 551*a325d9c4SApple OSS Distributionsstatic void 552*a325d9c4SApple OSS Distributionstest_semaphore_blocking(void) 553*a325d9c4SApple OSS Distributions{ 554*a325d9c4SApple OSS Distributions int ret = 0; 555*a325d9c4SApple OSS Distributions semaphore_t sem; 556*a325d9c4SApple OSS Distributions struct stackshot_thread_waitinfo waitinfo = { 0 }; 557*a325d9c4SApple OSS Distributions int len = 1; 558*a325d9c4SApple OSS Distributions uint64_t pid = 0; 559*a325d9c4SApple OSS Distributions 560*a325d9c4SApple OSS Distributions T_LOG("Starting %s", __FUNCTION__); 561*a325d9c4SApple OSS Distributions ret = semaphore_create(mach_task_self(), &sem, SYNC_POLICY_FIFO, 0); 562*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Creating semaphore"); 563*a325d9c4SApple OSS Distributions pthread_t tid; 564*a325d9c4SApple OSS Distributions ret = pthread_create(&tid, NULL, sem_grabbing_thread, (void*)&sem); // thread should immediately block 565*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Creating semaphore grabbing thread"); 566*a325d9c4SApple OSS Distributions 567*a325d9c4SApple OSS Distributions sleep(1); // give time for thread to block 568*a325d9c4SApple OSS Distributions 569*a325d9c4SApple OSS Distributions void * stackshot = take_stackshot(STACKSHOT_THREAD_WAITINFO, 0); 570*a325d9c4SApple OSS Distributions find_blocking_info(stackshot, (struct stackshot_thread_waitinfo *)&waitinfo, &len); 571*a325d9c4SApple OSS Distributions T_EXPECT_EQ(len, 1, "Only one blocking thread should exist"); 572*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.wait_type, kThreadWaitSemaphore, "Wait type should match expected Semaphore value"); 573*a325d9c4SApple OSS Distributions 574*a325d9c4SApple OSS Distributions pid = (uint64_t)getpid(); 575*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.owner, pid, "Owner value should match process ID"); 576*a325d9c4SApple OSS Distributions 577*a325d9c4SApple OSS Distributions check_python(stackshot, "thread \\d+: semaphore port \\w+ owned by pid %d", (int)pid); 578*a325d9c4SApple OSS Distributions 579*a325d9c4SApple OSS Distributions ret = semaphore_signal(sem); 580*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Signalling semaphore"); 581*a325d9c4SApple OSS Distributions ret = pthread_join(tid, NULL); 582*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Joining on grabber thread"); 583*a325d9c4SApple OSS Distributions ret = semaphore_destroy(mach_task_self(), sem); 584*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Destroying semaphore"); 585*a325d9c4SApple OSS Distributions stackshot_config_dealloc(stackshot); 586*a325d9c4SApple OSS Distributions} 587*a325d9c4SApple OSS Distributions 588*a325d9c4SApple OSS Distributions/* Spawn a process to send a message to, and block while both sending and receiving in different contexts. */ 589*a325d9c4SApple OSS Distributionsstatic void 590*a325d9c4SApple OSS Distributionstest_mach_msg_blocking(void) 591*a325d9c4SApple OSS Distributions{ 592*a325d9c4SApple OSS Distributions int ret = 0; 593*a325d9c4SApple OSS Distributions pthread_t tid; 594*a325d9c4SApple OSS Distributions void *stackshot = NULL; 595*a325d9c4SApple OSS Distributions struct stackshot_thread_waitinfo waitinfo = { 0 }; 596*a325d9c4SApple OSS Distributions int len = 1; 597*a325d9c4SApple OSS Distributions 598*a325d9c4SApple OSS Distributions T_LOG("Starting %s", __FUNCTION__); 599*a325d9c4SApple OSS Distributions ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &send); 600*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Allocating send port"); 601*a325d9c4SApple OSS Distributions ret = mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &recv); 602*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Allocating recv port"); 603*a325d9c4SApple OSS Distributions ret = mach_port_insert_right(mach_task_self(), send, send, MACH_MSG_TYPE_MAKE_SEND); 604*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Getting send right to send port"); 605*a325d9c4SApple OSS Distributions ret = mach_port_insert_right(mach_task_self(), recv, recv, MACH_MSG_TYPE_MAKE_SEND); 606*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "Getting send right to recv port"); 607*a325d9c4SApple OSS Distributions 608*a325d9c4SApple OSS Distributions ret = pthread_create(&tid, NULL, msg_blocking_thread, (void*)&send); // thread should block on recv soon 609*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Creating message blocking thread"); 610*a325d9c4SApple OSS Distributions 611*a325d9c4SApple OSS Distributions sleep(1); // give time for thread to block 612*a325d9c4SApple OSS Distributions stackshot = take_stackshot(STACKSHOT_THREAD_WAITINFO, 0); 613*a325d9c4SApple OSS Distributions find_blocking_info(stackshot, (struct stackshot_thread_waitinfo *)&waitinfo, &len); 614*a325d9c4SApple OSS Distributions 615*a325d9c4SApple OSS Distributions T_EXPECT_EQ(len, 1, "Only one blocking thread should exist"); 616*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.wait_type, kThreadWaitPortReceive, "Wait type should match expected PortReceive value"); 617*a325d9c4SApple OSS Distributions 618*a325d9c4SApple OSS Distributions check_python(stackshot, "thread \\d+: mach_msg receive on port \\w+ name %llx", (long long)send); 619*a325d9c4SApple OSS Distributions 620*a325d9c4SApple OSS Distributions stackshot_config_dealloc(stackshot); 621*a325d9c4SApple OSS Distributions 622*a325d9c4SApple OSS Distributions msg_send_helper(send); // ping! msg_blocking_thread will now try to send us stuff, and block until we receive. 623*a325d9c4SApple OSS Distributions 624*a325d9c4SApple OSS Distributions sleep(1); // give time for thread to block 625*a325d9c4SApple OSS Distributions stackshot = take_stackshot(STACKSHOT_THREAD_WAITINFO, 0); 626*a325d9c4SApple OSS Distributions find_blocking_info(stackshot, (struct stackshot_thread_waitinfo *)&waitinfo, &len); 627*a325d9c4SApple OSS Distributions T_EXPECT_EQ(len, 1, "Only one blocking thread should exist"); 628*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.wait_type, kThreadWaitPortSend, "Wait type should match expected PortSend value"); 629*a325d9c4SApple OSS Distributions 630*a325d9c4SApple OSS Distributions check_python(stackshot, "thread \\d+: mach_msg send on port \\w+ owned by pid %d", (int)getpid()); 631*a325d9c4SApple OSS Distributions 632*a325d9c4SApple OSS Distributions stackshot_config_dealloc(stackshot); 633*a325d9c4SApple OSS Distributions 634*a325d9c4SApple OSS Distributions msg_recv_helper(recv); // thread should block until we receive one of its messages 635*a325d9c4SApple OSS Distributions ret = pthread_join(tid, NULL); 636*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Joining on blocking thread"); 637*a325d9c4SApple OSS Distributions} 638*a325d9c4SApple OSS Distributions 639*a325d9c4SApple OSS Distributionsstatic void 640*a325d9c4SApple OSS Distributionstest_ulock_blocking(void) 641*a325d9c4SApple OSS Distributions{ 642*a325d9c4SApple OSS Distributions int ret = 0; 643*a325d9c4SApple OSS Distributions void *stackshot = NULL; 644*a325d9c4SApple OSS Distributions uint64_t thread_id = 0; 645*a325d9c4SApple OSS Distributions pthread_t tid; 646*a325d9c4SApple OSS Distributions struct os_unfair_lock_s ouls = OS_UNFAIR_LOCK_INIT; 647*a325d9c4SApple OSS Distributions os_unfair_lock_t oul = &ouls; 648*a325d9c4SApple OSS Distributions struct stackshot_thread_waitinfo waitinfo = { 0 }; 649*a325d9c4SApple OSS Distributions int len = 1; 650*a325d9c4SApple OSS Distributions 651*a325d9c4SApple OSS Distributions T_LOG("Starting %s", __FUNCTION__); 652*a325d9c4SApple OSS Distributions os_unfair_lock_lock(oul); 653*a325d9c4SApple OSS Distributions ret = pthread_create(&tid, NULL, ulock_blocking_thread, (void*)oul); 654*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Creating ulock blocking thread"); 655*a325d9c4SApple OSS Distributions sleep(3); // give time for thread to spawn, fall back to kernel for contention, and block 656*a325d9c4SApple OSS Distributions 657*a325d9c4SApple OSS Distributions stackshot = take_stackshot(STACKSHOT_THREAD_WAITINFO, 0); 658*a325d9c4SApple OSS Distributions 659*a325d9c4SApple OSS Distributions find_blocking_info(stackshot, (struct stackshot_thread_waitinfo *)&waitinfo, &len); 660*a325d9c4SApple OSS Distributions T_EXPECT_EQ(len, 1, "Only one blocking thread should exist"); 661*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.wait_type, kThreadWaitUserLock, "Wait type should match expected UserLock value"); 662*a325d9c4SApple OSS Distributions 663*a325d9c4SApple OSS Distributions os_unfair_lock_unlock(oul); 664*a325d9c4SApple OSS Distributions ret = pthread_join(tid, NULL); // wait for thread to unblock and exit 665*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Joining on blocking thread"); 666*a325d9c4SApple OSS Distributions 667*a325d9c4SApple OSS Distributions ret = pthread_threadid_np(NULL, &thread_id); // this thread is the "owner" of the ulock 668*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Getting integer value of thread id"); 669*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.owner, thread_id, "Thread ID of blocking thread should match 'owner' field in stackshot"); 670*a325d9c4SApple OSS Distributions 671*a325d9c4SApple OSS Distributions check_python(stackshot, "thread \\d+: unfair lock \\w+ owned by thread %lld", thread_id); 672*a325d9c4SApple OSS Distributions stackshot_config_dealloc(stackshot); 673*a325d9c4SApple OSS Distributions return; 674*a325d9c4SApple OSS Distributions} 675*a325d9c4SApple OSS Distributions 676*a325d9c4SApple OSS Distributionsstatic void 677*a325d9c4SApple OSS Distributionstest_krwlock_blocking(void) 678*a325d9c4SApple OSS Distributions{ 679*a325d9c4SApple OSS Distributions int ret = 0; 680*a325d9c4SApple OSS Distributions void *stackshot = NULL; 681*a325d9c4SApple OSS Distributions uint64_t thread_id = 0; 682*a325d9c4SApple OSS Distributions pthread_t waiting, grabbing; 683*a325d9c4SApple OSS Distributions int len = 2; 684*a325d9c4SApple OSS Distributions struct stackshot_thread_waitinfo waitinfo[2] = { { 0 }, { 0 } }; 685*a325d9c4SApple OSS Distributions 686*a325d9c4SApple OSS Distributions T_LOG("Starting %s", __FUNCTION__); 687*a325d9c4SApple OSS Distributions // this thread should spawn, acquire a kernel rwlock for write, and then wait on a semaphore 688*a325d9c4SApple OSS Distributions ret = pthread_create(&waiting, NULL, krwlck_write_waiting_thread, NULL); 689*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Creating krwlck write waiting thread"); 690*a325d9c4SApple OSS Distributions sleep(1); // give time for thread to block 691*a325d9c4SApple OSS Distributions // this thread should spawn and try to acquire the same kernel rwlock for read, but block 692*a325d9c4SApple OSS Distributions ret = pthread_create(&grabbing, NULL, krwlck_read_grabbing_thread, NULL); 693*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Creating krwlck read grabbing thread"); 694*a325d9c4SApple OSS Distributions sleep(1); // give time for thread to block 695*a325d9c4SApple OSS Distributions 696*a325d9c4SApple OSS Distributions stackshot = take_stackshot(STACKSHOT_THREAD_WAITINFO, 0); 697*a325d9c4SApple OSS Distributions 698*a325d9c4SApple OSS Distributions check_python(stackshot, "thread \\d+: semaphore port \\w+ with unknown owner"); 699*a325d9c4SApple OSS Distributions 700*a325d9c4SApple OSS Distributions find_blocking_info(stackshot, (struct stackshot_thread_waitinfo *)&waitinfo, &len); 701*a325d9c4SApple OSS Distributions 702*a325d9c4SApple OSS Distributions T_EXPECT_EQ(len, 2, "There should only be two blocking threads"); 703*a325d9c4SApple OSS Distributions for (int i = 0; i < len; i++) { 704*a325d9c4SApple OSS Distributions struct stackshot_thread_waitinfo *curr = &waitinfo[i]; 705*a325d9c4SApple OSS Distributions if (curr->wait_type == kThreadWaitSemaphore) 706*a325d9c4SApple OSS Distributions continue; 707*a325d9c4SApple OSS Distributions T_EXPECT_EQ(curr->wait_type, kThreadWaitKernelRWLockRead, "Wait type should match expected KRWLockRead value"); 708*a325d9c4SApple OSS Distributions sysctl_krwlck_test_match(curr->context); 709*a325d9c4SApple OSS Distributions 710*a325d9c4SApple OSS Distributions check_python(stackshot, "thread \\d+: krwlock %llx for reading", curr->context); 711*a325d9c4SApple OSS Distributions 712*a325d9c4SApple OSS Distributions#if KRWLCK_STORES_EXCL_OWNER /* A future planned enhancement */ 713*a325d9c4SApple OSS Distributions ret = pthread_threadid_np(waiting, &thread_id); // this is the thread that currently holds the kernel mutex 714*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Getting integer value of thread id"); 715*a325d9c4SApple OSS Distributions T_EXPECT_EQ(curr->owner, thread_id, "Thread ID of blocking thread should match 'owner' field in stackshot"); 716*a325d9c4SApple OSS Distributions#else 717*a325d9c4SApple OSS Distributions (void)thread_id; // suppress compiler warning about unused variable 718*a325d9c4SApple OSS Distributions#endif /* RWLCK_STORES_EXCL_OWNER */ 719*a325d9c4SApple OSS Distributions } 720*a325d9c4SApple OSS Distributions 721*a325d9c4SApple OSS Distributions krwlck_action(KRWLCK_SYSCTL_SIGNAL); // pthread should now unblock & finish 722*a325d9c4SApple OSS Distributions ret = pthread_join(waiting, NULL); 723*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Joining on waiting thread"); 724*a325d9c4SApple OSS Distributions ret = pthread_join(grabbing, NULL); 725*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Joining on grabbing thread"); 726*a325d9c4SApple OSS Distributions krwlck_action(KRWLCK_SYSCTL_TEARDOWN); 727*a325d9c4SApple OSS Distributions stackshot_config_dealloc(stackshot); 728*a325d9c4SApple OSS Distributions} 729*a325d9c4SApple OSS Distributions 730*a325d9c4SApple OSS Distributions 731*a325d9c4SApple OSS Distributionsstatic void 732*a325d9c4SApple OSS Distributionstest_pthread_mutex_blocking(void) 733*a325d9c4SApple OSS Distributions{ 734*a325d9c4SApple OSS Distributions int ret = 0; 735*a325d9c4SApple OSS Distributions void *stackshot = NULL; 736*a325d9c4SApple OSS Distributions uint64_t thread_id = 0; 737*a325d9c4SApple OSS Distributions pthread_t tid; 738*a325d9c4SApple OSS Distributions struct stackshot_thread_waitinfo waitinfo = { 0 }; 739*a325d9c4SApple OSS Distributions pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; 740*a325d9c4SApple OSS Distributions int len = 1; 741*a325d9c4SApple OSS Distributions 742*a325d9c4SApple OSS Distributions T_LOG("Starting %s", __FUNCTION__); 743*a325d9c4SApple OSS Distributions 744*a325d9c4SApple OSS Distributions ret = pthread_threadid_np(NULL, &thread_id); // this thread is the "owner" of the mutex 745*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Getting integer value of thread id"); 746*a325d9c4SApple OSS Distributions 747*a325d9c4SApple OSS Distributions pthread_mutex_lock(&mtx); 748*a325d9c4SApple OSS Distributions ret = pthread_create(&tid, NULL, pthread_mutex_blocking_thread, (void*)&mtx); 749*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Creating pthread mutex blocking thread"); 750*a325d9c4SApple OSS Distributions sleep(2); // give time for thread to block 751*a325d9c4SApple OSS Distributions 752*a325d9c4SApple OSS Distributions stackshot = take_stackshot(STACKSHOT_THREAD_WAITINFO, 0); 753*a325d9c4SApple OSS Distributions 754*a325d9c4SApple OSS Distributions check_python(stackshot, "thread \\d+: pthread mutex %llx owned by thread %lld", &mtx, thread_id); 755*a325d9c4SApple OSS Distributions 756*a325d9c4SApple OSS Distributions find_blocking_info(stackshot, (struct stackshot_thread_waitinfo *)&waitinfo, &len); 757*a325d9c4SApple OSS Distributions T_EXPECT_EQ(len, 1, "Only one blocking thread should exist"); 758*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.wait_type, kThreadWaitPThreadMutex, 759*a325d9c4SApple OSS Distributions "Wait type should match expected PThreadMutex value"); 760*a325d9c4SApple OSS Distributions stackshot_config_dealloc(stackshot); 761*a325d9c4SApple OSS Distributions 762*a325d9c4SApple OSS Distributions pthread_mutex_unlock(&mtx); 763*a325d9c4SApple OSS Distributions ret = pthread_join(tid, NULL); // wait for thread to unblock and exit 764*a325d9c4SApple OSS Distributions 765*a325d9c4SApple OSS Distributions 766*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.owner, thread_id, 767*a325d9c4SApple OSS Distributions "Thread ID of blocking thread should match 'owner' field in stackshot"); 768*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.context, (uint64_t)&mtx, 769*a325d9c4SApple OSS Distributions "Userspace address of mutex should match 'context' field in stackshot"); 770*a325d9c4SApple OSS Distributions} 771*a325d9c4SApple OSS Distributions 772*a325d9c4SApple OSS Distributionsstatic void 773*a325d9c4SApple OSS Distributionstest_pthread_rwlck_blocking(void) 774*a325d9c4SApple OSS Distributions{ 775*a325d9c4SApple OSS Distributions int ret = 0; 776*a325d9c4SApple OSS Distributions void *stackshot = NULL; 777*a325d9c4SApple OSS Distributions pthread_t tid; 778*a325d9c4SApple OSS Distributions struct stackshot_thread_waitinfo waitinfo = { 0 }; 779*a325d9c4SApple OSS Distributions pthread_rwlock_t rwlck = PTHREAD_RWLOCK_INITIALIZER; 780*a325d9c4SApple OSS Distributions int len = 1; 781*a325d9c4SApple OSS Distributions 782*a325d9c4SApple OSS Distributions T_LOG("Starting %s", __FUNCTION__); 783*a325d9c4SApple OSS Distributions pthread_rwlock_wrlock(&rwlck); 784*a325d9c4SApple OSS Distributions ret = pthread_create(&tid, NULL, pthread_rwlck_blocking_thread, (void*)&rwlck); 785*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Creating pthread rwlck blocking thread"); 786*a325d9c4SApple OSS Distributions sleep(2); 787*a325d9c4SApple OSS Distributions 788*a325d9c4SApple OSS Distributions stackshot = take_stackshot(STACKSHOT_THREAD_WAITINFO, 0); 789*a325d9c4SApple OSS Distributions 790*a325d9c4SApple OSS Distributions check_python(stackshot, "thread \\d+: pthread rwlock %llx for reading", (long long)&rwlck); 791*a325d9c4SApple OSS Distributions 792*a325d9c4SApple OSS Distributions find_blocking_info(stackshot, (struct stackshot_thread_waitinfo *)&waitinfo, &len); 793*a325d9c4SApple OSS Distributions T_EXPECT_EQ(len, 1, "Only one blocking thread should exist"); 794*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.wait_type, kThreadWaitPThreadRWLockRead, 795*a325d9c4SApple OSS Distributions "Wait type should match expected PThreadRWLockRead value"); 796*a325d9c4SApple OSS Distributions stackshot_config_dealloc(stackshot); 797*a325d9c4SApple OSS Distributions 798*a325d9c4SApple OSS Distributions pthread_rwlock_unlock(&rwlck); 799*a325d9c4SApple OSS Distributions ret = pthread_join(tid, NULL); // wait for thread to unblock and exit 800*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.context, (uint64_t)&rwlck, 801*a325d9c4SApple OSS Distributions "Userspace address of rwlck should match 'context' field in stackshot"); 802*a325d9c4SApple OSS Distributions} 803*a325d9c4SApple OSS Distributions 804*a325d9c4SApple OSS Distributions 805*a325d9c4SApple OSS Distributions 806*a325d9c4SApple OSS Distributionsstatic void 807*a325d9c4SApple OSS Distributionstest_pthread_cond_blocking(void) 808*a325d9c4SApple OSS Distributions{ 809*a325d9c4SApple OSS Distributions int ret = 0; 810*a325d9c4SApple OSS Distributions void *stackshot = NULL; 811*a325d9c4SApple OSS Distributions pthread_t tid; 812*a325d9c4SApple OSS Distributions pthread_cond_t cond = PTHREAD_COND_INITIALIZER; 813*a325d9c4SApple OSS Distributions struct stackshot_thread_waitinfo waitinfo = { 0 }; 814*a325d9c4SApple OSS Distributions int len = 1; 815*a325d9c4SApple OSS Distributions 816*a325d9c4SApple OSS Distributions T_LOG("Starting %s", __FUNCTION__); 817*a325d9c4SApple OSS Distributions ret = pthread_create(&tid, NULL, pthread_cond_blocking_thread, (void*)&cond); 818*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Creating pthread condvar blocking thread"); 819*a325d9c4SApple OSS Distributions sleep(2); 820*a325d9c4SApple OSS Distributions 821*a325d9c4SApple OSS Distributions stackshot = take_stackshot(STACKSHOT_THREAD_WAITINFO, 0); 822*a325d9c4SApple OSS Distributions 823*a325d9c4SApple OSS Distributions check_python(stackshot, "thread \\d+: pthread condvar %llx", (long long)&cond); 824*a325d9c4SApple OSS Distributions 825*a325d9c4SApple OSS Distributions find_blocking_info(stackshot, (struct stackshot_thread_waitinfo *)&waitinfo, &len); 826*a325d9c4SApple OSS Distributions T_EXPECT_EQ(len, 1, "Only one blocking thread should exist"); 827*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.wait_type, kThreadWaitPThreadCondVar, 828*a325d9c4SApple OSS Distributions "Wait type should match expected PThreadCondVar value"); 829*a325d9c4SApple OSS Distributions stackshot_config_dealloc(stackshot); 830*a325d9c4SApple OSS Distributions 831*a325d9c4SApple OSS Distributions pthread_cond_signal(&cond); 832*a325d9c4SApple OSS Distributions ret = pthread_join(tid, NULL); // wait for thread to unblock and exit 833*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.context, (uint64_t)&cond, 834*a325d9c4SApple OSS Distributions "Userspace address of condvar should match 'context' field in stackshot"); 835*a325d9c4SApple OSS Distributions pthread_cond_destroy(&cond); 836*a325d9c4SApple OSS Distributions} 837*a325d9c4SApple OSS Distributions 838*a325d9c4SApple OSS Distributionsstatic void 839*a325d9c4SApple OSS Distributionstest_waitpid_blocking(void) 840*a325d9c4SApple OSS Distributions{ 841*a325d9c4SApple OSS Distributions int ret = 0; 842*a325d9c4SApple OSS Distributions pid_t pid = 0; 843*a325d9c4SApple OSS Distributions void *stackshot = NULL; 844*a325d9c4SApple OSS Distributions struct stackshot_thread_waitinfo waitinfo = { 0 }; 845*a325d9c4SApple OSS Distributions int len = 1; 846*a325d9c4SApple OSS Distributions pthread_t tid; 847*a325d9c4SApple OSS Distributions 848*a325d9c4SApple OSS Distributions T_LOG("Starting %s", __FUNCTION__); 849*a325d9c4SApple OSS Distributions if ((pid = fork()) == 0) { 850*a325d9c4SApple OSS Distributions pause(); 851*a325d9c4SApple OSS Distributions } else { 852*a325d9c4SApple OSS Distributions T_ASSERT_POSIX_SUCCESS(ret, "Running in parent. Child pid is %d", pid); 853*a325d9c4SApple OSS Distributions 854*a325d9c4SApple OSS Distributions sleep(1); // allow enough time for child to run & sleep 855*a325d9c4SApple OSS Distributions ret = pthread_create(&tid, NULL, waitpid_blocking_thread, (void*)pid); 856*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_ZERO(ret, "Creating waitpid blocking thread"); 857*a325d9c4SApple OSS Distributions 858*a325d9c4SApple OSS Distributions sleep(1); // allow enough time for reaping thread to waitpid & block 859*a325d9c4SApple OSS Distributions stackshot = take_stackshot(STACKSHOT_THREAD_WAITINFO, 0); 860*a325d9c4SApple OSS Distributions find_blocking_info(stackshot, (struct stackshot_thread_waitinfo *)&waitinfo, &len); 861*a325d9c4SApple OSS Distributions T_EXPECT_EQ(len, 1, "Only one blocking thread should exist"); 862*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.wait_type, kThreadWaitOnProcess, 863*a325d9c4SApple OSS Distributions "Wait type should match expected WaitOnProcess value"); 864*a325d9c4SApple OSS Distributions 865*a325d9c4SApple OSS Distributions check_python(stackshot, "thread \\d+: waitpid, for pid %d", (int)pid); 866*a325d9c4SApple OSS Distributions 867*a325d9c4SApple OSS Distributions stackshot_config_dealloc(stackshot); 868*a325d9c4SApple OSS Distributions T_EXPECT_EQ(waitinfo.owner, pid, 869*a325d9c4SApple OSS Distributions "Process ID of blocking process should match 'owner' field in stackshot"); 870*a325d9c4SApple OSS Distributions 871*a325d9c4SApple OSS Distributions ret = kill(pid, SIGUSR1); // wake up child so waitpid thread can reap it & exit 872*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "Send SIGUSR1 to child process"); 873*a325d9c4SApple OSS Distributions ret = pthread_join(tid, NULL); 874*a325d9c4SApple OSS Distributions T_QUIET; T_ASSERT_POSIX_SUCCESS(ret, "Join on waitpid thread"); 875*a325d9c4SApple OSS Distributions } 876*a325d9c4SApple OSS Distributions} 877*a325d9c4SApple OSS Distributions 878*a325d9c4SApple OSS Distributions/* 879*a325d9c4SApple OSS Distributions * 880*a325d9c4SApple OSS Distributions * Test declarations 881*a325d9c4SApple OSS Distributions * 882*a325d9c4SApple OSS Distributions */ 883*a325d9c4SApple OSS Distributions 884*a325d9c4SApple OSS DistributionsT_DECL(stackshot_block_owner_klocks, "tests stackshot block owner for kernel locks") { 885*a325d9c4SApple OSS Distributions /* check to see if kmutex sysctl exists before running kmutex test */ 886*a325d9c4SApple OSS Distributions if (kmutex_action(KMUTEX_SYSCTL_CHECK_EXISTS)) 887*a325d9c4SApple OSS Distributions test_kmutex_blocking(); 888*a325d9c4SApple OSS Distributions /* check to see if krwlck sysctl exists before running krwlck test */ 889*a325d9c4SApple OSS Distributions if (krwlck_action(KRWLCK_SYSCTL_CHECK_EXISTS)) 890*a325d9c4SApple OSS Distributions test_krwlock_blocking(); 891*a325d9c4SApple OSS Distributions test_ulock_blocking(); 892*a325d9c4SApple OSS Distributions} 893*a325d9c4SApple OSS Distributions 894*a325d9c4SApple OSS DistributionsT_DECL(stackshot_block_owner_pthread_mutex, "tests stackshot block owner: pthread mutex") { 895*a325d9c4SApple OSS Distributions test_pthread_mutex_blocking(); 896*a325d9c4SApple OSS Distributions} 897*a325d9c4SApple OSS Distributions 898*a325d9c4SApple OSS DistributionsT_DECL(stackshot_block_owner_pthread_rwlck, "tests stackshot block owner: pthread rw locks") { 899*a325d9c4SApple OSS Distributions test_pthread_rwlck_blocking(); 900*a325d9c4SApple OSS Distributions} 901*a325d9c4SApple OSS Distributions 902*a325d9c4SApple OSS DistributionsT_DECL(stackshot_block_owner_pthread_condvar, "tests stackshot block owner: pthread condvar") { 903*a325d9c4SApple OSS Distributions test_pthread_cond_blocking(); 904*a325d9c4SApple OSS Distributions} 905*a325d9c4SApple OSS Distributions 906*a325d9c4SApple OSS DistributionsT_DECL(stackshot_block_owner_semaphore, "tests stackshot block owner: semaphore") { 907*a325d9c4SApple OSS Distributions test_semaphore_blocking(); 908*a325d9c4SApple OSS Distributions} 909*a325d9c4SApple OSS Distributions 910*a325d9c4SApple OSS DistributionsT_DECL(stackshot_block_owner_mach_msg, "tests stackshot block owner: mach messaging") { 911*a325d9c4SApple OSS Distributions test_mach_msg_blocking(); 912*a325d9c4SApple OSS Distributions} 913*a325d9c4SApple OSS Distributions 914*a325d9c4SApple OSS DistributionsT_DECL(stackshot_block_owner_waitpid, "tests stackshot block owner: waitpid") { 915*a325d9c4SApple OSS Distributions test_waitpid_blocking(); 916*a325d9c4SApple OSS Distributions} 917