rustix_futex_sync/
once.rs

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