1821fe7bfSAndreas Hindborg // SPDX-License-Identifier: GPL-2.0 2821fe7bfSAndreas Hindborg 3821fe7bfSAndreas Hindborg //! A container that can be initialized at most once. 4821fe7bfSAndreas Hindborg 5821fe7bfSAndreas Hindborg use super::atomic::{ 6821fe7bfSAndreas Hindborg ordering::{Acquire, Relaxed, Release}, 7821fe7bfSAndreas Hindborg Atomic, 8821fe7bfSAndreas Hindborg }; 9821fe7bfSAndreas Hindborg use core::{cell::UnsafeCell, mem::MaybeUninit}; 10821fe7bfSAndreas Hindborg 11821fe7bfSAndreas Hindborg /// A container that can be populated at most once. Thread safe. 12821fe7bfSAndreas Hindborg /// 13821fe7bfSAndreas Hindborg /// Once the a [`SetOnce`] is populated, it remains populated by the same object for the 14821fe7bfSAndreas Hindborg /// lifetime `Self`. 15821fe7bfSAndreas Hindborg /// 16821fe7bfSAndreas Hindborg /// # Invariants 17821fe7bfSAndreas Hindborg /// 18821fe7bfSAndreas Hindborg /// - `init` may only increase in value. 19821fe7bfSAndreas Hindborg /// - `init` may only assume values in the range `0..=2`. 20821fe7bfSAndreas Hindborg /// - `init == 0` if and only if `value` is uninitialized. 21821fe7bfSAndreas Hindborg /// - `init == 1` if and only if there is exactly one thread with exclusive 22821fe7bfSAndreas Hindborg /// access to `self.value`. 23821fe7bfSAndreas Hindborg /// - `init == 2` if and only if `value` is initialized and valid for shared 24821fe7bfSAndreas Hindborg /// access. 25821fe7bfSAndreas Hindborg /// 26821fe7bfSAndreas Hindborg /// # Example 27821fe7bfSAndreas Hindborg /// 28821fe7bfSAndreas Hindborg /// ``` 29821fe7bfSAndreas Hindborg /// # use kernel::sync::SetOnce; 30821fe7bfSAndreas Hindborg /// let value = SetOnce::new(); 31821fe7bfSAndreas Hindborg /// assert_eq!(None, value.as_ref()); 32821fe7bfSAndreas Hindborg /// 33821fe7bfSAndreas Hindborg /// let status = value.populate(42u8); 34821fe7bfSAndreas Hindborg /// assert_eq!(true, status); 35821fe7bfSAndreas Hindborg /// assert_eq!(Some(&42u8), value.as_ref()); 36821fe7bfSAndreas Hindborg /// assert_eq!(Some(42u8), value.copy()); 37821fe7bfSAndreas Hindborg /// 38821fe7bfSAndreas Hindborg /// let status = value.populate(101u8); 39821fe7bfSAndreas Hindborg /// assert_eq!(false, status); 40821fe7bfSAndreas Hindborg /// assert_eq!(Some(&42u8), value.as_ref()); 41821fe7bfSAndreas Hindborg /// assert_eq!(Some(42u8), value.copy()); 42821fe7bfSAndreas Hindborg /// ``` 43821fe7bfSAndreas Hindborg pub struct SetOnce<T> { 44821fe7bfSAndreas Hindborg init: Atomic<u32>, 45821fe7bfSAndreas Hindborg value: UnsafeCell<MaybeUninit<T>>, 46821fe7bfSAndreas Hindborg } 47821fe7bfSAndreas Hindborg 48821fe7bfSAndreas Hindborg impl<T> Default for SetOnce<T> { 49821fe7bfSAndreas Hindborg fn default() -> Self { 50821fe7bfSAndreas Hindborg Self::new() 51821fe7bfSAndreas Hindborg } 52821fe7bfSAndreas Hindborg } 53821fe7bfSAndreas Hindborg 54821fe7bfSAndreas Hindborg impl<T> SetOnce<T> { 55821fe7bfSAndreas Hindborg /// Create a new [`SetOnce`]. 56821fe7bfSAndreas Hindborg /// 57821fe7bfSAndreas Hindborg /// The returned instance will be empty. 58821fe7bfSAndreas Hindborg pub const fn new() -> Self { 59821fe7bfSAndreas Hindborg // INVARIANT: The container is empty and we initialize `init` to `0`. 60821fe7bfSAndreas Hindborg Self { 61821fe7bfSAndreas Hindborg value: UnsafeCell::new(MaybeUninit::uninit()), 62821fe7bfSAndreas Hindborg init: Atomic::new(0), 63821fe7bfSAndreas Hindborg } 64821fe7bfSAndreas Hindborg } 65821fe7bfSAndreas Hindborg 66821fe7bfSAndreas Hindborg /// Get a reference to the contained object. 67821fe7bfSAndreas Hindborg /// 68821fe7bfSAndreas Hindborg /// Returns [`None`] if this [`SetOnce`] is empty. 69821fe7bfSAndreas Hindborg pub fn as_ref(&self) -> Option<&T> { 70821fe7bfSAndreas Hindborg if self.init.load(Acquire) == 2 { 71821fe7bfSAndreas Hindborg // SAFETY: By the type invariants of `Self`, `self.init == 2` means that `self.value` 72821fe7bfSAndreas Hindborg // is initialized and valid for shared access. 73821fe7bfSAndreas Hindborg Some(unsafe { &*self.value.get().cast() }) 74821fe7bfSAndreas Hindborg } else { 75821fe7bfSAndreas Hindborg None 76821fe7bfSAndreas Hindborg } 77821fe7bfSAndreas Hindborg } 78821fe7bfSAndreas Hindborg 79821fe7bfSAndreas Hindborg /// Populate the [`SetOnce`]. 80821fe7bfSAndreas Hindborg /// 81821fe7bfSAndreas Hindborg /// Returns `true` if the [`SetOnce`] was successfully populated. 82821fe7bfSAndreas Hindborg pub fn populate(&self, value: T) -> bool { 83821fe7bfSAndreas Hindborg // INVARIANT: If the swap succeeds: 84821fe7bfSAndreas Hindborg // - We increase `init`. 85821fe7bfSAndreas Hindborg // - We write the valid value `1` to `init`. 86821fe7bfSAndreas Hindborg // - Only one thread can succeed in this write, so we have exclusive access after the 87821fe7bfSAndreas Hindborg // write. 88821fe7bfSAndreas Hindborg if let Ok(0) = self.init.cmpxchg(0, 1, Relaxed) { 89821fe7bfSAndreas Hindborg // SAFETY: By the type invariants of `Self`, the fact that we succeeded in writing `1` 90821fe7bfSAndreas Hindborg // to `self.init` means we obtained exclusive access to `self.value`. 91821fe7bfSAndreas Hindborg unsafe { core::ptr::write(self.value.get().cast(), value) }; 92821fe7bfSAndreas Hindborg // INVARIANT: 93821fe7bfSAndreas Hindborg // - We increase `init`. 94821fe7bfSAndreas Hindborg // - We write the valid value `2` to `init`. 95821fe7bfSAndreas Hindborg // - We release our exclusive access to `self.value` and it is now valid for shared 96821fe7bfSAndreas Hindborg // access. 97821fe7bfSAndreas Hindborg self.init.store(2, Release); 98821fe7bfSAndreas Hindborg true 99821fe7bfSAndreas Hindborg } else { 100821fe7bfSAndreas Hindborg false 101821fe7bfSAndreas Hindborg } 102821fe7bfSAndreas Hindborg } 103821fe7bfSAndreas Hindborg 104821fe7bfSAndreas Hindborg /// Get a copy of the contained object. 105821fe7bfSAndreas Hindborg /// 106821fe7bfSAndreas Hindborg /// Returns [`None`] if the [`SetOnce`] is empty. 107821fe7bfSAndreas Hindborg pub fn copy(&self) -> Option<T> 108821fe7bfSAndreas Hindborg where 109821fe7bfSAndreas Hindborg T: Copy, 110821fe7bfSAndreas Hindborg { 111821fe7bfSAndreas Hindborg self.as_ref().copied() 112821fe7bfSAndreas Hindborg } 113821fe7bfSAndreas Hindborg } 114821fe7bfSAndreas Hindborg 115821fe7bfSAndreas Hindborg impl<T> Drop for SetOnce<T> { 116821fe7bfSAndreas Hindborg fn drop(&mut self) { 117821fe7bfSAndreas Hindborg if *self.init.get_mut() == 2 { 118821fe7bfSAndreas Hindborg let value = self.value.get_mut(); 119821fe7bfSAndreas Hindborg // SAFETY: By the type invariants of `Self`, `self.init == 2` means that `self.value` 120821fe7bfSAndreas Hindborg // contains a valid value. We have exclusive access, as we hold a `mut` reference to 121821fe7bfSAndreas Hindborg // `self`. 122821fe7bfSAndreas Hindborg unsafe { value.assume_init_drop() }; 123821fe7bfSAndreas Hindborg } 124821fe7bfSAndreas Hindborg } 125821fe7bfSAndreas Hindborg } 126*8a581130SFUJITA Tomonori 127*8a581130SFUJITA Tomonori // SAFETY: `SetOnce` can be transferred across thread boundaries iff the data it contains can. 128*8a581130SFUJITA Tomonori unsafe impl<T: Send> Send for SetOnce<T> {} 129*8a581130SFUJITA Tomonori 130*8a581130SFUJITA Tomonori // SAFETY: `SetOnce` synchronises access to the inner value via atomic operations, 131*8a581130SFUJITA Tomonori // so shared references are safe when `T: Sync`. Since the inner `T` may be dropped 132*8a581130SFUJITA Tomonori // on any thread, we also require `T: Send`. 133*8a581130SFUJITA Tomonori unsafe impl<T: Send + Sync> Sync for SetOnce<T> {} 134