1*4f1223e8SApple OSS Distributions #include <darwintest.h>
2*4f1223e8SApple OSS Distributions
3*4f1223e8SApple OSS Distributions #include <stdatomic.h>
4*4f1223e8SApple OSS Distributions
5*4f1223e8SApple OSS Distributions #include <unistd.h>
6*4f1223e8SApple OSS Distributions #include <pthread.h>
7*4f1223e8SApple OSS Distributions #include <sys/ulock.h>
8*4f1223e8SApple OSS Distributions
9*4f1223e8SApple OSS Distributions #include <os/tsd.h>
10*4f1223e8SApple OSS Distributions
11*4f1223e8SApple OSS Distributions #ifndef __TSD_MACH_THREAD_SELF
12*4f1223e8SApple OSS Distributions #define __TSD_MACH_THREAD_SELF 3
13*4f1223e8SApple OSS Distributions #endif
14*4f1223e8SApple OSS Distributions
15*4f1223e8SApple OSS Distributions #pragma clang diagnostic push
16*4f1223e8SApple OSS Distributions #pragma clang diagnostic ignored "-Wbad-function-cast"
17*4f1223e8SApple OSS Distributions __inline static mach_port_name_t
_os_get_self(void)18*4f1223e8SApple OSS Distributions _os_get_self(void)
19*4f1223e8SApple OSS Distributions {
20*4f1223e8SApple OSS Distributions mach_port_name_t self = (mach_port_name_t)_os_tsd_get_direct(__TSD_MACH_THREAD_SELF);
21*4f1223e8SApple OSS Distributions return self;
22*4f1223e8SApple OSS Distributions }
23*4f1223e8SApple OSS Distributions #pragma clang diagnostic pop
24*4f1223e8SApple OSS Distributions
25*4f1223e8SApple OSS Distributions T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
26*4f1223e8SApple OSS Distributions
27*4f1223e8SApple OSS Distributions #pragma mark ulock_non_owner_wake
28*4f1223e8SApple OSS Distributions
29*4f1223e8SApple OSS Distributions static _Atomic uint32_t test_ulock;
30*4f1223e8SApple OSS Distributions
31*4f1223e8SApple OSS Distributions static void *
test_waiter(void * arg __unused)32*4f1223e8SApple OSS Distributions test_waiter(void *arg __unused)
33*4f1223e8SApple OSS Distributions {
34*4f1223e8SApple OSS Distributions for (;;) {
35*4f1223e8SApple OSS Distributions uint32_t test_ulock_owner = atomic_load_explicit(&test_ulock,
36*4f1223e8SApple OSS Distributions memory_order_relaxed);
37*4f1223e8SApple OSS Distributions int rc = __ulock_wait(UL_UNFAIR_LOCK | ULF_NO_ERRNO, &test_ulock,
38*4f1223e8SApple OSS Distributions test_ulock_owner, 0);
39*4f1223e8SApple OSS Distributions if (rc == -EINTR || rc == -EFAULT) {
40*4f1223e8SApple OSS Distributions continue;
41*4f1223e8SApple OSS Distributions }
42*4f1223e8SApple OSS Distributions T_ASSERT_GE(rc, 0, "__ulock_wait");
43*4f1223e8SApple OSS Distributions break;
44*4f1223e8SApple OSS Distributions }
45*4f1223e8SApple OSS Distributions
46*4f1223e8SApple OSS Distributions T_PASS("Waiter woke");
47*4f1223e8SApple OSS Distributions T_END;
48*4f1223e8SApple OSS Distributions
49*4f1223e8SApple OSS Distributions return NULL;
50*4f1223e8SApple OSS Distributions }
51*4f1223e8SApple OSS Distributions
52*4f1223e8SApple OSS Distributions static mach_timebase_info_data_t timebase_info;
53*4f1223e8SApple OSS Distributions
54*4f1223e8SApple OSS Distributions static uint64_t
nanos_to_abs(uint64_t nanos)55*4f1223e8SApple OSS Distributions nanos_to_abs(uint64_t nanos)
56*4f1223e8SApple OSS Distributions {
57*4f1223e8SApple OSS Distributions return nanos * timebase_info.denom / timebase_info.numer;
58*4f1223e8SApple OSS Distributions }
59*4f1223e8SApple OSS Distributions
60*4f1223e8SApple OSS Distributions static void *
test_waiter_with_timeout(void * arg)61*4f1223e8SApple OSS Distributions test_waiter_with_timeout(void *arg)
62*4f1223e8SApple OSS Distributions {
63*4f1223e8SApple OSS Distributions uint64_t deadline = (uint64_t) arg;
64*4f1223e8SApple OSS Distributions
65*4f1223e8SApple OSS Distributions for (;;) {
66*4f1223e8SApple OSS Distributions uint32_t test_ulock_owner = atomic_load_explicit(&test_ulock,
67*4f1223e8SApple OSS Distributions memory_order_relaxed);
68*4f1223e8SApple OSS Distributions int rc = __ulock_wait2(UL_UNFAIR_LOCK | ULF_NO_ERRNO | ULF_DEADLINE, &test_ulock,
69*4f1223e8SApple OSS Distributions test_ulock_owner, deadline, 0);
70*4f1223e8SApple OSS Distributions if (rc == -EINTR || rc == -EFAULT) {
71*4f1223e8SApple OSS Distributions continue;
72*4f1223e8SApple OSS Distributions }
73*4f1223e8SApple OSS Distributions T_ASSERT_EQ(rc, -ETIMEDOUT, "__ulock_wait");
74*4f1223e8SApple OSS Distributions break;
75*4f1223e8SApple OSS Distributions }
76*4f1223e8SApple OSS Distributions
77*4f1223e8SApple OSS Distributions T_ASSERT_GE(mach_absolute_time(), deadline, "Current time is past the deadline specified");
78*4f1223e8SApple OSS Distributions
79*4f1223e8SApple OSS Distributions T_PASS("Waiter woke");
80*4f1223e8SApple OSS Distributions
81*4f1223e8SApple OSS Distributions return NULL;
82*4f1223e8SApple OSS Distributions }
83*4f1223e8SApple OSS Distributions
84*4f1223e8SApple OSS Distributions static void *
test_waker(void * arg __unused)85*4f1223e8SApple OSS Distributions test_waker(void *arg __unused)
86*4f1223e8SApple OSS Distributions {
87*4f1223e8SApple OSS Distributions for (;;) {
88*4f1223e8SApple OSS Distributions int rc = __ulock_wake(UL_UNFAIR_LOCK | ULF_NO_ERRNO | ULF_WAKE_ALLOW_NON_OWNER,
89*4f1223e8SApple OSS Distributions &test_ulock, 0);
90*4f1223e8SApple OSS Distributions if (rc == -EINTR) {
91*4f1223e8SApple OSS Distributions continue;
92*4f1223e8SApple OSS Distributions }
93*4f1223e8SApple OSS Distributions T_ASSERT_EQ(rc, 0, "__ulock_wake");
94*4f1223e8SApple OSS Distributions break;
95*4f1223e8SApple OSS Distributions }
96*4f1223e8SApple OSS Distributions return NULL;
97*4f1223e8SApple OSS Distributions }
98*4f1223e8SApple OSS Distributions
99*4f1223e8SApple OSS Distributions T_DECL(ulock_non_owner_wake, "ulock_wake respects non-owner wakes",
100*4f1223e8SApple OSS Distributions T_META_CHECK_LEAKS(false), T_META_TAG_VM_PREFERRED)
101*4f1223e8SApple OSS Distributions {
102*4f1223e8SApple OSS Distributions pthread_t waiter, waker;
103*4f1223e8SApple OSS Distributions
104*4f1223e8SApple OSS Distributions atomic_store_explicit(&test_ulock, _os_get_self() & ~0x3u, memory_order_relaxed);
105*4f1223e8SApple OSS Distributions
106*4f1223e8SApple OSS Distributions T_ASSERT_POSIX_ZERO(pthread_create(&waiter, NULL, test_waiter, NULL), "create waiter");
107*4f1223e8SApple OSS Distributions
108*4f1223e8SApple OSS Distributions // wait for the waiter to reach the kernel
109*4f1223e8SApple OSS Distributions for (;;) {
110*4f1223e8SApple OSS Distributions int kernel_ulocks = __ulock_wake(UL_DEBUG_HASH_DUMP_PID, NULL, 0);
111*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_NE(kernel_ulocks, -1, "UL_DEBUG_HASH_DUMP_PID");
112*4f1223e8SApple OSS Distributions
113*4f1223e8SApple OSS Distributions if (kernel_ulocks == 1) {
114*4f1223e8SApple OSS Distributions T_LOG("waiter is now waiting");
115*4f1223e8SApple OSS Distributions break;
116*4f1223e8SApple OSS Distributions }
117*4f1223e8SApple OSS Distributions usleep(100);
118*4f1223e8SApple OSS Distributions }
119*4f1223e8SApple OSS Distributions
120*4f1223e8SApple OSS Distributions T_ASSERT_POSIX_ZERO(pthread_create(&waker, NULL, test_waker, NULL), "create waker");
121*4f1223e8SApple OSS Distributions
122*4f1223e8SApple OSS Distributions // won't ever actually join
123*4f1223e8SApple OSS Distributions pthread_join(waiter, NULL);
124*4f1223e8SApple OSS Distributions }
125*4f1223e8SApple OSS Distributions
126*4f1223e8SApple OSS Distributions T_DECL(ulock_wait_deadline, "ulock_wait2 with deadline", T_META_CHECK_LEAKS(false), T_META_TAG_VM_PREFERRED)
127*4f1223e8SApple OSS Distributions {
128*4f1223e8SApple OSS Distributions kern_return_t kr = mach_timebase_info(&timebase_info);
129*4f1223e8SApple OSS Distributions T_QUIET; T_ASSERT_MACH_SUCCESS(kr, "mach_timebase_info");
130*4f1223e8SApple OSS Distributions
131*4f1223e8SApple OSS Distributions // Take the lock as self
132*4f1223e8SApple OSS Distributions atomic_store_explicit(&test_ulock, _os_get_self() & ~0x3u, memory_order_relaxed);
133*4f1223e8SApple OSS Distributions
134*4f1223e8SApple OSS Distributions pthread_t waiter;
135*4f1223e8SApple OSS Distributions
136*4f1223e8SApple OSS Distributions // Deadline in the past
137*4f1223e8SApple OSS Distributions uint64_t deadline = mach_absolute_time() - nanos_to_abs(3 * NSEC_PER_SEC);
138*4f1223e8SApple OSS Distributions T_ASSERT_POSIX_ZERO(pthread_create(&waiter, NULL, test_waiter_with_timeout, (void *) deadline), "create waiter");
139*4f1223e8SApple OSS Distributions
140*4f1223e8SApple OSS Distributions pthread_join(waiter, NULL);
141*4f1223e8SApple OSS Distributions
142*4f1223e8SApple OSS Distributions // Deadline in the future
143*4f1223e8SApple OSS Distributions deadline = mach_absolute_time() + nanos_to_abs(3 * NSEC_PER_SEC);
144*4f1223e8SApple OSS Distributions T_ASSERT_POSIX_ZERO(pthread_create(&waiter, NULL, test_waiter_with_timeout, (void *) deadline), "create waiter");
145*4f1223e8SApple OSS Distributions
146*4f1223e8SApple OSS Distributions pthread_join(waiter, NULL);
147*4f1223e8SApple OSS Distributions T_END;
148*4f1223e8SApple OSS Distributions }
149