kernel/lib/sync/niche_cell.rs
1// SPDX-License-Identifier: GPL-3.0-only
2//! NicheCell datatype; a wrapper around `UnsafeCell<Option<T>>` which
3//! is designed to take advantage of niche optimization
4//!
5//! Authors: MarioS271
6
7use core::cell::UnsafeCell;
8
9/// A datatype with interior mutability, which can be uninitialized via [`Option`].
10/// This datatype is designed to be used with values that can take advantage of niche
11/// optimization (where the datatype `T` has a value which is guaranteed to be invalid, like
12/// a [`NonZeroU64`](core::num::NonZeroU64) being zero)
13///
14/// The caller may also use this datatype if [`Option`] instead of [`MaybeUninit`]
15/// is necessary for code safety, as this type returns [`None`] on calling
16/// [`Self::get`] if [`Self::init`] has not been run yet, compared to [`UncheckedCell`]
17/// where calling [`UncheckedCell::get`] before [`UncheckedCell::init`] is undefined behavior.
18///
19/// [`MaybeUninit`]: core::mem::MaybeUninit
20/// [`UncheckedCell`]: super::unchecked_cell::UncheckedCell
21/// [`UncheckedCell::get`]: super::unchecked_cell::UncheckedCell::get
22/// [`UncheckedCell::init`]: super::unchecked_cell::UncheckedCell::init
23pub struct NicheCell<T>(
24 UnsafeCell<Option<T>>
25);
26
27/// Safety: this type can be shared across CPUs as the callers have the responsibility to
28/// ensure proper data safety because of the `unsafe` contracts on [`init`](Self::init) and [`get`](Self::get)
29unsafe impl<T: Send + Sync> Sync for NicheCell<T> {}
30
31impl<T> NicheCell<T> {
32 /// Constructor; creates a new [`NicheCell`] containing [`None`]
33 #[allow(clippy::new_without_default)]
34 pub const fn new() -> Self {
35 Self(
36 UnsafeCell::new(None)
37 )
38 }
39
40 /// Set the inner value
41 ///
42 /// # Safety
43 /// The caller must guarantee the following:
44 /// - That this method has never been called before and will never be called again
45 /// - That at the time of calling this method, no references or pointers to this data exist
46 /// - While this method is being called, no other CPU is working with the given data
47 pub unsafe fn init(&self, value: T) {
48 #[cfg(feature = "debug-checks")]
49 {
50 use crate::lib::panic::kernel_panic;
51 use crate::lib::panic_codes::PanicCode;
52
53 if unsafe { self.get().is_some() } {
54 kernel_panic(
55 PanicCode::DoubleInitialization,
56 "Attempted to double-initialize a NicheCell"
57 );
58 }
59 }
60
61 unsafe { *self.0.get() = Some(value) };
62 }
63
64 /// Get a reference to the inner value
65 ///
66 /// # Safety
67 /// The caller must guarantee that at this method's entire execution time,
68 /// no mutable references or pointers to this data exist or will exist
69 pub unsafe fn get(&self) -> &Option<T> {
70 unsafe { &*self.0.get() }
71 }
72}