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