1use core::ops::{Deref, DerefMut};
2use crate::sync::atomic::{AtomicUsize, Ordering};
3use crate::sync::index_types::TickType;
4use core::cell::{Cell, RefCell};
5use alloc::vec::Vec;
6
7#[cfg_attr(any(target_arch = "aarch64", target_arch = "arm"), repr(C, align(128)))]
14#[cfg_attr(not(any(target_arch = "aarch64", target_arch = "arm")), repr(C, align(64)))]
15pub struct CachePadded<T>(pub T);
16
17impl<T> CachePadded<T> {
18 #[inline(always)]
19 pub fn new(val: T) -> Self {
20 Self(val)
21 }
22
23 #[inline(always)]
24 pub fn into_inner(self) -> T {
25 self.0
26 }
27}
28
29impl<T> Deref for CachePadded<T> {
30 type Target = T;
31 #[inline(always)]
32 fn deref(&self) -> &T {
33 &self.0
34 }
35}
36
37impl<T> DerefMut for CachePadded<T> {
38 #[inline(always)]
39 fn deref_mut(&mut self) -> &mut T {
40 &mut self.0
41 }
42}
43
44#[derive(Debug, Clone, Copy, Default)]
47pub struct DefaultSpawner;
48
49impl DefaultSpawner {
50 #[inline]
51 #[cfg(all(feature = "std", not(any(feature = "loom", loom))))]
52 pub fn spawn(&self, f: alloc::boxed::Box<dyn FnOnce() + Send + 'static>) {
53 std::thread::spawn(f);
54 }
55
56 #[inline]
57 #[cfg(any(feature = "loom", loom))]
58 pub fn spawn(&self, f: alloc::boxed::Box<dyn FnOnce() + Send + 'static>) {
59 loom::thread::spawn(move || f());
60 }
61}
62
63#[cfg(all(feature = "std", not(any(feature = "loom", loom))))]
66mod std_tls_impl {
67 use super::*;
68 use std::sync::Mutex;
69
70 struct IdAllocator {
71 free_list: Mutex<Vec<usize>>,
72 next_id: AtomicUsize,
73 }
74
75 static ALLOCATOR: IdAllocator = IdAllocator {
76 free_list: Mutex::new(Vec::new()),
77 next_id: AtomicUsize::new(0),
78 };
79
80 struct ThreadIdGuard {
81 id: usize,
82 }
83
84 impl Drop for ThreadIdGuard {
85 fn drop(&mut self) {
86 if let Ok(mut list) = ALLOCATOR.free_list.lock() {
87 list.push(self.id);
88 }
89 }
90 }
91
92 thread_local! {
93 static WORKER_ID: usize = {
94 let id = if let Ok(mut list) = ALLOCATOR.free_list.lock() {
95 list.pop().unwrap_or_else(|| ALLOCATOR.next_id.fetch_add(1, Ordering::Relaxed))
96 } else {
97 ALLOCATOR.next_id.fetch_add(1, Ordering::Relaxed)
98 };
99
100 GUARD.with(|g| {
101 *g.borrow_mut() = Some(ThreadIdGuard { id });
102 });
103 id
104 };
105
106 static GUARD: RefCell<Option<ThreadIdGuard>> = const { RefCell::new(None) };
107 static HIT_BUF: RefCell<([usize; 64], usize)> = const { RefCell::new(([0; 64], 0)) };
108 static L1_FILTER: RefCell<([u8; 4096], usize)> = const { RefCell::new(([0; 4096], 0)) };
109 static LAST_FLUSH_TICK: Cell<TickType> = const { Cell::new(0) };
110 static WARMUP_STATE: Cell<u8> = const { Cell::new(0) };
111 }
112
113 #[derive(Clone, Default)]
114 pub struct DefaultTls;
115
116 impl DefaultTls {
117 #[inline(always)]
118 pub fn get_worker_id(&self) -> Option<usize> {
119 Some(WORKER_ID.with(|id| *id))
120 }
121
122 #[inline(always)]
123 pub fn with_hit_buf<F, R>(&self, f: F) -> Option<R>
124 where
125 F: FnOnce(&mut ([usize; 64], usize)) -> R,
126 {
127 Some(HIT_BUF.with(|buf| f(&mut buf.borrow_mut())))
128 }
129
130 #[inline(always)]
131 pub fn with_l1_filter<F, R>(&self, f: F) -> Option<R>
132 where
133 F: FnOnce(&mut ([u8; 4096], usize)) -> R,
134 {
135 Some(L1_FILTER.with(|filter| f(&mut filter.borrow_mut())))
136 }
137
138 #[inline(always)]
139 pub fn with_last_flush_tick<F, R>(&self, f: F) -> Option<R>
140 where
141 F: FnOnce(&mut TickType) -> R,
142 {
143 Some(LAST_FLUSH_TICK.with(|cell| {
144 let mut val = cell.get();
145 let res = f(&mut val);
146 cell.set(val);
147 res
148 }))
149 }
150
151 #[inline(always)]
152 pub fn with_warmup_state<F, R>(&self, f: F) -> R
153 where
154 F: FnOnce(&mut u8) -> R,
155 {
156 WARMUP_STATE.with(|cell| {
157 let mut val = cell.get();
158 let res = f(&mut val);
159 cell.set(val);
160 res
161 })
162 }
163 }
164}
165
166#[cfg(all(feature = "std", not(any(feature = "loom", loom))))]
167pub use std_tls_impl::DefaultTls;
168
169#[cfg(any(feature = "loom", loom))]
170mod loom_tls_impl {
171 use super::*;
172 use std::sync::Mutex;
173
174 struct IdAllocator {
175 free_list: Mutex<Vec<usize>>,
176 next_id: AtomicUsize,
177 }
178
179 loom::lazy_static! {
180 static ref ALLOCATOR: IdAllocator = IdAllocator {
181 free_list: Mutex::new(Vec::new()),
182 next_id: AtomicUsize::new(0),
183 };
184 }
185
186 struct ThreadIdGuard {
187 id: usize,
188 }
189
190 impl Drop for ThreadIdGuard {
191 fn drop(&mut self) {
192 if let Ok(mut list) = ALLOCATOR.free_list.lock() {
193 list.push(self.id);
194 }
195 }
196 }
197
198 loom::thread_local! {
199 static WORKER_ID: usize = {
200 let id = if let Ok(mut list) = ALLOCATOR.free_list.lock() {
201 list.pop().unwrap_or_else(|| ALLOCATOR.next_id.fetch_add(1, Ordering::Relaxed))
202 } else {
203 ALLOCATOR.next_id.fetch_add(1, Ordering::Relaxed)
204 };
205 GUARD.with(|g| {
206 *g.borrow_mut() = Some(ThreadIdGuard { id });
207 });
208 id
209 };
210
211 static GUARD: RefCell<Option<ThreadIdGuard>> = RefCell::new(None);
212 static HIT_BUF: RefCell<([usize; 64], usize)> = RefCell::new(([0; 64], 0));
213 static L1_FILTER: RefCell<([u8; 4096], usize)> = RefCell::new(([0; 4096], 0));
214 static LAST_FLUSH_TICK: Cell<TickType> = Cell::new(0);
215 static WARMUP_STATE: Cell<u8> = Cell::new(0);
216 }
217
218 #[derive(Clone, Default)]
219 pub struct DefaultTls;
220
221 impl DefaultTls {
222 #[inline(always)]
223 pub fn get_worker_id(&self) -> Option<usize> {
224 Some(WORKER_ID.with(|id| *id))
225 }
226
227 #[inline(always)]
228 pub fn with_hit_buf<F, R>(&self, f: F) -> Option<R>
229 where
230 F: FnOnce(&mut ([usize; 64], usize)) -> R,
231 {
232 Some(HIT_BUF.with(|buf| f(&mut *buf.borrow_mut())))
233 }
234
235 #[inline(always)]
236 pub fn with_l1_filter<F, R>(&self, f: F) -> Option<R>
237 where
238 F: FnOnce(&mut ([u8; 4096], usize)) -> R,
239 {
240 Some(L1_FILTER.with(|filter| f(&mut *filter.borrow_mut())))
241 }
242
243 #[inline(always)]
244 pub fn with_last_flush_tick<F, R>(&self, f: F) -> Option<R>
245 where
246 F: FnOnce(&mut TickType) -> R,
247 {
248 Some(LAST_FLUSH_TICK.with(|cell| {
249 let mut val = cell.get();
250 let res = f(&mut val);
251 cell.set(val);
252 res
253 }))
254 }
255
256 #[inline(always)]
257 pub fn with_warmup_state<F, R>(&self, f: F) -> R
258 where
259 F: FnOnce(&mut u8) -> R,
260 {
261 WARMUP_STATE.with(|cell| {
262 let mut val = cell.get();
263 let res = f(&mut val);
264 cell.set(val);
265 res
266 })
267 }
268 }
269}
270
271#[cfg(any(feature = "loom", loom))]
272pub use loom_tls_impl::DefaultTls;
273
274#[cfg(not(any(feature = "std", feature = "loom", loom)))]
275mod no_std_tls_impl {
276 use super::*;
277
278 #[derive(Clone, Default)]
279 pub struct DefaultTls;
280
281 impl DefaultTls {
282 #[inline(always)]
283 pub fn get_worker_id(&self) -> Option<usize> {
284 None
285 }
286
287 #[inline(always)]
288 pub fn with_hit_buf<F, R>(&self, _f: F) -> Option<R>
289 where
290 F: FnOnce(&mut ([usize; 64], usize)) -> R,
291 {
292 None
293 }
294
295 #[inline(always)]
296 pub fn with_l1_filter<F, R>(&self, _f: F) -> Option<R>
297 where
298 F: FnOnce(&mut ([u8; 4096], usize)) -> R,
299 {
300 None
301 }
302
303 #[inline(always)]
304 pub fn with_last_flush_tick<F, R>(&self, _f: F) -> Option<R>
305 where
306 F: FnOnce(&mut TickType) -> R,
307 {
308 None
309 }
310
311 #[inline(always)]
312 pub fn with_warmup_state<F, R>(&self, f: F) -> R
313 where
314 F: FnOnce(&mut u8) -> R,
315 {
316 let mut state = 255;
317 f(&mut state)
318 }
319 }
320}
321
322#[cfg(not(any(feature = "std", feature = "loom", loom)))]
323pub use no_std_tls_impl::DefaultTls;