xref: /xnu-11417.140.69/tests/mach_eventlink.c (revision 43a90889846e00bfb5cf1d255cdc0a701a1e05a4)
1 /*
2  * mach eventlink: Tests mach eventlink kernel synchronization primitive.
3  */
4 
5 #include <darwintest.h>
6 #include <darwintest_multiprocess.h>
7 
8 #include <pthread.h>
9 #include <launch.h>
10 #include <mach/mach.h>
11 #include <mach/message.h>
12 #include <mach/mach_voucher.h>
13 #include <pthread/workqueue_private.h>
14 #include <voucher/ipc_pthread_priority_types.h>
15 #include <servers/bootstrap.h>
16 #include <stdlib.h>
17 #include <sys/event.h>
18 #include <unistd.h>
19 #include <crt_externs.h>
20 #include <signal.h>
21 #include <sys/types.h>
22 #include <sys/sysctl.h>
23 #include <libkern/OSAtomic.h>
24 #include <sys/wait.h>
25 #include <spawn.h>
26 #include <spawn_private.h>
27 #include <mach/mach_eventlink.h>
28 #include <os/atomic_private.h>
29 
30 T_GLOBAL_META(T_META_NAMESPACE("xnu.mach_eventlink"),
31     T_META_RUN_CONCURRENTLY(true));
32 
33 static int g_loop_iterations = 100000;
34 
35 static kern_return_t
test_eventlink_create(mach_port_t * port_pair)36 test_eventlink_create(mach_port_t *port_pair)
37 {
38 	kern_return_t kr;
39 
40 	kr = mach_eventlink_create(mach_task_self(), MELC_OPTION_NO_COPYIN, port_pair);
41 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_create");
42 
43 	return kr;
44 }
45 
46 static pthread_t
thread_create_for_test(void * (* function)(void *),void * arg)47 thread_create_for_test(void * (*function)(void *), void *arg)
48 {
49 	pthread_t pthread;
50 	pthread_attr_t attr;
51 
52 	pthread_attr_init(&attr);
53 	pthread_create(&pthread, &attr, function, arg);
54 
55 	T_LOG("pthread created\n");
56 	return pthread;
57 }
58 
59 static void *
while1loop(__unused void * arg)60 while1loop(__unused void *arg)
61 {
62 	while (1) {
63 		;
64 	}
65 	return NULL;
66 }
67 
68 static void *
test_eventlink_wait_with_timeout(void * arg)69 test_eventlink_wait_with_timeout(void *arg)
70 {
71 	kern_return_t kr;
72 	mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
73 	mach_port_t self = mach_thread_self();
74 	uint64_t ticks = mach_absolute_time();
75 	uint64_t count = 1;
76 
77 	/* Associate thread with eventlink port */
78 	kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
79 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
80 
81 	/* Wait on the eventlink with timeout */
82 	kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
83 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, ticks + 5000);
84 
85 	T_EXPECT_MACH_ERROR(kr, KERN_OPERATION_TIMED_OUT, "mach_eventlink_wait_until returned expected error");
86 	T_EXPECT_EQ(count, (uint64_t)0, "mach_eventlink_wait_until returned correct count value");
87 
88 	return NULL;
89 }
90 
91 static void *
test_eventlink_wait_no_wait(void * arg)92 test_eventlink_wait_no_wait(void *arg)
93 {
94 	kern_return_t kr;
95 	mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
96 	mach_port_t self = mach_thread_self();
97 	uint64_t count = 1;
98 
99 	/* Associate thread with eventlink port */
100 	kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
101 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
102 
103 	/* Wait on the eventlink */
104 	kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NO_WAIT,
105 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
106 
107 	T_EXPECT_MACH_ERROR(kr, KERN_OPERATION_TIMED_OUT, "mach_eventlink_wait_until returned expected error");
108 	T_EXPECT_EQ(count, (uint64_t)0, "mach_eventlink_wait_until returned correct count value");
109 
110 	return NULL;
111 }
112 
113 static void *
test_eventlink_wait_destroy(void * arg)114 test_eventlink_wait_destroy(void *arg)
115 {
116 	kern_return_t kr;
117 	mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
118 	mach_port_t self = mach_thread_self();
119 	uint64_t count = 1;
120 
121 	/* Associate thread with eventlink port */
122 	kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
123 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
124 
125 	/* Wait on the eventlink */
126 	kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
127 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
128 
129 	T_EXPECT_MACH_ERROR(kr, KERN_TERMINATED, "mach_eventlink_wait_until returned expected error");
130 
131 	return NULL;
132 }
133 
134 static void *
test_eventlink_wait_for_signal(void * arg)135 test_eventlink_wait_for_signal(void *arg)
136 {
137 	kern_return_t kr;
138 	mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
139 	mach_port_t self = mach_thread_self();
140 	uint64_t count = 0;
141 
142 	/* Associate thread with eventlink port */
143 	kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
144 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
145 
146 	/* Wait on the eventlink */
147 	kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
148 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
149 
150 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_wait_until");
151 	T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
152 
153 	return NULL;
154 }
155 
156 static void *
test_eventlink_wait_then_signal(void * arg)157 test_eventlink_wait_then_signal(void *arg)
158 {
159 	kern_return_t kr;
160 	mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
161 	mach_port_t self = mach_thread_self();
162 	uint64_t count = 0;
163 
164 	/* Associate thread with eventlink port */
165 	kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
166 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
167 
168 	/* Wait on the eventlink */
169 	kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
170 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
171 
172 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_wait_until");
173 	T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
174 
175 	/* Signal the eventlink to wakeup other side */
176 	kr = mach_eventlink_signal(eventlink_port, 0);
177 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal");
178 
179 	return NULL;
180 }
181 
182 static void *
test_eventlink_wait_then_wait_signal_with_no_wait(void * arg)183 test_eventlink_wait_then_wait_signal_with_no_wait(void *arg)
184 {
185 	kern_return_t kr;
186 	mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
187 	mach_port_t self = mach_thread_self();
188 	uint64_t count = 0;
189 
190 	/* Associate thread with eventlink port */
191 	kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
192 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
193 
194 	/* Wait on the eventlink */
195 	kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
196 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
197 
198 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_wait_until");
199 	T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
200 
201 	/* Signal wait the eventlink */
202 	kr = mach_eventlink_signal_wait_until(eventlink_port, &count, 0, MELSW_OPTION_NO_WAIT,
203 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
204 
205 	T_EXPECT_MACH_ERROR(kr, KERN_OPERATION_TIMED_OUT, "mach_eventlink_wait_until returned expected error");
206 	T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
207 
208 	return NULL;
209 }
210 
211 static void *
test_eventlink_wait_then_wait_signal_with_prepost(void * arg)212 test_eventlink_wait_then_wait_signal_with_prepost(void *arg)
213 {
214 	kern_return_t kr;
215 	mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
216 	mach_port_t self = mach_thread_self();
217 	uint64_t count = 0;
218 
219 	/* Associate thread with eventlink port */
220 	kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
221 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
222 
223 	/* Wait on the eventlink */
224 	kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
225 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
226 
227 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_wait_until");
228 	T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
229 
230 	/* Signal wait the eventlink with stale counter value */
231 	count = 0;
232 	kr = mach_eventlink_signal_wait_until(eventlink_port, &count, 0, MELSW_OPTION_NONE,
233 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
234 
235 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal_wait_until");
236 	T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
237 
238 	return NULL;
239 }
240 
241 static void *
test_eventlink_wait_then_signal_loop(void * arg)242 test_eventlink_wait_then_signal_loop(void *arg)
243 {
244 	kern_return_t kr;
245 	mach_port_t eventlink_port = (mach_port_t) (uintptr_t)arg;
246 	mach_port_t self = mach_thread_self();
247 	uint64_t count = 0;
248 	int i;
249 
250 	/* Associate thread with eventlink port */
251 	kr = mach_eventlink_associate(eventlink_port, self, 0, 0, 0, 0, MELA_OPTION_NONE);
252 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate");
253 
254 	/* Wait on the eventlink */
255 	kr = mach_eventlink_wait_until(eventlink_port, &count, MELSW_OPTION_NONE,
256 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
257 
258 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_wait_until");
259 	T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_wait_until returned correct count value");
260 
261 	for (i = 1; i < g_loop_iterations; i++) {
262 		/* Signal wait the eventlink */
263 		kr = mach_eventlink_signal_wait_until(eventlink_port, &count, 0, MELSW_OPTION_NONE,
264 		    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
265 
266 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal_wait_until");
267 		T_QUIET; T_EXPECT_EQ(count, (uint64_t)(i + 1), "mach_eventlink_wait_until returned correct count value");
268 	}
269 
270 	/* Signal the eventlink to wakeup other side */
271 	kr = mach_eventlink_signal(eventlink_port, 0);
272 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal");
273 
274 	return NULL;
275 }
276 
277 /*
278  * Test 1: Create ipc eventlink kernel object.
279  *
280  * Calls eventlink creates which returns a pair of eventlink port objects.
281  */
282 T_DECL(test_eventlink_create, "eventlink create test", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
283 {
284 	kern_return_t kr;
285 	mach_port_t port_pair[2];
286 
287 	kr = test_eventlink_create(port_pair);
288 	if (kr != KERN_SUCCESS) {
289 		return;
290 	}
291 
292 	mach_port_deallocate(mach_task_self(), port_pair[0]);
293 	mach_port_deallocate(mach_task_self(), port_pair[1]);
294 }
295 
296 /*
297  * Test 2: Create ipc eventlink kernel object and call eventlink destroy
298  *
299  * Calls eventlink creates which returns a pair of eventlink port objects.
300  * Calls eventlink destroy on eventlink port pair.
301  */
302 T_DECL(test_eventlink_destroy, "eventlink destroy test", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
303 {
304 	kern_return_t kr;
305 	mach_port_t port_pair[2];
306 
307 	kr = test_eventlink_create(port_pair);
308 	if (kr != KERN_SUCCESS) {
309 		return;
310 	}
311 
312 	kr = mach_eventlink_destroy(port_pair[0]);
313 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_destroy");
314 	kr = mach_eventlink_destroy(port_pair[1]);
315 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_destroy");
316 }
317 
318 /*
319  * Test 3: Associate threads to eventlink object.
320  *
321  * Create eventlink object pair and associate threads to each side and then
322  * disassociate threads and check for error conditions.
323  */
324 T_DECL(test_eventlink_associate, "eventlink associate test", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
325 {
326 	kern_return_t kr;
327 	mach_port_t port_pair[2];
328 	mach_port_t self = mach_thread_self();
329 	mach_port_t other_thread = MACH_PORT_NULL;
330 	pthread_t pthread;
331 
332 	/* eventlink associate to NULL eventlink object */
333 	kr = mach_eventlink_associate(MACH_PORT_NULL, self, 0, 0, 0, 0, MELA_OPTION_NONE);
334 	T_EXPECT_MACH_ERROR(kr, MACH_SEND_INVALID_DEST, "mach_eventlink_associate with null eventlink returned expected error");
335 
336 	/* eventlink disassociate to NULL eventlink object */
337 	kr = mach_eventlink_disassociate(MACH_PORT_NULL, MELD_OPTION_NONE);
338 	T_EXPECT_MACH_ERROR(kr, MACH_SEND_INVALID_DEST, "mach_eventlink_disassociate with null eventlink returned expected error");
339 
340 	/* Create an eventlink and associate threads to it */
341 	kr = test_eventlink_create(port_pair);
342 	if (kr != KERN_SUCCESS) {
343 		return;
344 	}
345 
346 	pthread = thread_create_for_test(while1loop, NULL);
347 	other_thread = pthread_mach_thread_np(pthread);
348 
349 	for (int i = 0; i < 3; i++) {
350 		/* Associate thread to eventlink objects */
351 		kr = mach_eventlink_associate(port_pair[0], self, 0, 0, 0, 0, MELA_OPTION_NONE);
352 		T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 1");
353 
354 		kr = mach_eventlink_associate(port_pair[1], other_thread, 0, 0, 0, 0, MELA_OPTION_NONE);
355 		T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
356 
357 		/* Try to associate again with diff threads, expect failure */
358 		kr = mach_eventlink_associate(port_pair[0], other_thread, 0, 0, 0, 0, MELA_OPTION_NONE);
359 		T_EXPECT_MACH_ERROR(kr, KERN_NAME_EXISTS, "mach_eventlink_associate for associated "
360 		    "objects returned expected error");
361 
362 		kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
363 		T_EXPECT_MACH_ERROR(kr, KERN_NAME_EXISTS, "mach_eventlink_associate for associated "
364 		    "objects return expected error");
365 
366 		/* Try to disassociate the threads */
367 		kr = mach_eventlink_disassociate(port_pair[0], MELD_OPTION_NONE);
368 		T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_disassociate for object 1");
369 
370 		kr = mach_eventlink_disassociate(port_pair[1], MELD_OPTION_NONE);
371 		T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_disassociate for object 2");
372 
373 		/* Try to disassociate the threads again, expect failure */
374 		kr = mach_eventlink_disassociate(port_pair[0], MELD_OPTION_NONE);
375 		T_EXPECT_MACH_ERROR(kr, KERN_INVALID_ARGUMENT, "mach_eventlink_disassociate for "
376 		    "disassociated objects returned expected error");
377 
378 		kr = mach_eventlink_disassociate(port_pair[1], MELD_OPTION_NONE);
379 		T_EXPECT_MACH_ERROR(kr, KERN_INVALID_ARGUMENT, "mach_eventlink_disassociate for "
380 		    "disassociated objects returned expected error");
381 	}
382 
383 	kr = mach_eventlink_destroy(port_pair[0]);
384 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_destroy");
385 
386 	/* Try disassociate on other end of destoryed eventlink pair */
387 	kr = mach_eventlink_disassociate(port_pair[1], MELD_OPTION_NONE);
388 	T_EXPECT_MACH_ERROR(kr, KERN_TERMINATED, "mach_eventlink_disassociate for "
389 	    "terminated object returned expected error");
390 
391 	kr = mach_eventlink_destroy(port_pair[1]);
392 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_destroy");
393 }
394 
395 /*
396  * Test 4: Test eventlink wait with timeout.
397  *
398  * Create an eventlink object, associate threads and test eventlink wait with timeout.
399  */
400 T_DECL(test_eventlink_wait_timeout, "eventlink wait timeout test", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
401 {
402 	kern_return_t kr;
403 	mach_port_t port_pair[2];
404 	pthread_t pthread;
405 
406 	/* Create an eventlink and associate threads to it */
407 	kr = test_eventlink_create(port_pair);
408 	if (kr != KERN_SUCCESS) {
409 		return;
410 	}
411 
412 	pthread = thread_create_for_test(test_eventlink_wait_with_timeout, (void *)(uintptr_t)port_pair[0]);
413 	sleep(10);
414 
415 	/* destroy the eventlink object, the wake status of thread will check if the test passsed or failed */
416 	mach_port_deallocate(mach_task_self(), port_pair[0]);
417 	mach_port_deallocate(mach_task_self(), port_pair[1]);
418 
419 	pthread_join(pthread, NULL);
420 }
421 
422 /*
423  * Test 5: Test eventlink wait with no wait.
424  *
425  * Create an eventlink object, associate threads and test eventlink wait with no wait flag.
426  */
427 T_DECL(test_eventlink_wait_no_wait, "eventlink wait no wait test", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
428 {
429 	kern_return_t kr;
430 	mach_port_t port_pair[2];
431 	pthread_t pthread;
432 
433 	/* Create an eventlink and associate threads to it */
434 	kr = test_eventlink_create(port_pair);
435 	if (kr != KERN_SUCCESS) {
436 		return;
437 	}
438 
439 	pthread = thread_create_for_test(test_eventlink_wait_no_wait, (void *)(uintptr_t)port_pair[0]);
440 	pthread_join(pthread, NULL);
441 
442 	mach_port_deallocate(mach_task_self(), port_pair[0]);
443 	mach_port_deallocate(mach_task_self(), port_pair[1]);
444 }
445 
446 /*
447  * Test 6: Test eventlink wait and destroy.
448  *
449  * Create an eventlink object, associate threads and destroy the port.
450  */
451 T_DECL(test_eventlink_wait_and_destroy, "eventlink wait and destroy", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
452 {
453 	kern_return_t kr;
454 	mach_port_t port_pair[2];
455 	pthread_t pthread;
456 
457 	/* Create an eventlink and associate threads to it */
458 	kr = test_eventlink_create(port_pair);
459 	if (kr != KERN_SUCCESS) {
460 		return;
461 	}
462 
463 	pthread = thread_create_for_test(test_eventlink_wait_destroy, (void *)(uintptr_t)port_pair[0]);
464 
465 	sleep(5);
466 
467 	/* Increase the send right count for port before destroy to make sure no sender does not fire on destroy */
468 	kr = mach_port_mod_refs(mach_task_self(), port_pair[0], MACH_PORT_RIGHT_SEND, 2);
469 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_mod_refs");
470 
471 	/* Destroy the port for thread to wakeup */
472 	kr = mach_eventlink_destroy(port_pair[0]);
473 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_destroy");
474 
475 	pthread_join(pthread, NULL);
476 	mach_port_deallocate(mach_task_self(), port_pair[1]);
477 }
478 
479 
480 /*
481  * Test 7: Test eventlink wait and destroy remote side.
482  *
483  * Create an eventlink object, associate threads, wait and destroy the remote eventlink port.
484  */
485 T_DECL(test_eventlink_wait_and_destroy_remote, "eventlink wait and remote destroy", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
486 {
487 	kern_return_t kr;
488 	mach_port_t port_pair[2];
489 	pthread_t pthread;
490 
491 	/* Create an eventlink and associate threads to it */
492 	kr = test_eventlink_create(port_pair);
493 	if (kr != KERN_SUCCESS) {
494 		return;
495 	}
496 
497 	pthread = thread_create_for_test(test_eventlink_wait_destroy, (void *)(uintptr_t)port_pair[0]);
498 
499 	sleep(5);
500 
501 	/* Increase the send right count for port before destroy to make sure no sender does not fire on destroy */
502 	kr = mach_port_mod_refs(mach_task_self(), port_pair[1], MACH_PORT_RIGHT_SEND, 2);
503 	T_ASSERT_MACH_SUCCESS(kr, "mach_port_mod_refs");
504 
505 	/* Destroy the port for thread to wakeup */
506 	kr = mach_eventlink_destroy(port_pair[1]);
507 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_destroy");
508 
509 	pthread_join(pthread, NULL);
510 	mach_port_deallocate(mach_task_self(), port_pair[0]);
511 }
512 
513 /*
514  * Test 8: Test eventlink wait and deallocate port.
515  *
516  * Create an eventlink object, associate threads, wait and deallocate the eventlink port.
517  */
518 T_DECL(test_eventlink_wait_and_deallocate, "eventlink wait and deallocate", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
519 {
520 	kern_return_t kr;
521 	mach_port_t port_pair[2];
522 	pthread_t pthread;
523 
524 	/* Create an eventlink and associate threads to it */
525 	kr = test_eventlink_create(port_pair);
526 	if (kr != KERN_SUCCESS) {
527 		return;
528 	}
529 
530 	pthread = thread_create_for_test(test_eventlink_wait_destroy, (void *)(uintptr_t)port_pair[0]);
531 
532 	sleep(5);
533 
534 	/* Destroy the port for thread to wakeup */
535 	mach_port_deallocate(mach_task_self(), port_pair[0]);
536 
537 	pthread_join(pthread, NULL);
538 	mach_port_deallocate(mach_task_self(), port_pair[1]);
539 }
540 
541 /*
542  * Test 9: Test eventlink wait and disassociate.
543  *
544  * Create an eventlink object, associate threads, wait and disassociate thread from the eventlink port.
545  */
546 T_DECL(test_eventlink_wait_and_disassociate, "eventlink wait and disassociate", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
547 {
548 	kern_return_t kr;
549 	mach_port_t port_pair[2];
550 	pthread_t pthread;
551 
552 	/* Create an eventlink and associate threads to it */
553 	kr = test_eventlink_create(port_pair);
554 	if (kr != KERN_SUCCESS) {
555 		return;
556 	}
557 
558 	pthread = thread_create_for_test(test_eventlink_wait_destroy, (void *)(uintptr_t)port_pair[0]);
559 
560 	sleep(5);
561 
562 	/* Disassociate thread from eventlink for thread to wakeup */
563 	kr = mach_eventlink_disassociate(port_pair[0], MELD_OPTION_NONE);
564 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_disassociate");
565 
566 	pthread_join(pthread, NULL);
567 	mach_port_deallocate(mach_task_self(), port_pair[1]);
568 	mach_port_deallocate(mach_task_self(), port_pair[0]);
569 }
570 
571 /*
572  * Test 10: Test eventlink wait and signal.
573  *
574  * Create an eventlink object, associate threads and test wait signal.
575  */
576 T_DECL(test_eventlink_wait_and_signal, "eventlink wait and signal", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
577 {
578 	kern_return_t kr;
579 	mach_port_t port_pair[2];
580 	pthread_t pthread;
581 	mach_port_t self = mach_thread_self();
582 
583 	/* Create an eventlink and associate threads to it */
584 	kr = test_eventlink_create(port_pair);
585 	if (kr != KERN_SUCCESS) {
586 		return;
587 	}
588 
589 	pthread = thread_create_for_test(test_eventlink_wait_for_signal, (void *)(uintptr_t)port_pair[0]);
590 
591 	sleep(5);
592 
593 	/* Associate thread and signal the eventlink */
594 	kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
595 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
596 
597 	kr = mach_eventlink_signal(port_pair[1], 0);
598 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal for object 2");
599 
600 	pthread_join(pthread, NULL);
601 
602 	mach_port_deallocate(mach_task_self(), port_pair[0]);
603 	mach_port_deallocate(mach_task_self(), port_pair[1]);
604 }
605 
606 /*
607  * Test 11: Test eventlink wait_signal.
608  *
609  * Create an eventlink object, associate threads and test wait_signal.
610  */
611 T_DECL(test_eventlink_wait_signal, "eventlink wait_signal", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
612 {
613 	kern_return_t kr;
614 	mach_port_t port_pair[2];
615 	pthread_t pthread;
616 	mach_port_t self = mach_thread_self();
617 	uint64_t count = 0;
618 
619 	/* Create an eventlink and associate threads to it */
620 	kr = test_eventlink_create(port_pair);
621 	if (kr != KERN_SUCCESS) {
622 		return;
623 	}
624 
625 	pthread = thread_create_for_test(test_eventlink_wait_then_signal, (void *)(uintptr_t)port_pair[0]);
626 
627 	sleep(5);
628 
629 	/* Associate thread and wait_signal the eventlink */
630 	kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
631 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
632 
633 	/* Wait on the eventlink with timeout */
634 	kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
635 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
636 
637 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal_wait_until");
638 	T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_signal_wait_until returned correct count value");
639 
640 	pthread_join(pthread, NULL);
641 
642 	mach_port_deallocate(mach_task_self(), port_pair[0]);
643 	mach_port_deallocate(mach_task_self(), port_pair[1]);
644 }
645 
646 /*
647  * Test 12: Test eventlink wait_signal with no wait.
648  *
649  * Create an eventlink object, associate threads and test wait_signal with no wait.
650  */
651 T_DECL(test_eventlink_wait_signal_no_wait, "eventlink wait_signal with no wait", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
652 {
653 	kern_return_t kr;
654 	mach_port_t port_pair[2];
655 	pthread_t pthread;
656 	mach_port_t self = mach_thread_self();
657 	uint64_t count = 0;
658 
659 	/* Create an eventlink and associate threads to it */
660 	kr = test_eventlink_create(port_pair);
661 	if (kr != KERN_SUCCESS) {
662 		return;
663 	}
664 
665 	pthread = thread_create_for_test(test_eventlink_wait_then_wait_signal_with_no_wait, (void *)(uintptr_t)port_pair[0]);
666 
667 	sleep(5);
668 
669 	/* Associate thread and wait_signal the eventlink */
670 	kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
671 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
672 
673 	/* Wait on the eventlink with timeout */
674 	kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
675 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
676 
677 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal_wait_until");
678 	T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_signal_wait_until returned correct count value");
679 
680 	pthread_join(pthread, NULL);
681 
682 	mach_port_deallocate(mach_task_self(), port_pair[0]);
683 	mach_port_deallocate(mach_task_self(), port_pair[1]);
684 }
685 
686 /*
687  * Test 13: Test eventlink wait_signal with prepost.
688  *
689  * Create an eventlink object, associate threads and test wait_signal with prepost.
690  */
691 T_DECL(test_eventlink_wait_signal_prepost, "eventlink wait_signal with prepost", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
692 {
693 	kern_return_t kr;
694 	mach_port_t port_pair[2];
695 	pthread_t pthread;
696 	mach_port_t self = mach_thread_self();
697 	uint64_t count = 0;
698 
699 	/* Create an eventlink and associate threads to it */
700 	kr = test_eventlink_create(port_pair);
701 	if (kr != KERN_SUCCESS) {
702 		return;
703 	}
704 
705 	pthread = thread_create_for_test(test_eventlink_wait_then_wait_signal_with_prepost, (void *)(uintptr_t)port_pair[0]);
706 
707 	sleep(5);
708 
709 	/* Associate thread and wait_signal the eventlink */
710 	kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
711 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
712 
713 	/* Wait on the eventlink with timeout */
714 	kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
715 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
716 
717 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal_wait_until");
718 	T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_signal_wait_until returned correct count value");
719 
720 	pthread_join(pthread, NULL);
721 
722 	mach_port_deallocate(mach_task_self(), port_pair[0]);
723 	mach_port_deallocate(mach_task_self(), port_pair[1]);
724 }
725 
726 /*
727  * Test 14: Test eventlink wait_signal with associate on wait option.
728  *
729  * Create an eventlink object, set associate on wait on one side and test wait_signal.
730  */
731 T_DECL(test_eventlink_wait_signal_associate_on_wait, "eventlink wait_signal associate on wait", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
732 {
733 	kern_return_t kr;
734 	mach_port_t port_pair[2];
735 	pthread_t pthread;
736 	uint64_t count = 0;
737 
738 	/* Create an eventlink and associate threads to it */
739 	kr = test_eventlink_create(port_pair);
740 	if (kr != KERN_SUCCESS) {
741 		return;
742 	}
743 
744 	pthread = thread_create_for_test(test_eventlink_wait_then_signal, (void *)(uintptr_t)port_pair[0]);
745 
746 	sleep(5);
747 
748 	/* Set associate on wait and wait_signal the eventlink */
749 	kr = mach_eventlink_associate(port_pair[1], MACH_PORT_NULL, 0, 0, 0, 0, MELA_OPTION_ASSOCIATE_ON_WAIT);
750 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate with associate on wait for object 2");
751 
752 	/* Wait on the eventlink with timeout */
753 	kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
754 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
755 
756 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_signal_wait_until");
757 	T_EXPECT_EQ(count, (uint64_t)1, "mach_eventlink_signal_wait_until returned correct count value");
758 
759 	/* Remove associate on wait option */
760 	kr = mach_eventlink_disassociate(port_pair[1], MELD_OPTION_NONE);
761 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_disassociate");
762 
763 	/* Wait on the eventlink with timeout */
764 	kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
765 	    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
766 
767 	T_EXPECT_MACH_ERROR(kr, KERN_INVALID_ARGUMENT, "mach_eventlink_wait_until returned expected error");
768 
769 	pthread_join(pthread, NULL);
770 
771 	mach_port_deallocate(mach_task_self(), port_pair[0]);
772 	mach_port_deallocate(mach_task_self(), port_pair[1]);
773 }
774 
775 /*
776  * Test 15: Test eventlink wait_signal_loop.
777  *
778  * Create an eventlink object, associate threads and test wait_signal in a loop.
779  */
780 T_DECL(test_eventlink_wait_signal_loop, "eventlink wait_signal in loop", T_META_ASROOT(YES), T_META_TAG_VM_PREFERRED)
781 {
782 	kern_return_t kr;
783 	mach_port_t port_pair[2];
784 	pthread_t pthread;
785 	mach_port_t self = mach_thread_self();
786 	uint64_t count = 0;
787 	int i;
788 
789 	/* Create an eventlink and associate threads to it */
790 	kr = test_eventlink_create(port_pair);
791 	if (kr != KERN_SUCCESS) {
792 		return;
793 	}
794 
795 	pthread = thread_create_for_test(test_eventlink_wait_then_signal_loop, (void *)(uintptr_t)port_pair[0]);
796 
797 	/* Associate thread and wait_signal the eventlink */
798 	kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
799 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
800 
801 	for (i = 0; i < g_loop_iterations; i++) {
802 		/* Wait on the eventlink with timeout */
803 		kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
804 		    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
805 
806 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "main thread: mach_eventlink_signal_wait_until");
807 		T_QUIET; T_EXPECT_EQ(count, (uint64_t)(i + 1), "main thread: mach_eventlink_signal_wait_until returned correct count value");
808 	}
809 
810 	pthread_join(pthread, NULL);
811 
812 	mach_port_deallocate(mach_task_self(), port_pair[0]);
813 	mach_port_deallocate(mach_task_self(), port_pair[1]);
814 }
815 
816 
817 static uint64_t
nanos_to_abs(uint64_t nanos)818 nanos_to_abs(uint64_t nanos)
819 {
820 	static mach_timebase_info_data_t timebase_info;
821 	mach_timebase_info(&timebase_info);
822 	return nanos * timebase_info.denom / timebase_info.numer;
823 }
824 
825 static const uint64_t DEFAULT_INTERVAL_NS = 15000000; // 15 ms
826 
827 static void
set_realtime(pthread_t thread,uint64_t interval_nanos)828 set_realtime(pthread_t thread, uint64_t interval_nanos)
829 {
830 	kern_return_t kr;
831 	thread_time_constraint_policy_data_t pol;
832 
833 	mach_port_t target_thread = pthread_mach_thread_np(thread);
834 	T_QUIET; T_ASSERT_GT(target_thread, 0, "pthread_mach_thread_np");
835 
836 	/* 1s 100ms 10ms */
837 	pol.period      = (uint32_t)nanos_to_abs(interval_nanos);
838 	pol.constraint  = (uint32_t)nanos_to_abs(interval_nanos);
839 	pol.computation = (uint32_t)nanos_to_abs(interval_nanos - 1000000); // 1 ms of leeway
840 
841 	pol.preemptible = 0; /* Ignored by OS */
842 	kr = thread_policy_set(target_thread, THREAD_TIME_CONSTRAINT_POLICY, (thread_policy_t) &pol,
843 	    THREAD_TIME_CONSTRAINT_POLICY_COUNT);
844 	T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "thread_policy_set(THREAD_TIME_CONSTRAINT_POLICY)");
845 }
846 
847 
848 static _Atomic bool suspend_resume_thread_stop = false;
849 
850 static void *
test_suspend_resume_thread(void * arg)851 test_suspend_resume_thread(void *arg)
852 {
853 	uint64_t count = 0;
854 	mach_port_t suspend_resume_other_thread_port = (mach_port_t) (uintptr_t)arg;
855 	kern_return_t kr1 = KERN_SUCCESS, kr2 = KERN_SUCCESS;
856 
857 	while (!os_atomic_load(&suspend_resume_thread_stop, relaxed) && kr1 == KERN_SUCCESS && kr2 == KERN_SUCCESS) {
858 		kr1 = thread_suspend(suspend_resume_other_thread_port);
859 		kr2 = thread_resume(suspend_resume_other_thread_port);
860 		count++;
861 	}
862 
863 	T_ASSERT_MACH_SUCCESS(kr1, "thread_suspend #%lld", count);
864 	T_ASSERT_MACH_SUCCESS(kr2, "thread_resume #%lld", count);
865 
866 	return NULL;
867 }
868 
869 /*
870  * Test 16: Test suspension of a thread in the middle of a wait-signal operation
871  * rdar://120761588 rdar://123887338
872  */
873 T_DECL(test_eventlink_wait_signal_suspend_loop, "eventlink wait_signal + thread_suspend/resume in loop", T_META_ASROOT(YES))
874 {
875 	kern_return_t kr;
876 	mach_port_t port_pair[2];
877 	pthread_t pthread, suspend_thread;
878 	mach_port_t self = mach_thread_self();
879 	uint64_t count = 0;
880 	int i;
881 
882 	/* Create an eventlink and associate threads to it */
883 	kr = test_eventlink_create(port_pair);
884 	if (kr != KERN_SUCCESS) {
885 		return;
886 	}
887 
888 	pthread = thread_create_for_test(test_eventlink_wait_then_signal_loop, (void *)(uintptr_t)port_pair[0]);
889 	mach_port_t suspend_resume_other_thread_port = pthread_mach_thread_np(pthread);
890 
891 	/*
892 	 * Threads must be RT to get direct handoff mode.
893 	 */
894 	set_realtime(pthread_self(), DEFAULT_INTERVAL_NS);
895 	set_realtime(pthread, DEFAULT_INTERVAL_NS);
896 
897 	suspend_thread = thread_create_for_test(test_suspend_resume_thread, (void *)(uintptr_t)suspend_resume_other_thread_port);
898 
899 	/* Associate thread and wait_signal the eventlink */
900 	kr = mach_eventlink_associate(port_pair[1], self, 0, 0, 0, 0, MELA_OPTION_NONE);
901 	T_ASSERT_MACH_SUCCESS(kr, "mach_eventlink_associate for object 2");
902 
903 	for (i = 0; i < g_loop_iterations; i++) {
904 		/* Wait on the eventlink with timeout */
905 		kr = mach_eventlink_signal_wait_until(port_pair[1], &count, 0, MELSW_OPTION_NONE,
906 		    KERN_CLOCK_MACH_ABSOLUTE_TIME, 0);
907 
908 		T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "main thread: mach_eventlink_signal_wait_until");
909 		T_QUIET; T_EXPECT_EQ(count, (uint64_t)(i + 1), "main thread: mach_eventlink_signal_wait_until returned correct count value");
910 	}
911 
912 	os_atomic_store(&suspend_resume_thread_stop, true, relaxed);
913 
914 	pthread_join(suspend_thread, NULL);
915 	pthread_join(pthread, NULL);
916 
917 	mach_port_deallocate(mach_task_self(), port_pair[0]);
918 	mach_port_deallocate(mach_task_self(), port_pair[1]);
919 }
920