kernel_api/sync/
irq_cell.rs

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