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