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