1*bbb1b6f9SApple OSS Distributions // vim:noexpandtab
2*bbb1b6f9SApple OSS Distributions #include <stdint.h>
3*bbb1b6f9SApple OSS Distributions #include <stdlib.h>
4*bbb1b6f9SApple OSS Distributions #include <stdio.h>
5*bbb1b6f9SApple OSS Distributions #include <stdbool.h>
6*bbb1b6f9SApple OSS Distributions #include <stdarg.h>
7*bbb1b6f9SApple OSS Distributions #include <errno.h>
8*bbb1b6f9SApple OSS Distributions #include <string.h>
9*bbb1b6f9SApple OSS Distributions #include <unistd.h>
10*bbb1b6f9SApple OSS Distributions #include <sys/syscall.h>
11*bbb1b6f9SApple OSS Distributions #include <sys/ulock.h>
12*bbb1b6f9SApple OSS Distributions
13*bbb1b6f9SApple OSS Distributions #include "turnstile_multihop_types.h"
14*bbb1b6f9SApple OSS Distributions
15*bbb1b6f9SApple OSS Distributions typedef _Atomic(u32) lock_t;
16*bbb1b6f9SApple OSS Distributions
17*bbb1b6f9SApple OSS Distributions __inline static void
yield(void)18*bbb1b6f9SApple OSS Distributions yield(void)
19*bbb1b6f9SApple OSS Distributions {
20*bbb1b6f9SApple OSS Distributions #if !defined(__x86_64__) && !defined(__i386__)
21*bbb1b6f9SApple OSS Distributions __asm volatile ("yield");
22*bbb1b6f9SApple OSS Distributions #else
23*bbb1b6f9SApple OSS Distributions __asm volatile ("pause");
24*bbb1b6f9SApple OSS Distributions #endif
25*bbb1b6f9SApple OSS Distributions }
26*bbb1b6f9SApple OSS Distributions
27*bbb1b6f9SApple OSS Distributions __inline static void
wfe(void)28*bbb1b6f9SApple OSS Distributions wfe(void)
29*bbb1b6f9SApple OSS Distributions {
30*bbb1b6f9SApple OSS Distributions #if !defined(__x86_64__) && !defined(__i386__)
31*bbb1b6f9SApple OSS Distributions __asm volatile ("wfe");
32*bbb1b6f9SApple OSS Distributions #else
33*bbb1b6f9SApple OSS Distributions __asm volatile ("pause");
34*bbb1b6f9SApple OSS Distributions #endif
35*bbb1b6f9SApple OSS Distributions }
36*bbb1b6f9SApple OSS Distributions
37*bbb1b6f9SApple OSS Distributions __inline static void
wfi(void)38*bbb1b6f9SApple OSS Distributions wfi(void)
39*bbb1b6f9SApple OSS Distributions {
40*bbb1b6f9SApple OSS Distributions #if !defined(__x86_64__) && !defined(__i386__)
41*bbb1b6f9SApple OSS Distributions __asm volatile ("wfi");
42*bbb1b6f9SApple OSS Distributions #else
43*bbb1b6f9SApple OSS Distributions __asm volatile ("pause");
44*bbb1b6f9SApple OSS Distributions #endif
45*bbb1b6f9SApple OSS Distributions }
46*bbb1b6f9SApple OSS Distributions
47*bbb1b6f9SApple OSS Distributions __inline static void
sev(void)48*bbb1b6f9SApple OSS Distributions sev(void)
49*bbb1b6f9SApple OSS Distributions {
50*bbb1b6f9SApple OSS Distributions #if !defined(__x86_64__) && !defined(__i386__)
51*bbb1b6f9SApple OSS Distributions __asm volatile ("sev");
52*bbb1b6f9SApple OSS Distributions #endif
53*bbb1b6f9SApple OSS Distributions }
54*bbb1b6f9SApple OSS Distributions
55*bbb1b6f9SApple OSS Distributions #include <os/tsd.h>
56*bbb1b6f9SApple OSS Distributions
57*bbb1b6f9SApple OSS Distributions #ifndef __TSD_MACH_THREAD_SELF
58*bbb1b6f9SApple OSS Distributions #define __TSD_MACH_THREAD_SELF 3
59*bbb1b6f9SApple OSS Distributions #endif
60*bbb1b6f9SApple OSS Distributions
61*bbb1b6f9SApple OSS Distributions __inline static mach_port_name_t
_os_get_self(void)62*bbb1b6f9SApple OSS Distributions _os_get_self(void)
63*bbb1b6f9SApple OSS Distributions {
64*bbb1b6f9SApple OSS Distributions mach_port_name_t self = (mach_port_name_t)(uintptr_t)(void *)_os_tsd_get_direct(__TSD_MACH_THREAD_SELF);
65*bbb1b6f9SApple OSS Distributions return self;
66*bbb1b6f9SApple OSS Distributions }
67*bbb1b6f9SApple OSS Distributions
68*bbb1b6f9SApple OSS Distributions #define ULL_WAITERS 1U
69*bbb1b6f9SApple OSS Distributions
70*bbb1b6f9SApple OSS Distributions static uint32_t lock_no_wait[4] = { 0, 0, 0, 0};
71*bbb1b6f9SApple OSS Distributions static uint32_t lock_wait[4] = { 0, 0, 0, 0};
72*bbb1b6f9SApple OSS Distributions
73*bbb1b6f9SApple OSS Distributions static mach_port_name_t main_thread_name = 0;
74*bbb1b6f9SApple OSS Distributions
75*bbb1b6f9SApple OSS Distributions __inline static void
ull_lock(lock_t * lock,int id,uint opcode,uint flags)76*bbb1b6f9SApple OSS Distributions ull_lock(lock_t *lock, int id, uint opcode, uint flags)
77*bbb1b6f9SApple OSS Distributions {
78*bbb1b6f9SApple OSS Distributions u32 thread_id = _os_get_self() & ~0x3u;
79*bbb1b6f9SApple OSS Distributions u32 ull_locked = (opcode == UL_UNFAIR_LOCK) ? thread_id : 4u;
80*bbb1b6f9SApple OSS Distributions u32 mach_id = _os_get_self() >> 2;
81*bbb1b6f9SApple OSS Distributions u32 prev;
82*bbb1b6f9SApple OSS Distributions bool succeeded = false;
83*bbb1b6f9SApple OSS Distributions bool waiters = false;
84*bbb1b6f9SApple OSS Distributions bool called_wait = false;
85*bbb1b6f9SApple OSS Distributions u32 count = 0;
86*bbb1b6f9SApple OSS Distributions
87*bbb1b6f9SApple OSS Distributions do {
88*bbb1b6f9SApple OSS Distributions count++;
89*bbb1b6f9SApple OSS Distributions if ((count % 100000) == 0) {
90*bbb1b6f9SApple OSS Distributions printf("[%d,%d]%s>top of loop count=%d\n", id, mach_id, __FUNCTION__, count);
91*bbb1b6f9SApple OSS Distributions }
92*bbb1b6f9SApple OSS Distributions u32 new = waiters ? (ULL_WAITERS | ull_locked) : ull_locked;
93*bbb1b6f9SApple OSS Distributions prev = 0;
94*bbb1b6f9SApple OSS Distributions __c11_atomic_compare_exchange_strong(lock, &prev, new, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED);
95*bbb1b6f9SApple OSS Distributions if (prev == 0) {
96*bbb1b6f9SApple OSS Distributions /* Was unlocked, now locked */
97*bbb1b6f9SApple OSS Distributions succeeded = true;
98*bbb1b6f9SApple OSS Distributions break;
99*bbb1b6f9SApple OSS Distributions }
100*bbb1b6f9SApple OSS Distributions
101*bbb1b6f9SApple OSS Distributions u32 value = prev;
102*bbb1b6f9SApple OSS Distributions if (!(value & ULL_WAITERS)) {
103*bbb1b6f9SApple OSS Distributions new = value | ULL_WAITERS;
104*bbb1b6f9SApple OSS Distributions __c11_atomic_compare_exchange_strong(lock, &prev, new, __ATOMIC_RELAXED, __ATOMIC_RELAXED);
105*bbb1b6f9SApple OSS Distributions if (prev == value) {
106*bbb1b6f9SApple OSS Distributions /* succeeded in setting ULL_WAITERS */
107*bbb1b6f9SApple OSS Distributions value = new;
108*bbb1b6f9SApple OSS Distributions } else if (prev & ULL_WAITERS) {
109*bbb1b6f9SApple OSS Distributions /* Didn't succeed, but someone else already set ULL_WAITERS */
110*bbb1b6f9SApple OSS Distributions value = prev;
111*bbb1b6f9SApple OSS Distributions } else {
112*bbb1b6f9SApple OSS Distributions /* Something changed under us, so try again */
113*bbb1b6f9SApple OSS Distributions if (count % 100000 == 0) {
114*bbb1b6f9SApple OSS Distributions printf("[%d,%d]%s>Something changed under us, prev=%d\n", id, mach_id, __FUNCTION__, prev);
115*bbb1b6f9SApple OSS Distributions }
116*bbb1b6f9SApple OSS Distributions continue;
117*bbb1b6f9SApple OSS Distributions }
118*bbb1b6f9SApple OSS Distributions }
119*bbb1b6f9SApple OSS Distributions /* Locked with waiters indication, so block */
120*bbb1b6f9SApple OSS Distributions int ret = __ulock_wait(flags | opcode, lock, value, 0);
121*bbb1b6f9SApple OSS Distributions called_wait = true;
122*bbb1b6f9SApple OSS Distributions if (ret < 0) {
123*bbb1b6f9SApple OSS Distributions if (flags & ULF_NO_ERRNO) {
124*bbb1b6f9SApple OSS Distributions errno = -ret;
125*bbb1b6f9SApple OSS Distributions }
126*bbb1b6f9SApple OSS Distributions if (errno == EFAULT) {
127*bbb1b6f9SApple OSS Distributions continue;
128*bbb1b6f9SApple OSS Distributions }
129*bbb1b6f9SApple OSS Distributions printf("[%d,%d]%s>ull_wait() error: %s\n", id, mach_id, __FUNCTION__, strerror(errno));
130*bbb1b6f9SApple OSS Distributions exit(1);
131*bbb1b6f9SApple OSS Distributions }
132*bbb1b6f9SApple OSS Distributions waiters = (ret > 0);
133*bbb1b6f9SApple OSS Distributions
134*bbb1b6f9SApple OSS Distributions if (count % 100000 == 0) {
135*bbb1b6f9SApple OSS Distributions printf("[%d,%d]%s>bottom of loop prev=%d\n", id, mach_id, __FUNCTION__, prev);
136*bbb1b6f9SApple OSS Distributions }
137*bbb1b6f9SApple OSS Distributions } while (!succeeded);
138*bbb1b6f9SApple OSS Distributions
139*bbb1b6f9SApple OSS Distributions if (called_wait) {
140*bbb1b6f9SApple OSS Distributions lock_wait[id]++;
141*bbb1b6f9SApple OSS Distributions } else {
142*bbb1b6f9SApple OSS Distributions lock_no_wait[id]++;
143*bbb1b6f9SApple OSS Distributions }
144*bbb1b6f9SApple OSS Distributions }
145*bbb1b6f9SApple OSS Distributions
146*bbb1b6f9SApple OSS Distributions static uint32_t unlock_no_waiters[4] = { 0, 0, 0, 0};
147*bbb1b6f9SApple OSS Distributions static uint32_t unlock_waiters[4] = { 0, 0, 0, 0 };
148*bbb1b6f9SApple OSS Distributions static uint32_t unlock_waiters_gone[4] = { 0, 0, 0, 0 };
149*bbb1b6f9SApple OSS Distributions static uint32_t unlock_waiters_wake_thread[4] = { 0, 0, 0, 0 };
150*bbb1b6f9SApple OSS Distributions
151*bbb1b6f9SApple OSS Distributions __inline static void
ull_unlock(lock_t * lock,int id,uint opcode,uint flags)152*bbb1b6f9SApple OSS Distributions ull_unlock(lock_t *lock, int id, uint opcode, uint flags)
153*bbb1b6f9SApple OSS Distributions {
154*bbb1b6f9SApple OSS Distributions u32 thread_id = _os_get_self() & ~0x3u;
155*bbb1b6f9SApple OSS Distributions u32 ull_locked = (opcode == UL_UNFAIR_LOCK) ? thread_id : 4u;
156*bbb1b6f9SApple OSS Distributions u32 mach_id = _os_get_self() >> 2;
157*bbb1b6f9SApple OSS Distributions u32 prev = ull_locked;
158*bbb1b6f9SApple OSS Distributions __c11_atomic_compare_exchange_strong(lock, &prev, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED);
159*bbb1b6f9SApple OSS Distributions if (prev == ull_locked) {
160*bbb1b6f9SApple OSS Distributions unlock_no_waiters[id]++;
161*bbb1b6f9SApple OSS Distributions return;
162*bbb1b6f9SApple OSS Distributions }
163*bbb1b6f9SApple OSS Distributions
164*bbb1b6f9SApple OSS Distributions if (prev == 0) {
165*bbb1b6f9SApple OSS Distributions printf("%s>already unlocked\n", __FUNCTION__);
166*bbb1b6f9SApple OSS Distributions exit(1);
167*bbb1b6f9SApple OSS Distributions }
168*bbb1b6f9SApple OSS Distributions
169*bbb1b6f9SApple OSS Distributions if (prev == (ULL_WAITERS | ull_locked)) {
170*bbb1b6f9SApple OSS Distributions /* locked with waiters */
171*bbb1b6f9SApple OSS Distributions __c11_atomic_store(lock, 0, __ATOMIC_SEQ_CST);
172*bbb1b6f9SApple OSS Distributions
173*bbb1b6f9SApple OSS Distributions if ((flags & ULF_WAKE_THREAD) && (_os_get_self() == main_thread_name)) {
174*bbb1b6f9SApple OSS Distributions flags &= ~(uint)ULF_WAKE_THREAD;
175*bbb1b6f9SApple OSS Distributions }
176*bbb1b6f9SApple OSS Distributions int ret = __ulock_wake((flags | opcode), lock, main_thread_name);
177*bbb1b6f9SApple OSS Distributions if ((ret < 0) && (flags & ULF_NO_ERRNO)) {
178*bbb1b6f9SApple OSS Distributions errno = -ret;
179*bbb1b6f9SApple OSS Distributions }
180*bbb1b6f9SApple OSS Distributions if ((flags & ULF_WAKE_THREAD) && (ret < 0) && (errno == EALREADY)) {
181*bbb1b6f9SApple OSS Distributions flags &= ~(uint)ULF_WAKE_THREAD;
182*bbb1b6f9SApple OSS Distributions ret = __ulock_wake((flags | opcode), lock, 0);
183*bbb1b6f9SApple OSS Distributions if ((ret < 0) && (flags & ULF_NO_ERRNO)) {
184*bbb1b6f9SApple OSS Distributions errno = -ret;
185*bbb1b6f9SApple OSS Distributions }
186*bbb1b6f9SApple OSS Distributions } else if ((flags & ULF_WAKE_THREAD) && (ret == 0)) {
187*bbb1b6f9SApple OSS Distributions unlock_waiters_wake_thread[id]++;
188*bbb1b6f9SApple OSS Distributions }
189*bbb1b6f9SApple OSS Distributions if (ret < 0) {
190*bbb1b6f9SApple OSS Distributions if (errno == ENOENT) {
191*bbb1b6f9SApple OSS Distributions unlock_waiters_gone[id]++;
192*bbb1b6f9SApple OSS Distributions } else {
193*bbb1b6f9SApple OSS Distributions printf("[%d,%d]%s>ull_wake() error: %s\n", id, mach_id, __FUNCTION__, strerror(errno));
194*bbb1b6f9SApple OSS Distributions exit(1);
195*bbb1b6f9SApple OSS Distributions }
196*bbb1b6f9SApple OSS Distributions }
197*bbb1b6f9SApple OSS Distributions unlock_waiters[id]++;
198*bbb1b6f9SApple OSS Distributions } else {
199*bbb1b6f9SApple OSS Distributions printf("%s>unexpected lock value %d\n", __FUNCTION__, prev);
200*bbb1b6f9SApple OSS Distributions exit(1);
201*bbb1b6f9SApple OSS Distributions }
202*bbb1b6f9SApple OSS Distributions }
203