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}