xref: /xnu-8019.80.24/tests/stackshot_block_owner_14362384.m (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
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