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