1 | //! A "once initialization" primitive |
2 | //! |
3 | //! This primitive is meant to be used to run one-time initialization. An |
4 | //! example use case would be for initializing an FFI library. |
5 | |
6 | #[cfg (all(test, not(target_os = "emscripten" )))] |
7 | mod tests; |
8 | |
9 | use crate::fmt; |
10 | use crate::panic::{RefUnwindSafe, UnwindSafe}; |
11 | use crate::sys::sync as sys; |
12 | |
13 | /// A synchronization primitive which can be used to run a one-time global |
14 | /// initialization. Useful for one-time initialization for FFI or related |
15 | /// functionality. This type can only be constructed with [`Once::new()`]. |
16 | /// |
17 | /// # Examples |
18 | /// |
19 | /// ``` |
20 | /// use std::sync::Once; |
21 | /// |
22 | /// static START: Once = Once::new(); |
23 | /// |
24 | /// START.call_once(|| { |
25 | /// // run initialization here |
26 | /// }); |
27 | /// ``` |
28 | #[stable (feature = "rust1" , since = "1.0.0" )] |
29 | pub struct Once { |
30 | inner: sys::Once, |
31 | } |
32 | |
33 | #[stable (feature = "sync_once_unwind_safe" , since = "1.59.0" )] |
34 | impl UnwindSafe for Once {} |
35 | |
36 | #[stable (feature = "sync_once_unwind_safe" , since = "1.59.0" )] |
37 | impl RefUnwindSafe for Once {} |
38 | |
39 | /// State yielded to [`Once::call_once_force()`]’s closure parameter. The state |
40 | /// can be used to query the poison status of the [`Once`]. |
41 | #[stable (feature = "once_poison" , since = "1.51.0" )] |
42 | pub struct OnceState { |
43 | pub(crate) inner: sys::OnceState, |
44 | } |
45 | |
46 | pub(crate) enum ExclusiveState { |
47 | Incomplete, |
48 | Poisoned, |
49 | Complete, |
50 | } |
51 | |
52 | /// Initialization value for static [`Once`] values. |
53 | /// |
54 | /// # Examples |
55 | /// |
56 | /// ``` |
57 | /// use std::sync::{Once, ONCE_INIT}; |
58 | /// |
59 | /// static START: Once = ONCE_INIT; |
60 | /// ``` |
61 | #[stable (feature = "rust1" , since = "1.0.0" )] |
62 | #[deprecated ( |
63 | since = "1.38.0" , |
64 | note = "the `new` function is now preferred" , |
65 | suggestion = "Once::new()" |
66 | )] |
67 | pub const ONCE_INIT: Once = Once::new(); |
68 | |
69 | impl Once { |
70 | /// Creates a new `Once` value. |
71 | #[inline ] |
72 | #[stable (feature = "once_new" , since = "1.2.0" )] |
73 | #[rustc_const_stable (feature = "const_once_new" , since = "1.32.0" )] |
74 | #[must_use ] |
75 | pub const fn new() -> Once { |
76 | Once { inner: sys::Once::new() } |
77 | } |
78 | |
79 | /// Performs an initialization routine once and only once. The given closure |
80 | /// will be executed if this is the first time `call_once` has been called, |
81 | /// and otherwise the routine will *not* be invoked. |
82 | /// |
83 | /// This method will block the calling thread if another initialization |
84 | /// routine is currently running. |
85 | /// |
86 | /// When this function returns, it is guaranteed that some initialization |
87 | /// has run and completed (it might not be the closure specified). It is also |
88 | /// guaranteed that any memory writes performed by the executed closure can |
89 | /// be reliably observed by other threads at this point (there is a |
90 | /// happens-before relation between the closure and code executing after the |
91 | /// return). |
92 | /// |
93 | /// If the given closure recursively invokes `call_once` on the same [`Once`] |
94 | /// instance, the exact behavior is not specified: allowed outcomes are |
95 | /// a panic or a deadlock. |
96 | /// |
97 | /// # Examples |
98 | /// |
99 | /// ``` |
100 | /// use std::sync::Once; |
101 | /// |
102 | /// static mut VAL: usize = 0; |
103 | /// static INIT: Once = Once::new(); |
104 | /// |
105 | /// // Accessing a `static mut` is unsafe much of the time, but if we do so |
106 | /// // in a synchronized fashion (e.g., write once or read all) then we're |
107 | /// // good to go! |
108 | /// // |
109 | /// // This function will only call `expensive_computation` once, and will |
110 | /// // otherwise always return the value returned from the first invocation. |
111 | /// fn get_cached_val() -> usize { |
112 | /// unsafe { |
113 | /// INIT.call_once(|| { |
114 | /// VAL = expensive_computation(); |
115 | /// }); |
116 | /// VAL |
117 | /// } |
118 | /// } |
119 | /// |
120 | /// fn expensive_computation() -> usize { |
121 | /// // ... |
122 | /// # 2 |
123 | /// } |
124 | /// ``` |
125 | /// |
126 | /// # Panics |
127 | /// |
128 | /// The closure `f` will only be executed once even if this is called |
129 | /// concurrently amongst many threads. If that closure panics, however, then |
130 | /// it will *poison* this [`Once`] instance, causing all future invocations of |
131 | /// `call_once` to also panic. |
132 | /// |
133 | /// This is similar to [poisoning with mutexes][poison]. |
134 | /// |
135 | /// [poison]: struct.Mutex.html#poisoning |
136 | #[inline ] |
137 | #[stable (feature = "rust1" , since = "1.0.0" )] |
138 | #[track_caller ] |
139 | pub fn call_once<F>(&self, f: F) |
140 | where |
141 | F: FnOnce(), |
142 | { |
143 | // Fast path check |
144 | if self.inner.is_completed() { |
145 | return; |
146 | } |
147 | |
148 | let mut f = Some(f); |
149 | self.inner.call(false, &mut |_| f.take().unwrap()()); |
150 | } |
151 | |
152 | /// Performs the same function as [`call_once()`] except ignores poisoning. |
153 | /// |
154 | /// Unlike [`call_once()`], if this [`Once`] has been poisoned (i.e., a previous |
155 | /// call to [`call_once()`] or [`call_once_force()`] caused a panic), calling |
156 | /// [`call_once_force()`] will still invoke the closure `f` and will _not_ |
157 | /// result in an immediate panic. If `f` panics, the [`Once`] will remain |
158 | /// in a poison state. If `f` does _not_ panic, the [`Once`] will no |
159 | /// longer be in a poison state and all future calls to [`call_once()`] or |
160 | /// [`call_once_force()`] will be no-ops. |
161 | /// |
162 | /// The closure `f` is yielded a [`OnceState`] structure which can be used |
163 | /// to query the poison status of the [`Once`]. |
164 | /// |
165 | /// [`call_once()`]: Once::call_once |
166 | /// [`call_once_force()`]: Once::call_once_force |
167 | /// |
168 | /// # Examples |
169 | /// |
170 | /// ``` |
171 | /// use std::sync::Once; |
172 | /// use std::thread; |
173 | /// |
174 | /// static INIT: Once = Once::new(); |
175 | /// |
176 | /// // poison the once |
177 | /// let handle = thread::spawn(|| { |
178 | /// INIT.call_once(|| panic!()); |
179 | /// }); |
180 | /// assert!(handle.join().is_err()); |
181 | /// |
182 | /// // poisoning propagates |
183 | /// let handle = thread::spawn(|| { |
184 | /// INIT.call_once(|| {}); |
185 | /// }); |
186 | /// assert!(handle.join().is_err()); |
187 | /// |
188 | /// // call_once_force will still run and reset the poisoned state |
189 | /// INIT.call_once_force(|state| { |
190 | /// assert!(state.is_poisoned()); |
191 | /// }); |
192 | /// |
193 | /// // once any success happens, we stop propagating the poison |
194 | /// INIT.call_once(|| {}); |
195 | /// ``` |
196 | #[inline ] |
197 | #[stable (feature = "once_poison" , since = "1.51.0" )] |
198 | pub fn call_once_force<F>(&self, f: F) |
199 | where |
200 | F: FnOnce(&OnceState), |
201 | { |
202 | // Fast path check |
203 | if self.inner.is_completed() { |
204 | return; |
205 | } |
206 | |
207 | let mut f = Some(f); |
208 | self.inner.call(true, &mut |p| f.take().unwrap()(p)); |
209 | } |
210 | |
211 | /// Returns `true` if some [`call_once()`] call has completed |
212 | /// successfully. Specifically, `is_completed` will return false in |
213 | /// the following situations: |
214 | /// * [`call_once()`] was not called at all, |
215 | /// * [`call_once()`] was called, but has not yet completed, |
216 | /// * the [`Once`] instance is poisoned |
217 | /// |
218 | /// This function returning `false` does not mean that [`Once`] has not been |
219 | /// executed. For example, it may have been executed in the time between |
220 | /// when `is_completed` starts executing and when it returns, in which case |
221 | /// the `false` return value would be stale (but still permissible). |
222 | /// |
223 | /// [`call_once()`]: Once::call_once |
224 | /// |
225 | /// # Examples |
226 | /// |
227 | /// ``` |
228 | /// use std::sync::Once; |
229 | /// |
230 | /// static INIT: Once = Once::new(); |
231 | /// |
232 | /// assert_eq!(INIT.is_completed(), false); |
233 | /// INIT.call_once(|| { |
234 | /// assert_eq!(INIT.is_completed(), false); |
235 | /// }); |
236 | /// assert_eq!(INIT.is_completed(), true); |
237 | /// ``` |
238 | /// |
239 | /// ``` |
240 | /// use std::sync::Once; |
241 | /// use std::thread; |
242 | /// |
243 | /// static INIT: Once = Once::new(); |
244 | /// |
245 | /// assert_eq!(INIT.is_completed(), false); |
246 | /// let handle = thread::spawn(|| { |
247 | /// INIT.call_once(|| panic!()); |
248 | /// }); |
249 | /// assert!(handle.join().is_err()); |
250 | /// assert_eq!(INIT.is_completed(), false); |
251 | /// ``` |
252 | #[stable (feature = "once_is_completed" , since = "1.43.0" )] |
253 | #[inline ] |
254 | pub fn is_completed(&self) -> bool { |
255 | self.inner.is_completed() |
256 | } |
257 | |
258 | /// Returns the current state of the `Once` instance. |
259 | /// |
260 | /// Since this takes a mutable reference, no initialization can currently |
261 | /// be running, so the state must be either "incomplete", "poisoned" or |
262 | /// "complete". |
263 | #[inline ] |
264 | pub(crate) fn state(&mut self) -> ExclusiveState { |
265 | self.inner.state() |
266 | } |
267 | } |
268 | |
269 | #[stable (feature = "std_debug" , since = "1.16.0" )] |
270 | impl fmt::Debug for Once { |
271 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
272 | f.debug_struct(name:"Once" ).finish_non_exhaustive() |
273 | } |
274 | } |
275 | |
276 | impl OnceState { |
277 | /// Returns `true` if the associated [`Once`] was poisoned prior to the |
278 | /// invocation of the closure passed to [`Once::call_once_force()`]. |
279 | /// |
280 | /// # Examples |
281 | /// |
282 | /// A poisoned [`Once`]: |
283 | /// |
284 | /// ``` |
285 | /// use std::sync::Once; |
286 | /// use std::thread; |
287 | /// |
288 | /// static INIT: Once = Once::new(); |
289 | /// |
290 | /// // poison the once |
291 | /// let handle = thread::spawn(|| { |
292 | /// INIT.call_once(|| panic!()); |
293 | /// }); |
294 | /// assert!(handle.join().is_err()); |
295 | /// |
296 | /// INIT.call_once_force(|state| { |
297 | /// assert!(state.is_poisoned()); |
298 | /// }); |
299 | /// ``` |
300 | /// |
301 | /// An unpoisoned [`Once`]: |
302 | /// |
303 | /// ``` |
304 | /// use std::sync::Once; |
305 | /// |
306 | /// static INIT: Once = Once::new(); |
307 | /// |
308 | /// INIT.call_once_force(|state| { |
309 | /// assert!(!state.is_poisoned()); |
310 | /// }); |
311 | #[stable (feature = "once_poison" , since = "1.51.0" )] |
312 | #[inline ] |
313 | pub fn is_poisoned(&self) -> bool { |
314 | self.inner.is_poisoned() |
315 | } |
316 | |
317 | /// Poison the associated [`Once`] without explicitly panicking. |
318 | // NOTE: This is currently only exposed for `OnceLock`. |
319 | #[inline ] |
320 | pub(crate) fn poison(&self) { |
321 | self.inner.poison(); |
322 | } |
323 | } |
324 | |
325 | #[stable (feature = "std_debug" , since = "1.16.0" )] |
326 | impl fmt::Debug for OnceState { |
327 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
328 | f.debug_struct("OnceState" ).field(name:"poisoned" , &self.is_poisoned()).finish() |
329 | } |
330 | } |
331 | |