| // A "once" is a relatively simple primitive, and it's also typically provided |
| // by the OS as well (see `pthread_once` or `InitOnceExecuteOnce`). The OS |
| // primitives, however, tend to have surprising restrictions, such as the Unix |
| // one doesn't allow an argument to be passed to the function. |
| // |
| // As a result, we end up implementing it ourselves in the standard library. |
| // This also gives us the opportunity to optimize the implementation a bit which |
| // should help the fast path on call sites. |
| // |
| // So to recap, the guarantees of a Once are that it will call the |
| // initialization closure at most once, and it will never return until the one |
| // that's running has finished running. This means that we need some form of |
| // blocking here while the custom callback is running at the very least. |
| // Additionally, we add on the restriction of **poisoning**. Whenever an |
| // initialization closure panics, the Once enters a "poisoned" state which means |
| // that all future calls will immediately panic as well. |
| // |
| // So to implement this, one might first reach for a `Mutex`, but those cannot |
| // be put into a `static`. It also gets a lot harder with poisoning to figure |
| // out when the mutex needs to be deallocated because it's not after the closure |
| // finishes, but after the first successful closure finishes. |
| // |
| // All in all, this is instead implemented with atomics and lock-free |
| // operations! Whee! |
| |
| cfg_if::cfg_if! { |
| if #[cfg(any( |
| target_os = "linux", |
| target_os = "android", |
| all(target_arch = "wasm32", target_feature = "atomics"), |
| target_os = "freebsd", |
| target_os = "openbsd", |
| target_os = "dragonfly", |
| target_os = "fuchsia", |
| target_os = "hermit", |
| ))] { |
| mod futex; |
| pub use futex::{Once, OnceState}; |
| } else { |
| mod generic; |
| pub use generic::{Once, OnceState}; |
| } |
| } |