core/io/error/os_functions_atomic.rs
1//! OS-dependent functions
2//!
3//! `Error` needs OS functionalities to work interpret raw OS errors, but
4//! we can't link to anythink here in `alloc`. Therefore, we restrict
5//! creation of `Error` from raw OS errors in `std`, and require providing
6//! a vtable of operations when creating one.
7
8// FIXME: replace this with externally implementable items once they are more stable
9
10use super::{ErrorKind, OsFunctions, RawOsError};
11use crate::fmt;
12use crate::sync::atomic;
13
14/// These default functions are not reachable, but have them just to be safe.
15static OS_FUNCTIONS: atomic::AtomicPtr<OsFunctions> =
16 atomic::AtomicPtr::new(OsFunctions::DEFAULT as *const _ as *mut _);
17
18fn get_os_functions() -> &'static OsFunctions {
19 // SAFETY:
20 // * `OS_FUNCTIONS` is initially a pointer to `OsFunctions::DEFAULT`, which is valid for a static lifetime.
21 // * `OS_FUNCTIONS` can only be changed by `set_functions`, which only accepts `&'static OsFunctions`.
22 // * Therefore, `OS_FUNCTIONS` must always contain a valid non-null pointer with a static lifetime.
23 // * `Relaxed` ordering is sufficient as the only way to write to `OS_FUNCTIONS` is through
24 // `set_functions`, which has as a safety precondition that any value passed in must
25 // be constant and not created during runtime.
26 unsafe { &*OS_FUNCTIONS.load(atomic::Ordering::Relaxed) }
27}
28
29/// # Safety
30///
31/// The provided reference must point to data that is entirely constant; it must
32/// not be created during runtime.
33#[inline]
34pub(super) unsafe fn set_functions(f: &'static OsFunctions) {
35 #[cold]
36 fn set_functions_inner(f: &'static OsFunctions) {
37 OS_FUNCTIONS.store(f as *const _ as *mut _, atomic::Ordering::Relaxed);
38 }
39
40 if OS_FUNCTIONS.load(atomic::Ordering::Relaxed) != f as *const _ as *mut _ {
41 set_functions_inner(f);
42 }
43}
44
45#[inline]
46pub(super) fn format_os_error(errno: RawOsError, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
47 let f = get_os_functions();
48 (f.format_os_error)(errno, fmt)
49}
50
51#[inline]
52pub(super) fn decode_error_kind(errno: RawOsError) -> ErrorKind {
53 let f = get_os_functions();
54 (f.decode_error_kind)(errno)
55}
56
57#[inline]
58pub(super) fn is_interrupted(errno: RawOsError) -> bool {
59 let f = get_os_functions();
60 (f.is_interrupted)(errno)
61}