v / vlib / goroutines / tls.c
128 lines · 101 sloc · 3.93 KB · 0480d0b9a920efc39d5ca3c43509a6cf6ebca274
Raw
1// Thread-local storage, atomic operations, and spinlock for goroutines scheduler.
2#include <stddef.h>
3#include <stdint.h>
4
5#if defined(_WIN32) || defined(_WIN64)
6#include <windows.h>
7#else
8#include <stdatomic.h>
9#include <sched.h>
10#endif
11
12// Thread-local Machine pointer
13#if defined(_WIN32) || defined(_WIN64)
14static __declspec(thread) void *_goroutines_current_m = NULL;
15#else
16static _Thread_local void *_goroutines_current_m = NULL;
17#endif
18
19void *goroutines_get_current_m(void) {
20 return _goroutines_current_m;
21}
22
23void goroutines_set_current_m(void *mp) {
24 _goroutines_current_m = mp;
25}
26
27#if defined(_WIN32) || defined(_WIN64)
28// Windows atomic operations using MSVC intrinsics / WinAPI
29
30uint32_t goroutines_atomic_load_u32(volatile uint32_t *ptr) {
31 return InterlockedCompareExchange((volatile LONG *)ptr, 0, 0);
32}
33
34void goroutines_atomic_store_u32(volatile uint32_t *ptr, uint32_t val) {
35 InterlockedExchange((volatile LONG *)ptr, (LONG)val);
36}
37
38uint32_t goroutines_atomic_fetch_add_u32(volatile uint32_t *ptr, uint32_t val) {
39 return (uint32_t)InterlockedExchangeAdd((volatile LONG *)ptr, (LONG)val);
40}
41
42int32_t goroutines_atomic_fetch_add_i32(volatile int32_t *ptr, int32_t val) {
43 return (int32_t)InterlockedExchangeAdd((volatile LONG *)ptr, (LONG)val);
44}
45
46int32_t goroutines_atomic_fetch_sub_i32(volatile int32_t *ptr, int32_t val) {
47 return (int32_t)InterlockedExchangeAdd((volatile LONG *)ptr, (LONG)(-val));
48}
49
50uint64_t goroutines_atomic_fetch_add_u64(volatile uint64_t *ptr, uint64_t val) {
51 return (uint64_t)InterlockedExchangeAdd64((volatile LONG64 *)ptr, (LONG64)val);
52}
53
54int goroutines_atomic_cas_u32(volatile uint32_t *ptr, uint32_t *expected, uint32_t desired) {
55 uint32_t old = (uint32_t)InterlockedCompareExchange((volatile LONG *)ptr, (LONG)desired, (LONG)*expected);
56 if (old == *expected) return 1;
57 *expected = old;
58 return 0;
59}
60
61int goroutines_atomic_cas_ptr(void *volatile *ptr, void **expected, void *desired) {
62 void *old = InterlockedCompareExchangePointer(ptr, desired, *expected);
63 if (old == *expected) return 1;
64 *expected = old;
65 return 0;
66}
67
68void grt_spinlock_lock(volatile int32_t *lock) {
69 while (InterlockedExchange((volatile LONG *)lock, 1) != 0) {
70 YieldProcessor();
71 }
72}
73
74void grt_spinlock_unlock(volatile int32_t *lock) {
75 InterlockedExchange((volatile LONG *)lock, 0);
76}
77
78#else
79// POSIX atomic operations using C11 stdatomic
80
81uint32_t goroutines_atomic_load_u32(volatile uint32_t *ptr) {
82 return atomic_load((_Atomic uint32_t *)ptr);
83}
84
85void goroutines_atomic_store_u32(volatile uint32_t *ptr, uint32_t val) {
86 atomic_store((_Atomic uint32_t *)ptr, val);
87}
88
89uint32_t goroutines_atomic_fetch_add_u32(volatile uint32_t *ptr, uint32_t val) {
90 return atomic_fetch_add((_Atomic uint32_t *)ptr, val);
91}
92
93int32_t goroutines_atomic_fetch_add_i32(volatile int32_t *ptr, int32_t val) {
94 return atomic_fetch_add((_Atomic int32_t *)ptr, val);
95}
96
97int32_t goroutines_atomic_fetch_sub_i32(volatile int32_t *ptr, int32_t val) {
98 return atomic_fetch_sub((_Atomic int32_t *)ptr, val);
99}
100
101uint64_t goroutines_atomic_fetch_add_u64(volatile uint64_t *ptr, uint64_t val) {
102 return atomic_fetch_add((_Atomic uint64_t *)ptr, val);
103}
104
105int goroutines_atomic_cas_u32(volatile uint32_t *ptr, uint32_t *expected, uint32_t desired) {
106 return atomic_compare_exchange_strong((_Atomic uint32_t *)ptr, expected, desired);
107}
108
109int goroutines_atomic_cas_ptr(void *volatile *ptr, void **expected, void *desired) {
110 return atomic_compare_exchange_strong((_Atomic(void *) *)ptr, expected, desired);
111}
112
113void grt_spinlock_lock(volatile int32_t *lock) {
114 while (atomic_exchange((_Atomic int32_t *)lock, 1) != 0) {
115 // Spin with pause hint
116 #if defined(__x86_64__) || defined(__i386__)
117 __asm__ volatile("pause");
118 #elif defined(__aarch64__)
119 __asm__ volatile("yield");
120 #endif
121 }
122}
123
124void grt_spinlock_unlock(volatile int32_t *lock) {
125 atomic_store((_Atomic int32_t *)lock, 0);
126}
127
128#endif
129