Skip to main content

rustubs/proc/sync/
spin.rs

1//! RAII spin mutex with irqsave.
2//! the spin mutex part is core::spin::Mutex
3//!
4//! it seems that this can handle nested calls.
5//!
6//! stuffs are learned from:
7//! https://mara.nl/atomics/building-spinlock.html
8
9use crate::arch::x86_64::interrupt::{irq_restore, irq_save};
10use core::ops::{Deref, DerefMut};
11
12// wrappers for the spin mutex (and guard)
13pub struct SpinMutexIRQ<T: ?Sized> {
14	inner: spin::Mutex<T>,
15}
16
17pub struct SpinMutexIRQGuard<'a, T: ?Sized + 'a> {
18	spin_guard: Option<spin::MutexGuard<'a, T>>,
19	irq_was_enabled: bool,
20}
21
22// irq state is per CPU.
23unsafe impl<T: ?Sized> Send for SpinMutexIRQ<T> {}
24unsafe impl<T: ?Sized> Sync for SpinMutexIRQ<T> {}
25
26impl<T> SpinMutexIRQ<T> {
27	pub const fn new(data: T) -> Self { Self { inner: spin::Mutex::new(data) } }
28	pub fn into_inner(self) -> T { self.inner.into_inner() }
29}
30
31impl<T: ?Sized> SpinMutexIRQ<T> {
32	#[inline]
33	pub fn lock(&self) -> SpinMutexIRQGuard<'_, T> {
34		// am I sure about out-of-order?
35		let irq_was_enabled = irq_save();
36		let spin_guard = self.inner.lock();
37		SpinMutexIRQGuard {
38			spin_guard: Some(spin_guard),
39			irq_was_enabled,
40		}
41	}
42}
43
44impl<T: ?Sized> Drop for SpinMutexIRQGuard<'_, T> {
45	fn drop(&mut self) {
46		self.spin_guard.take();
47		irq_restore(self.irq_was_enabled);
48	}
49}
50
51impl<T: ?Sized> Deref for SpinMutexIRQGuard<'_, T> {
52	type Target = T;
53	fn deref(&self) -> &T { self.spin_guard.as_ref().expect("guard taken") }
54}
55
56impl<T: ?Sized> DerefMut for SpinMutexIRQGuard<'_, T> {
57	fn deref_mut(&mut self) -> &mut T {
58		self.spin_guard.as_mut().expect("guard taken")
59	}
60}