|
13 | 13 | #![warn(missing_docs)]
|
14 | 14 | #![deny(missing_debug_implementations)]
|
15 | 15 |
|
| 16 | +use core::cell::UnsafeCell; |
| 17 | +use core::sync::atomic::{AtomicBool, Ordering}; |
| 18 | + |
16 | 19 | pub use crate::addr::{align_down, align_up, PhysAddr, VirtAddr};
|
17 | 20 |
|
18 | 21 | /// Makes a function const only when `feature = "const_fn"` is enabled.
|
@@ -112,3 +115,60 @@ impl PrivilegeLevel {
|
112 | 115 | }
|
113 | 116 | }
|
114 | 117 | }
|
| 118 | + |
| 119 | +/// A wrapper that can be used to safely create one mutable reference `&'static mut T` from a static variable. |
| 120 | +/// |
| 121 | +/// `SingleUseCell` is safe because it ensures that it only ever gives out one reference. |
| 122 | +/// |
| 123 | +/// ``SingleUseCell<T>` is a safe alternative to `static mut` or a static `UnsafeCell<T>`. |
| 124 | +#[derive(Debug)] |
| 125 | +pub struct SingleUseCell<T> { |
| 126 | + used: AtomicBool, |
| 127 | + value: UnsafeCell<T>, |
| 128 | +} |
| 129 | + |
| 130 | +impl<T> SingleUseCell<T> { |
| 131 | + /// Construct a new SingleUseCell. |
| 132 | + pub const fn new(value: T) -> Self { |
| 133 | + Self { |
| 134 | + used: AtomicBool::new(false), |
| 135 | + value: UnsafeCell::new(value), |
| 136 | + } |
| 137 | + } |
| 138 | + |
| 139 | + /// Try to acquire a mutable reference to the wrapped value. |
| 140 | + /// This will only succeed the first time the function is |
| 141 | + /// called and fail on all following calls. |
| 142 | + /// |
| 143 | + /// ``` |
| 144 | + /// use x86_64::SingleUseCell; |
| 145 | + /// |
| 146 | + /// static FOO: SingleUseCell<i32> = SingleUseCell::new(0); |
| 147 | + /// |
| 148 | + /// // Call `try_get_mut` for the first time and get a reference. |
| 149 | + /// let first: &'static mut i32 = FOO.try_get_mut().unwrap(); |
| 150 | + /// assert_eq!(first, &0); |
| 151 | + /// |
| 152 | + /// // Calling `try_get_mut` again will return `None`. |
| 153 | + /// assert_eq!(FOO.try_get_mut(), None); |
| 154 | + /// ``` |
| 155 | + pub fn try_get_mut(&self) -> Option<&mut T> { |
| 156 | + let already_used = self.used.swap(true, Ordering::AcqRel); |
| 157 | + if already_used { |
| 158 | + None |
| 159 | + } else { |
| 160 | + Some(unsafe { |
| 161 | + // SAFETY: no reference has been given out yet and we won't give out another. |
| 162 | + &mut *self.value.get() |
| 163 | + }) |
| 164 | + } |
| 165 | + } |
| 166 | +} |
| 167 | + |
| 168 | +// SAFETY: Sharing a `SingleUseCell<T>` between threads is safe regardless of whether `T` is `Sync` |
| 169 | +// because we only expose the inner value once to one thread. The `T: Send` bound makes sure that |
| 170 | +// sending a unique reference to another thread is safe. |
| 171 | +unsafe impl<T: Send> Sync for SingleUseCell<T> {} |
| 172 | + |
| 173 | +// SAFETY: It's safe to send a `SingleUseCell<T>` to another thread if it's safe to send `T`. |
| 174 | +unsafe impl<T: Send> Send for SingleUseCell<T> {} |
0 commit comments