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