]> git.saurik.com Git - apple/xnu.git/blame - tests/ulock.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / tests / ulock.c
CommitLineData
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
25T_GLOBAL_META(T_META_RUN_CONCURRENTLY(true));
26
27#pragma mark ulock_non_owner_wake
28
29static _Atomic uint32_t test_ulock;
30
31static void *
32test_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
52static void *
53test_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
67T_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}