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