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