xref: /linux/rust/kernel/sync/set_once.rs (revision c17ee635fd3a482b2ad2bf5e269755c2eae5f25e)
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