Add more from the std

This commit is contained in:
2026-03-17 21:33:34 +01:00
parent 56ad115e58
commit 9958b23c89
32 changed files with 10515 additions and 6 deletions

114
crates/std/src/sys/cmath.rs Normal file
View File

@@ -0,0 +1,114 @@
#![cfg(not(test))]
// These symbols are all defined by `libm`,
// or by `compiler-builtins` on unsupported platforms.
unsafe extern "C" {
pub safe fn acos(n: f64) -> f64;
pub safe fn asin(n: f64) -> f64;
pub safe fn atan(n: f64) -> f64;
pub safe fn atan2(a: f64, b: f64) -> f64;
pub safe fn cosh(n: f64) -> f64;
pub safe fn expm1(n: f64) -> f64;
pub safe fn expm1f(n: f32) -> f32;
#[cfg_attr(target_env = "msvc", link_name = "_hypot")]
pub safe fn hypot(x: f64, y: f64) -> f64;
#[cfg_attr(target_env = "msvc", link_name = "_hypotf")]
pub safe fn hypotf(x: f32, y: f32) -> f32;
pub safe fn log1p(n: f64) -> f64;
pub safe fn log1pf(n: f32) -> f32;
pub safe fn sinh(n: f64) -> f64;
pub safe fn tan(n: f64) -> f64;
pub safe fn tanh(n: f64) -> f64;
pub safe fn tgamma(n: f64) -> f64;
pub safe fn tgammaf(n: f32) -> f32;
pub safe fn lgamma_r(n: f64, s: &mut i32) -> f64;
#[cfg(not(target_os = "aix"))]
pub safe fn lgammaf_r(n: f32, s: &mut i32) -> f32;
pub safe fn erf(n: f64) -> f64;
pub safe fn erff(n: f32) -> f32;
pub safe fn erfc(n: f64) -> f64;
pub safe fn erfcf(n: f32) -> f32;
pub safe fn acosf128(n: f128) -> f128;
pub safe fn asinf128(n: f128) -> f128;
pub safe fn atanf128(n: f128) -> f128;
pub safe fn atan2f128(a: f128, b: f128) -> f128;
pub safe fn cbrtf128(n: f128) -> f128;
pub safe fn coshf128(n: f128) -> f128;
pub safe fn expm1f128(n: f128) -> f128;
pub safe fn hypotf128(x: f128, y: f128) -> f128;
pub safe fn log1pf128(n: f128) -> f128;
pub safe fn sinhf128(n: f128) -> f128;
pub safe fn tanf128(n: f128) -> f128;
pub safe fn tanhf128(n: f128) -> f128;
pub safe fn tgammaf128(n: f128) -> f128;
pub safe fn lgammaf128_r(n: f128, s: &mut i32) -> f128;
pub safe fn erff128(n: f128) -> f128;
pub safe fn erfcf128(n: f128) -> f128;
}
cfg_select! {
all(target_os = "windows", target_env = "msvc", target_arch = "x86") => {
// On 32-bit x86 MSVC these functions aren't defined, so we just define shims
// which promote everything to f64, perform the calculation, and then demote
// back to f32. While not precisely correct should be "correct enough" for now.
#[inline]
pub fn acosf(n: f32) -> f32 {
f64::acos(n as f64) as f32
}
#[inline]
pub fn asinf(n: f32) -> f32 {
f64::asin(n as f64) as f32
}
#[inline]
pub fn atan2f(n: f32, b: f32) -> f32 {
f64::atan2(n as f64, b as f64) as f32
}
#[inline]
pub fn atanf(n: f32) -> f32 {
f64::atan(n as f64) as f32
}
#[inline]
pub fn coshf(n: f32) -> f32 {
f64::cosh(n as f64) as f32
}
#[inline]
pub fn sinhf(n: f32) -> f32 {
f64::sinh(n as f64) as f32
}
#[inline]
pub fn tanf(n: f32) -> f32 {
f64::tan(n as f64) as f32
}
#[inline]
pub fn tanhf(n: f32) -> f32 {
f64::tanh(n as f64) as f32
}
}
_ => {
unsafe extern "C" {
pub safe fn acosf(n: f32) -> f32;
pub safe fn asinf(n: f32) -> f32;
pub safe fn atan2f(a: f32, b: f32) -> f32;
pub safe fn atanf(n: f32) -> f32;
pub safe fn coshf(n: f32) -> f32;
pub safe fn sinhf(n: f32) -> f32;
pub safe fn tanf(n: f32) -> f32;
pub safe fn tanhf(n: f32) -> f32;
}
}
}
// On AIX, we don't have lgammaf_r only the f64 version, so we can
// use the f64 version lgamma_r
#[cfg(target_os = "aix")]
pub fn lgammaf_r(n: f32, s: &mut i32) -> f32 {
lgamma_r(n.into(), s) as f32
}

View File

@@ -0,0 +1,62 @@
//! The configure builtins provides runtime support compiler-builtin features
//! which require dynamic initialization to work as expected, e.g. aarch64
//! outline-atomics.
/// Enable LSE atomic operations at startup, if supported.
///
/// Linker sections are based on what [`ctor`] does, with priorities to run slightly before user
/// code:
///
/// - Apple uses the section `__mod_init_func`, `mod_init_funcs` is needed to set
/// `S_MOD_INIT_FUNC_POINTERS`. There doesn't seem to be a way to indicate priorities.
/// - Windows uses `.CRT$XCT`, which is run before user constructors (these should use `.CRT$XCU`).
/// - ELF uses `.init_array` with a priority of 90, which runs before our `ARGV_INIT_ARRAY`
/// initializer (priority 99). Both are within the 0-100 implementation-reserved range, per docs
/// for the [`prio-ctor-dtor`] warning, and this matches compiler-rt's `CONSTRUCTOR_PRIORITY`.
///
/// To save startup time, the initializer is only run if outline atomic routines from
/// compiler-builtins may be used. If LSE is known to be available then the calls are never
/// emitted, and if we build the C intrinsics then it has its own initializer using the symbol
/// `__aarch64_have_lse_atomics`.
///
/// Initialization is done in a global constructor to so we get the same behavior regardless of
/// whether Rust's `init` is used, or if we are in a `dylib` or `no_main` situation (as opposed
/// to doing it as part of pre-main startup). This also matches C implementations.
///
/// Ideally `core` would have something similar, but detecting the CPU features requires the
/// auxiliary vector from the OS. We do the initialization in `std` rather than as part of
/// `compiler-builtins` because a builtins->std dependency isn't possible, and inlining parts of
/// `std-detect` would be much messier.
///
/// [`ctor`]: https://github.com/mmastrac/rust-ctor/blob/63382b833ddcbfb8b064f4e86bfa1ed4026ff356/shared/src/macros/mod.rs#L522-L534
/// [`prio-ctor-dtor`]: https://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html
#[cfg(all(
target_arch = "aarch64",
target_feature = "outline-atomics",
not(target_feature = "lse"),
not(feature = "compiler-builtins-c"),
))]
#[used]
#[cfg_attr(target_vendor = "apple", unsafe(link_section = "__DATA,__mod_init_func,mod_init_funcs"))]
#[cfg_attr(target_os = "windows", unsafe(link_section = ".CRT$XCT"))]
#[cfg_attr(
not(any(target_vendor = "apple", target_os = "windows")),
unsafe(link_section = ".init_array.90")
)]
static RUST_LSE_INIT: extern "C" fn() = {
extern "C" fn init_lse() {
use crate::arch;
// This is provided by compiler-builtins::aarch64_outline_atomics.
unsafe extern "C" {
fn __rust_enable_lse();
}
if arch::is_aarch64_feature_detected!("lse") {
unsafe {
__rust_enable_lse();
}
}
}
init_lse
};

31
crates/std/src/sys/env/common.rs vendored Normal file
View File

@@ -0,0 +1,31 @@
use crate::ffi::OsString;
use crate::{fmt, vec};
pub struct Env {
iter: vec::IntoIter<(OsString, OsString)>,
}
impl Env {
pub(super) fn new(env: Vec<(OsString, OsString)>) -> Self {
Env { iter: env.into_iter() }
}
}
impl fmt::Debug for Env {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.iter.as_slice()).finish()
}
}
impl !Send for Env {}
impl !Sync for Env {}
impl Iterator for Env {
type Item = (OsString, OsString);
fn next(&mut self) -> Option<(OsString, OsString)> {
self.iter.next()
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}

View File

@@ -11,6 +11,7 @@
target_os = "uefi",
target_os = "wasi",
target_os = "xous",
target_os = "survos",
))]
mod common;

View File

@@ -0,0 +1,426 @@
//! Constants associated with each target.
// Replaces the #[else] gate with #[cfg(not(any(…)))] of all the other gates.
// This ensures that they must be mutually exclusive and do not have precedence
// like cfg_select!.
macro cfg_unordered(
$(#[cfg($cfg:meta)] $os:item)*
#[else] $fallback:item
) {
$(#[cfg($cfg)] $os)*
#[cfg(not(any($($cfg),*)))] $fallback
}
// Keep entries sorted alphabetically and mutually exclusive.
cfg_unordered! {
#[cfg(target_os = "aix")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "aix";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".a";
pub const DLL_EXTENSION: &str = "a";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "android")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "android";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "cygwin")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "cygwin";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = ".dll";
pub const DLL_EXTENSION: &str = "dll";
pub const EXE_SUFFIX: &str = ".exe";
pub const EXE_EXTENSION: &str = "exe";
}
#[cfg(target_os = "dragonfly")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "dragonfly";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "emscripten")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "emscripten";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = ".js";
pub const EXE_EXTENSION: &str = "js";
}
#[cfg(target_os = "espidf")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "espidf";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "freebsd")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "freebsd";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "fuchsia")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "fuchsia";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "haiku")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "haiku";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "hermit")]
pub mod os {
pub const FAMILY: &str = "";
pub const OS: &str = "hermit";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = "";
pub const DLL_EXTENSION: &str = "";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "horizon")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "horizon";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = ".elf";
pub const EXE_EXTENSION: &str = "elf";
}
#[cfg(target_os = "hurd")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "hurd";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "illumos")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "illumos";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "ios")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "ios";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".dylib";
pub const DLL_EXTENSION: &str = "dylib";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "l4re")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "l4re";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "linux")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "linux";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "macos")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "macos";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".dylib";
pub const DLL_EXTENSION: &str = "dylib";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "netbsd")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "netbsd";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "nto")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "nto";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "nuttx")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "nuttx";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "openbsd")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "openbsd";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "redox")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "redox";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "rtems")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "rtems";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(all(target_vendor = "fortanix", target_env = "sgx"))]
pub mod os {
pub const FAMILY: &str = "";
pub const OS: &str = "";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = ".sgxs";
pub const DLL_EXTENSION: &str = "sgxs";
pub const EXE_SUFFIX: &str = ".sgxs";
pub const EXE_EXTENSION: &str = "sgxs";
}
#[cfg(target_os = "solaris")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "solaris";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "solid_asp3")]
pub mod os {
pub const FAMILY: &str = "itron";
pub const OS: &str = "solid";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "tvos")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "tvos";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".dylib";
pub const DLL_EXTENSION: &str = "dylib";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "uefi")]
pub mod os {
pub const FAMILY: &str = "";
pub const OS: &str = "uefi";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = "";
pub const DLL_EXTENSION: &str = "";
pub const EXE_SUFFIX: &str = ".efi";
pub const EXE_EXTENSION: &str = "efi";
}
#[cfg(target_os = "vexos")]
pub mod os {
pub const FAMILY: &str = "";
pub const OS: &str = "vexos";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = "";
pub const DLL_EXTENSION: &str = "";
pub const EXE_SUFFIX: &str = ".bin";
pub const EXE_EXTENSION: &str = "bin";
}
#[cfg(target_os = "visionos")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "visionos";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".dylib";
pub const DLL_EXTENSION: &str = "dylib";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "vita")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "vita";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = ".elf";
pub const EXE_EXTENSION: &str = "elf";
}
#[cfg(target_os = "vxworks")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "vxworks";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".so";
pub const DLL_EXTENSION: &str = "so";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(all(target_family = "wasm", not(any(target_os = "emscripten", target_os = "linux"))))]
pub mod os {
pub const FAMILY: &str = "";
pub const OS: &str = "";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = ".wasm";
pub const DLL_EXTENSION: &str = "wasm";
pub const EXE_SUFFIX: &str = ".wasm";
pub const EXE_EXTENSION: &str = "wasm";
}
#[cfg(target_os = "watchos")]
pub mod os {
pub const FAMILY: &str = "unix";
pub const OS: &str = "watchos";
pub const DLL_PREFIX: &str = "lib";
pub const DLL_SUFFIX: &str = ".dylib";
pub const DLL_EXTENSION: &str = "dylib";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
#[cfg(target_os = "windows")]
pub mod os {
pub const FAMILY: &str = "windows";
pub const OS: &str = "windows";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = ".dll";
pub const DLL_EXTENSION: &str = "dll";
pub const EXE_SUFFIX: &str = ".exe";
pub const EXE_EXTENSION: &str = "exe";
}
#[cfg(target_os = "zkvm")]
pub mod os {
pub const FAMILY: &str = "";
pub const OS: &str = "";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = ".elf";
pub const DLL_EXTENSION: &str = "elf";
pub const EXE_SUFFIX: &str = ".elf";
pub const EXE_EXTENSION: &str = "elf";
}
// The fallback when none of the other gates match.
#[else]
pub mod os {
pub const FAMILY: &str = "";
pub const OS: &str = "";
pub const DLL_PREFIX: &str = "";
pub const DLL_SUFFIX: &str = "";
pub const DLL_EXTENSION: &str = "";
pub const EXE_SUFFIX: &str = "";
pub const EXE_EXTENSION: &str = "";
}
}

143
crates/std/src/sys/exit.rs Normal file
View File

@@ -0,0 +1,143 @@
cfg_select! {
target_os = "linux" => {
/// Mitigation for <https://github.com/rust-lang/rust/issues/126600>
///
/// On glibc, `libc::exit` has been observed to not always be thread-safe.
/// It is currently unclear whether that is a glibc bug or allowed by the standard.
/// To mitigate this problem, we ensure that only one
/// Rust thread calls `libc::exit` (or returns from `main`) by calling this function before
/// calling `libc::exit` (or returning from `main`).
///
/// Technically, this is not enough to ensure soundness, since other code directly calling
/// `libc::exit` will still race with this.
///
/// *This function does not itself call `libc::exit`.* This is so it can also be used
/// to guard returning from `main`.
///
/// This function will return only the first time it is called in a process.
///
/// * If it is called again on the same thread as the first call, it will abort.
/// * If it is called again on a different thread, it will wait in a loop
/// (waiting for the process to exit).
pub fn unique_thread_exit() {
use crate::ffi::c_int;
use crate::ptr;
use crate::sync::atomic::AtomicPtr;
use crate::sync::atomic::Ordering::{Acquire, Relaxed};
static EXITING_THREAD_ID: AtomicPtr<c_int> = AtomicPtr::new(ptr::null_mut());
// We use the address of `errno` as a cheap and safe way to identify
// threads. As the C standard mandates that `errno` must have thread
// storage duration, we can rely on its address not changing over the
// lifetime of the thread. Additionally, accesses to `errno` are
// async-signal-safe, so this function is available in all imaginable
// circumstances.
let this_thread_id = crate::sys::io::errno_location();
match EXITING_THREAD_ID.compare_exchange(ptr::null_mut(), this_thread_id, Acquire, Relaxed) {
Ok(_) => {
// This is the first thread to call `unique_thread_exit`,
// and this is the first time it is called. Continue exiting.
}
Err(exiting_thread_id) if exiting_thread_id == this_thread_id => {
// This is the first thread to call `unique_thread_exit`,
// but this is the second time it is called.
// Abort the process.
core::panicking::panic_nounwind("std::process::exit called re-entrantly")
}
Err(_) => {
// This is not the first thread to call `unique_thread_exit`.
// Pause until the process exits.
loop {
// Safety: libc::pause is safe to call.
unsafe { libc::pause(); }
}
}
}
}
}
_ => {
/// Mitigation for <https://github.com/rust-lang/rust/issues/126600>
///
/// Mitigation is ***NOT*** implemented on this platform, either because this platform
/// is not affected, or because mitigation is not yet implemented for this platform.
#[cfg_attr(any(test, doctest), expect(dead_code))]
pub fn unique_thread_exit() {
// Mitigation not required on platforms where `exit` is thread-safe.
}
}
}
pub fn exit(code: i32) -> ! {
cfg_select! {
target_os = "hermit" => {
unsafe { hermit_abi::exit(code) }
}
target_os = "linux" => {
unsafe {
unique_thread_exit();
libc::exit(code)
}
}
target_os = "motor" => {
moto_rt::process::exit(code)
}
all(target_vendor = "fortanix", target_env = "sgx") => {
crate::sys::pal::abi::exit_with_code(code as _)
}
target_os = "solid_asp3" => {
rtabort!("exit({}) called", code)
}
target_os = "teeos" => {
let _ = code;
panic!("TA should not call `exit`")
}
target_os = "uefi" => {
use r_efi::base::Status;
use crate::os::uefi::env;
if let (Some(boot_services), Some(handle)) =
(env::boot_services(), env::try_image_handle())
{
let boot_services = boot_services.cast::<r_efi::efi::BootServices>();
let _ = unsafe {
((*boot_services.as_ptr()).exit)(
handle.as_ptr(),
Status::from_usize(code as usize),
0,
crate::ptr::null_mut(),
)
};
}
crate::intrinsics::abort()
}
any(
target_family = "unix",
target_os = "wasi",
) => {
unsafe { libc::exit(code as crate::ffi::c_int) }
}
target_os = "vexos" => {
let _ = code;
unsafe {
vex_sdk::vexSystemExitRequest();
loop {
vex_sdk::vexTasksRun();
}
}
}
target_os = "windows" => {
unsafe { crate::sys::pal::c::ExitProcess(code as u32) }
}
target_os = "xous" => {
crate::os::xous::ffi::exit(code as u32)
}
_ => {
let _ = code;
crate::intrinsics::abort()
}
}
}

View File

@@ -0,0 +1,81 @@
#![allow(dead_code)] // not used on all platforms
use crate::io::{self, Error, ErrorKind};
use crate::path::{Path, PathBuf};
use crate::sys::fs::{File, OpenOptions};
use crate::sys::helpers::ignore_notfound;
use crate::{fmt, fs};
pub(crate) const NOT_FILE_ERROR: Error = io::const_error!(
ErrorKind::InvalidInput,
"the source path is neither a regular file nor a symlink to a regular file",
);
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
let mut reader = fs::File::open(from)?;
let metadata = reader.metadata()?;
if !metadata.is_file() {
return Err(NOT_FILE_ERROR);
}
let mut writer = fs::File::create(to)?;
let perm = metadata.permissions();
let ret = io::copy(&mut reader, &mut writer)?;
writer.set_permissions(perm)?;
Ok(ret)
}
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
let filetype = fs::symlink_metadata(path)?.file_type();
if filetype.is_symlink() { fs::remove_file(path) } else { remove_dir_all_recursive(path) }
}
fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
for child in fs::read_dir(path)? {
let result: io::Result<()> = try {
let child = child?;
if child.file_type()?.is_dir() {
remove_dir_all_recursive(&child.path())?;
} else {
fs::remove_file(&child.path())?;
}
};
// ignore internal NotFound errors to prevent race conditions
if let Err(err) = &result
&& err.kind() != io::ErrorKind::NotFound
{
return result;
}
}
ignore_notfound(fs::remove_dir(path))
}
pub fn exists(path: &Path) -> io::Result<bool> {
match fs::metadata(path) {
Ok(_) => Ok(true),
Err(error) if error.kind() == io::ErrorKind::NotFound => Ok(false),
Err(error) => Err(error),
}
}
pub struct Dir {
path: PathBuf,
}
impl Dir {
pub fn open(path: &Path, _opts: &OpenOptions) -> io::Result<Self> {
path.canonicalize().map(|path| Self { path })
}
pub fn open_file(&self, path: &Path, opts: &OpenOptions) -> io::Result<File> {
File::open(&self.path.join(path), &opts)
}
}
impl fmt::Debug for Dir {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Dir").field("path", &self.path).finish()
}
}

View File

@@ -0,0 +1,173 @@
#![deny(unsafe_op_in_unsafe_fn)]
use crate::io;
use crate::path::{Path, PathBuf};
pub mod common;
cfg_select! {
any(target_family = "unix", target_os = "wasi") => {
mod unix;
use unix as imp;
#[cfg(not(target_os = "wasi"))]
pub use unix::{chown, fchown, lchown, mkfifo};
#[cfg(not(any(target_os = "fuchsia", target_os = "wasi")))]
pub use unix::chroot;
#[cfg(not(target_os = "wasi"))]
pub(crate) use unix::debug_assert_fd_is_open;
#[cfg(any(target_os = "linux", target_os = "android"))]
pub(super) use unix::CachedFileMetadata;
use crate::sys::helpers::run_path_with_cstr as with_native_path;
}
target_os = "windows" => {
mod windows;
use windows as imp;
pub use windows::{symlink_inner, junction_point};
use crate::sys::path::with_native_path;
}
target_os = "hermit" => {
mod hermit;
use hermit as imp;
}
target_os = "motor" => {
mod motor;
use motor as imp;
}
target_os = "solid_asp3" => {
mod solid;
use solid as imp;
}
target_os = "uefi" => {
mod uefi;
use uefi as imp;
}
target_os = "vexos" => {
mod vexos;
use vexos as imp;
}
_ => {
mod unsupported;
use unsupported as imp;
}
}
// FIXME: Replace this with platform-specific path conversion functions.
#[cfg(not(any(target_family = "unix", target_os = "windows", target_os = "wasi")))]
#[inline]
pub fn with_native_path<T>(path: &Path, f: &dyn Fn(&Path) -> io::Result<T>) -> io::Result<T> {
f(path)
}
pub use imp::{
Dir, DirBuilder, DirEntry, File, FileAttr, FilePermissions, FileTimes, FileType, OpenOptions,
ReadDir,
};
pub fn read_dir(path: &Path) -> io::Result<ReadDir> {
// FIXME: use with_native_path on all platforms
imp::readdir(path)
}
pub fn remove_file(path: &Path) -> io::Result<()> {
with_native_path(path, &imp::unlink)
}
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
with_native_path(old, &|old| with_native_path(new, &|new| imp::rename(old, new)))
}
pub fn remove_dir(path: &Path) -> io::Result<()> {
with_native_path(path, &imp::rmdir)
}
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
// FIXME: use with_native_path on all platforms
#[cfg(not(windows))]
return imp::remove_dir_all(path);
#[cfg(windows)]
with_native_path(path, &imp::remove_dir_all)
}
pub fn read_link(path: &Path) -> io::Result<PathBuf> {
with_native_path(path, &imp::readlink)
}
pub fn symlink(original: &Path, link: &Path) -> io::Result<()> {
// FIXME: use with_native_path on all platforms
#[cfg(windows)]
return imp::symlink(original, link);
#[cfg(not(windows))]
with_native_path(original, &|original| {
with_native_path(link, &|link| imp::symlink(original, link))
})
}
pub fn hard_link(original: &Path, link: &Path) -> io::Result<()> {
with_native_path(original, &|original| {
with_native_path(link, &|link| imp::link(original, link))
})
}
pub fn metadata(path: &Path) -> io::Result<FileAttr> {
with_native_path(path, &imp::stat)
}
pub fn symlink_metadata(path: &Path) -> io::Result<FileAttr> {
with_native_path(path, &imp::lstat)
}
pub fn set_permissions(path: &Path, perm: FilePermissions) -> io::Result<()> {
with_native_path(path, &|path| imp::set_perm(path, perm.clone()))
}
#[cfg(all(unix, not(target_os = "vxworks")))]
pub fn set_permissions_nofollow(path: &Path, perm: crate::fs::Permissions) -> io::Result<()> {
use crate::fs::OpenOptions;
let mut options = OpenOptions::new();
// ESP-IDF and Horizon do not support O_NOFOLLOW, so we skip setting it.
// Their filesystems do not have symbolic links, so no special handling is required.
#[cfg(not(any(target_os = "espidf", target_os = "horizon")))]
{
use crate::os::unix::fs::OpenOptionsExt;
options.custom_flags(libc::O_NOFOLLOW);
}
options.open(path)?.set_permissions(perm)
}
#[cfg(any(not(unix), target_os = "vxworks"))]
pub fn set_permissions_nofollow(_path: &Path, _perm: crate::fs::Permissions) -> io::Result<()> {
crate::unimplemented!(
"`set_permissions_nofollow` is currently only implemented on Unix platforms"
)
}
pub fn canonicalize(path: &Path) -> io::Result<PathBuf> {
with_native_path(path, &imp::canonicalize)
}
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
// FIXME: use with_native_path on all platforms
#[cfg(not(windows))]
return imp::copy(from, to);
#[cfg(windows)]
with_native_path(from, &|from| with_native_path(to, &|to| imp::copy(from, to)))
}
pub fn exists(path: &Path) -> io::Result<bool> {
// FIXME: use with_native_path on all platforms
#[cfg(not(windows))]
return imp::exists(path);
#[cfg(windows)]
with_native_path(path, &imp::exists)
}
pub fn set_times(path: &Path, times: FileTimes) -> io::Result<()> {
with_native_path(path, &|path| imp::set_times(path, times.clone()))
}
pub fn set_times_nofollow(path: &Path, times: FileTimes) -> io::Result<()> {
with_native_path(path, &|path| imp::set_times_nofollow(path, times.clone()))
}

View File

@@ -0,0 +1,362 @@
use crate::ffi::OsString;
use crate::fmt;
use crate::fs::TryLockError;
use crate::hash::{Hash, Hasher};
use crate::io::{self, BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
use crate::path::{Path, PathBuf};
pub use crate::sys::fs::common::Dir;
use crate::sys::time::SystemTime;
use crate::sys::unsupported;
pub struct File(!);
pub struct FileAttr(!);
pub struct ReadDir(!);
pub struct DirEntry(!);
#[derive(Clone, Debug)]
pub struct OpenOptions {}
#[derive(Copy, Clone, Debug, Default)]
pub struct FileTimes {}
pub struct FilePermissions(!);
pub struct FileType(!);
#[derive(Debug)]
pub struct DirBuilder {}
impl FileAttr {
pub fn size(&self) -> u64 {
self.0
}
pub fn perm(&self) -> FilePermissions {
self.0
}
pub fn file_type(&self) -> FileType {
self.0
}
pub fn modified(&self) -> io::Result<SystemTime> {
self.0
}
pub fn accessed(&self) -> io::Result<SystemTime> {
self.0
}
pub fn created(&self) -> io::Result<SystemTime> {
self.0
}
}
impl Clone for FileAttr {
fn clone(&self) -> FileAttr {
self.0
}
}
impl FilePermissions {
pub fn readonly(&self) -> bool {
self.0
}
pub fn set_readonly(&mut self, _readonly: bool) {
self.0
}
}
impl Clone for FilePermissions {
fn clone(&self) -> FilePermissions {
self.0
}
}
impl PartialEq for FilePermissions {
fn eq(&self, _other: &FilePermissions) -> bool {
self.0
}
}
impl Eq for FilePermissions {}
impl fmt::Debug for FilePermissions {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0
}
}
impl FileTimes {
pub fn set_accessed(&mut self, _t: SystemTime) {}
pub fn set_modified(&mut self, _t: SystemTime) {}
}
impl FileType {
pub fn is_dir(&self) -> bool {
self.0
}
pub fn is_file(&self) -> bool {
self.0
}
pub fn is_symlink(&self) -> bool {
self.0
}
}
impl Clone for FileType {
fn clone(&self) -> FileType {
self.0
}
}
impl Copy for FileType {}
impl PartialEq for FileType {
fn eq(&self, _other: &FileType) -> bool {
self.0
}
}
impl Eq for FileType {}
impl Hash for FileType {
fn hash<H: Hasher>(&self, _h: &mut H) {
self.0
}
}
impl fmt::Debug for FileType {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0
}
}
impl fmt::Debug for ReadDir {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0
}
}
impl Iterator for ReadDir {
type Item = io::Result<DirEntry>;
fn next(&mut self) -> Option<io::Result<DirEntry>> {
self.0
}
}
impl DirEntry {
pub fn path(&self) -> PathBuf {
self.0
}
pub fn file_name(&self) -> OsString {
self.0
}
pub fn metadata(&self) -> io::Result<FileAttr> {
self.0
}
pub fn file_type(&self) -> io::Result<FileType> {
self.0
}
}
impl OpenOptions {
pub fn new() -> OpenOptions {
OpenOptions {}
}
pub fn read(&mut self, _read: bool) {}
pub fn write(&mut self, _write: bool) {}
pub fn append(&mut self, _append: bool) {}
pub fn truncate(&mut self, _truncate: bool) {}
pub fn create(&mut self, _create: bool) {}
pub fn create_new(&mut self, _create_new: bool) {}
}
impl File {
pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
unsupported()
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
self.0
}
pub fn fsync(&self) -> io::Result<()> {
self.0
}
pub fn datasync(&self) -> io::Result<()> {
self.0
}
pub fn lock(&self) -> io::Result<()> {
self.0
}
pub fn lock_shared(&self) -> io::Result<()> {
self.0
}
pub fn try_lock(&self) -> Result<(), TryLockError> {
self.0
}
pub fn try_lock_shared(&self) -> Result<(), TryLockError> {
self.0
}
pub fn unlock(&self) -> io::Result<()> {
self.0
}
pub fn truncate(&self, _size: u64) -> io::Result<()> {
self.0
}
pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
self.0
}
pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.0
}
pub fn is_read_vectored(&self) -> bool {
self.0
}
pub fn read_buf(&self, _cursor: BorrowedCursor<'_>) -> io::Result<()> {
self.0
}
pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
self.0
}
pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.0
}
pub fn is_write_vectored(&self) -> bool {
self.0
}
pub fn flush(&self) -> io::Result<()> {
self.0
}
pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
self.0
}
pub fn size(&self) -> Option<io::Result<u64>> {
self.0
}
pub fn tell(&self) -> io::Result<u64> {
self.0
}
pub fn duplicate(&self) -> io::Result<File> {
self.0
}
pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
self.0
}
pub fn set_times(&self, _times: FileTimes) -> io::Result<()> {
self.0
}
}
impl DirBuilder {
pub fn new() -> DirBuilder {
DirBuilder {}
}
pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
unsupported()
}
}
impl fmt::Debug for File {
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0
}
}
pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
unsupported()
}
pub fn unlink(_p: &Path) -> io::Result<()> {
unsupported()
}
pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
unsupported()
}
pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
match perm.0 {}
}
pub fn set_times(_p: &Path, _times: FileTimes) -> io::Result<()> {
unsupported()
}
pub fn set_times_nofollow(_p: &Path, _times: FileTimes) -> io::Result<()> {
unsupported()
}
pub fn rmdir(_p: &Path) -> io::Result<()> {
unsupported()
}
pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
unsupported()
}
pub fn exists(_path: &Path) -> io::Result<bool> {
unsupported()
}
pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
unsupported()
}
pub fn symlink(_original: &Path, _link: &Path) -> io::Result<()> {
unsupported()
}
pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
unsupported()
}
pub fn stat(_p: &Path) -> io::Result<FileAttr> {
unsupported()
}
pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
unsupported()
}
pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
unsupported()
}
pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
unsupported()
}

View File

@@ -1,5 +1,14 @@
pub mod cmath;
pub mod configure_builtins;
pub mod env;
pub mod env_consts;
pub mod exit;
pub mod os_str;
pub mod path;
pub mod sync;
pub mod thread;
pub mod time;
// pub mod fs;
/// A trait for viewing representations from std types.
#[cfg_attr(not(target_os = "linux"), allow(unused))]

View File

@@ -0,0 +1,28 @@
cfg_select! {
target_os = "windows" => {
mod windows;
mod windows_prefix;
pub use windows::*;
}
all(target_vendor = "fortanix", target_env = "sgx") => {
mod sgx;
pub use sgx::*;
}
target_os = "solid_asp3" => {
mod unsupported_backslash;
pub use unsupported_backslash::*;
}
target_os = "uefi" => {
mod uefi;
pub use uefi::*;
}
target_os = "cygwin" => {
mod cygwin;
mod windows_prefix;
pub use cygwin::*;
}
_ => {
mod unix;
pub use unix::*;
}
}

View File

@@ -0,0 +1,72 @@
use crate::ffi::OsStr;
use crate::path::{Path, PathBuf, Prefix};
use crate::{env, io};
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
b == b'/'
}
#[inline]
pub fn is_verbatim_sep(b: u8) -> bool {
b == b'/'
}
#[inline]
pub fn parse_prefix(_: &OsStr) -> Option<Prefix<'_>> {
None
}
pub const HAS_PREFIXES: bool = false;
pub const MAIN_SEP_STR: &str = "/";
pub const MAIN_SEP: char = '/';
/// Make a POSIX path absolute without changing its semantics.
pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
// This is mostly a wrapper around collecting `Path::components`, with
// exceptions made where this conflicts with the POSIX specification.
// See 4.13 Pathname Resolution, IEEE Std 1003.1-2017
// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html#tag_04_13
// Get the components, skipping the redundant leading "." component if it exists.
let mut components = path.strip_prefix(".").unwrap_or(path).components();
let path_os = path.as_os_str().as_encoded_bytes();
let mut normalized = if path.is_absolute() {
// "If a pathname begins with two successive <slash> characters, the
// first component following the leading <slash> characters may be
// interpreted in an implementation-defined manner, although more than
// two leading <slash> characters shall be treated as a single <slash>
// character."
if path_os.starts_with(b"//") && !path_os.starts_with(b"///") {
components.next();
PathBuf::from("//")
} else {
PathBuf::new()
}
} else {
// env::current_dir()?
todo!()
};
normalized.extend(components);
// "Interfaces using pathname resolution may specify additional constraints
// when a pathname that does not name an existing directory contains at
// least one non- <slash> character and contains one or more trailing
// <slash> characters".
// A trailing <slash> is also meaningful if "a symbolic link is
// encountered during pathname resolution".
if path_os.ends_with(b"/") {
normalized.push("");
}
Ok(normalized)
}
pub(crate) fn is_absolute(path: &Path) -> bool {
if cfg!(any(unix, target_os = "hermit", target_os = "wasi", target_os = "motor")) {
path.has_root()
} else {
path.has_root() && path.prefix().is_some()
}
}

View File

@@ -0,0 +1,44 @@
cfg_select! {
any(
all(target_os = "windows", not(target_vendor="win7")),
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "openbsd",
target_os = "dragonfly",
target_os = "motor",
target_os = "fuchsia",
all(target_family = "wasm", target_feature = "atomics"),
target_os = "hermit",
) => {
mod futex;
pub use futex::Condvar;
}
any(
target_family = "unix",
target_os = "teeos",
) => {
mod pthread;
pub use pthread::Condvar;
}
all(target_os = "windows", target_vendor = "win7") => {
mod windows7;
pub use windows7::Condvar;
}
all(target_vendor = "fortanix", target_env = "sgx") => {
mod sgx;
pub use sgx::Condvar;
}
target_os = "solid_asp3" => {
mod itron;
pub use itron::Condvar;
}
target_os = "xous" => {
mod xous;
pub use xous::Condvar;
}
_ => {
mod no_threads;
pub use no_threads::Condvar;
}
}

View File

@@ -0,0 +1,27 @@
use crate::sys::sync::Mutex;
use crate::thread::sleep;
use crate::time::Duration;
pub struct Condvar {}
impl Condvar {
#[inline]
pub const fn new() -> Condvar {
Condvar {}
}
#[inline]
pub fn notify_one(&self) {}
#[inline]
pub fn notify_all(&self) {}
pub unsafe fn wait(&self, _mutex: &Mutex) {
panic!("condvar wait not supported")
}
pub unsafe fn wait_timeout(&self, _mutex: &Mutex, dur: Duration) -> bool {
sleep(dur);
false
}
}

View File

@@ -0,0 +1,5 @@
mod condvar;
mod mutex;
pub use condvar::Condvar;
pub use mutex::Mutex;

View File

@@ -0,0 +1,47 @@
cfg_select! {
any(
all(target_os = "windows", not(target_vendor = "win7")),
target_os = "linux",
target_os = "android",
target_os = "freebsd",
target_os = "openbsd",
target_os = "motor",
target_os = "dragonfly",
all(target_family = "wasm", target_feature = "atomics"),
target_os = "hermit",
) => {
mod futex;
pub use futex::Mutex;
}
target_os = "fuchsia" => {
mod fuchsia;
pub use fuchsia::Mutex;
}
any(
target_family = "unix",
target_os = "teeos",
) => {
mod pthread;
pub use pthread::Mutex;
}
all(target_os = "windows", target_vendor = "win7") => {
mod windows7;
pub use windows7::{Mutex, raw};
}
all(target_vendor = "fortanix", target_env = "sgx") => {
mod sgx;
pub use sgx::Mutex;
}
target_os = "solid_asp3" => {
mod itron;
pub use itron::Mutex;
}
target_os = "xous" => {
mod xous;
pub use xous::Mutex;
}
_ => {
mod no_threads;
pub use no_threads::Mutex;
}
}

View File

@@ -0,0 +1,31 @@
use crate::cell::Cell;
pub struct Mutex {
// This platform has no threads, so we can use a Cell here.
locked: Cell<bool>,
}
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {} // no threads on this platform
impl Mutex {
#[inline]
pub const fn new() -> Mutex {
Mutex { locked: Cell::new(false) }
}
#[inline]
pub fn lock(&self) {
assert_eq!(self.locked.replace(true), false, "cannot recursively acquire mutex");
}
#[inline]
pub unsafe fn unlock(&self) {
self.locked.set(false);
}
#[inline]
pub fn try_lock(&self) -> bool {
self.locked.replace(true) == false
}
}

View File

@@ -0,0 +1,154 @@
cfg_select! {
target_os = "hermit" => {
mod hermit;
pub use hermit::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{current_os_id, set_name};
}
target_os = "motor" => {
mod motor;
pub use motor::*;
}
all(target_vendor = "fortanix", target_env = "sgx") => {
mod sgx;
pub use sgx::{Thread, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
// SGX should protect in-enclave data from outside attackers, so there
// must not be any data leakage to the OS, particularly no 1-1 mapping
// between SGX thread names and OS thread names. Hence `set_name` is
// intentionally a no-op.
//
// Note that the internally visible SGX thread name is already provided
// by the platform-agnostic Rust thread code. This can be observed in
// the [`std::thread::tests::test_named_thread`] test, which succeeds
// as-is with the SGX target.
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{available_parallelism, set_name};
}
target_os = "solid_asp3" => {
mod solid;
pub use solid::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{available_parallelism, current_os_id, set_name};
}
target_os = "teeos" => {
mod teeos;
pub use teeos::{Thread, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{available_parallelism, current_os_id, set_name};
}
target_os = "uefi" => {
mod uefi;
pub use uefi::{available_parallelism, sleep};
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{Thread, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
}
any(target_family = "unix", target_os = "wasi") => {
mod unix;
pub use unix::{Thread, available_parallelism, current_os_id, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
#[cfg(not(any(
target_env = "newlib",
target_os = "l4re",
target_os = "emscripten",
target_os = "redox",
target_os = "hurd",
target_os = "aix",
target_os = "wasi",
)))]
pub use unix::set_name;
#[cfg(any(
target_os = "freebsd",
target_os = "netbsd",
target_os = "linux",
target_os = "android",
target_os = "solaris",
target_os = "illumos",
target_os = "dragonfly",
target_os = "hurd",
target_os = "vxworks",
target_os = "wasi",
target_vendor = "apple",
))]
pub use unix::sleep_until;
#[expect(dead_code)]
mod unsupported;
#[cfg(any(
target_env = "newlib",
target_os = "l4re",
target_os = "emscripten",
target_os = "redox",
target_os = "hurd",
target_os = "aix",
target_os = "wasi",
))]
pub use unsupported::set_name;
}
target_os = "vexos" => {
mod vexos;
pub use vexos::{sleep, sleep_until, yield_now};
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, DEFAULT_MIN_STACK_SIZE};
}
all(target_family = "wasm", target_feature = "atomics") => {
mod wasm;
pub use wasm::sleep;
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, yield_now, DEFAULT_MIN_STACK_SIZE};
}
target_os = "windows" => {
mod windows;
pub use windows::{Thread, available_parallelism, current_os_id, set_name, set_name_wide, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
}
target_os = "xous" => {
mod xous;
pub use xous::{Thread, available_parallelism, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
#[expect(dead_code)]
mod unsupported;
pub use unsupported::{current_os_id, set_name};
}
_ => {
mod unsupported;
pub use unsupported::{Thread, available_parallelism, current_os_id, set_name, sleep, yield_now, DEFAULT_MIN_STACK_SIZE};
}
}
#[cfg(not(any(
target_os = "freebsd",
target_os = "netbsd",
target_os = "linux",
target_os = "android",
target_os = "solaris",
target_os = "illumos",
target_os = "dragonfly",
target_os = "hurd",
target_os = "vxworks",
target_os = "wasi",
target_vendor = "apple",
target_os = "motor",
target_os = "vexos"
)))]
pub fn sleep_until(deadline: crate::time::Instant) {
use crate::time::Instant;
// The clock source used for `sleep` might not be the same used for `Instant`.
// Since this function *must not* return before the deadline, we recheck the
// time after every call to `sleep`. See #149935 for an example of this
// occurring on older Windows systems.
while let Some(delay) = deadline.checked_duration_since(Instant::now()) {
// Sleep for the estimated time remaining until the deadline.
//
// If your system has a better way of estimating the delay time or
// provides a way to sleep until an absolute time, specialize this
// function for your system.
sleep(delay);
}
}

View File

@@ -0,0 +1,46 @@
use crate::ffi::CStr;
use crate::io;
use crate::num::NonZero;
use crate::thread::ThreadInit;
use crate::time::Duration;
// Silence dead code warnings for the otherwise unused ThreadInit::init() call.
#[expect(dead_code)]
fn dummy_init_call(init: Box<ThreadInit>) {
drop(init.init());
}
pub struct Thread(!);
pub const DEFAULT_MIN_STACK_SIZE: usize = 64 * 1024;
impl Thread {
// unsafe: see thread::Builder::spawn_unchecked for safety requirements
pub unsafe fn new(_stack: usize, _init: Box<ThreadInit>) -> io::Result<Thread> {
Err(io::Error::UNSUPPORTED_PLATFORM)
}
pub fn join(self) {
self.0
}
}
pub fn available_parallelism() -> io::Result<NonZero<usize>> {
Err(io::Error::UNKNOWN_THREAD_COUNT)
}
pub fn current_os_id() -> Option<u64> {
None
}
pub fn yield_now() {
// do nothing
}
pub fn set_name(_name: &CStr) {
// nope
}
pub fn sleep(_dur: Duration) {
panic!("can't sleep");
}

View File

@@ -0,0 +1,53 @@
cfg_select! {
target_os = "hermit" => {
mod hermit;
use hermit as imp;
}
target_os = "motor" => {
use moto_rt::time as imp;
}
all(target_vendor = "fortanix", target_env = "sgx") => {
mod sgx;
use sgx as imp;
}
target_os = "solid_asp3" => {
mod solid;
use solid as imp;
}
target_os = "uefi" => {
mod uefi;
use uefi as imp;
}
any(
target_os = "teeos",
target_family = "unix",
target_os = "wasi",
) => {
mod unix;
use unix as imp;
}
target_os = "vexos" => {
mod vexos;
#[expect(unused)]
mod unsupported;
mod imp {
pub use super::vexos::Instant;
pub use super::unsupported::{SystemTime, UNIX_EPOCH};
}
}
target_os = "windows" => {
mod windows;
use windows as imp;
}
target_os = "xous" => {
mod xous;
use xous as imp;
}
_ => {
mod unsupported;
use unsupported as imp;
}
}
pub use imp::{Instant, SystemTime, UNIX_EPOCH};

View File

@@ -0,0 +1,49 @@
use crate::time::Duration;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant(Duration);
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct SystemTime(Duration);
pub const UNIX_EPOCH: SystemTime = SystemTime(Duration::from_secs(0));
impl Instant {
pub fn now() -> Instant {
panic!("time not implemented on this platform")
}
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
self.0.checked_sub(other.0)
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant(self.0.checked_add(*other)?))
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
Some(Instant(self.0.checked_sub(*other)?))
}
}
impl SystemTime {
pub const MAX: SystemTime = SystemTime(Duration::MAX);
pub const MIN: SystemTime = SystemTime(Duration::ZERO);
pub fn now() -> SystemTime {
panic!("time not implemented on this platform")
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
self.0.checked_sub(other.0).ok_or_else(|| other.0 - self.0)
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_add(*other)?))
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
Some(SystemTime(self.0.checked_sub(*other)?))
}
}