]>
Commit | Line | Data |
---|---|---|
f427ee49 A |
1 | #include <darwintest.h> |
2 | ||
3 | #include <stdatomic.h> | |
4 | ||
5 | #include <unistd.h> | |
6 | #include <pthread.h> | |
7 | #include <sys/ulock.h> | |
8 | ||
9 | #include <os/tsd.h> | |
10 | ||
11 | #ifndef __TSD_MACH_THREAD_SELF | |
12 | #define __TSD_MACH_THREAD_SELF 3 | |
13 | #endif | |
14 | ||
15 | #pragma clang diagnostic push | |
16 | #pragma clang diagnostic ignored "-Wbad-function-cast" | |
17 | __inline static mach_port_name_t | |
18 | _os_get_self(void) | |
19 | { | |
20 | mach_port_name_t self = (mach_port_name_t)_os_tsd_get_direct(__TSD_MACH_THREAD_SELF); | |
21 | return self; | |
22 | } | |
23 | #pragma clang diagnostic pop | |
24 | ||
25 | T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true)); | |
26 | ||
27 | #pragma mark ulock_non_owner_wake | |
28 | ||
29 | static _Atomic uint32_t test_ulock; | |
30 | ||
31 | static void * | |
32 | test_waiter(void *arg __unused) | |
33 | { | |
34 | for (;;) { | |
35 | uint32_t test_ulock_owner = atomic_load_explicit(&test_ulock, | |
36 | memory_order_relaxed); | |
37 | int rc = __ulock_wait(UL_UNFAIR_LOCK | ULF_NO_ERRNO, &test_ulock, | |
38 | test_ulock_owner, 0); | |
39 | if (rc == -EINTR || rc == -EFAULT) { | |
40 | continue; | |
41 | } | |
42 | T_ASSERT_GE(rc, 0, "__ulock_wait"); | |
43 | break; | |
44 | } | |
45 | ||
46 | T_PASS("Waiter woke"); | |
47 | T_END; | |
48 | ||
49 | return NULL; | |
50 | } | |
51 | ||
52 | static void * | |
53 | test_waker(void *arg __unused) | |
54 | { | |
55 | for (;;) { | |
56 | int rc = __ulock_wake(UL_UNFAIR_LOCK | ULF_NO_ERRNO | ULF_WAKE_ALLOW_NON_OWNER, | |
57 | &test_ulock, 0); | |
58 | if (rc == -EINTR) { | |
59 | continue; | |
60 | } | |
61 | T_ASSERT_EQ(rc, 0, "__ulock_wake"); | |
62 | break; | |
63 | } | |
64 | return NULL; | |
65 | } | |
66 | ||
67 | T_DECL(ulock_non_owner_wake, "ulock_wake respects non-owner wakes", | |
68 | T_META_CHECK_LEAKS(false)) | |
69 | { | |
70 | pthread_t waiter, waker; | |
71 | ||
72 | atomic_store_explicit(&test_ulock, _os_get_self() & ~0x3u, memory_order_relaxed); | |
73 | ||
74 | T_ASSERT_POSIX_ZERO(pthread_create(&waiter, NULL, test_waiter, NULL), "create waiter"); | |
75 | ||
76 | // wait for the waiter to reach the kernel | |
77 | for (;;) { | |
78 | int kernel_ulocks = __ulock_wake(UL_DEBUG_HASH_DUMP_PID, NULL, 0); | |
79 | T_QUIET; T_ASSERT_NE(kernel_ulocks, -1, "UL_DEBUG_HASH_DUMP_PID"); | |
80 | ||
81 | if (kernel_ulocks == 1) { | |
82 | T_LOG("waiter is now waiting"); | |
83 | break; | |
84 | } | |
85 | usleep(100); | |
86 | } | |
87 | ||
88 | T_ASSERT_POSIX_ZERO(pthread_create(&waker, NULL, test_waker, NULL), "create waker"); | |
89 | ||
90 | // won't ever actually join | |
91 | pthread_join(waiter, NULL); | |
92 | } |