xref: /xnu-8792.81.2/tests/turnstiles_test.c (revision 19c3b8c28c31cb8130e034cfb5df6bf9ba342d90)
1*19c3b8c2SApple OSS Distributions /*
2*19c3b8c2SApple OSS Distributions  * turnstiles_test: Tests turnstile kernel primitive.
3*19c3b8c2SApple OSS Distributions  */
4*19c3b8c2SApple OSS Distributions 
5*19c3b8c2SApple OSS Distributions #ifdef T_NAMESPACE
6*19c3b8c2SApple OSS Distributions #undef T_NAMESPACE
7*19c3b8c2SApple OSS Distributions #endif
8*19c3b8c2SApple OSS Distributions 
9*19c3b8c2SApple OSS Distributions #include <darwintest.h>
10*19c3b8c2SApple OSS Distributions #include <darwintest_multiprocess.h>
11*19c3b8c2SApple OSS Distributions 
12*19c3b8c2SApple OSS Distributions #include <pthread.h>
13*19c3b8c2SApple OSS Distributions #include <launch.h>
14*19c3b8c2SApple OSS Distributions #include <servers/bootstrap.h>
15*19c3b8c2SApple OSS Distributions #include <stdlib.h>
16*19c3b8c2SApple OSS Distributions #include <sys/event.h>
17*19c3b8c2SApple OSS Distributions #include <unistd.h>
18*19c3b8c2SApple OSS Distributions #include <crt_externs.h>
19*19c3b8c2SApple OSS Distributions #include <sys/sysctl.h>
20*19c3b8c2SApple OSS Distributions #include <sys/types.h>
21*19c3b8c2SApple OSS Distributions 
22*19c3b8c2SApple OSS Distributions #define SYSCTL_TURNSTILE_TEST_USER_DEFAULT            1
23*19c3b8c2SApple OSS Distributions #define SYSCTL_TURNSTILE_TEST_USER_HASHTABLE          2
24*19c3b8c2SApple OSS Distributions #define SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT          3
25*19c3b8c2SApple OSS Distributions #define SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE        4
26*19c3b8c2SApple OSS Distributions 
27*19c3b8c2SApple OSS Distributions T_GLOBAL_META(T_META_NAMESPACE("xnu.turnstiles_test"));
28*19c3b8c2SApple OSS Distributions 
29*19c3b8c2SApple OSS Distributions static void
thread_create_at_qos(qos_class_t qos,void * (* function)(void *),int type)30*19c3b8c2SApple OSS Distributions thread_create_at_qos(qos_class_t qos, void * (*function)(void *), int type)
31*19c3b8c2SApple OSS Distributions {
32*19c3b8c2SApple OSS Distributions 	qos_class_t qos_thread;
33*19c3b8c2SApple OSS Distributions 	pthread_t thread;
34*19c3b8c2SApple OSS Distributions 	pthread_attr_t attr;
35*19c3b8c2SApple OSS Distributions 	int ret;
36*19c3b8c2SApple OSS Distributions 
37*19c3b8c2SApple OSS Distributions 	ret = setpriority(PRIO_DARWIN_ROLE, 0, PRIO_DARWIN_ROLE_UI_FOCAL);
38*19c3b8c2SApple OSS Distributions 	if (ret != 0) {
39*19c3b8c2SApple OSS Distributions 		T_LOG("set priority failed\n");
40*19c3b8c2SApple OSS Distributions 	}
41*19c3b8c2SApple OSS Distributions 
42*19c3b8c2SApple OSS Distributions 	pthread_attr_init(&attr);
43*19c3b8c2SApple OSS Distributions 	pthread_attr_set_qos_class_np(&attr, qos, 0);
44*19c3b8c2SApple OSS Distributions 	pthread_create(&thread, &attr, function, (void *)type);
45*19c3b8c2SApple OSS Distributions 
46*19c3b8c2SApple OSS Distributions 	T_LOG("pthread created\n");
47*19c3b8c2SApple OSS Distributions 	pthread_get_qos_class_np(thread, &qos_thread, NULL);
48*19c3b8c2SApple OSS Distributions 	T_EXPECT_EQ(qos_thread, (qos_class_t)qos, NULL);
49*19c3b8c2SApple OSS Distributions }
50*19c3b8c2SApple OSS Distributions 
51*19c3b8c2SApple OSS Distributions static int
get_sched_pri(thread_t thread_port)52*19c3b8c2SApple OSS Distributions get_sched_pri(thread_t thread_port)
53*19c3b8c2SApple OSS Distributions {
54*19c3b8c2SApple OSS Distributions 	kern_return_t kr;
55*19c3b8c2SApple OSS Distributions 
56*19c3b8c2SApple OSS Distributions 	thread_extended_info_data_t extended_info;
57*19c3b8c2SApple OSS Distributions 	mach_msg_type_number_t count = THREAD_EXTENDED_INFO_COUNT;
58*19c3b8c2SApple OSS Distributions 	kr = thread_info(thread_port, THREAD_EXTENDED_INFO,
59*19c3b8c2SApple OSS Distributions 	    (thread_info_t)&extended_info, &count);
60*19c3b8c2SApple OSS Distributions 
61*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_info");
62*19c3b8c2SApple OSS Distributions 	return extended_info.pth_curpri;
63*19c3b8c2SApple OSS Distributions }
64*19c3b8c2SApple OSS Distributions 
65*19c3b8c2SApple OSS Distributions static int
get_base_pri(thread_t thread_port)66*19c3b8c2SApple OSS Distributions get_base_pri(thread_t thread_port)
67*19c3b8c2SApple OSS Distributions {
68*19c3b8c2SApple OSS Distributions 	kern_return_t kr;
69*19c3b8c2SApple OSS Distributions 
70*19c3b8c2SApple OSS Distributions 	thread_extended_info_data_t extended_info;
71*19c3b8c2SApple OSS Distributions 	mach_msg_type_number_t count = THREAD_EXTENDED_INFO_COUNT;
72*19c3b8c2SApple OSS Distributions 	kr = thread_info(thread_port, THREAD_EXTENDED_INFO,
73*19c3b8c2SApple OSS Distributions 	    (thread_info_t)&extended_info, &count);
74*19c3b8c2SApple OSS Distributions 
75*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_info");
76*19c3b8c2SApple OSS Distributions 	return extended_info.pth_priority;
77*19c3b8c2SApple OSS Distributions }
78*19c3b8c2SApple OSS Distributions 
79*19c3b8c2SApple OSS Distributions static void
turnstile_prim_lock(int type)80*19c3b8c2SApple OSS Distributions turnstile_prim_lock(int type)
81*19c3b8c2SApple OSS Distributions {
82*19c3b8c2SApple OSS Distributions 	int ret;
83*19c3b8c2SApple OSS Distributions 	uint64_t tid;
84*19c3b8c2SApple OSS Distributions 	int in_val = type;
85*19c3b8c2SApple OSS Distributions 	pthread_threadid_np(NULL, &tid);
86*19c3b8c2SApple OSS Distributions 	T_LOG("sysctlbyname lock type %d called from thread %llu \n", type, tid);
87*19c3b8c2SApple OSS Distributions 	ret = sysctlbyname("kern.turnstiles_test_lock", NULL, 0, &in_val, sizeof(in_val));
88*19c3b8c2SApple OSS Distributions 	T_LOG("sysctlbyname lock returned from thread %llu with value %d \n", tid, ret);
89*19c3b8c2SApple OSS Distributions }
90*19c3b8c2SApple OSS Distributions 
91*19c3b8c2SApple OSS Distributions static void
turnstile_prim_unlock(int type)92*19c3b8c2SApple OSS Distributions turnstile_prim_unlock(int type)
93*19c3b8c2SApple OSS Distributions {
94*19c3b8c2SApple OSS Distributions 	int ret;
95*19c3b8c2SApple OSS Distributions 	uint64_t tid;
96*19c3b8c2SApple OSS Distributions 	int in_val = type;
97*19c3b8c2SApple OSS Distributions 	pthread_threadid_np(NULL, &tid);
98*19c3b8c2SApple OSS Distributions 	T_LOG("sysctlbyname unlock type %d called from thread %llu \n", type, tid);
99*19c3b8c2SApple OSS Distributions 	ret = sysctlbyname("kern.turnstiles_test_unlock", NULL, 0, &in_val, sizeof(in_val));
100*19c3b8c2SApple OSS Distributions 	T_LOG("sysctlbyname unlock returned from thread %llu with value %d \n", tid, ret);
101*19c3b8c2SApple OSS Distributions }
102*19c3b8c2SApple OSS Distributions 
103*19c3b8c2SApple OSS Distributions struct thread_data {
104*19c3b8c2SApple OSS Distributions 	int pri_to_set;
105*19c3b8c2SApple OSS Distributions 	int lock1;
106*19c3b8c2SApple OSS Distributions 	int lock2;
107*19c3b8c2SApple OSS Distributions 	unsigned int sleep;
108*19c3b8c2SApple OSS Distributions 	int sched_pri_to_check;
109*19c3b8c2SApple OSS Distributions 	int base_pri_to_check;
110*19c3b8c2SApple OSS Distributions };
111*19c3b8c2SApple OSS Distributions 
112*19c3b8c2SApple OSS Distributions static void *
chain_locking(void * args)113*19c3b8c2SApple OSS Distributions chain_locking(void* args)
114*19c3b8c2SApple OSS Distributions {
115*19c3b8c2SApple OSS Distributions 	struct thread_data* data = (struct thread_data*) args;
116*19c3b8c2SApple OSS Distributions 	int policy, pri;
117*19c3b8c2SApple OSS Distributions 	int ret;
118*19c3b8c2SApple OSS Distributions 	struct sched_param param;
119*19c3b8c2SApple OSS Distributions 
120*19c3b8c2SApple OSS Distributions 	/* Change our priority to pri_to_set */
121*19c3b8c2SApple OSS Distributions 	ret = pthread_getschedparam(pthread_self(), &policy, &param);
122*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "pthread_getschedparam");
123*19c3b8c2SApple OSS Distributions 
124*19c3b8c2SApple OSS Distributions 	param.sched_priority = data->pri_to_set;
125*19c3b8c2SApple OSS Distributions 
126*19c3b8c2SApple OSS Distributions 	/* this sets both sched and base pri */
127*19c3b8c2SApple OSS Distributions 	ret = pthread_setschedparam(pthread_self(), policy, &param);
128*19c3b8c2SApple OSS Distributions 	T_QUIET; T_ASSERT_MACH_SUCCESS(ret, "pthread_setschedparam");
129*19c3b8c2SApple OSS Distributions 
130*19c3b8c2SApple OSS Distributions 	pri = get_sched_pri(mach_thread_self());
131*19c3b8c2SApple OSS Distributions 
132*19c3b8c2SApple OSS Distributions 	T_ASSERT_EQ(pri, data->pri_to_set, "Priority before holding locks");
133*19c3b8c2SApple OSS Distributions 
134*19c3b8c2SApple OSS Distributions 	/* take lock1 */
135*19c3b8c2SApple OSS Distributions 	if (data->lock1) {
136*19c3b8c2SApple OSS Distributions 		turnstile_prim_lock(data->lock1);
137*19c3b8c2SApple OSS Distributions 	}
138*19c3b8c2SApple OSS Distributions 
139*19c3b8c2SApple OSS Distributions 	/* take lock2 */
140*19c3b8c2SApple OSS Distributions 	if (data->lock2) {
141*19c3b8c2SApple OSS Distributions 		turnstile_prim_lock(data->lock2);
142*19c3b8c2SApple OSS Distributions 	}
143*19c3b8c2SApple OSS Distributions 
144*19c3b8c2SApple OSS Distributions 	if (data->sleep) {
145*19c3b8c2SApple OSS Distributions 		sleep(data->sleep);
146*19c3b8c2SApple OSS Distributions 	}
147*19c3b8c2SApple OSS Distributions 
148*19c3b8c2SApple OSS Distributions 	if (data->sched_pri_to_check) {
149*19c3b8c2SApple OSS Distributions 		pri = get_sched_pri(mach_thread_self());
150*19c3b8c2SApple OSS Distributions 		T_ASSERT_EQ(pri, data->sched_pri_to_check, "Sched priority while holding locks");
151*19c3b8c2SApple OSS Distributions 	}
152*19c3b8c2SApple OSS Distributions 
153*19c3b8c2SApple OSS Distributions 	if (data->base_pri_to_check) {
154*19c3b8c2SApple OSS Distributions 		pri = get_base_pri(mach_thread_self());
155*19c3b8c2SApple OSS Distributions 		T_ASSERT_EQ(pri, data->base_pri_to_check, "Base priority while holding locks");
156*19c3b8c2SApple OSS Distributions 	}
157*19c3b8c2SApple OSS Distributions 
158*19c3b8c2SApple OSS Distributions 	if (data->lock2) {
159*19c3b8c2SApple OSS Distributions 		turnstile_prim_unlock(data->lock2);
160*19c3b8c2SApple OSS Distributions 	}
161*19c3b8c2SApple OSS Distributions 
162*19c3b8c2SApple OSS Distributions 	if (data->lock1) {
163*19c3b8c2SApple OSS Distributions 		turnstile_prim_unlock(data->lock1);
164*19c3b8c2SApple OSS Distributions 	}
165*19c3b8c2SApple OSS Distributions 
166*19c3b8c2SApple OSS Distributions 	pri = get_sched_pri(mach_thread_self());
167*19c3b8c2SApple OSS Distributions 	T_ASSERT_EQ(pri, data->pri_to_set, "Priority after releasing locks");
168*19c3b8c2SApple OSS Distributions 
169*19c3b8c2SApple OSS Distributions 	return NULL;
170*19c3b8c2SApple OSS Distributions }
171*19c3b8c2SApple OSS Distributions 
172*19c3b8c2SApple OSS Distributions static void *
take_lock_check_priority(void * arg)173*19c3b8c2SApple OSS Distributions take_lock_check_priority(void * arg)
174*19c3b8c2SApple OSS Distributions {
175*19c3b8c2SApple OSS Distributions 	int old_pri = get_base_pri(mach_thread_self());
176*19c3b8c2SApple OSS Distributions 	int unboosted_pri;
177*19c3b8c2SApple OSS Distributions 	int boosted_pri;
178*19c3b8c2SApple OSS Distributions 	int after_unlock_pri;
179*19c3b8c2SApple OSS Distributions 	uint64_t tid;
180*19c3b8c2SApple OSS Distributions 	int type = (int)arg;
181*19c3b8c2SApple OSS Distributions 
182*19c3b8c2SApple OSS Distributions 	pthread_threadid_np(NULL, &tid);
183*19c3b8c2SApple OSS Distributions 
184*19c3b8c2SApple OSS Distributions 	T_ASSERT_EQ(old_pri, 37, "thread(%llu) priority before acquiring the lock is %d\n", tid, old_pri);
185*19c3b8c2SApple OSS Distributions 
186*19c3b8c2SApple OSS Distributions 	/* Take the test lock */
187*19c3b8c2SApple OSS Distributions 	turnstile_prim_lock(type);
188*19c3b8c2SApple OSS Distributions 
189*19c3b8c2SApple OSS Distributions 	unboosted_pri = get_base_pri(mach_thread_self());
190*19c3b8c2SApple OSS Distributions 	T_ASSERT_EQ(unboosted_pri, 37, "thread(%llu) priority after acquiring the lock (uncontended) is %d\n", tid, unboosted_pri);
191*19c3b8c2SApple OSS Distributions 
192*19c3b8c2SApple OSS Distributions 	sleep(8);
193*19c3b8c2SApple OSS Distributions 
194*19c3b8c2SApple OSS Distributions 	/* Check for elevated priority */
195*19c3b8c2SApple OSS Distributions 	boosted_pri =  get_base_pri(mach_thread_self());
196*19c3b8c2SApple OSS Distributions 	T_ASSERT_EQ(boosted_pri, 47, "thread(%llu) priority after contention by 47 thread is %d\n", tid, boosted_pri);
197*19c3b8c2SApple OSS Distributions 
198*19c3b8c2SApple OSS Distributions 	/* Drop the lock */
199*19c3b8c2SApple OSS Distributions 	turnstile_prim_unlock(type);
200*19c3b8c2SApple OSS Distributions 
201*19c3b8c2SApple OSS Distributions 	/* Check for regular priority */
202*19c3b8c2SApple OSS Distributions 	after_unlock_pri =  get_base_pri(mach_thread_self());
203*19c3b8c2SApple OSS Distributions 	T_ASSERT_EQ(after_unlock_pri, 37, "thread(%llu) priority after dropping lock is %d\n", tid, after_unlock_pri);
204*19c3b8c2SApple OSS Distributions 
205*19c3b8c2SApple OSS Distributions 	return NULL;
206*19c3b8c2SApple OSS Distributions }
207*19c3b8c2SApple OSS Distributions 
208*19c3b8c2SApple OSS Distributions static void *
try_to_take_lock_and_unlock(void * arg)209*19c3b8c2SApple OSS Distributions try_to_take_lock_and_unlock(void *arg)
210*19c3b8c2SApple OSS Distributions {
211*19c3b8c2SApple OSS Distributions 	uint64_t tid;
212*19c3b8c2SApple OSS Distributions 	int type = (int)arg;
213*19c3b8c2SApple OSS Distributions 
214*19c3b8c2SApple OSS Distributions 	pthread_threadid_np(NULL, &tid);
215*19c3b8c2SApple OSS Distributions 	sleep(4);
216*19c3b8c2SApple OSS Distributions 
217*19c3b8c2SApple OSS Distributions 	int old_pri = get_base_pri(mach_thread_self());
218*19c3b8c2SApple OSS Distributions 	T_ASSERT_EQ(old_pri, 47, "thread(%llu) priority before acquiring the lock is %d\n", tid, old_pri);
219*19c3b8c2SApple OSS Distributions 
220*19c3b8c2SApple OSS Distributions 	/* Try taking the test lock */
221*19c3b8c2SApple OSS Distributions 	turnstile_prim_lock(type);
222*19c3b8c2SApple OSS Distributions 	sleep(2);
223*19c3b8c2SApple OSS Distributions 	turnstile_prim_unlock(type);
224*19c3b8c2SApple OSS Distributions 	return NULL;
225*19c3b8c2SApple OSS Distributions }
226*19c3b8c2SApple OSS Distributions 
227*19c3b8c2SApple OSS Distributions static void *
take_lock_and_exit(void * arg)228*19c3b8c2SApple OSS Distributions take_lock_and_exit(void * arg)
229*19c3b8c2SApple OSS Distributions {
230*19c3b8c2SApple OSS Distributions 	int old_pri = get_base_pri(mach_thread_self());
231*19c3b8c2SApple OSS Distributions 	int unboosted_pri;
232*19c3b8c2SApple OSS Distributions 	int boosted_pri;
233*19c3b8c2SApple OSS Distributions 	uint64_t tid;
234*19c3b8c2SApple OSS Distributions 	int type = (int)arg;
235*19c3b8c2SApple OSS Distributions 
236*19c3b8c2SApple OSS Distributions 	pthread_threadid_np(NULL, &tid);
237*19c3b8c2SApple OSS Distributions 
238*19c3b8c2SApple OSS Distributions 	T_ASSERT_EQ(old_pri, 37, "thread(%llu) priority before acquiring the lock is %d\n", tid, old_pri);
239*19c3b8c2SApple OSS Distributions 
240*19c3b8c2SApple OSS Distributions 	/* Take the test lock */
241*19c3b8c2SApple OSS Distributions 	turnstile_prim_lock(type);
242*19c3b8c2SApple OSS Distributions 
243*19c3b8c2SApple OSS Distributions 	unboosted_pri =  get_base_pri(mach_thread_self());
244*19c3b8c2SApple OSS Distributions 	T_ASSERT_EQ(unboosted_pri, 37, "thread(%llu) priority after acquiring the lock (uncontended) is %d\n", tid, unboosted_pri);
245*19c3b8c2SApple OSS Distributions 
246*19c3b8c2SApple OSS Distributions 	sleep(8);
247*19c3b8c2SApple OSS Distributions 
248*19c3b8c2SApple OSS Distributions 	/* Check for elevated priority */
249*19c3b8c2SApple OSS Distributions 	boosted_pri =  get_base_pri(mach_thread_self());
250*19c3b8c2SApple OSS Distributions 	T_ASSERT_EQ(boosted_pri, 47, "thread(%llu) priority after contention by 47 thread is %d\n", tid, boosted_pri);
251*19c3b8c2SApple OSS Distributions 
252*19c3b8c2SApple OSS Distributions 	/* return without unlocking the lock */
253*19c3b8c2SApple OSS Distributions 	return NULL;
254*19c3b8c2SApple OSS Distributions }
255*19c3b8c2SApple OSS Distributions 
256*19c3b8c2SApple OSS Distributions static void *
unlock_an_owner_exited_lock(void * arg)257*19c3b8c2SApple OSS Distributions unlock_an_owner_exited_lock(void *arg)
258*19c3b8c2SApple OSS Distributions {
259*19c3b8c2SApple OSS Distributions 	uint64_t tid;
260*19c3b8c2SApple OSS Distributions 	int type = (int)arg;
261*19c3b8c2SApple OSS Distributions 
262*19c3b8c2SApple OSS Distributions 	pthread_threadid_np(NULL, &tid);
263*19c3b8c2SApple OSS Distributions 	sleep(12);
264*19c3b8c2SApple OSS Distributions 
265*19c3b8c2SApple OSS Distributions 	int old_pri = get_base_pri(mach_thread_self());
266*19c3b8c2SApple OSS Distributions 	T_ASSERT_EQ(old_pri, 47, "thread(%llu) priority before acquiring the lock is %d\n", tid, old_pri);
267*19c3b8c2SApple OSS Distributions 
268*19c3b8c2SApple OSS Distributions 	/* Unlock the test lock causing the turnstile code to call thread_deallocate_safe */
269*19c3b8c2SApple OSS Distributions 	turnstile_prim_unlock(type);
270*19c3b8c2SApple OSS Distributions 	return NULL;
271*19c3b8c2SApple OSS Distributions }
272*19c3b8c2SApple OSS Distributions 
273*19c3b8c2SApple OSS Distributions /*
274*19c3b8c2SApple OSS Distributions  * Test 1: test if lock contended by a UI thread boosts the owner to UI qos.
275*19c3b8c2SApple OSS Distributions  */
276*19c3b8c2SApple OSS Distributions static void
test1(int type)277*19c3b8c2SApple OSS Distributions test1(int type)
278*19c3b8c2SApple OSS Distributions {
279*19c3b8c2SApple OSS Distributions 	T_LOG("Test 1: test if lock contended by a UI thread boosts the owner to UI qos");
280*19c3b8c2SApple OSS Distributions 
281*19c3b8c2SApple OSS Distributions 	/* Create a thread at IN and take lock */
282*19c3b8c2SApple OSS Distributions 	thread_create_at_qos(QOS_CLASS_USER_INITIATED, &take_lock_check_priority, type);
283*19c3b8c2SApple OSS Distributions 
284*19c3b8c2SApple OSS Distributions 	/* Create a thread at UI and try to take lock */
285*19c3b8c2SApple OSS Distributions 	thread_create_at_qos(QOS_CLASS_USER_INTERACTIVE, &try_to_take_lock_and_unlock, type);
286*19c3b8c2SApple OSS Distributions 
287*19c3b8c2SApple OSS Distributions 	sleep(12);
288*19c3b8c2SApple OSS Distributions 	return;
289*19c3b8c2SApple OSS Distributions }
290*19c3b8c2SApple OSS Distributions 
291*19c3b8c2SApple OSS Distributions /*
292*19c3b8c2SApple OSS Distributions  * Test 2: test if lock contended by a 2 UI thread boosts the owner to UI qos.
293*19c3b8c2SApple OSS Distributions  */
294*19c3b8c2SApple OSS Distributions static void
test2(int type)295*19c3b8c2SApple OSS Distributions test2(int type)
296*19c3b8c2SApple OSS Distributions {
297*19c3b8c2SApple OSS Distributions 	T_LOG("Test 2: test if lock contended by a 2 UI thread boosts the owner to UI qos");
298*19c3b8c2SApple OSS Distributions 
299*19c3b8c2SApple OSS Distributions 	/* Create a thread at IN and take lock */
300*19c3b8c2SApple OSS Distributions 	thread_create_at_qos(QOS_CLASS_USER_INITIATED, &take_lock_check_priority, type);
301*19c3b8c2SApple OSS Distributions 
302*19c3b8c2SApple OSS Distributions 	/* Create a thread at UI and try to take lock */
303*19c3b8c2SApple OSS Distributions 	thread_create_at_qos(QOS_CLASS_USER_INTERACTIVE, &try_to_take_lock_and_unlock, type);
304*19c3b8c2SApple OSS Distributions 
305*19c3b8c2SApple OSS Distributions 	/* Create a thread at UI and try to take lock */
306*19c3b8c2SApple OSS Distributions 	thread_create_at_qos(QOS_CLASS_USER_INTERACTIVE, &try_to_take_lock_and_unlock, type);
307*19c3b8c2SApple OSS Distributions 
308*19c3b8c2SApple OSS Distributions 	sleep(16);
309*19c3b8c2SApple OSS Distributions 	return;
310*19c3b8c2SApple OSS Distributions }
311*19c3b8c2SApple OSS Distributions 
312*19c3b8c2SApple OSS Distributions /*
313*19c3b8c2SApple OSS Distributions  * Test 3: test if lock owner thread exiting without unlocking allows turnstile to work correctly.
314*19c3b8c2SApple OSS Distributions  */
315*19c3b8c2SApple OSS Distributions static void
test3(int type)316*19c3b8c2SApple OSS Distributions test3(int type)
317*19c3b8c2SApple OSS Distributions {
318*19c3b8c2SApple OSS Distributions 	T_LOG("Test 3: test if lock owner thread exiting without unlocking allows turnstile to work correctly");
319*19c3b8c2SApple OSS Distributions 
320*19c3b8c2SApple OSS Distributions 	/* Create a thread at IN and take lock */
321*19c3b8c2SApple OSS Distributions 	thread_create_at_qos(QOS_CLASS_USER_INITIATED, &take_lock_and_exit, type);
322*19c3b8c2SApple OSS Distributions 
323*19c3b8c2SApple OSS Distributions 	/* Create a thread at UI and try to take lock */
324*19c3b8c2SApple OSS Distributions 	thread_create_at_qos(QOS_CLASS_USER_INTERACTIVE, &try_to_take_lock_and_unlock, type);
325*19c3b8c2SApple OSS Distributions 
326*19c3b8c2SApple OSS Distributions 	/* Create a thread at UI and try to take lock */
327*19c3b8c2SApple OSS Distributions 	thread_create_at_qos(QOS_CLASS_USER_INTERACTIVE, &unlock_an_owner_exited_lock, type);
328*19c3b8c2SApple OSS Distributions 
329*19c3b8c2SApple OSS Distributions 	sleep(16);
330*19c3b8c2SApple OSS Distributions 	return;
331*19c3b8c2SApple OSS Distributions }
332*19c3b8c2SApple OSS Distributions 
333*19c3b8c2SApple OSS Distributions /*
334*19c3b8c2SApple OSS Distributions  * Test 4: test if a chain of user-space turnstile primitives followed by kernel primitives works correctly.
335*19c3b8c2SApple OSS Distributions  */
336*19c3b8c2SApple OSS Distributions static void
test4(void)337*19c3b8c2SApple OSS Distributions test4(void)
338*19c3b8c2SApple OSS Distributions {
339*19c3b8c2SApple OSS Distributions 	pthread_t threads[5] = {};
340*19c3b8c2SApple OSS Distributions 	struct thread_data data[5] = {};
341*19c3b8c2SApple OSS Distributions 
342*19c3b8c2SApple OSS Distributions 	T_LOG("Test 4: test if a chain of user-space turnstile primitives followed by kernel primitives works correctly");
343*19c3b8c2SApple OSS Distributions 
344*19c3b8c2SApple OSS Distributions 	/*
345*19c3b8c2SApple OSS Distributions 	 * Chain: t4->ud->t3->uh->t2->kh->t1->kd->t0
346*19c3b8c2SApple OSS Distributions 	 * ud and uh (user space turnstiles) will push base pri and sched pri
347*19c3b8c2SApple OSS Distributions 	 * kd and kh (kernel space turnstiles) will push sched pri
348*19c3b8c2SApple OSS Distributions 	 * sched pri should be propagated up to the end
349*19c3b8c2SApple OSS Distributions 	 * kh is the breaking point of the chain for sched pri
350*19c3b8c2SApple OSS Distributions 	 */
351*19c3b8c2SApple OSS Distributions 
352*19c3b8c2SApple OSS Distributions 
353*19c3b8c2SApple OSS Distributions 	/* Create a thread at priority 4 and take SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT lock */
354*19c3b8c2SApple OSS Distributions 	data[0].pri_to_set = 4;
355*19c3b8c2SApple OSS Distributions 	data[0].lock1 = SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT; /* this should be not locked */
356*19c3b8c2SApple OSS Distributions 	data[0].lock2 = NULL;
357*19c3b8c2SApple OSS Distributions 	data[0].sleep = 10; /* long sleep, nothing is blocking this thread */
358*19c3b8c2SApple OSS Distributions 	data[0].sched_pri_to_check = 60;
359*19c3b8c2SApple OSS Distributions 	data[0].base_pri_to_check = 4;
360*19c3b8c2SApple OSS Distributions 	pthread_create(&threads[0], NULL, chain_locking, (void *)&data[0]);
361*19c3b8c2SApple OSS Distributions 	sleep(2); /* give the thread time to acquire the lock */
362*19c3b8c2SApple OSS Distributions 
363*19c3b8c2SApple OSS Distributions 	/* Create a thread at priority 31 and take SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE lock followed by SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT */
364*19c3b8c2SApple OSS Distributions 	data[1].pri_to_set = 31;
365*19c3b8c2SApple OSS Distributions 	data[1].lock1 = SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE; /* this should be not locked */
366*19c3b8c2SApple OSS Distributions 	data[1].lock2 = SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT; /* this should be locked */
367*19c3b8c2SApple OSS Distributions 	data[1].sleep = 0; /* no need to sleep, everything should be pushing by the time it acquires the lock */
368*19c3b8c2SApple OSS Distributions 	data[1].sched_pri_to_check = 60;
369*19c3b8c2SApple OSS Distributions 	data[1].base_pri_to_check = 31;
370*19c3b8c2SApple OSS Distributions 	pthread_create(&threads[1], NULL, chain_locking, (void *)&data[1]);
371*19c3b8c2SApple OSS Distributions 	sleep(2); /* give the thread time to acquire the lock */
372*19c3b8c2SApple OSS Distributions 
373*19c3b8c2SApple OSS Distributions 	/* Create a thread at priority 40 and take SYSCTL_TURNSTILE_TEST_USER_HASHTABLE lock followed by SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE */
374*19c3b8c2SApple OSS Distributions 	data[2].pri_to_set = 40;
375*19c3b8c2SApple OSS Distributions 	data[2].lock1 = SYSCTL_TURNSTILE_TEST_USER_HASHTABLE; /* this should be not locked */
376*19c3b8c2SApple OSS Distributions 	data[2].lock2 = SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE; /* this should be locked */
377*19c3b8c2SApple OSS Distributions 	data[2].sleep = 0; /* no need to sleep, everything should be pushing by the time it acquires the lock */
378*19c3b8c2SApple OSS Distributions 	data[2].sched_pri_to_check = 60;
379*19c3b8c2SApple OSS Distributions 	data[2].base_pri_to_check = 60;
380*19c3b8c2SApple OSS Distributions 	pthread_create(&threads[2], NULL, chain_locking, (void *)&data[2]);
381*19c3b8c2SApple OSS Distributions 	sleep(2); /* give the thread time to acquire the lock */
382*19c3b8c2SApple OSS Distributions 
383*19c3b8c2SApple OSS Distributions 	/* Create a thread at priority 47 and take SYSCTL_TURNSTILE_TEST_USER_DEFAULT lock followed by SYSCTL_TURNSTILE_TEST_USER_HASHTABLE */
384*19c3b8c2SApple OSS Distributions 	data[3].pri_to_set = 47;
385*19c3b8c2SApple OSS Distributions 	data[3].lock1 = SYSCTL_TURNSTILE_TEST_USER_DEFAULT; /* this should be not locked */
386*19c3b8c2SApple OSS Distributions 	data[3].lock2 = SYSCTL_TURNSTILE_TEST_USER_HASHTABLE; /* this should be locked */
387*19c3b8c2SApple OSS Distributions 	data[3].sleep = 0; /* no need to sleep, everything should be pushing by the time it acquires the lock */
388*19c3b8c2SApple OSS Distributions 	data[3].sched_pri_to_check = 60;
389*19c3b8c2SApple OSS Distributions 	data[3].base_pri_to_check = 60;
390*19c3b8c2SApple OSS Distributions 	pthread_create(&threads[3], NULL, chain_locking, (void *)&data[3]);
391*19c3b8c2SApple OSS Distributions 	sleep(2); /* give the thread time to acquire the lock */
392*19c3b8c2SApple OSS Distributions 
393*19c3b8c2SApple OSS Distributions 	/* Create a thread at priority 60 and take SYSCTL_TURNSTILE_TEST_USER_DEFAULT */
394*19c3b8c2SApple OSS Distributions 	data[4].pri_to_set = 60;
395*19c3b8c2SApple OSS Distributions 	data[4].lock1 = SYSCTL_TURNSTILE_TEST_USER_DEFAULT; /* this should be locked */
396*19c3b8c2SApple OSS Distributions 	data[4].lock2 = NULL;
397*19c3b8c2SApple OSS Distributions 	data[4].sleep = 0; /* no need to sleep, nothing should be pushing by the time it acquires the lock */
398*19c3b8c2SApple OSS Distributions 	data[4].sched_pri_to_check = 60; /* this is its own priority */
399*19c3b8c2SApple OSS Distributions 	data[4].base_pri_to_check = 60;
400*19c3b8c2SApple OSS Distributions 	pthread_create(&threads[4], NULL, chain_locking, (void *)&data[4]);
401*19c3b8c2SApple OSS Distributions 
402*19c3b8c2SApple OSS Distributions 	sleep(16);
403*19c3b8c2SApple OSS Distributions 	return;
404*19c3b8c2SApple OSS Distributions }
405*19c3b8c2SApple OSS Distributions 
406*19c3b8c2SApple OSS Distributions /*
407*19c3b8c2SApple OSS Distributions  * Test 5: test if a chain of user-space turnstile primitives interleaved by kernel primitives works correctly.
408*19c3b8c2SApple OSS Distributions  */
409*19c3b8c2SApple OSS Distributions static void
test5(void)410*19c3b8c2SApple OSS Distributions test5(void)
411*19c3b8c2SApple OSS Distributions {
412*19c3b8c2SApple OSS Distributions 	pthread_t threads[5] = {};
413*19c3b8c2SApple OSS Distributions 	struct thread_data data[5] = {};
414*19c3b8c2SApple OSS Distributions 
415*19c3b8c2SApple OSS Distributions 	T_LOG("Test 5: test if a chain of user-space turnstile primitives interleaved by kernel primitives works correctly");
416*19c3b8c2SApple OSS Distributions 
417*19c3b8c2SApple OSS Distributions 	/*
418*19c3b8c2SApple OSS Distributions 	 * Chain: t4->ud->t3->kh->t2->uh->t1->kd->t0
419*19c3b8c2SApple OSS Distributions 	 * ud and uh (user space turnstiles) will push base pri and sched pri
420*19c3b8c2SApple OSS Distributions 	 * kd and kh (kernel space turnstiles) will push sched pri
421*19c3b8c2SApple OSS Distributions 	 * uh is the breaking point of the chain for sched pri
422*19c3b8c2SApple OSS Distributions 	 */
423*19c3b8c2SApple OSS Distributions 
424*19c3b8c2SApple OSS Distributions 	/* Create a thread at priority 4 and take SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT lock */
425*19c3b8c2SApple OSS Distributions 	data[0].pri_to_set = 4;
426*19c3b8c2SApple OSS Distributions 	data[0].lock1 = SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT; /* this should be not locked */
427*19c3b8c2SApple OSS Distributions 	data[0].lock2 = NULL;
428*19c3b8c2SApple OSS Distributions 	data[0].sleep = 10; /* long sleep, nothing is blocking this thread */
429*19c3b8c2SApple OSS Distributions 	data[0].sched_pri_to_check = 41;
430*19c3b8c2SApple OSS Distributions 	data[0].base_pri_to_check = 4;
431*19c3b8c2SApple OSS Distributions 	pthread_create(&threads[0], NULL, chain_locking, (void *)&data[0]);
432*19c3b8c2SApple OSS Distributions 	sleep(2); /* give the thread time to acquire the lock */
433*19c3b8c2SApple OSS Distributions 
434*19c3b8c2SApple OSS Distributions 	/* Create a thread at priority 31 and take SYSCTL_TURNSTILE_TEST_USER_HASHTABLE lock followed by SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT */
435*19c3b8c2SApple OSS Distributions 	data[1].pri_to_set = 31;
436*19c3b8c2SApple OSS Distributions 	data[1].lock1 = SYSCTL_TURNSTILE_TEST_USER_HASHTABLE; /* this should be not locked */
437*19c3b8c2SApple OSS Distributions 	data[1].lock2 = SYSCTL_TURNSTILE_TEST_KERNEL_DEFAULT; /* this should be locked */
438*19c3b8c2SApple OSS Distributions 	data[1].sleep = 0; /* no need to sleep, everything should be pushing by the time it acquires the lock */
439*19c3b8c2SApple OSS Distributions 	data[1].sched_pri_to_check = 41;
440*19c3b8c2SApple OSS Distributions 	data[1].base_pri_to_check = 41;
441*19c3b8c2SApple OSS Distributions 	pthread_create(&threads[1], NULL, chain_locking, (void *)&data[1]);
442*19c3b8c2SApple OSS Distributions 	sleep(2); /* give the thread time to acquire the lock */
443*19c3b8c2SApple OSS Distributions 
444*19c3b8c2SApple OSS Distributions 	/* Create a thread at priority 41 and take SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE lock followed by SYSCTL_TURNSTILE_TEST_USER_HASHTABLE */
445*19c3b8c2SApple OSS Distributions 	data[2].pri_to_set = 41;
446*19c3b8c2SApple OSS Distributions 	data[2].lock1 = SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE; /* this should be not locked */
447*19c3b8c2SApple OSS Distributions 	data[2].lock2 = SYSCTL_TURNSTILE_TEST_USER_HASHTABLE; /* this should be locked */
448*19c3b8c2SApple OSS Distributions 	data[2].sleep = 0; /* no need to sleep, everything should be pushing by the time it acquires the lock */
449*19c3b8c2SApple OSS Distributions 	data[2].sched_pri_to_check = 60;
450*19c3b8c2SApple OSS Distributions 	data[2].base_pri_to_check = 41;
451*19c3b8c2SApple OSS Distributions 	pthread_create(&threads[2], NULL, chain_locking, (void *)&data[2]);
452*19c3b8c2SApple OSS Distributions 	sleep(2); /* give the thread time to acquire the lock */
453*19c3b8c2SApple OSS Distributions 
454*19c3b8c2SApple OSS Distributions 	/* Create a thread at priority 47 and take SYSCTL_TURNSTILE_TEST_USER_DEFAULT lock followed by SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE */
455*19c3b8c2SApple OSS Distributions 	data[3].pri_to_set = 47;
456*19c3b8c2SApple OSS Distributions 	data[3].lock1 = SYSCTL_TURNSTILE_TEST_USER_DEFAULT; /* this should be not locked */
457*19c3b8c2SApple OSS Distributions 	data[3].lock2 = SYSCTL_TURNSTILE_TEST_KERNEL_HASHTABLE; /* this should be locked */
458*19c3b8c2SApple OSS Distributions 	data[3].sleep = 0; /* no need to sleep, everything should be pushing by the time it acquires the lock */
459*19c3b8c2SApple OSS Distributions 	data[3].sched_pri_to_check = 60;
460*19c3b8c2SApple OSS Distributions 	data[3].base_pri_to_check = 60;
461*19c3b8c2SApple OSS Distributions 	pthread_create(&threads[3], NULL, chain_locking, (void *)&data[3]);
462*19c3b8c2SApple OSS Distributions 	sleep(2); /* give the thread time to acquire the lock */
463*19c3b8c2SApple OSS Distributions 
464*19c3b8c2SApple OSS Distributions 	/* Create a thread at priority 60 and take SYSCTL_TURNSTILE_TEST_USER_DEFAULT */
465*19c3b8c2SApple OSS Distributions 	data[4].pri_to_set = 60;
466*19c3b8c2SApple OSS Distributions 	data[4].lock1 = SYSCTL_TURNSTILE_TEST_USER_DEFAULT; /* this should be locked */
467*19c3b8c2SApple OSS Distributions 	data[4].lock2 = NULL;
468*19c3b8c2SApple OSS Distributions 	data[4].sleep = 0; /* no need to sleep, nothing should be pushing by the time it acquires the lock */
469*19c3b8c2SApple OSS Distributions 	data[4].sched_pri_to_check = 60; /* this is its own priority */
470*19c3b8c2SApple OSS Distributions 	data[4].base_pri_to_check = 60;
471*19c3b8c2SApple OSS Distributions 	pthread_create(&threads[4], NULL, chain_locking, (void *)&data[4]);
472*19c3b8c2SApple OSS Distributions 
473*19c3b8c2SApple OSS Distributions 	sleep(16);
474*19c3b8c2SApple OSS Distributions 	return;
475*19c3b8c2SApple OSS Distributions }
476*19c3b8c2SApple OSS Distributions 
477*19c3b8c2SApple OSS Distributions T_DECL(turnstile_test, "Turnstile test", T_META_ASROOT(YES))
478*19c3b8c2SApple OSS Distributions {
479*19c3b8c2SApple OSS Distributions 	test1(SYSCTL_TURNSTILE_TEST_USER_DEFAULT);
480*19c3b8c2SApple OSS Distributions 	test2(SYSCTL_TURNSTILE_TEST_USER_DEFAULT);
481*19c3b8c2SApple OSS Distributions 	test3(SYSCTL_TURNSTILE_TEST_USER_DEFAULT);
482*19c3b8c2SApple OSS Distributions 
483*19c3b8c2SApple OSS Distributions 	test1(SYSCTL_TURNSTILE_TEST_USER_HASHTABLE);
484*19c3b8c2SApple OSS Distributions 	test2(SYSCTL_TURNSTILE_TEST_USER_HASHTABLE);
485*19c3b8c2SApple OSS Distributions 	test3(SYSCTL_TURNSTILE_TEST_USER_HASHTABLE);
486*19c3b8c2SApple OSS Distributions 
487*19c3b8c2SApple OSS Distributions 	/*
488*19c3b8c2SApple OSS Distributions 	 * rdar://problem/46302128
489*19c3b8c2SApple OSS Distributions 	 * These tests are using a sysctl to lock a dummy kernel resource that uses turnstile.
490*19c3b8c2SApple OSS Distributions 	 * However a thread holding a kernel push from turnstile should never return in
491*19c3b8c2SApple OSS Distributions 	 * userspace, and rdar://problem/24194397 adds an assert for it.
492*19c3b8c2SApple OSS Distributions 	 */
493*19c3b8c2SApple OSS Distributions 	//test4();
494*19c3b8c2SApple OSS Distributions 	//test5();
495*19c3b8c2SApple OSS Distributions }
496