10 #include <sys/syscall.h>
11 #include <sys/ulock.h>
13 #include "turnstile_multihop_types.h"
15 typedef _Atomic(u32
) lock_t
;
20 #if !defined(__x86_64__) && !defined(__i386__)
21 __asm
volatile ("yield");
23 __asm
volatile ("pause");
30 #if !defined(__x86_64__) && !defined(__i386__)
31 __asm
volatile ("wfe");
33 __asm
volatile ("pause");
40 #if !defined(__x86_64__) && !defined(__i386__)
41 __asm
volatile ("wfi");
43 __asm
volatile ("pause");
50 #if !defined(__x86_64__) && !defined(__i386__)
51 __asm
volatile ("sev");
57 #ifndef __TSD_MACH_THREAD_SELF
58 #define __TSD_MACH_THREAD_SELF 3
61 __inline
static mach_port_name_t
64 mach_port_name_t self
= (mach_port_name_t
)(uintptr_t)(void *)_os_tsd_get_direct(__TSD_MACH_THREAD_SELF
);
68 #define ULL_WAITERS 1U
70 static uint32_t lock_no_wait
[4] = { 0, 0, 0, 0};
71 static uint32_t lock_wait
[4] = { 0, 0, 0, 0};
73 static mach_port_name_t main_thread_name
= 0;
76 ull_lock(lock_t
*lock
, int id
, uint opcode
, uint flags
)
78 u32 thread_id
= _os_get_self() & ~0x3u
;
79 u32 ull_locked
= (opcode
== UL_UNFAIR_LOCK
) ? thread_id
: 4u;
80 u32 mach_id
= _os_get_self() >> 2;
82 bool succeeded
= false;
84 bool called_wait
= false;
89 if ((count
% 100000) == 0) {
90 printf("[%d,%d]%s>top of loop count=%d\n", id
, mach_id
, __FUNCTION__
, count
);
92 u32
new = waiters
? (ULL_WAITERS
| ull_locked
) : ull_locked
;
94 __c11_atomic_compare_exchange_strong(lock
, &prev
, new, __ATOMIC_ACQUIRE
, __ATOMIC_RELAXED
);
96 /* Was unlocked, now locked */
102 if (!(value
& ULL_WAITERS
)) {
103 new = value
| ULL_WAITERS
;
104 __c11_atomic_compare_exchange_strong(lock
, &prev
, new, __ATOMIC_RELAXED
, __ATOMIC_RELAXED
);
106 /* succeeded in setting ULL_WAITERS */
108 } else if (prev
& ULL_WAITERS
) {
109 /* Didn't succeed, but someone else already set ULL_WAITERS */
112 /* Something changed under us, so try again */
113 if (count
% 100000 == 0) {
114 printf("[%d,%d]%s>Something changed under us, prev=%d\n", id
, mach_id
, __FUNCTION__
, prev
);
119 /* Locked with waiters indication, so block */
120 int ret
= __ulock_wait(flags
| opcode
, lock
, value
, 0);
123 if (flags
& ULF_NO_ERRNO
) {
126 if (errno
== EFAULT
) {
129 printf("[%d,%d]%s>ull_wait() error: %s\n", id
, mach_id
, __FUNCTION__
, strerror(errno
));
134 if (count
% 100000 == 0) {
135 printf("[%d,%d]%s>bottom of loop prev=%d\n", id
, mach_id
, __FUNCTION__
, prev
);
137 } while (!succeeded
);
146 static uint32_t unlock_no_waiters
[4] = { 0, 0, 0, 0};
147 static uint32_t unlock_waiters
[4] = { 0, 0, 0, 0 };
148 static uint32_t unlock_waiters_gone
[4] = { 0, 0, 0, 0 };
149 static uint32_t unlock_waiters_wake_thread
[4] = { 0, 0, 0, 0 };
152 ull_unlock(lock_t
*lock
, int id
, uint opcode
, uint flags
)
154 u32 thread_id
= _os_get_self() & ~0x3u
;
155 u32 ull_locked
= (opcode
== UL_UNFAIR_LOCK
) ? thread_id
: 4u;
156 u32 mach_id
= _os_get_self() >> 2;
157 u32 prev
= ull_locked
;
158 __c11_atomic_compare_exchange_strong(lock
, &prev
, 0, __ATOMIC_RELEASE
, __ATOMIC_RELAXED
);
159 if (prev
== ull_locked
) {
160 unlock_no_waiters
[id
]++;
165 printf("%s>already unlocked\n", __FUNCTION__
);
169 if (prev
== (ULL_WAITERS
| ull_locked
)) {
170 /* locked with waiters */
171 __c11_atomic_store(lock
, 0, __ATOMIC_SEQ_CST
);
173 if ((flags
& ULF_WAKE_THREAD
) && (_os_get_self() == main_thread_name
)) {
174 flags
&= ~(uint
)ULF_WAKE_THREAD
;
176 int ret
= __ulock_wake((flags
| opcode
), lock
, main_thread_name
);
177 if ((ret
< 0) && (flags
& ULF_NO_ERRNO
)) {
180 if ((flags
& ULF_WAKE_THREAD
) && (ret
< 0) && (errno
== EALREADY
)) {
181 flags
&= ~(uint
)ULF_WAKE_THREAD
;
182 ret
= __ulock_wake((flags
| opcode
), lock
, 0);
183 if ((ret
< 0) && (flags
& ULF_NO_ERRNO
)) {
186 } else if ((flags
& ULF_WAKE_THREAD
) && (ret
== 0)) {
187 unlock_waiters_wake_thread
[id
]++;
190 if (errno
== ENOENT
) {
191 unlock_waiters_gone
[id
]++;
193 printf("[%d,%d]%s>ull_wake() error: %s\n", id
, mach_id
, __FUNCTION__
, strerror(errno
));
197 unlock_waiters
[id
]++;
199 printf("%s>unexpected lock value %d\n", __FUNCTION__
, prev
);