Skip to main content

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}