Skip to main content

kernel_api/sync/
irq_cell.rs

1use core::cell::{Cell, UnsafeCell};
2use core::fmt::{Debug, Formatter};
3use core::marker::{PhantomData, Unsize};
4use core::mem::ManuallyDrop;
5use core::ops::{CoerceUnsized, Deref, DerefMut, DispatchFromDyn};
6
7pub struct IrqCell<T: ?Sized> {
8	state: Cell<Option<usize>>,
9	data: UnsafeCell<T>
10}
11
12impl<T> IrqCell<T> {
13	pub const fn new(val: T) -> Self {
14		Self { state: Cell::new(None), data: UnsafeCell::new(val) }
15	}
16}
17
18impl<T: ?Sized> IrqCell<T> {
19	pub fn lock(&self) -> IrqGuard<'_, T> {
20		// Unsafety: is this actually needed?
21		if self.state.get().is_some() { panic!("IrqCell cannot be borrowed multiple times"); }
22
23		self.state.set(Some(crate::bridge::irq::disable()));
24		IrqGuard { cell: self, _phantom_not_send: PhantomData }
25	}
26
27	pub unsafe fn make_guard_unchecked(&self) -> IrqGuard<'_, T> {
28		// Unsafety: is this actually needed?
29		debug_assert!(self.state.get().is_some(), "Created IrqGuard for unlocked IrqCell");
30
31		IrqGuard { cell: self, _phantom_not_send: PhantomData }
32	}
33
34	pub unsafe fn unlock(&self) {
35		let old_state = self.state.take();
36		crate::bridge::irq::set(old_state.unwrap());
37	}
38}
39
40impl<T: Debug> Debug for IrqCell<T> {
41	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
42		let guard = self.lock();
43		let r = f.debug_struct("IrqCell")
44		 .field("data", &*guard)
45		 .finish_non_exhaustive();
46		IrqGuard::unlock(guard);
47		r
48	}
49}
50
51pub struct IrqGuard<'cell, T: ?Sized> {
52	cell: &'cell IrqCell<T>,
53	_phantom_not_send: PhantomData<*mut u8>, // Dropping guard on other core would cause interrupts to be enabled in the wrong place
54}
55
56impl<T: ?Sized> IrqGuard<'_, T> {
57	pub fn unlock_no_interrupts(this: IrqGuard<T>) {
58		let this = ManuallyDrop::new(this);
59		this.cell.state.take();
60	}
61
62	fn unlock(this: IrqGuard<T>) {
63		let this = ManuallyDrop::new(this);
64		unsafe { this.cell.unlock(); }
65	}
66}
67
68impl<T: Debug> Debug for IrqGuard<'_, T> {
69	fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
70		f.debug_struct("IrqGuard")
71		 .field("cell", &**self)
72		 .finish()
73	}
74}
75
76impl<T: ?Sized> Deref for IrqGuard<'_, T> {
77	type Target = T;
78
79	fn deref(&self) -> &T {
80		unsafe { &*self.cell.data.get() }
81	}
82}
83
84impl<T: ?Sized> DerefMut for IrqGuard<'_, T> {
85	fn deref_mut(&mut self) -> &mut T {
86		unsafe { &mut *self.cell.data.get() }
87	}
88}
89
90impl<T: ?Sized> Drop for IrqGuard<'_, T> {
91	fn drop(&mut self) {
92		unsafe { self.cell.unlock(); }
93	}
94}
95
96impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<IrqGuard<'a, U>> for IrqGuard<'a, T> {}
97impl<'b, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<IrqGuard<'b, U>> for IrqGuard<'b, T> {}