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