xref: /DragonOS/kernel/src/libs/lazy_init.rs (revision fae6e9ade46a52976ad5d099643d51cc20876448)
1 // Copyright (C) DragonOS Community  longjin
2 
3 // This program is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU General Public License
5 // as published by the Free Software Foundation; either version 2
6 // of the License, or (at your option) any later version.
7 
8 // This program is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 // GNU General Public License for more details.
12 
13 // You should have received a copy of the GNU General Public License
14 // along with this program; if not, write to the Free Software
15 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
16 // Or you can visit https://www.gnu.org/licenses/gpl-2.0.html
17 #![allow(dead_code)]
18 
19 use core::cell::UnsafeCell;
20 use core::fmt::Debug;
21 use core::mem::MaybeUninit;
22 use core::ops::{Deref, DerefMut};
23 use core::sync::atomic::{AtomicBool, Ordering};
24 
25 use super::spinlock::SpinLock;
26 
27 /// A wrapper around a value that is initialized lazily.
28 pub struct Lazy<T> {
29     /// The lock that is used to ensure that only one thread calls the init function at the same time.
30     init_lock: SpinLock<()>,
31     /// The value that is initialized lazily.
32     value: UnsafeCell<MaybeUninit<T>>,
33     /// Whether the value has been initialized.
34     initialized: AtomicBool,
35 }
36 
37 impl<T> Lazy<T> {
38     /// Creates a new `Lazy` value that will be initialized with the
39     /// result of the closure `init`.
40     pub const fn new() -> Lazy<T> {
41         Lazy {
42             value: UnsafeCell::new(MaybeUninit::uninit()),
43             initialized: AtomicBool::new(false),
44             init_lock: SpinLock::new(()),
45         }
46     }
47 
48     /// Returns true if the value has been initialized.
49     #[inline(always)]
50     pub fn initialized(&self) -> bool {
51         let initialized = self.initialized.load(Ordering::Acquire);
52         if initialized {
53             return true;
54         }
55         return false;
56     }
57 
58     /// Ensures that this lazy value is initialized. If the value has not
59     /// yet been initialized, this will raise a panic.
60     #[inline(always)]
61     pub fn ensure(&self) {
62         if self.initialized() {
63             return;
64         }
65         panic!("Lazy value was not initialized");
66     }
67 
68     pub fn init(&self, value: T) {
69         assert!(!self.initialized());
70 
71         // We need this lock to ensure that only one thread calls the init function at the same time.
72         let _init_guard = self.init_lock.lock();
73         // Check again, in case another thread initialized it while we were waiting for the lock.
74         let initialized = self.initialized();
75         if initialized {
76             return;
77         }
78         unsafe {
79             (*self.value.get()).as_mut_ptr().write(value);
80         }
81         self.initialized.store(true, Ordering::Release);
82     }
83     /// Forces the evaluation of this lazy value and returns a reference to
84     /// the result. This is equivalent to the `Deref` impl, but is explicit.
85     /// This will initialize the value if it has not yet been initialized.
86     pub fn get(&self) -> &T {
87         self.ensure();
88         return unsafe { self.get_unchecked() };
89     }
90 
91     /// Returns a reference to the value if it has been initialized.
92     /// Otherwise, returns `None`.
93     pub fn try_get(&self) -> Option<&T> {
94         if self.initialized() {
95             return Some(unsafe { self.get_unchecked() });
96         }
97         return None;
98     }
99 
100     /// Forces the evaluation of this lazy value and returns a mutable
101     /// reference to the result. This is equivalent to the `DerefMut` impl,
102     /// but is explicit. This will initialize the value if it has not yet
103     /// been initialized.
104     pub fn get_mut(&mut self) -> &mut T {
105         self.ensure();
106         return unsafe { self.get_mut_unchecked() };
107     }
108 
109     #[inline(always)]
110     pub unsafe fn get_unchecked(&self) -> &T {
111         return &*(*self.value.get()).as_ptr();
112     }
113 
114     #[inline(always)]
115     pub unsafe fn get_mut_unchecked(&mut self) -> &mut T {
116         return &mut *(*self.value.get()).as_mut_ptr();
117     }
118 }
119 
120 impl<T> Deref for Lazy<T> {
121     type Target = T;
122 
123     #[inline(always)]
124     fn deref(&self) -> &T {
125         return self.get();
126     }
127 }
128 
129 impl<T> DerefMut for Lazy<T> {
130     #[inline(always)]
131     fn deref_mut(&mut self) -> &mut T {
132         return self.get_mut();
133     }
134 }
135 
136 impl<T: Debug> Debug for Lazy<T> {
137     fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
138         if let Some(value) = self.try_get() {
139             return write!(f, "Lazy({:?})", value);
140         } else {
141             return write!(f, "Lazy(uninitialized)");
142         }
143     }
144 }
145 
146 impl<T> Drop for Lazy<T> {
147     fn drop(&mut self) {
148         if self.initialized() {
149             unsafe {
150                 (*self.value.get()).as_mut_ptr().drop_in_place();
151             }
152         }
153     }
154 }
155 
156 unsafe impl<T: Send + Sync> Sync for Lazy<T> {}
157 unsafe impl<T: Send> Send for Lazy<T> {}
158