1#![allow(dead_code)]
3
4use crate::hal;
5
6use core::cell::UnsafeCell;
7use core::ptr::NonNull;
8use core::sync::atomic::AtomicBool;
9use core::sync::atomic::AtomicIsize;
10use core::sync::atomic::Ordering;
11
12pub struct RwSpinLock {
14 lock: AtomicIsize,
15}
16
17impl RwSpinLock {
18 pub const fn new() -> Self {
20 RwSpinLock {
21 lock: AtomicIsize::new(0),
22 }
23 }
24
25 pub fn read_lock(&self) {
27 loop {
28 let count = self.lock.load(Ordering::Acquire);
29 if count >= 0 && count < isize::MAX {
30 if self
31 .lock
32 .compare_exchange_weak(count, count + 1, Ordering::SeqCst, Ordering::Relaxed)
33 .is_ok()
34 {
35 break;
36 }
37 }
38 }
39 }
40
41 pub unsafe fn read_unlock(&self) {
47 self.lock.fetch_sub(1, Ordering::Release);
48 }
49
50 pub fn write_lock(&self) {
52 while self
53 .lock
54 .compare_exchange_weak(0, -1, Ordering::SeqCst, Ordering::Relaxed)
55 .is_err()
56 {}
57 }
58
59 pub unsafe fn write_unlock(&self) {
65 self.lock.store(0, Ordering::Release);
66 }
67}
68
69#[proc_macros::fmt]
71pub struct SpinLock {
72 lock: AtomicBool,
73}
74
75impl SpinLock {
76 pub const fn new() -> Self {
78 SpinLock {
79 lock: AtomicBool::new(false),
80 }
81 }
82
83 pub fn lock(&self) {
85 let lock = &self.lock;
86
87 if lock.load(Ordering::Relaxed) {
88 hal::asm::nop!();
89 }
90
91 loop {
92 if lock
93 .compare_exchange_weak(false, true, Ordering::SeqCst, Ordering::Relaxed)
94 .is_ok()
95 {
96 break;
97 }
98 }
99 }
100
101 pub fn try_lock(&self) -> bool {
104 !self.lock.swap(true, Ordering::Acquire)
105 }
106
107 pub unsafe fn unlock(&self) {
114 self.lock.store(false, Ordering::Release)
115 }
116}
117
118pub struct RwSpinLockReadGuard<'a, T: ?Sized> {
120 lock: &'a RwSpinLock,
121 value: NonNull<T>,
122 marker: core::marker::PhantomData<&'a T>,
123}
124
125impl<T: ?Sized> core::ops::Deref for RwSpinLockReadGuard<'_, T> {
126 type Target = T;
127
128 #[inline]
129 fn deref(&self) -> &T {
130 unsafe { self.value.as_ref() }
131 }
132}
133
134impl<T: ?Sized> Drop for RwSpinLockReadGuard<'_, T> {
135 fn drop(&mut self) {
136 unsafe {
137 self.lock.read_unlock();
138 }
139 }
140}
141
142pub struct RwSpinLockWriteGuard<'a, T: ?Sized> {
144 lock: &'a RwSpinLock,
145 value: NonNull<T>,
146 marker: core::marker::PhantomData<&'a mut T>,
147}
148
149impl<T: ?Sized> core::ops::Deref for RwSpinLockWriteGuard<'_, T> {
150 type Target = T;
151
152 #[inline]
153 fn deref(&self) -> &T {
154 unsafe { self.value.as_ref() }
155 }
156}
157
158impl<T: ?Sized> core::ops::DerefMut for RwSpinLockWriteGuard<'_, T> {
159 fn deref_mut(&mut self) -> &mut T {
160 unsafe { self.value.as_mut() }
161 }
162}
163
164impl<T: ?Sized> Drop for RwSpinLockWriteGuard<'_, T> {
165 fn drop(&mut self) {
166 unsafe {
167 self.lock.write_unlock();
168 }
169 }
170}
171
172#[proc_macros::fmt]
174pub struct SpinLockGuard<'a, T: ?Sized> {
175 lock: &'a SpinLock,
176 value: NonNull<T>,
177 marker: core::marker::PhantomData<&'a mut T>,
178}
179
180impl<T: ?Sized> core::ops::Deref for SpinLockGuard<'_, T> {
181 type Target = T;
182
183 #[inline]
184 fn deref(&self) -> &T {
185 unsafe { self.value.as_ref() }
186 }
187}
188
189impl<T: ?Sized> core::ops::DerefMut for SpinLockGuard<'_, T> {
190 fn deref_mut(&mut self) -> &mut T {
191 unsafe { self.value.as_mut() }
192 }
193}
194
195impl<T: ?Sized> Drop for SpinLockGuard<'_, T> {
196 fn drop(&mut self) {
197 unsafe {
198 self.lock.unlock();
199 }
200 }
201}
202
203pub struct RwSpinLocked<T> {
209 lock: RwSpinLock,
210 value: UnsafeCell<T>,
211}
212
213unsafe impl<T: Send> Send for RwSpinLocked<T> {}
217unsafe impl<T: Send + Sync> Sync for RwSpinLocked<T> {}
218
219impl<T> RwSpinLocked<T> {
220 pub const fn new(value: T) -> Self {
222 RwSpinLocked {
223 lock: RwSpinLock::new(),
224 value: UnsafeCell::new(value),
225 }
226 }
227
228 pub fn read_lock(&self) -> RwSpinLockReadGuard<'_, T> {
230 self.lock.read_lock();
231 RwSpinLockReadGuard {
232 lock: &self.lock,
233 value: unsafe { NonNull::new_unchecked(self.value.get()) },
234 marker: core::marker::PhantomData,
235 }
236 }
237
238 pub fn write_lock(&self) -> RwSpinLockWriteGuard<'_, T> {
240 self.lock.write_lock();
241 RwSpinLockWriteGuard {
242 lock: &self.lock,
243 value: unsafe { NonNull::new_unchecked(self.value.get()) },
244 marker: core::marker::PhantomData,
245 }
246 }
247}
248
249pub struct SpinLocked<T> {
251 lock: SpinLock,
252 value: UnsafeCell<T>,
253}
254
255unsafe impl<T: Send> Send for SpinLocked<T> {}
258unsafe impl<T: Sync> Sync for SpinLocked<T> {}
259
260impl<T> SpinLocked<T> {
262 pub const fn new(value: T) -> Self {
264 SpinLocked {
265 lock: SpinLock::new(),
266 value: UnsafeCell::new(value),
267 }
268 }
269
270 pub fn lock(&self) -> SpinLockGuard<'_, T> {
272 self.lock.lock();
273 SpinLockGuard {
274 lock: &self.lock,
275 value: unsafe { NonNull::new_unchecked(self.value.get()) },
276 marker: core::marker::PhantomData,
277 }
278 }
279
280 pub fn try_lock(&self) -> Option<SpinLockGuard<'_, T>> {
282 if self.lock.try_lock() {
283 Some(SpinLockGuard {
284 lock: &self.lock,
285 value: unsafe { NonNull::new_unchecked(self.value.get()) },
286 marker: core::marker::PhantomData,
287 })
288 } else {
289 None
290 }
291 }
292}
293
294#[cfg(test)]
295mod tests {
296 use super::*;
297
298 #[test]
299 fn rw_spin_lock_tracks_multiple_readers() {
300 let lock = RwSpinLock::new();
301
302 lock.read_lock();
303 lock.read_lock();
304
305 assert_eq!(lock.lock.load(Ordering::Acquire), 2);
306
307 unsafe {
308 lock.read_unlock();
309 }
310
311 assert_eq!(lock.lock.load(Ordering::Acquire), 1);
312
313 unsafe {
314 lock.read_unlock();
315 }
316
317 assert_eq!(lock.lock.load(Ordering::Acquire), 0);
318 }
319
320 #[test]
321 fn rw_spin_lock_tracks_writer() {
322 let lock = RwSpinLock::new();
323
324 lock.write_lock();
325
326 assert_eq!(lock.lock.load(Ordering::Acquire), -1);
327
328 unsafe {
329 lock.write_unlock();
330 }
331
332 assert_eq!(lock.lock.load(Ordering::Acquire), 0);
333 }
334
335 #[test]
336 fn rw_spin_locked_read_guards_allow_shared_access() {
337 let value = RwSpinLocked::new(7usize);
338 let first = value.read_lock();
339 let second = value.read_lock();
340
341 assert_eq!(*first, 7);
342 assert_eq!(*second, 7);
343 assert_eq!(value.lock.lock.load(Ordering::Acquire), 2);
344 }
345
346 #[test]
347 fn rw_spin_locked_read_guard_releases_on_drop() {
348 let value = RwSpinLocked::new(7usize);
349
350 {
351 let _guard = value.read_lock();
352
353 assert_eq!(value.lock.lock.load(Ordering::Acquire), 1);
354 }
355
356 assert_eq!(value.lock.lock.load(Ordering::Acquire), 0);
357 }
358
359 #[test]
360 fn rw_spin_locked_write_guard_updates_value() {
361 let value = RwSpinLocked::new(7usize);
362
363 {
364 let mut guard = value.write_lock();
365 *guard = 11;
366
367 assert_eq!(*guard, 11);
368 assert_eq!(value.lock.lock.load(Ordering::Acquire), -1);
369 }
370
371 assert_eq!(value.lock.lock.load(Ordering::Acquire), 0);
372 assert_eq!(*value.read_lock(), 11);
373 }
374
375 #[test]
376 fn spin_lock_try_lock_reports_state() {
377 let lock = SpinLock::new();
378
379 assert!(lock.try_lock());
380 assert!(!lock.try_lock());
381
382 unsafe {
383 lock.unlock();
384 }
385
386 assert!(lock.try_lock());
387
388 unsafe {
389 lock.unlock();
390 }
391 }
392
393 #[test]
394 fn spin_lock_lock_and_unlock_update_state() {
395 let lock = SpinLock::new();
396
397 lock.lock();
398
399 assert!(lock.lock.load(Ordering::Acquire));
400
401 unsafe {
402 lock.unlock();
403 }
404
405 assert!(!lock.lock.load(Ordering::Acquire));
406 }
407
408 #[test]
409 fn spin_locked_guard_updates_value() {
410 let value = SpinLocked::new(7usize);
411
412 {
413 let mut guard = value.lock();
414 *guard = 11;
415
416 assert_eq!(*guard, 11);
417 }
418
419 assert_eq!(*value.lock(), 11);
420 }
421
422 #[test]
423 fn spin_locked_try_lock_returns_guard_when_unlocked() {
424 let value = SpinLocked::new(7usize);
425
426 {
427 let mut guard = value.try_lock().expect("lock should be available");
428 *guard = 11;
429
430 assert!(value.try_lock().is_none());
431 }
432
433 assert_eq!(*value.try_lock().expect("lock should be available"), 11);
434 }
435
436 #[test]
437 fn locked_types_are_sync_for_shareable_values() {
438 fn assert_sync<T: Sync>() {}
439
440 assert_sync::<RwSpinLocked<usize>>();
441 assert_sync::<SpinLocked<usize>>();
442 }
443}