summaryrefslogtreecommitdiffstats
path: root/library/std/src/sys
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/common/small_c_string.rs2
-rw-r--r--library/std/src/sys/common/tests.rs4
-rw-r--r--library/std/src/sys/common/thread_local/mod.rs2
-rw-r--r--library/std/src/sys/hermit/mod.rs8
-rw-r--r--library/std/src/sys/hermit/net.rs10
-rw-r--r--library/std/src/sys/itron/error.rs5
-rw-r--r--library/std/src/sys/mod.rs9
-rw-r--r--library/std/src/sys/sgx/mod.rs6
-rw-r--r--library/std/src/sys/solid/mod.rs5
-rw-r--r--library/std/src/sys/solid/net.rs5
-rw-r--r--library/std/src/sys/solid/os.rs2
-rw-r--r--library/std/src/sys/uefi/alloc.rs33
-rw-r--r--library/std/src/sys/uefi/env.rs9
-rw-r--r--library/std/src/sys/uefi/helpers.rs141
-rw-r--r--library/std/src/sys/uefi/mod.rs244
-rw-r--r--library/std/src/sys/uefi/os.rs237
-rw-r--r--library/std/src/sys/uefi/path.rs25
-rw-r--r--library/std/src/sys/uefi/tests.rs21
-rw-r--r--library/std/src/sys/unix/alloc.rs6
-rw-r--r--library/std/src/sys/unix/args.rs1
-rw-r--r--library/std/src/sys/unix/env.rs11
-rw-r--r--library/std/src/sys/unix/fd.rs18
-rw-r--r--library/std/src/sys/unix/fs.rs62
-rw-r--r--library/std/src/sys/unix/kernel_copy.rs4
-rw-r--r--library/std/src/sys/unix/mod.rs11
-rw-r--r--library/std/src/sys/unix/net.rs9
-rw-r--r--library/std/src/sys/unix/os.rs15
-rw-r--r--library/std/src/sys/unix/os_str.rs10
-rw-r--r--library/std/src/sys/unix/os_str/tests.rs4
-rw-r--r--library/std/src/sys/unix/path.rs2
-rw-r--r--library/std/src/sys/unix/pipe.rs9
-rw-r--r--library/std/src/sys/unix/process/process_common.rs51
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs15
-rw-r--r--library/std/src/sys/unix/stack_overflow.rs2
-rw-r--r--library/std/src/sys/unix/thread.rs37
-rw-r--r--library/std/src/sys/unix/thread_local_dtor.rs4
-rw-r--r--library/std/src/sys/unix/thread_parking/darwin.rs3
-rw-r--r--library/std/src/sys/unix/time.rs2
-rw-r--r--library/std/src/sys/unsupported/common.rs4
-rw-r--r--library/std/src/sys/unsupported/process.rs20
-rw-r--r--library/std/src/sys/wasi/mod.rs5
-rw-r--r--library/std/src/sys/windows/args.rs4
-rw-r--r--library/std/src/sys/windows/c.rs6
-rw-r--r--library/std/src/sys/windows/c/windows_sys.lst21
-rw-r--r--library/std/src/sys/windows/c/windows_sys.rs201
-rw-r--r--library/std/src/sys/windows/handle.rs9
-rw-r--r--library/std/src/sys/windows/mod.rs5
-rw-r--r--library/std/src/sys/windows/net.rs38
-rw-r--r--library/std/src/sys/windows/os_str.rs8
-rw-r--r--library/std/src/sys/windows/path.rs28
-rw-r--r--library/std/src/sys/windows/pipe.rs8
-rw-r--r--library/std/src/sys/windows/process.rs151
-rw-r--r--library/std/src/sys/xous/alloc.rs62
-rw-r--r--library/std/src/sys/xous/locks/condvar.rs111
-rw-r--r--library/std/src/sys/xous/locks/mod.rs7
-rw-r--r--library/std/src/sys/xous/locks/mutex.rs116
-rw-r--r--library/std/src/sys/xous/locks/rwlock.rs72
-rw-r--r--library/std/src/sys/xous/mod.rs37
-rw-r--r--library/std/src/sys/xous/os.rs147
-rw-r--r--library/std/src/sys/xous/stdio.rs131
-rw-r--r--library/std/src/sys/xous/thread.rs144
-rw-r--r--library/std/src/sys/xous/thread_local_key.rs190
-rw-r--r--library/std/src/sys/xous/time.rs57
63 files changed, 2402 insertions, 224 deletions
diff --git a/library/std/src/sys/common/small_c_string.rs b/library/std/src/sys/common/small_c_string.rs
index 963d17a47..af9b18e37 100644
--- a/library/std/src/sys/common/small_c_string.rs
+++ b/library/std/src/sys/common/small_c_string.rs
@@ -19,7 +19,7 @@ pub fn run_path_with_cstr<T, F>(path: &Path, f: F) -> io::Result<T>
where
F: FnOnce(&CStr) -> io::Result<T>,
{
- run_with_cstr(path.as_os_str().as_os_str_bytes(), f)
+ run_with_cstr(path.as_os_str().as_encoded_bytes(), f)
}
#[inline]
diff --git a/library/std/src/sys/common/tests.rs b/library/std/src/sys/common/tests.rs
index 0a1cbcbe8..32dc18ee1 100644
--- a/library/std/src/sys/common/tests.rs
+++ b/library/std/src/sys/common/tests.rs
@@ -8,7 +8,7 @@ use core::iter::repeat;
fn stack_allocation_works() {
let path = Path::new("abc");
let result = run_path_with_cstr(path, |p| {
- assert_eq!(p, &*CString::new(path.as_os_str().as_os_str_bytes()).unwrap());
+ assert_eq!(p, &*CString::new(path.as_os_str().as_encoded_bytes()).unwrap());
Ok(42)
});
assert_eq!(result.unwrap(), 42);
@@ -25,7 +25,7 @@ fn heap_allocation_works() {
let path = repeat("a").take(384).collect::<String>();
let path = Path::new(&path);
let result = run_path_with_cstr(path, |p| {
- assert_eq!(p, &*CString::new(path.as_os_str().as_os_str_bytes()).unwrap());
+ assert_eq!(p, &*CString::new(path.as_os_str().as_encoded_bytes()).unwrap());
Ok(42)
});
assert_eq!(result.unwrap(), 42);
diff --git a/library/std/src/sys/common/thread_local/mod.rs b/library/std/src/sys/common/thread_local/mod.rs
index 975509bd4..8b2c839f8 100644
--- a/library/std/src/sys/common/thread_local/mod.rs
+++ b/library/std/src/sys/common/thread_local/mod.rs
@@ -6,7 +6,7 @@
// "static" is for single-threaded platforms where a global static is sufficient.
cfg_if::cfg_if! {
- if #[cfg(all(target_family = "wasm", not(target_feature = "atomics")))] {
+ if #[cfg(any(all(target_family = "wasm", not(target_feature = "atomics")), target_os = "uefi"))] {
#[doc(hidden)]
mod static_local;
#[doc(hidden)]
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index c7cb84667..abd7eb353 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -101,7 +101,6 @@ pub extern "C" fn __rust_abort() {
// SAFETY: must be called only once during runtime initialization.
// NOTE: this is not guaranteed to run, for example when Rust code is called externally.
pub unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
- let _ = net::init();
args::init(argc, argv);
}
@@ -130,6 +129,11 @@ pub unsafe extern "C" fn runtime_entry(
abi::exit(result);
}
+#[inline]
+pub(crate) fn is_interrupted(errno: i32) -> bool {
+ errno == abi::errno::EINTR
+}
+
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno {
abi::errno::EACCES => ErrorKind::PermissionDenied,
@@ -196,7 +200,7 @@ where
{
loop {
match cvt(f()) {
- Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
other => return other,
}
}
diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs
index 8c2d489d6..a564f1698 100644
--- a/library/std/src/sys/hermit/net.rs
+++ b/library/std/src/sys/hermit/net.rs
@@ -33,13 +33,7 @@ pub fn cvt_gai(err: i32) -> io::Result<()> {
))
}
-/// Checks whether the HermitCore's socket interface has been started already, and
-/// if not, starts it.
-pub fn init() {
- if unsafe { netc::network_init() } < 0 {
- panic!("Unable to initialize network interface");
- }
-}
+pub fn init() {}
#[derive(Debug)]
pub struct Socket(FileDesc);
@@ -108,7 +102,7 @@ impl Socket {
match unsafe { netc::poll(&mut pollfd, 1, timeout) } {
-1 => {
let err = io::Error::last_os_error();
- if err.kind() != io::ErrorKind::Interrupted {
+ if !err.is_interrupted() {
return Err(err);
}
}
diff --git a/library/std/src/sys/itron/error.rs b/library/std/src/sys/itron/error.rs
index 830c60d32..fbc822d4e 100644
--- a/library/std/src/sys/itron/error.rs
+++ b/library/std/src/sys/itron/error.rs
@@ -79,6 +79,11 @@ pub fn error_name(er: abi::ER) -> Option<&'static str> {
}
}
+#[inline]
+pub fn is_interrupted(er: abi::ER) -> bool {
+ er == abi::E_RLWAI
+}
+
pub fn decode_error_kind(er: abi::ER) -> ErrorKind {
match er {
// Success
diff --git a/library/std/src/sys/mod.rs b/library/std/src/sys/mod.rs
index beea3f23c..159ffe7ac 100644
--- a/library/std/src/sys/mod.rs
+++ b/library/std/src/sys/mod.rs
@@ -44,6 +44,12 @@ cfg_if::cfg_if! {
} else if #[cfg(target_family = "wasm")] {
mod wasm;
pub use self::wasm::*;
+ } else if #[cfg(target_os = "xous")] {
+ mod xous;
+ pub use self::xous::*;
+ } else if #[cfg(target_os = "uefi")] {
+ mod uefi;
+ pub use self::uefi::*;
} else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] {
mod sgx;
pub use self::sgx::*;
@@ -110,3 +116,6 @@ pub fn log_wrapper<F: Fn(f64) -> f64>(n: f64, log_fn: F) -> f64 {
pub fn log_wrapper<F: Fn(f64) -> f64>(n: f64, log_fn: F) -> f64 {
log_fn(n)
}
+
+#[cfg(not(target_os = "uefi"))]
+pub type RawOsError = i32;
diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs
index 9865a945b..09d3f7638 100644
--- a/library/std/src/sys/sgx/mod.rs
+++ b/library/std/src/sys/sgx/mod.rs
@@ -86,6 +86,12 @@ pub fn sgx_ineffective<T>(v: T) -> crate::io::Result<T> {
}
}
+#[inline]
+pub fn is_interrupted(code: i32) -> bool {
+ use fortanix_sgx_abi::Error;
+ code == Error::Interrupted as _
+}
+
pub fn decode_error_kind(code: i32) -> ErrorKind {
use fortanix_sgx_abi::Error;
diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs
index 923d27fd9..5af83653c 100644
--- a/library/std/src/sys/solid/mod.rs
+++ b/library/std/src/sys/solid/mod.rs
@@ -72,6 +72,11 @@ pub fn unsupported_err() -> crate::io::Error {
)
}
+#[inline]
+pub fn is_interrupted(code: i32) -> bool {
+ net::is_interrupted(code)
+}
+
pub fn decode_error_kind(code: i32) -> crate::io::ErrorKind {
error::decode_error_kind(code)
}
diff --git a/library/std/src/sys/solid/net.rs b/library/std/src/sys/solid/net.rs
index 0bd2bc3b9..6adced787 100644
--- a/library/std/src/sys/solid/net.rs
+++ b/library/std/src/sys/solid/net.rs
@@ -181,6 +181,11 @@ pub(super) fn error_name(er: abi::ER) -> Option<&'static str> {
unsafe { CStr::from_ptr(netc::strerror(er)) }.to_str().ok()
}
+#[inline]
+pub fn is_interrupted(er: abi::ER) -> bool {
+ er == netc::SOLID_NET_ERR_BASE - libc::EINTR
+}
+
pub(super) fn decode_error_kind(er: abi::ER) -> ErrorKind {
let errno = netc::SOLID_NET_ERR_BASE - er;
match errno as libc::c_int {
diff --git a/library/std/src/sys/solid/os.rs b/library/std/src/sys/solid/os.rs
index 9f4e66d62..ff81544ba 100644
--- a/library/std/src/sys/solid/os.rs
+++ b/library/std/src/sys/solid/os.rs
@@ -8,7 +8,7 @@ use crate::os::{
solid::ffi::{OsStrExt, OsStringExt},
};
use crate::path::{self, PathBuf};
-use crate::sync::RwLock;
+use crate::sync::{PoisonError, RwLock};
use crate::sys::common::small_c_string::run_with_cstr;
use crate::vec;
diff --git a/library/std/src/sys/uefi/alloc.rs b/library/std/src/sys/uefi/alloc.rs
new file mode 100644
index 000000000..789e3cbd8
--- /dev/null
+++ b/library/std/src/sys/uefi/alloc.rs
@@ -0,0 +1,33 @@
+//! Global Allocator for UEFI.
+//! Uses [r-efi-alloc](https://crates.io/crates/r-efi-alloc)
+
+use crate::alloc::{GlobalAlloc, Layout, System};
+
+const MEMORY_TYPE: u32 = r_efi::efi::LOADER_DATA;
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ // Return null pointer if boot services are not available
+ if crate::os::uefi::env::boot_services().is_none() {
+ return crate::ptr::null_mut();
+ }
+
+ // If boot services is valid then SystemTable is not null.
+ let system_table = crate::os::uefi::env::system_table().as_ptr().cast();
+ // The caller must ensure non-0 layout
+ unsafe { r_efi_alloc::raw::alloc(system_table, layout, MEMORY_TYPE) }
+ }
+
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ // Do nothing if boot services are not available
+ if crate::os::uefi::env::boot_services().is_none() {
+ return;
+ }
+
+ // If boot services is valid then SystemTable is not null.
+ let system_table = crate::os::uefi::env::system_table().as_ptr().cast();
+ // The caller must ensure non-0 layout
+ unsafe { r_efi_alloc::raw::dealloc(system_table, ptr, layout) }
+ }
+}
diff --git a/library/std/src/sys/uefi/env.rs b/library/std/src/sys/uefi/env.rs
new file mode 100644
index 000000000..c106d5fed
--- /dev/null
+++ b/library/std/src/sys/uefi/env.rs
@@ -0,0 +1,9 @@
+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";
+}
diff --git a/library/std/src/sys/uefi/helpers.rs b/library/std/src/sys/uefi/helpers.rs
new file mode 100644
index 000000000..126661bfc
--- /dev/null
+++ b/library/std/src/sys/uefi/helpers.rs
@@ -0,0 +1,141 @@
+//! Contains most of the shared UEFI specific stuff. Some of this might be moved to `std::os::uefi`
+//! if needed but no point in adding extra public API when there is not Std support for UEFI in the
+//! first place
+//!
+//! Some Nomenclature
+//! * Protocol:
+//! - Protocols serve to enable communication between separately built modules, including drivers.
+//! - Every protocol has a GUID associated with it. The GUID serves as the name for the protocol.
+//! - Protocols are produced and consumed.
+//! - More information about protocols can be found [here](https://edk2-docs.gitbook.io/edk-ii-uefi-driver-writer-s-guide/3_foundation/36_protocols_and_handles)
+
+use r_efi::efi::{self, Guid};
+
+use crate::mem::{size_of, MaybeUninit};
+use crate::os::uefi;
+use crate::ptr::NonNull;
+use crate::{
+ io::{self, const_io_error},
+ os::uefi::env::boot_services,
+};
+
+const BOOT_SERVICES_UNAVAILABLE: io::Error =
+ const_io_error!(io::ErrorKind::Other, "Boot Services are no longer available");
+
+/// Locate Handles with a particular Protocol GUID
+/// Implemented using `EFI_BOOT_SERVICES.LocateHandles()`
+///
+/// Returns an array of [Handles](r_efi::efi::Handle) that support a specified protocol.
+pub(crate) fn locate_handles(mut guid: Guid) -> io::Result<Vec<NonNull<crate::ffi::c_void>>> {
+ fn inner(
+ guid: &mut Guid,
+ boot_services: NonNull<r_efi::efi::BootServices>,
+ buf_size: &mut usize,
+ buf: *mut r_efi::efi::Handle,
+ ) -> io::Result<()> {
+ let r = unsafe {
+ ((*boot_services.as_ptr()).locate_handle)(
+ r_efi::efi::BY_PROTOCOL,
+ guid,
+ crate::ptr::null_mut(),
+ buf_size,
+ buf,
+ )
+ };
+
+ if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
+ }
+
+ let boot_services = boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
+ let mut buf_len = 0usize;
+
+ // This should always fail since the size of buffer is 0. This call should update the buf_len
+ // variable with the required buffer length
+ match inner(&mut guid, boot_services, &mut buf_len, crate::ptr::null_mut()) {
+ Ok(()) => unreachable!(),
+ Err(e) => match e.kind() {
+ io::ErrorKind::FileTooLarge => {}
+ _ => return Err(e),
+ },
+ }
+
+ // The returned buf_len is in bytes
+ assert_eq!(buf_len % size_of::<r_efi::efi::Handle>(), 0);
+ let num_of_handles = buf_len / size_of::<r_efi::efi::Handle>();
+ let mut buf: Vec<r_efi::efi::Handle> = Vec::with_capacity(num_of_handles);
+ match inner(&mut guid, boot_services, &mut buf_len, buf.as_mut_ptr()) {
+ Ok(()) => {
+ // This is safe because the call will succeed only if buf_len >= required length.
+ // Also, on success, the `buf_len` is updated with the size of bufferv (in bytes) written
+ unsafe { buf.set_len(num_of_handles) };
+ Ok(buf.into_iter().filter_map(|x| NonNull::new(x)).collect())
+ }
+ Err(e) => Err(e),
+ }
+}
+
+/// Open Protocol on a handle.
+/// Internally just a call to `EFI_BOOT_SERVICES.OpenProtocol()`.
+///
+/// Queries a handle to determine if it supports a specified protocol. If the protocol is
+/// supported by the handle, it opens the protocol on behalf of the calling agent.
+pub(crate) fn open_protocol<T>(
+ handle: NonNull<crate::ffi::c_void>,
+ mut protocol_guid: Guid,
+) -> io::Result<NonNull<T>> {
+ let boot_services: NonNull<efi::BootServices> =
+ boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
+ let system_handle = uefi::env::image_handle();
+ let mut protocol: MaybeUninit<*mut T> = MaybeUninit::uninit();
+
+ let r = unsafe {
+ ((*boot_services.as_ptr()).open_protocol)(
+ handle.as_ptr(),
+ &mut protocol_guid,
+ protocol.as_mut_ptr().cast(),
+ system_handle.as_ptr(),
+ crate::ptr::null_mut(),
+ r_efi::system::OPEN_PROTOCOL_GET_PROTOCOL,
+ )
+ };
+
+ if r.is_error() {
+ Err(crate::io::Error::from_raw_os_error(r.as_usize()))
+ } else {
+ NonNull::new(unsafe { protocol.assume_init() })
+ .ok_or(const_io_error!(io::ErrorKind::Other, "null protocol"))
+ }
+}
+
+pub(crate) fn create_event(
+ signal: u32,
+ tpl: efi::Tpl,
+ handler: Option<efi::EventNotify>,
+ context: *mut crate::ffi::c_void,
+) -> io::Result<NonNull<crate::ffi::c_void>> {
+ let boot_services: NonNull<efi::BootServices> =
+ boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
+ let mut event: r_efi::efi::Event = crate::ptr::null_mut();
+ let r = unsafe {
+ let create_event = (*boot_services.as_ptr()).create_event;
+ (create_event)(signal, tpl, handler, context, &mut event)
+ };
+ if r.is_error() {
+ Err(crate::io::Error::from_raw_os_error(r.as_usize()))
+ } else {
+ NonNull::new(event).ok_or(const_io_error!(io::ErrorKind::Other, "null protocol"))
+ }
+}
+
+/// # SAFETY
+/// - The supplied event must be valid
+pub(crate) unsafe fn close_event(evt: NonNull<crate::ffi::c_void>) -> io::Result<()> {
+ let boot_services: NonNull<efi::BootServices> =
+ boot_services().ok_or(BOOT_SERVICES_UNAVAILABLE)?.cast();
+ let r = unsafe {
+ let close_event = (*boot_services.as_ptr()).close_event;
+ (close_event)(evt.as_ptr())
+ };
+
+ if r.is_error() { Err(crate::io::Error::from_raw_os_error(r.as_usize())) } else { Ok(()) }
+}
diff --git a/library/std/src/sys/uefi/mod.rs b/library/std/src/sys/uefi/mod.rs
new file mode 100644
index 000000000..9a10395af
--- /dev/null
+++ b/library/std/src/sys/uefi/mod.rs
@@ -0,0 +1,244 @@
+//! Platform-specific extensions to `std` for UEFI platforms.
+//!
+//! Provides access to platform-level information on UEFI platforms, and
+//! exposes UEFI-specific functions that would otherwise be inappropriate as
+//! part of the core `std` library.
+//!
+//! It exposes more ways to deal with platform-specific strings ([`OsStr`],
+//! [`OsString`]), allows to set permissions more granularly, extract low-level
+//! file descriptors from files and sockets, and has platform-specific helpers
+//! for spawning processes.
+//!
+//! [`OsStr`]: crate::ffi::OsStr
+//! [`OsString`]: crate::ffi::OsString
+
+pub mod alloc;
+#[path = "../unsupported/args.rs"]
+pub mod args;
+#[path = "../unix/cmath.rs"]
+pub mod cmath;
+pub mod env;
+#[path = "../unsupported/fs.rs"]
+pub mod fs;
+#[path = "../unsupported/io.rs"]
+pub mod io;
+#[path = "../unsupported/locks/mod.rs"]
+pub mod locks;
+#[path = "../unsupported/net.rs"]
+pub mod net;
+#[path = "../unsupported/once.rs"]
+pub mod once;
+pub mod os;
+#[path = "../windows/os_str.rs"]
+pub mod os_str;
+pub mod path;
+#[path = "../unsupported/pipe.rs"]
+pub mod pipe;
+#[path = "../unsupported/process.rs"]
+pub mod process;
+#[path = "../unsupported/stdio.rs"]
+pub mod stdio;
+#[path = "../unsupported/thread.rs"]
+pub mod thread;
+#[path = "../unsupported/thread_local_key.rs"]
+pub mod thread_local_key;
+#[path = "../unsupported/thread_parking.rs"]
+pub mod thread_parking;
+#[path = "../unsupported/time.rs"]
+pub mod time;
+
+mod helpers;
+
+#[cfg(test)]
+mod tests;
+
+pub type RawOsError = usize;
+
+use crate::io as std_io;
+use crate::os::uefi;
+use crate::ptr::NonNull;
+use crate::sync::atomic::{AtomicPtr, Ordering};
+
+pub mod memchr {
+ pub use core::slice::memchr::{memchr, memrchr};
+}
+
+static EXIT_BOOT_SERVICE_EVENT: AtomicPtr<crate::ffi::c_void> =
+ AtomicPtr::new(crate::ptr::null_mut());
+
+/// # SAFETY
+/// - must be called only once during runtime initialization.
+/// - argc must be 2.
+/// - argv must be &[Handle, *mut SystemTable].
+pub(crate) unsafe fn init(argc: isize, argv: *const *const u8, _sigpipe: u8) {
+ assert_eq!(argc, 2);
+ let image_handle = unsafe { NonNull::new(*argv as *mut crate::ffi::c_void).unwrap() };
+ let system_table = unsafe { NonNull::new(*argv.add(1) as *mut crate::ffi::c_void).unwrap() };
+ unsafe { uefi::env::init_globals(image_handle, system_table) };
+
+ // Register exit boot services handler
+ match helpers::create_event(
+ r_efi::efi::EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ r_efi::efi::TPL_NOTIFY,
+ Some(exit_boot_service_handler),
+ crate::ptr::null_mut(),
+ ) {
+ Ok(x) => {
+ if EXIT_BOOT_SERVICE_EVENT
+ .compare_exchange(
+ crate::ptr::null_mut(),
+ x.as_ptr(),
+ Ordering::Release,
+ Ordering::Acquire,
+ )
+ .is_err()
+ {
+ abort_internal();
+ };
+ }
+ Err(_) => abort_internal(),
+ }
+}
+
+/// # SAFETY
+/// this is not guaranteed to run, for example when the program aborts.
+/// - must be called only once during runtime cleanup.
+pub unsafe fn cleanup() {
+ if let Some(exit_boot_service_event) =
+ NonNull::new(EXIT_BOOT_SERVICE_EVENT.swap(crate::ptr::null_mut(), Ordering::Acquire))
+ {
+ let _ = unsafe { helpers::close_event(exit_boot_service_event) };
+ }
+}
+
+#[inline]
+pub const fn unsupported<T>() -> std_io::Result<T> {
+ Err(unsupported_err())
+}
+
+#[inline]
+pub const fn unsupported_err() -> std_io::Error {
+ std_io::const_io_error!(std_io::ErrorKind::Unsupported, "operation not supported on UEFI",)
+}
+
+pub fn decode_error_kind(code: RawOsError) -> crate::io::ErrorKind {
+ use crate::io::ErrorKind;
+ use r_efi::efi::Status;
+
+ match r_efi::efi::Status::from_usize(code) {
+ Status::ALREADY_STARTED
+ | Status::COMPROMISED_DATA
+ | Status::CONNECTION_FIN
+ | Status::CRC_ERROR
+ | Status::DEVICE_ERROR
+ | Status::END_OF_MEDIA
+ | Status::HTTP_ERROR
+ | Status::ICMP_ERROR
+ | Status::INCOMPATIBLE_VERSION
+ | Status::LOAD_ERROR
+ | Status::MEDIA_CHANGED
+ | Status::NO_MAPPING
+ | Status::NO_MEDIA
+ | Status::NOT_STARTED
+ | Status::PROTOCOL_ERROR
+ | Status::PROTOCOL_UNREACHABLE
+ | Status::TFTP_ERROR
+ | Status::VOLUME_CORRUPTED => ErrorKind::Other,
+ Status::BAD_BUFFER_SIZE | Status::INVALID_LANGUAGE => ErrorKind::InvalidData,
+ Status::ABORTED => ErrorKind::ConnectionAborted,
+ Status::ACCESS_DENIED => ErrorKind::PermissionDenied,
+ Status::BUFFER_TOO_SMALL => ErrorKind::FileTooLarge,
+ Status::CONNECTION_REFUSED => ErrorKind::ConnectionRefused,
+ Status::CONNECTION_RESET => ErrorKind::ConnectionReset,
+ Status::END_OF_FILE => ErrorKind::UnexpectedEof,
+ Status::HOST_UNREACHABLE => ErrorKind::HostUnreachable,
+ Status::INVALID_PARAMETER => ErrorKind::InvalidInput,
+ Status::IP_ADDRESS_CONFLICT => ErrorKind::AddrInUse,
+ Status::NETWORK_UNREACHABLE => ErrorKind::NetworkUnreachable,
+ Status::NO_RESPONSE => ErrorKind::HostUnreachable,
+ Status::NOT_FOUND => ErrorKind::NotFound,
+ Status::NOT_READY => ErrorKind::ResourceBusy,
+ Status::OUT_OF_RESOURCES => ErrorKind::OutOfMemory,
+ Status::SECURITY_VIOLATION => ErrorKind::PermissionDenied,
+ Status::TIMEOUT => ErrorKind::TimedOut,
+ Status::UNSUPPORTED => ErrorKind::Unsupported,
+ Status::VOLUME_FULL => ErrorKind::StorageFull,
+ Status::WRITE_PROTECTED => ErrorKind::ReadOnlyFilesystem,
+ _ => ErrorKind::Uncategorized,
+ }
+}
+
+pub fn abort_internal() -> ! {
+ if let Some(exit_boot_service_event) =
+ NonNull::new(EXIT_BOOT_SERVICE_EVENT.load(Ordering::Acquire))
+ {
+ let _ = unsafe { helpers::close_event(exit_boot_service_event) };
+ }
+
+ if let (Some(boot_services), Some(handle)) =
+ (uefi::env::boot_services(), uefi::env::try_image_handle())
+ {
+ let boot_services: NonNull<r_efi::efi::BootServices> = boot_services.cast();
+ let _ = unsafe {
+ ((*boot_services.as_ptr()).exit)(
+ handle.as_ptr(),
+ r_efi::efi::Status::ABORTED,
+ 0,
+ crate::ptr::null_mut(),
+ )
+ };
+ }
+
+ // In case SystemTable and ImageHandle cannot be reached, use `core::intrinsics::abort`
+ core::intrinsics::abort();
+}
+
+// This function is needed by the panic runtime. The symbol is named in
+// pre-link args for the target specification, so keep that in sync.
+#[cfg(not(test))]
+#[no_mangle]
+pub extern "C" fn __rust_abort() {
+ abort_internal();
+}
+
+#[inline]
+pub fn hashmap_random_keys() -> (u64, u64) {
+ get_random().unwrap()
+}
+
+fn get_random() -> Option<(u64, u64)> {
+ use r_efi::protocols::rng;
+
+ let mut buf = [0u8; 16];
+ let handles = helpers::locate_handles(rng::PROTOCOL_GUID).ok()?;
+ for handle in handles {
+ if let Ok(protocol) = helpers::open_protocol::<rng::Protocol>(handle, rng::PROTOCOL_GUID) {
+ let r = unsafe {
+ ((*protocol.as_ptr()).get_rng)(
+ protocol.as_ptr(),
+ crate::ptr::null_mut(),
+ buf.len(),
+ buf.as_mut_ptr(),
+ )
+ };
+ if r.is_error() {
+ continue;
+ } else {
+ return Some((
+ u64::from_le_bytes(buf[..8].try_into().ok()?),
+ u64::from_le_bytes(buf[8..].try_into().ok()?),
+ ));
+ }
+ }
+ }
+ None
+}
+
+/// Disable access to BootServices if `EVT_SIGNAL_EXIT_BOOT_SERVICES` is signaled
+extern "efiapi" fn exit_boot_service_handler(_e: r_efi::efi::Event, _ctx: *mut crate::ffi::c_void) {
+ uefi::env::disable_boot_services();
+}
+
+pub fn is_interrupted(_code: RawOsError) -> bool {
+ false
+}
diff --git a/library/std/src/sys/uefi/os.rs b/library/std/src/sys/uefi/os.rs
new file mode 100644
index 000000000..e6693db68
--- /dev/null
+++ b/library/std/src/sys/uefi/os.rs
@@ -0,0 +1,237 @@
+use super::{unsupported, RawOsError};
+use crate::error::Error as StdError;
+use crate::ffi::{OsStr, OsString};
+use crate::fmt;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::os::uefi;
+use crate::path::{self, PathBuf};
+use crate::ptr::NonNull;
+use r_efi::efi::Status;
+
+pub fn errno() -> RawOsError {
+ 0
+}
+
+pub fn error_string(errno: RawOsError) -> String {
+ // Keep the List in Alphabetical Order
+ // The Messages are taken from UEFI Specification Appendix D - Status Codes
+ match r_efi::efi::Status::from_usize(errno) {
+ Status::ABORTED => "The operation was aborted.".to_owned(),
+ Status::ACCESS_DENIED => "Access was denied.".to_owned(),
+ Status::ALREADY_STARTED => "The protocol has already been started.".to_owned(),
+ Status::BAD_BUFFER_SIZE => "The buffer was not the proper size for the request.".to_owned(),
+ Status::BUFFER_TOO_SMALL => {
+ "The buffer is not large enough to hold the requested data. The required buffer size is returned in the appropriate parameter when this error occurs.".to_owned()
+ }
+ Status::COMPROMISED_DATA => {
+ "The security status of the data is unknown or compromised and the data must be updated or replaced to restore a valid security status.".to_owned()
+ }
+ Status::CONNECTION_FIN => {
+ "The receiving operation fails because the communication peer has closed the connection and there is no more data in the receive buffer of the instance.".to_owned()
+ }
+ Status::CONNECTION_REFUSED => {
+ "The receiving or transmission operation fails because this connection is refused.".to_owned()
+ }
+ Status::CONNECTION_RESET => {
+ "The connect fails because the connection is reset either by instance itself or the communication peer.".to_owned()
+ }
+ Status::CRC_ERROR => "A CRC error was detected.".to_owned(),
+ Status::DEVICE_ERROR => "The physical device reported an error while attempting the operation.".to_owned()
+ ,
+ Status::END_OF_FILE => {
+ "The end of the file was reached.".to_owned()
+ }
+ Status::END_OF_MEDIA => {
+ "Beginning or end of media was reached".to_owned()
+ }
+ Status::HOST_UNREACHABLE => {
+ "The remote host is not reachable.".to_owned()
+ }
+ Status::HTTP_ERROR => {
+ "A HTTP error occurred during the network operation.".to_owned()
+ }
+ Status::ICMP_ERROR => {
+ "An ICMP error occurred during the network operation.".to_owned()
+ }
+ Status::INCOMPATIBLE_VERSION => {
+ "The function encountered an internal version that was incompatible with a version requested by the caller.".to_owned()
+ }
+ Status::INVALID_LANGUAGE => {
+ "The language specified was invalid.".to_owned()
+ }
+ Status::INVALID_PARAMETER => {
+ "A parameter was incorrect.".to_owned()
+ }
+ Status::IP_ADDRESS_CONFLICT => {
+ "There is an address conflict address allocation".to_owned()
+ }
+ Status::LOAD_ERROR => {
+ "The image failed to load.".to_owned()
+ }
+ Status::MEDIA_CHANGED => {
+ "The medium in the device has changed since the last access.".to_owned()
+ }
+ Status::NETWORK_UNREACHABLE => {
+ "The network containing the remote host is not reachable.".to_owned()
+ }
+ Status::NO_MAPPING => {
+ "A mapping to a device does not exist.".to_owned()
+ }
+ Status::NO_MEDIA => {
+ "The device does not contain any medium to perform the operation.".to_owned()
+ }
+ Status::NO_RESPONSE => {
+ "The server was not found or did not respond to the request.".to_owned()
+ }
+ Status::NOT_FOUND => "The item was not found.".to_owned(),
+ Status::NOT_READY => {
+ "There is no data pending upon return.".to_owned()
+ }
+ Status::NOT_STARTED => {
+ "The protocol has not been started.".to_owned()
+ }
+ Status::OUT_OF_RESOURCES => {
+ "A resource has run out.".to_owned()
+ }
+ Status::PROTOCOL_ERROR => {
+ "A protocol error occurred during the network operation.".to_owned()
+ }
+ Status::PROTOCOL_UNREACHABLE => {
+ "An ICMP protocol unreachable error is received.".to_owned()
+ }
+ Status::SECURITY_VIOLATION => {
+ "The function was not performed due to a security violation.".to_owned()
+ }
+ Status::TFTP_ERROR => {
+ "A TFTP error occurred during the network operation.".to_owned()
+ }
+ Status::TIMEOUT => "The timeout time expired.".to_owned(),
+ Status::UNSUPPORTED => {
+ "The operation is not supported.".to_owned()
+ }
+ Status::VOLUME_FULL => {
+ "There is no more space on the file system.".to_owned()
+ }
+ Status::VOLUME_CORRUPTED => {
+ "An inconstancy was detected on the file system causing the operating to fail.".to_owned()
+ }
+ Status::WRITE_PROTECTED => {
+ "The device cannot be written to.".to_owned()
+ }
+ _ => format!("Status: {}", errno),
+ }
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub struct SplitPaths<'a>(!, PhantomData<&'a ()>);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+ panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> {
+ self.0
+ }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+where
+ I: Iterator<Item = T>,
+ T: AsRef<OsStr>,
+{
+ Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "not supported on this platform yet".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub struct Env(!);
+
+impl Env {
+ // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
+ pub fn str_debug(&self) -> impl fmt::Debug + '_ {
+ let Self(inner) = self;
+ match *inner {}
+ }
+}
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> {
+ self.0
+ }
+}
+
+impl fmt::Debug for Env {
+ fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let Self(inner) = self;
+ match *inner {}
+ }
+}
+
+pub fn env() -> Env {
+ panic!("not supported on this platform")
+}
+
+pub fn getenv(_: &OsStr) -> Option<OsString> {
+ None
+}
+
+pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
+}
+
+pub fn unsetenv(_: &OsStr) -> io::Result<()> {
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
+}
+
+pub fn temp_dir() -> PathBuf {
+ panic!("no filesystem on this platform")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ None
+}
+
+pub fn exit(code: i32) -> ! {
+ if let (Some(boot_services), Some(handle)) =
+ (uefi::env::boot_services(), uefi::env::try_image_handle())
+ {
+ let boot_services: NonNull<r_efi::efi::BootServices> = boot_services.cast();
+ let _ = unsafe {
+ ((*boot_services.as_ptr()).exit)(
+ handle.as_ptr(),
+ Status::from_usize(code as usize),
+ 0,
+ crate::ptr::null_mut(),
+ )
+ };
+ }
+ crate::intrinsics::abort()
+}
+
+pub fn getpid() -> u32 {
+ panic!("no pids on this platform")
+}
diff --git a/library/std/src/sys/uefi/path.rs b/library/std/src/sys/uefi/path.rs
new file mode 100644
index 000000000..106682eee
--- /dev/null
+++ b/library/std/src/sys/uefi/path.rs
@@ -0,0 +1,25 @@
+use super::unsupported;
+use crate::ffi::OsStr;
+use crate::io;
+use crate::path::{Path, PathBuf, Prefix};
+
+pub const MAIN_SEP_STR: &str = "\\";
+pub const MAIN_SEP: char = '\\';
+
+#[inline]
+pub fn is_sep_byte(b: u8) -> bool {
+ b == b'\\'
+}
+
+#[inline]
+pub fn is_verbatim_sep(b: u8) -> bool {
+ b == b'\\'
+}
+
+pub fn parse_prefix(_p: &OsStr) -> Option<Prefix<'_>> {
+ None
+}
+
+pub(crate) fn absolute(_path: &Path) -> io::Result<PathBuf> {
+ unsupported()
+}
diff --git a/library/std/src/sys/uefi/tests.rs b/library/std/src/sys/uefi/tests.rs
new file mode 100644
index 000000000..8806eda3a
--- /dev/null
+++ b/library/std/src/sys/uefi/tests.rs
@@ -0,0 +1,21 @@
+use super::alloc::*;
+
+#[test]
+fn align() {
+ // UEFI ABI specifies that allocation alignment minimum is always 8. So this can be
+ // statically verified.
+ assert_eq!(POOL_ALIGNMENT, 8);
+
+ // Loop over allocation-request sizes from 0-256 and alignments from 1-128, and verify
+ // that in case of overalignment there is at least space for one additional pointer to
+ // store in the allocation.
+ for i in 0..256 {
+ for j in &[1, 2, 4, 8, 16, 32, 64, 128] {
+ if *j <= 8 {
+ assert_eq!(align_size(i, *j), i);
+ } else {
+ assert!(align_size(i, *j) > i + std::mem::size_of::<*mut ()>());
+ }
+ }
+ }
+}
diff --git a/library/std/src/sys/unix/alloc.rs b/library/std/src/sys/unix/alloc.rs
index 8604b5398..af0089978 100644
--- a/library/std/src/sys/unix/alloc.rs
+++ b/library/std/src/sys/unix/alloc.rs
@@ -86,7 +86,11 @@ cfg_if::cfg_if! {
} else if #[cfg(target_os = "wasi")] {
#[inline]
unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 {
- libc::aligned_alloc(layout.align(), layout.size()) as *mut u8
+ // C11 aligned_alloc requires that the size be a multiple of the alignment.
+ // Layout already checks that the size rounded up doesn't overflow isize::MAX.
+ let align = layout.align();
+ let size = layout.size().next_multiple_of(align);
+ libc::aligned_alloc(align, size) as *mut u8
}
} else {
#[inline]
diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs
index eafd6821f..19334e2af 100644
--- a/library/std/src/sys/unix/args.rs
+++ b/library/std/src/sys/unix/args.rs
@@ -71,6 +71,7 @@ impl DoubleEndedIterator for Args {
target_os = "vxworks",
target_os = "horizon",
target_os = "nto",
+ target_os = "hurd",
))]
mod imp {
use super::Args;
diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs
index 929e9dae7..c6d8578a6 100644
--- a/library/std/src/sys/unix/env.rs
+++ b/library/std/src/sys/unix/env.rs
@@ -152,6 +152,17 @@ pub mod os {
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 = "vita")]
pub mod os {
pub const FAMILY: &str = "unix";
diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs
index 85e020ae4..6c4f40842 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -13,14 +13,16 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
target_os = "android",
target_os = "linux",
target_os = "emscripten",
- target_os = "l4re"
+ target_os = "l4re",
+ target_os = "hurd",
))]
use libc::off64_t;
#[cfg(not(any(
target_os = "linux",
target_os = "emscripten",
target_os = "l4re",
- target_os = "android"
+ target_os = "android",
+ target_os = "hurd",
)))]
use libc::off_t as off64_t;
@@ -124,9 +126,9 @@ impl FileDesc {
}
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
- #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "hurd")))]
use libc::pread as pread64;
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "hurd"))]
use libc::pread64;
unsafe {
@@ -160,6 +162,7 @@ impl FileDesc {
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "hurd",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
@@ -181,6 +184,7 @@ impl FileDesc {
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "hurd",
target_os = "illumos",
target_os = "ios",
target_os = "tvos",
@@ -281,9 +285,9 @@ impl FileDesc {
}
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
- #[cfg(not(any(target_os = "linux", target_os = "android")))]
+ #[cfg(not(any(target_os = "linux", target_os = "android", target_os = "hurd")))]
use libc::pwrite as pwrite64;
- #[cfg(any(target_os = "linux", target_os = "android"))]
+ #[cfg(any(target_os = "linux", target_os = "android", target_os = "hurd"))]
use libc::pwrite64;
unsafe {
@@ -301,6 +305,7 @@ impl FileDesc {
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "hurd",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
@@ -322,6 +327,7 @@ impl FileDesc {
target_os = "emscripten",
target_os = "freebsd",
target_os = "fuchsia",
+ target_os = "hurd",
target_os = "illumos",
target_os = "ios",
target_os = "tvos",
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index a5604c92a..764e1f257 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -39,9 +39,14 @@ use libc::{c_int, mode_t};
all(target_os = "linux", target_env = "gnu")
))]
use libc::c_char;
-#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
+#[cfg(any(
+ target_os = "linux",
+ target_os = "emscripten",
+ target_os = "android",
+ target_os = "hurd",
+))]
use libc::dirfd;
-#[cfg(any(target_os = "linux", target_os = "emscripten"))]
+#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "hurd"))]
use libc::fstatat64;
#[cfg(any(
target_os = "android",
@@ -53,7 +58,7 @@ use libc::fstatat64;
target_os = "vita",
))]
use libc::readdir as readdir64;
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "linux", target_os = "hurd"))]
use libc::readdir64;
#[cfg(any(target_os = "emscripten", target_os = "l4re"))]
use libc::readdir64_r;
@@ -68,6 +73,7 @@ use libc::readdir64_r;
target_os = "redox",
target_os = "nto",
target_os = "vita",
+ target_os = "hurd",
)))]
use libc::readdir_r as readdir64_r;
#[cfg(target_os = "android")]
@@ -79,13 +85,19 @@ use libc::{
target_os = "linux",
target_os = "emscripten",
target_os = "l4re",
- target_os = "android"
+ target_os = "android",
+ target_os = "hurd",
)))]
use libc::{
dirent as dirent64, fstat as fstat64, ftruncate as ftruncate64, lseek as lseek64,
lstat as lstat64, off_t as off64_t, open as open64, stat as stat64,
};
-#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))]
+#[cfg(any(
+ target_os = "linux",
+ target_os = "emscripten",
+ target_os = "l4re",
+ target_os = "hurd"
+))]
use libc::{dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, stat64};
pub use crate::sys_common::fs::try_exists;
@@ -277,7 +289,8 @@ unsafe impl Sync for Dir {}
target_os = "fuchsia",
target_os = "redox",
target_os = "nto",
- target_os = "vita"
+ target_os = "vita",
+ target_os = "hurd",
))]
pub struct DirEntry {
dir: Arc<InnerReadDir>,
@@ -300,6 +313,7 @@ pub struct DirEntry {
target_os = "redox",
target_os = "nto",
target_os = "vita",
+ target_os = "hurd",
))]
struct dirent64_min {
d_ino: u64,
@@ -321,6 +335,7 @@ struct dirent64_min {
target_os = "redox",
target_os = "nto",
target_os = "vita",
+ target_os = "hurd",
)))]
pub struct DirEntry {
dir: Arc<InnerReadDir>,
@@ -455,7 +470,8 @@ impl FileAttr {
target_os = "vxworks",
target_os = "espidf",
target_os = "horizon",
- target_os = "vita"
+ target_os = "vita",
+ target_os = "hurd",
)))]
pub fn modified(&self) -> io::Result<SystemTime> {
#[cfg(target_pointer_width = "32")]
@@ -473,7 +489,7 @@ impl FileAttr {
Ok(SystemTime::new(self.stat.st_mtime as i64, 0))
}
- #[cfg(target_os = "horizon")]
+ #[cfg(any(target_os = "horizon", target_os = "hurd"))]
pub fn modified(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(self.stat.st_mtim))
}
@@ -482,7 +498,8 @@ impl FileAttr {
target_os = "vxworks",
target_os = "espidf",
target_os = "horizon",
- target_os = "vita"
+ target_os = "vita",
+ target_os = "hurd",
)))]
pub fn accessed(&self) -> io::Result<SystemTime> {
#[cfg(target_pointer_width = "32")]
@@ -500,7 +517,7 @@ impl FileAttr {
Ok(SystemTime::new(self.stat.st_atime as i64, 0))
}
- #[cfg(target_os = "horizon")]
+ #[cfg(any(target_os = "horizon", target_os = "hurd"))]
pub fn accessed(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(self.stat.st_atim))
}
@@ -656,6 +673,7 @@ impl Iterator for ReadDir {
target_os = "illumos",
target_os = "nto",
target_os = "vita",
+ target_os = "hurd",
))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
if self.end_of_stream {
@@ -756,6 +774,7 @@ impl Iterator for ReadDir {
target_os = "illumos",
target_os = "nto",
target_os = "vita",
+ target_os = "hurd",
)))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
if self.end_of_stream {
@@ -792,7 +811,7 @@ impl Drop for Dir {
fn drop(&mut self) {
let r = unsafe { libc::closedir(self.0) };
assert!(
- r == 0 || crate::io::Error::last_os_error().kind() == crate::io::ErrorKind::Interrupted,
+ r == 0 || crate::io::Error::last_os_error().is_interrupted(),
"unexpected error during closedir: {:?}",
crate::io::Error::last_os_error()
);
@@ -809,7 +828,12 @@ impl DirEntry {
}
#[cfg(all(
- any(target_os = "linux", target_os = "emscripten", target_os = "android"),
+ any(
+ target_os = "linux",
+ target_os = "emscripten",
+ target_os = "android",
+ target_os = "hurd",
+ ),
not(miri)
))]
pub fn metadata(&self) -> io::Result<FileAttr> {
@@ -833,7 +857,12 @@ impl DirEntry {
}
#[cfg(any(
- not(any(target_os = "linux", target_os = "emscripten", target_os = "android")),
+ not(any(
+ target_os = "linux",
+ target_os = "emscripten",
+ target_os = "android",
+ target_os = "hurd",
+ )),
miri
))]
pub fn metadata(&self) -> io::Result<FileAttr> {
@@ -892,6 +921,7 @@ impl DirEntry {
target_os = "horizon",
target_os = "vita",
target_os = "nto",
+ target_os = "hurd",
))]
pub fn ino(&self) -> u64 {
self.entry.d_ino as u64
@@ -949,6 +979,7 @@ impl DirEntry {
target_os = "redox",
target_os = "nto",
target_os = "vita",
+ target_os = "hurd",
)))]
fn name_cstr(&self) -> &CStr {
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
@@ -962,6 +993,7 @@ impl DirEntry {
target_os = "redox",
target_os = "nto",
target_os = "vita",
+ target_os = "hurd",
))]
fn name_cstr(&self) -> &CStr {
&self.name
@@ -1131,6 +1163,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "nto",
+ target_os = "hurd",
))]
unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fdatasync(fd)
@@ -1146,6 +1179,7 @@ impl File {
target_os = "openbsd",
target_os = "watchos",
target_os = "nto",
+ target_os = "hurd",
)))]
unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fsync(fd)
@@ -1456,6 +1490,7 @@ impl fmt::Debug for File {
target_os = "linux",
target_os = "macos",
target_os = "freebsd",
+ target_os = "hurd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "vxworks"
@@ -1477,6 +1512,7 @@ impl fmt::Debug for File {
target_os = "linux",
target_os = "macos",
target_os = "freebsd",
+ target_os = "hurd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "vxworks"
diff --git a/library/std/src/sys/unix/kernel_copy.rs b/library/std/src/sys/unix/kernel_copy.rs
index 4d17a1b00..18acd5ecc 100644
--- a/library/std/src/sys/unix/kernel_copy.rs
+++ b/library/std/src/sys/unix/kernel_copy.rs
@@ -59,9 +59,9 @@ use crate::ptr;
use crate::sync::atomic::{AtomicBool, AtomicU8, Ordering};
use crate::sys::cvt;
use crate::sys::weak::syscall;
-#[cfg(not(all(target_os = "linux", target_env = "gnu")))]
+#[cfg(not(any(all(target_os = "linux", target_env = "gnu"), target_os = "hurd")))]
use libc::sendfile as sendfile64;
-#[cfg(all(target_os = "linux", target_env = "gnu"))]
+#[cfg(any(all(target_os = "linux", target_env = "gnu"), target_os = "hurd"))]
use libc::sendfile64;
use libc::{EBADF, EINVAL, ENOSYS, EOPNOTSUPP, EOVERFLOW, EPERM, EXDEV};
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 77ef086f2..3edafde71 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -204,6 +204,10 @@ pub unsafe fn init(argc: isize, argv: *const *const u8, sigpipe: u8) {
}
if let Some(handler) = handler {
rtassert!(signal(libc::SIGPIPE, handler) != libc::SIG_ERR);
+ #[cfg(target_os = "hurd")]
+ {
+ rtassert!(signal(libc::SIGLOST, handler) != libc::SIG_ERR);
+ }
}
}
}
@@ -240,6 +244,11 @@ pub use crate::sys::android::signal;
#[cfg(not(target_os = "android"))]
pub use libc::signal;
+#[inline]
+pub(crate) fn is_interrupted(errno: i32) -> bool {
+ errno == libc::EINTR
+}
+
pub fn decode_error_kind(errno: i32) -> ErrorKind {
use ErrorKind::*;
match errno as libc::c_int {
@@ -315,7 +324,7 @@ where
{
loop {
match cvt(f()) {
- Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
other => return other,
}
}
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index 7258c222a..f450d708d 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -75,6 +75,7 @@ impl Socket {
target_os = "dragonfly",
target_os = "freebsd",
target_os = "illumos",
+ target_os = "hurd",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
@@ -102,7 +103,7 @@ impl Socket {
}
}
- #[cfg(not(target_os = "vxworks"))]
+ #[cfg(not(any(target_os = "vxworks", target_os = "vita")))]
pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> {
unsafe {
let mut fds = [0, 0];
@@ -114,6 +115,7 @@ impl Socket {
target_os = "freebsd",
target_os = "illumos",
target_os = "linux",
+ target_os = "hurd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "nto",
@@ -133,7 +135,7 @@ impl Socket {
}
}
- #[cfg(target_os = "vxworks")]
+ #[cfg(any(target_os = "vxworks", target_os = "vita"))]
pub fn new_pair(_fam: c_int, _ty: c_int) -> io::Result<(Socket, Socket)> {
unimplemented!()
}
@@ -184,7 +186,7 @@ impl Socket {
match unsafe { libc::poll(&mut pollfd, 1, timeout) } {
-1 => {
let err = io::Error::last_os_error();
- if err.kind() != io::ErrorKind::Interrupted {
+ if !err.is_interrupted() {
return Err(err);
}
}
@@ -220,6 +222,7 @@ impl Socket {
target_os = "freebsd",
target_os = "illumos",
target_os = "linux",
+ target_os = "hurd",
target_os = "netbsd",
target_os = "openbsd",
))] {
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 57e1a36da..01ff375d2 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -46,7 +46,8 @@ extern "C" {
target_os = "linux",
target_os = "emscripten",
target_os = "fuchsia",
- target_os = "l4re"
+ target_os = "l4re",
+ target_os = "hurd",
),
link_name = "__errno_location"
)]
@@ -121,7 +122,10 @@ pub fn set_errno(e: i32) {
pub fn error_string(errno: i32) -> String {
extern "C" {
#[cfg_attr(
- all(any(target_os = "linux", target_env = "newlib"), not(target_env = "ohos")),
+ all(
+ any(target_os = "linux", target_os = "hurd", target_env = "newlib"),
+ not(target_env = "ohos")
+ ),
link_name = "__xpg_strerror_r"
)]
fn strerror_r(errnum: c_int, buf: *mut c_char, buflen: libc::size_t) -> c_int;
@@ -359,7 +363,12 @@ pub fn current_exe() -> io::Result<PathBuf> {
}
}
-#[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))]
+#[cfg(any(
+ target_os = "linux",
+ target_os = "hurd",
+ target_os = "android",
+ target_os = "emscripten"
+))]
pub fn current_exe() -> io::Result<PathBuf> {
match crate::fs::read_link("/proc/self/exe") {
Err(ref e) if e.kind() == io::ErrorKind::NotFound => Err(io::const_io_error!(
diff --git a/library/std/src/sys/unix/os_str.rs b/library/std/src/sys/unix/os_str.rs
index 463b0a275..7bd2f656a 100644
--- a/library/std/src/sys/unix/os_str.rs
+++ b/library/std/src/sys/unix/os_str.rs
@@ -97,12 +97,12 @@ impl AsInner<[u8]> for Buf {
impl Buf {
#[inline]
- pub fn into_os_str_bytes(self) -> Vec<u8> {
+ pub fn into_encoded_bytes(self) -> Vec<u8> {
self.inner
}
#[inline]
- pub unsafe fn from_os_str_bytes_unchecked(s: Vec<u8>) -> Self {
+ pub unsafe fn from_encoded_bytes_unchecked(s: Vec<u8>) -> Self {
Self { inner: s }
}
@@ -203,18 +203,18 @@ impl Buf {
impl Slice {
#[inline]
- pub fn as_os_str_bytes(&self) -> &[u8] {
+ pub fn as_encoded_bytes(&self) -> &[u8] {
&self.inner
}
#[inline]
- pub unsafe fn from_os_str_bytes_unchecked(s: &[u8]) -> &Slice {
+ pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &Slice {
unsafe { mem::transmute(s) }
}
#[inline]
pub fn from_str(s: &str) -> &Slice {
- unsafe { Slice::from_os_str_bytes_unchecked(s.as_bytes()) }
+ unsafe { Slice::from_encoded_bytes_unchecked(s.as_bytes()) }
}
pub fn to_str(&self) -> Result<&str, crate::str::Utf8Error> {
diff --git a/library/std/src/sys/unix/os_str/tests.rs b/library/std/src/sys/unix/os_str/tests.rs
index 91bc0e61a..e2a99045e 100644
--- a/library/std/src/sys/unix/os_str/tests.rs
+++ b/library/std/src/sys/unix/os_str/tests.rs
@@ -2,7 +2,7 @@ use super::*;
#[test]
fn slice_debug_output() {
- let input = unsafe { Slice::from_os_str_bytes_unchecked(b"\xF0hello,\tworld") };
+ let input = unsafe { Slice::from_encoded_bytes_unchecked(b"\xF0hello,\tworld") };
let expected = r#""\xF0hello,\tworld""#;
let output = format!("{input:?}");
@@ -12,6 +12,6 @@ fn slice_debug_output() {
#[test]
fn display() {
assert_eq!("Hello\u{FFFD}\u{FFFD} There\u{FFFD} Goodbye", unsafe {
- Slice::from_os_str_bytes_unchecked(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string()
+ Slice::from_encoded_bytes_unchecked(b"Hello\xC0\x80 There\xE6\x83 Goodbye").to_string()
},);
}
diff --git a/library/std/src/sys/unix/path.rs b/library/std/src/sys/unix/path.rs
index 935245f63..837f68d3e 100644
--- a/library/std/src/sys/unix/path.rs
+++ b/library/std/src/sys/unix/path.rs
@@ -30,7 +30,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
// 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_os_str_bytes();
+ 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
diff --git a/library/std/src/sys/unix/pipe.rs b/library/std/src/sys/unix/pipe.rs
index 938a46bfd..33db24e77 100644
--- a/library/std/src/sys/unix/pipe.rs
+++ b/library/std/src/sys/unix/pipe.rs
@@ -3,7 +3,7 @@ use crate::mem;
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::sys::fd::FileDesc;
use crate::sys::{cvt, cvt_r};
-use crate::sys_common::IntoInner;
+use crate::sys_common::{FromInner, IntoInner};
////////////////////////////////////////////////////////////////////////////////
// Anonymous pipes
@@ -21,6 +21,7 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
if #[cfg(any(
target_os = "dragonfly",
target_os = "freebsd",
+ target_os = "hurd",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
@@ -158,3 +159,9 @@ impl FromRawFd for AnonPipe {
Self(FromRawFd::from_raw_fd(raw_fd))
}
}
+
+impl FromInner<FileDesc> for AnonPipe {
+ fn from_inner(fd: FileDesc) -> Self {
+ Self(fd)
+ }
+}
diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs
index 640648e87..1ca11a7f9 100644
--- a/library/std/src/sys/unix/process/process_common.rs
+++ b/library/std/src/sys/unix/process/process_common.rs
@@ -13,7 +13,7 @@ use crate::sys::fd::FileDesc;
use crate::sys::fs::File;
use crate::sys::pipe::{self, AnonPipe};
use crate::sys_common::process::{CommandEnv, CommandEnvs};
-use crate::sys_common::IntoInner;
+use crate::sys_common::{FromInner, IntoInner};
#[cfg(not(target_os = "fuchsia"))]
use crate::sys::fs::OpenOptions;
@@ -150,6 +150,7 @@ pub enum Stdio {
Null,
MakePipe,
Fd(FileDesc),
+ StaticFd(BorrowedFd<'static>),
}
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -164,9 +165,9 @@ pub enum ProgramKind {
impl ProgramKind {
fn new(program: &OsStr) -> Self {
- if program.as_os_str_bytes().starts_with(b"/") {
+ if program.as_encoded_bytes().starts_with(b"/") {
Self::Absolute
- } else if program.as_os_str_bytes().contains(&b'/') {
+ } else if program.as_encoded_bytes().contains(&b'/') {
// If the program has more than one component in it, it is a relative path.
Self::Relative
} else {
@@ -463,6 +464,11 @@ impl Stdio {
}
}
+ Stdio::StaticFd(fd) => {
+ let fd = FileDesc::from_inner(fd.try_clone_to_owned()?);
+ Ok((ChildStdio::Owned(fd), None))
+ }
+
Stdio::MakePipe => {
let (reader, writer) = pipe::anon_pipe()?;
let (ours, theirs) = if readable { (writer, reader) } else { (reader, writer) };
@@ -497,6 +503,28 @@ impl From<File> for Stdio {
}
}
+impl From<io::Stdout> for Stdio {
+ fn from(_: io::Stdout) -> Stdio {
+ // This ought really to be is Stdio::StaticFd(input_argument.as_fd()).
+ // But AsFd::as_fd takes its argument by reference, and yields
+ // a bounded lifetime, so it's no use here. There is no AsStaticFd.
+ //
+ // Additionally AsFd is only implemented for the *locked* versions.
+ // We don't want to lock them here. (The implications of not locking
+ // are the same as those for process::Stdio::inherit().)
+ //
+ // Arguably the hypothetical AsStaticFd and AsFd<'static>
+ // should be implemented for io::Stdout, not just for StdoutLocked.
+ Stdio::StaticFd(unsafe { BorrowedFd::borrow_raw(libc::STDOUT_FILENO) })
+ }
+}
+
+impl From<io::Stderr> for Stdio {
+ fn from(_: io::Stderr) -> Stdio {
+ Stdio::StaticFd(unsafe { BorrowedFd::borrow_raw(libc::STDERR_FILENO) })
+ }
+}
+
impl ChildStdio {
pub fn fd(&self) -> Option<c_int> {
match *self {
@@ -558,6 +586,23 @@ impl fmt::Debug for Command {
if let Some(ref cwd) = self.cwd {
write!(f, "cd {cwd:?} && ")?;
}
+ if self.env.does_clear() {
+ write!(f, "env -i ")?;
+ // Altered env vars will be printed next, that should exactly work as expected.
+ } else {
+ // Removed env vars need the command to be wrapped in `env`.
+ let mut any_removed = false;
+ for (key, value_opt) in self.get_envs() {
+ if value_opt.is_none() {
+ if !any_removed {
+ write!(f, "env ")?;
+ any_removed = true;
+ }
+ write!(f, "-u {} ", key.to_string_lossy())?;
+ }
+ }
+ }
+ // Altered env vars can just be added in front of the program.
for (key, value_opt) in self.get_envs() {
if let Some(value) = value_opt {
write!(f, "{}={value:?} ", key.to_string_lossy())?;
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 3963e7f52..564f8c482 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -165,7 +165,7 @@ impl Command {
assert!(p.wait().is_ok(), "wait() should either return Ok or panic");
return Err(Error::from_raw_os_error(errno));
}
- Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => {
assert!(p.wait().is_ok(), "wait() should either return Ok or panic");
panic!("the CLOEXEC pipe failed: {e:?}")
@@ -374,6 +374,13 @@ impl Command {
return Err(io::Error::last_os_error());
}
}
+ #[cfg(target_os = "hurd")]
+ {
+ let ret = sys::signal(libc::SIGLOST, libc::SIG_DFL);
+ if ret == libc::SIG_ERR {
+ return Err(io::Error::last_os_error());
+ }
+ }
}
}
@@ -620,6 +627,10 @@ impl Command {
let mut default_set = MaybeUninit::<libc::sigset_t>::uninit();
cvt(sigemptyset(default_set.as_mut_ptr()))?;
cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGPIPE))?;
+ #[cfg(target_os = "hurd")]
+ {
+ cvt(sigaddset(default_set.as_mut_ptr(), libc::SIGLOST))?;
+ }
cvt_nz(libc::posix_spawnattr_setsigdefault(
attrs.0.as_mut_ptr(),
default_set.as_ptr(),
@@ -993,6 +1004,8 @@ fn signal_string(signal: i32) -> &'static str {
target_os = "dragonfly"
))]
libc::SIGINFO => " (SIGINFO)",
+ #[cfg(target_os = "hurd")]
+ libc::SIGLOST => " (SIGLOST)",
_ => "",
}
}
diff --git a/library/std/src/sys/unix/stack_overflow.rs b/library/std/src/sys/unix/stack_overflow.rs
index b59d4ba26..73c530786 100644
--- a/library/std/src/sys/unix/stack_overflow.rs
+++ b/library/std/src/sys/unix/stack_overflow.rs
@@ -32,6 +32,7 @@ impl Drop for Handler {
target_os = "macos",
target_os = "dragonfly",
target_os = "freebsd",
+ target_os = "hurd",
target_os = "solaris",
target_os = "illumos",
target_os = "netbsd",
@@ -193,6 +194,7 @@ mod imp {
target_os = "macos",
target_os = "dragonfly",
target_os = "freebsd",
+ target_os = "hurd",
target_os = "solaris",
target_os = "illumos",
target_os = "netbsd",
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 4f2d9cf36..311ed9502 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -182,6 +182,9 @@ impl Thread {
}
if let Some(f) = pthread_setname_np.get() {
+ #[cfg(target_os = "nto")]
+ let name = truncate_cstr::<{ libc::_NTO_THREAD_NAME_MAX as usize }>(name);
+
let res = unsafe { f(libc::pthread_self(), name.as_ptr()) };
debug_assert_eq!(res, 0);
}
@@ -213,7 +216,8 @@ impl Thread {
target_os = "l4re",
target_os = "emscripten",
target_os = "redox",
- target_os = "vxworks"
+ target_os = "vxworks",
+ target_os = "hurd",
))]
pub fn set_name(_name: &CStr) {
// Newlib, Emscripten, and VxWorks have no way to set a thread name.
@@ -290,6 +294,7 @@ impl Drop for Thread {
target_os = "ios",
target_os = "tvos",
target_os = "watchos",
+ target_os = "nto",
))]
fn truncate_cstr<const MAX_WITH_NUL: usize>(cstr: &CStr) -> [libc::c_char; MAX_WITH_NUL] {
let mut result = [0; MAX_WITH_NUL];
@@ -305,6 +310,7 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
target_os = "android",
target_os = "emscripten",
target_os = "fuchsia",
+ target_os = "hurd",
target_os = "ios",
target_os = "tvos",
target_os = "linux",
@@ -312,23 +318,38 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
target_os = "solaris",
target_os = "illumos",
))] {
+ #[allow(unused_assignments)]
+ #[allow(unused_mut)]
+ let mut quota = usize::MAX;
+
#[cfg(any(target_os = "android", target_os = "linux"))]
{
- let quota = cgroups::quota().max(1);
+ quota = cgroups::quota().max(1);
let mut set: libc::cpu_set_t = unsafe { mem::zeroed() };
unsafe {
if libc::sched_getaffinity(0, mem::size_of::<libc::cpu_set_t>(), &mut set) == 0 {
let count = libc::CPU_COUNT(&set) as usize;
let count = count.min(quota);
- // SAFETY: affinity mask can't be empty and the quota gets clamped to a minimum of 1
- return Ok(NonZeroUsize::new_unchecked(count));
+
+ // According to sched_getaffinity's API it should always be non-zero, but
+ // some old MIPS kernels were buggy and zero-initialized the mask if
+ // none was explicitly set.
+ // In that case we use the sysconf fallback.
+ if let Some(count) = NonZeroUsize::new(count) {
+ return Ok(count)
+ }
}
}
}
match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
-1 => Err(io::Error::last_os_error()),
0 => Err(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
- cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }),
+ cpus => {
+ let count = cpus as usize;
+ // Cover the unusual situation where we were able to get the quota but not the affinity mask
+ let count = count.min(quota);
+ Ok(unsafe { NonZeroUsize::new_unchecked(count) })
+ }
}
} else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
use crate::ptr;
@@ -686,6 +707,7 @@ mod cgroups {
#[cfg(all(
not(target_os = "linux"),
not(target_os = "freebsd"),
+ not(target_os = "hurd"),
not(target_os = "macos"),
not(target_os = "netbsd"),
not(target_os = "openbsd"),
@@ -706,6 +728,7 @@ pub mod guard {
#[cfg(any(
target_os = "linux",
target_os = "freebsd",
+ target_os = "hurd",
target_os = "macos",
target_os = "netbsd",
target_os = "openbsd",
@@ -762,6 +785,7 @@ pub mod guard {
#[cfg(any(
target_os = "android",
target_os = "freebsd",
+ target_os = "hurd",
target_os = "linux",
target_os = "netbsd",
target_os = "l4re"
@@ -899,6 +923,7 @@ pub mod guard {
#[cfg(any(
target_os = "android",
target_os = "freebsd",
+ target_os = "hurd",
target_os = "linux",
target_os = "netbsd",
target_os = "l4re"
@@ -930,7 +955,7 @@ pub mod guard {
assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackptr, &mut size), 0);
let stackaddr = stackptr.addr();
- ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd")) {
+ ret = if cfg!(any(target_os = "freebsd", target_os = "netbsd", target_os = "hurd")) {
Some(stackaddr - guardsize..stackaddr)
} else if cfg!(all(target_os = "linux", target_env = "musl")) {
Some(stackaddr - guardsize..stackaddr)
diff --git a/library/std/src/sys/unix/thread_local_dtor.rs b/library/std/src/sys/unix/thread_local_dtor.rs
index 236d2f2ee..fba2a676f 100644
--- a/library/std/src/sys/unix/thread_local_dtor.rs
+++ b/library/std/src/sys/unix/thread_local_dtor.rs
@@ -11,7 +11,7 @@
// Note, however, that we run on lots older linuxes, as well as cross
// compiling from a newer linux to an older linux, so we also have a
// fallback implementation to use as well.
-#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))]
+#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox", target_os = "hurd"))]
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
use crate::mem;
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
@@ -48,7 +48,7 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
// workaround below is to register, via _tlv_atexit, a custom DTOR list once per
// thread. thread_local dtors are pushed to the DTOR list without calling
// _tlv_atexit.
-#[cfg(target_os = "macos")]
+#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
use crate::cell::Cell;
use crate::mem;
diff --git a/library/std/src/sys/unix/thread_parking/darwin.rs b/library/std/src/sys/unix/thread_parking/darwin.rs
index b709fada3..8231f3cba 100644
--- a/library/std/src/sys/unix/thread_parking/darwin.rs
+++ b/library/std/src/sys/unix/thread_parking/darwin.rs
@@ -2,8 +2,7 @@
//!
//! Darwin actually has futex syscalls (`__ulock_wait`/`__ulock_wake`), but they
//! cannot be used in `std` because they are non-public (their use will lead to
-//! rejection from the App Store) and because they are only available starting
-//! with macOS version 10.12, even though the minimum target version is 10.7.
+//! rejection from the App Store).
//!
//! Therefore, we need to look for other synchronization primitives. Luckily, Darwin
//! supports semaphores, which allow us to implement the behaviour we need with
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index 17b4130c2..4fe61b284 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -35,7 +35,7 @@ pub(in crate::sys::unix) struct Timespec {
}
impl SystemTime {
- #[cfg_attr(target_os = "horizon", allow(unused))]
+ #[cfg_attr(any(target_os = "horizon", target_os = "hurd"), allow(unused))]
pub fn new(tv_sec: i64, tv_nsec: i64) -> SystemTime {
SystemTime { t: Timespec::new(tv_sec, tv_nsec) }
}
diff --git a/library/std/src/sys/unsupported/common.rs b/library/std/src/sys/unsupported/common.rs
index 5cd9e57de..5c379992b 100644
--- a/library/std/src/sys/unsupported/common.rs
+++ b/library/std/src/sys/unsupported/common.rs
@@ -23,6 +23,10 @@ pub fn unsupported_err() -> std_io::Error {
)
}
+pub fn is_interrupted(_code: i32) -> bool {
+ false
+}
+
pub fn decode_error_kind(_code: i32) -> crate::io::ErrorKind {
crate::io::ErrorKind::Uncategorized
}
diff --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs
index 77b675aaa..a639afcc6 100644
--- a/library/std/src/sys/unsupported/process.rs
+++ b/library/std/src/sys/unsupported/process.rs
@@ -27,6 +27,8 @@ pub struct StdioPipes {
pub stderr: Option<AnonPipe>,
}
+// FIXME: This should be a unit struct, so we can always construct it
+// The value here should be never used, since we cannot spawn processes.
pub enum Stdio {
Inherit,
Null,
@@ -87,8 +89,26 @@ impl From<AnonPipe> for Stdio {
}
}
+impl From<io::Stdout> for Stdio {
+ fn from(_: io::Stdout) -> Stdio {
+ // FIXME: This is wrong.
+ // Instead, the Stdio we have here should be a unit struct.
+ panic!("unsupported")
+ }
+}
+
+impl From<io::Stderr> for Stdio {
+ fn from(_: io::Stderr) -> Stdio {
+ // FIXME: This is wrong.
+ // Instead, the Stdio we have here should be a unit struct.
+ panic!("unsupported")
+ }
+}
+
impl From<File> for Stdio {
fn from(_file: File) -> Stdio {
+ // FIXME: This is wrong.
+ // Instead, the Stdio we have here should be a unit struct.
panic!("unsupported")
}
}
diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs
index 98517da1d..5cbb5cb65 100644
--- a/library/std/src/sys/wasi/mod.rs
+++ b/library/std/src/sys/wasi/mod.rs
@@ -76,6 +76,11 @@ cfg_if::cfg_if! {
mod common;
pub use common::*;
+#[inline]
+pub fn is_interrupted(errno: i32) -> bool {
+ errno == wasi::ERRNO_INTR.raw().into()
+}
+
pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind {
use std_io::ErrorKind::*;
if errno > u16::MAX as i32 || errno < 0 {
diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs
index 6b597f499..ee7dba6e5 100644
--- a/library/std/src/sys/windows/args.rs
+++ b/library/std/src/sys/windows/args.rs
@@ -226,7 +226,7 @@ pub(crate) fn append_arg(cmd: &mut Vec<u16>, arg: &Arg, force_quotes: bool) -> i
// that it actually gets passed through on the command line or otherwise
// it will be dropped entirely when parsed on the other end.
ensure_no_nuls(arg)?;
- let arg_bytes = arg.as_os_str_bytes();
+ let arg_bytes = arg.as_encoded_bytes();
let (quote, escape) = match quote {
Quote::Always => (true, true),
Quote::Auto => {
@@ -298,7 +298,7 @@ pub(crate) fn make_bat_command_line(
const SPECIAL: &[u8] = b"\t &()[]{}^=;!'+,`~%|<>";
let force_quotes = match arg {
Arg::Regular(arg) if !force_quotes => {
- arg.as_os_str_bytes().iter().any(|c| SPECIAL.contains(c))
+ arg.as_encoded_bytes().iter().any(|c| SPECIAL.contains(c))
}
_ => force_quotes,
};
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index d9ccba0e9..f3637cbb9 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -46,10 +46,6 @@ pub use FD_SET as fd_set;
pub use LINGER as linger;
pub use TIMEVAL as timeval;
-pub type CONDITION_VARIABLE = RTL_CONDITION_VARIABLE;
-pub type SRWLOCK = RTL_SRWLOCK;
-pub type INIT_ONCE = RTL_RUN_ONCE;
-
pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { Ptr: ptr::null_mut() };
pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { Ptr: ptr::null_mut() };
pub const INIT_ONCE_STATIC_INIT: INIT_ONCE = INIT_ONCE { Ptr: ptr::null_mut() };
@@ -224,7 +220,7 @@ pub unsafe extern "system" fn ReadFileEx(
) -> BOOL {
windows_sys::ReadFileEx(
hFile.as_raw_handle(),
- lpBuffer,
+ lpBuffer.cast::<u8>(),
nNumberOfBytesToRead,
lpOverlapped,
lpCompletionRoutine,
diff --git a/library/std/src/sys/windows/c/windows_sys.lst b/library/std/src/sys/windows/c/windows_sys.lst
index 631aedd26..0aca37e2d 100644
--- a/library/std/src/sys/windows/c/windows_sys.lst
+++ b/library/std/src/sys/windows/c/windows_sys.lst
@@ -1,3 +1,6 @@
+--out windows_sys.rs
+--config flatten std
+--filter
// tidy-alphabetical-start
Windows.Wdk.Storage.FileSystem.FILE_COMPLETE_IF_OPLOCKED
Windows.Wdk.Storage.FileSystem.FILE_CONTAINS_EXTENDED_CREATE_INFORMATION
@@ -2108,7 +2111,6 @@ Windows.Win32.Networking.WinSock.WSABASEERR
Windows.Win32.Networking.WinSock.WSABUF
Windows.Win32.Networking.WinSock.WSACleanup
Windows.Win32.Networking.WinSock.WSADATA
-Windows.Win32.Networking.WinSock.WSADATA
Windows.Win32.Networking.WinSock.WSADuplicateSocketW
Windows.Win32.Networking.WinSock.WSAEACCES
Windows.Win32.Networking.WinSock.WSAEADDRINUSE
@@ -2328,7 +2330,6 @@ Windows.Win32.Storage.FileSystem.FileStandardInfo
Windows.Win32.Storage.FileSystem.FileStorageInfo
Windows.Win32.Storage.FileSystem.FileStreamInfo
Windows.Win32.Storage.FileSystem.FindClose
-Windows.Win32.Storage.FileSystem.FindFileHandle
Windows.Win32.Storage.FileSystem.FindFirstFileW
Windows.Win32.Storage.FileSystem.FindNextFileW
Windows.Win32.Storage.FileSystem.FlushFileBuffers
@@ -2420,8 +2421,6 @@ Windows.Win32.System.Console.STD_OUTPUT_HANDLE
Windows.Win32.System.Console.WriteConsoleW
Windows.Win32.System.Diagnostics.Debug.ARM64_NT_NEON128
Windows.Win32.System.Diagnostics.Debug.CONTEXT
-Windows.Win32.System.Diagnostics.Debug.CONTEXT
-Windows.Win32.System.Diagnostics.Debug.CONTEXT
Windows.Win32.System.Diagnostics.Debug.EXCEPTION_RECORD
Windows.Win32.System.Diagnostics.Debug.FACILITY_CODE
Windows.Win32.System.Diagnostics.Debug.FACILITY_NT_BIT
@@ -2435,7 +2434,6 @@ Windows.Win32.System.Diagnostics.Debug.FORMAT_MESSAGE_OPTIONS
Windows.Win32.System.Diagnostics.Debug.FormatMessageW
Windows.Win32.System.Diagnostics.Debug.M128A
Windows.Win32.System.Diagnostics.Debug.XSAVE_FORMAT
-Windows.Win32.System.Diagnostics.Debug.XSAVE_FORMAT
Windows.Win32.System.Environment.FreeEnvironmentStringsW
Windows.Win32.System.Environment.GetCommandLineW
Windows.Win32.System.Environment.GetCurrentDirectoryW
@@ -2456,7 +2454,6 @@ Windows.Win32.System.Kernel.ExceptionContinueExecution
Windows.Win32.System.Kernel.ExceptionContinueSearch
Windows.Win32.System.Kernel.ExceptionNestedException
Windows.Win32.System.Kernel.FLOATING_SAVE_AREA
-Windows.Win32.System.Kernel.FLOATING_SAVE_AREA
Windows.Win32.System.Kernel.OBJ_DONT_REPARSE
Windows.Win32.System.LibraryLoader.GetModuleFileNameW
Windows.Win32.System.LibraryLoader.GetModuleHandleA
@@ -2482,6 +2479,7 @@ Windows.Win32.System.SystemInformation.GetSystemTimeAsFileTime
Windows.Win32.System.SystemInformation.GetWindowsDirectoryW
Windows.Win32.System.SystemInformation.PROCESSOR_ARCHITECTURE
Windows.Win32.System.SystemInformation.SYSTEM_INFO
+Windows.Win32.System.SystemServices.ALL_PROCESSOR_GROUPS
Windows.Win32.System.SystemServices.DLL_PROCESS_DETACH
Windows.Win32.System.SystemServices.DLL_THREAD_DETACH
Windows.Win32.System.SystemServices.EXCEPTION_MAXIMUM_PARAMETERS
@@ -2510,9 +2508,11 @@ Windows.Win32.System.Threading.CreateProcessW
Windows.Win32.System.Threading.CreateThread
Windows.Win32.System.Threading.DEBUG_ONLY_THIS_PROCESS
Windows.Win32.System.Threading.DEBUG_PROCESS
+Windows.Win32.System.Threading.DeleteProcThreadAttributeList
Windows.Win32.System.Threading.DETACHED_PROCESS
Windows.Win32.System.Threading.ExitProcess
Windows.Win32.System.Threading.EXTENDED_STARTUPINFO_PRESENT
+Windows.Win32.System.Threading.GetActiveProcessorCount
Windows.Win32.System.Threading.GetCurrentProcess
Windows.Win32.System.Threading.GetCurrentProcessId
Windows.Win32.System.Threading.GetCurrentThread
@@ -2524,8 +2524,10 @@ Windows.Win32.System.Threading.INFINITE
Windows.Win32.System.Threading.INHERIT_CALLER_PRIORITY
Windows.Win32.System.Threading.INHERIT_PARENT_AFFINITY
Windows.Win32.System.Threading.INIT_ONCE_INIT_FAILED
+Windows.Win32.System.Threading.InitializeProcThreadAttributeList
Windows.Win32.System.Threading.InitOnceBeginInitialize
Windows.Win32.System.Threading.InitOnceComplete
+Windows.Win32.System.Threading.LPPROC_THREAD_ATTRIBUTE_LIST
Windows.Win32.System.Threading.LPTHREAD_START_ROUTINE
Windows.Win32.System.Threading.NORMAL_PRIORITY_CLASS
Windows.Win32.System.Threading.OpenProcessToken
@@ -2539,9 +2541,6 @@ Windows.Win32.System.Threading.PROFILE_USER
Windows.Win32.System.Threading.REALTIME_PRIORITY_CLASS
Windows.Win32.System.Threading.ReleaseSRWLockExclusive
Windows.Win32.System.Threading.ReleaseSRWLockShared
-Windows.Win32.System.Threading.RTL_CONDITION_VARIABLE
-Windows.Win32.System.Threading.RTL_RUN_ONCE
-Windows.Win32.System.Threading.RTL_SRWLOCK
Windows.Win32.System.Threading.SetThreadStackGuarantee
Windows.Win32.System.Threading.Sleep
Windows.Win32.System.Threading.SleepConditionVariableSRW
@@ -2561,6 +2560,7 @@ Windows.Win32.System.Threading.STARTF_USEPOSITION
Windows.Win32.System.Threading.STARTF_USESHOWWINDOW
Windows.Win32.System.Threading.STARTF_USESIZE
Windows.Win32.System.Threading.STARTF_USESTDHANDLES
+Windows.Win32.System.Threading.STARTUPINFOEXW
Windows.Win32.System.Threading.STARTUPINFOW
Windows.Win32.System.Threading.STARTUPINFOW_FLAGS
Windows.Win32.System.Threading.SwitchToThread
@@ -2575,12 +2575,11 @@ Windows.Win32.System.Threading.TlsGetValue
Windows.Win32.System.Threading.TlsSetValue
Windows.Win32.System.Threading.TryAcquireSRWLockExclusive
Windows.Win32.System.Threading.TryAcquireSRWLockShared
+Windows.Win32.System.Threading.UpdateProcThreadAttribute
Windows.Win32.System.Threading.WaitForMultipleObjects
Windows.Win32.System.Threading.WaitForSingleObject
Windows.Win32.System.Threading.WakeAllConditionVariable
Windows.Win32.System.Threading.WakeConditionVariable
-Windows.Win32.System.WindowsProgramming.IO_STATUS_BLOCK
-Windows.Win32.System.WindowsProgramming.OBJECT_ATTRIBUTES
Windows.Win32.System.WindowsProgramming.PROGRESS_CONTINUE
Windows.Win32.UI.Shell.GetUserProfileDirectoryW
// tidy-alphabetical-end
diff --git a/library/std/src/sys/windows/c/windows_sys.rs b/library/std/src/sys/windows/c/windows_sys.rs
index 023770871..851d15915 100644
--- a/library/std/src/sys/windows/c/windows_sys.rs
+++ b/library/std/src/sys/windows/c/windows_sys.rs
@@ -4,7 +4,7 @@
// regenerate the bindings.
//
// ignore-tidy-filelength
-// Bindings generated by `windows-bindgen` 0.49.0
+// Bindings generated by `windows-bindgen` 0.51.1
#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]
#[link(name = "advapi32")]
@@ -32,11 +32,11 @@ extern "system" {
}
#[link(name = "kernel32")]
extern "system" {
- pub fn AcquireSRWLockExclusive(srwlock: *mut RTL_SRWLOCK) -> ();
+ pub fn AcquireSRWLockExclusive(srwlock: *mut SRWLOCK) -> ();
}
#[link(name = "kernel32")]
extern "system" {
- pub fn AcquireSRWLockShared(srwlock: *mut RTL_SRWLOCK) -> ();
+ pub fn AcquireSRWLockShared(srwlock: *mut SRWLOCK) -> ();
}
#[link(name = "kernel32")]
extern "system" {
@@ -156,6 +156,10 @@ extern "system" {
}
#[link(name = "kernel32")]
extern "system" {
+ pub fn DeleteProcThreadAttributeList(lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST) -> ();
+}
+#[link(name = "kernel32")]
+extern "system" {
pub fn DeviceIoControl(
hdevice: HANDLE,
dwiocontrolcode: u32,
@@ -185,18 +189,15 @@ extern "system" {
}
#[link(name = "kernel32")]
extern "system" {
- pub fn FindClose(hfindfile: FindFileHandle) -> BOOL;
+ pub fn FindClose(hfindfile: HANDLE) -> BOOL;
}
#[link(name = "kernel32")]
extern "system" {
- pub fn FindFirstFileW(
- lpfilename: PCWSTR,
- lpfindfiledata: *mut WIN32_FIND_DATAW,
- ) -> FindFileHandle;
+ pub fn FindFirstFileW(lpfilename: PCWSTR, lpfindfiledata: *mut WIN32_FIND_DATAW) -> HANDLE;
}
#[link(name = "kernel32")]
extern "system" {
- pub fn FindNextFileW(hfindfile: FindFileHandle, lpfindfiledata: *mut WIN32_FIND_DATAW) -> BOOL;
+ pub fn FindNextFileW(hfindfile: HANDLE, lpfindfiledata: *mut WIN32_FIND_DATAW) -> BOOL;
}
#[link(name = "kernel32")]
extern "system" {
@@ -220,6 +221,10 @@ extern "system" {
}
#[link(name = "kernel32")]
extern "system" {
+ pub fn GetActiveProcessorCount(groupnumber: u16) -> u32;
+}
+#[link(name = "kernel32")]
+extern "system" {
pub fn GetCommandLineW() -> PCWSTR;
}
#[link(name = "kernel32")]
@@ -356,7 +361,7 @@ extern "system" {
#[link(name = "kernel32")]
extern "system" {
pub fn InitOnceBeginInitialize(
- lpinitonce: *mut RTL_RUN_ONCE,
+ lpinitonce: *mut INIT_ONCE,
dwflags: u32,
fpending: *mut BOOL,
lpcontext: *mut *mut ::core::ffi::c_void,
@@ -365,13 +370,22 @@ extern "system" {
#[link(name = "kernel32")]
extern "system" {
pub fn InitOnceComplete(
- lpinitonce: *mut RTL_RUN_ONCE,
+ lpinitonce: *mut INIT_ONCE,
dwflags: u32,
lpcontext: *const ::core::ffi::c_void,
) -> BOOL;
}
#[link(name = "kernel32")]
extern "system" {
+ pub fn InitializeProcThreadAttributeList(
+ lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST,
+ dwattributecount: u32,
+ dwflags: u32,
+ lpsize: *mut usize,
+ ) -> BOOL;
+}
+#[link(name = "kernel32")]
+extern "system" {
pub fn MoveFileExW(
lpexistingfilename: PCWSTR,
lpnewfilename: PCWSTR,
@@ -411,7 +425,7 @@ extern "system" {
extern "system" {
pub fn ReadFile(
hfile: HANDLE,
- lpbuffer: *mut ::core::ffi::c_void,
+ lpbuffer: *mut u8,
nnumberofbytestoread: u32,
lpnumberofbytesread: *mut u32,
lpoverlapped: *mut OVERLAPPED,
@@ -421,7 +435,7 @@ extern "system" {
extern "system" {
pub fn ReadFileEx(
hfile: HANDLE,
- lpbuffer: *mut ::core::ffi::c_void,
+ lpbuffer: *mut u8,
nnumberofbytestoread: u32,
lpoverlapped: *mut OVERLAPPED,
lpcompletionroutine: LPOVERLAPPED_COMPLETION_ROUTINE,
@@ -429,11 +443,11 @@ extern "system" {
}
#[link(name = "kernel32")]
extern "system" {
- pub fn ReleaseSRWLockExclusive(srwlock: *mut RTL_SRWLOCK) -> ();
+ pub fn ReleaseSRWLockExclusive(srwlock: *mut SRWLOCK) -> ();
}
#[link(name = "kernel32")]
extern "system" {
- pub fn ReleaseSRWLockShared(srwlock: *mut RTL_SRWLOCK) -> ();
+ pub fn ReleaseSRWLockShared(srwlock: *mut SRWLOCK) -> ();
}
#[link(name = "kernel32")]
extern "system" {
@@ -500,8 +514,8 @@ extern "system" {
#[link(name = "kernel32")]
extern "system" {
pub fn SleepConditionVariableSRW(
- conditionvariable: *mut RTL_CONDITION_VARIABLE,
- srwlock: *mut RTL_SRWLOCK,
+ conditionvariable: *mut CONDITION_VARIABLE,
+ srwlock: *mut SRWLOCK,
dwmilliseconds: u32,
flags: u32,
) -> BOOL;
@@ -536,11 +550,23 @@ extern "system" {
}
#[link(name = "kernel32")]
extern "system" {
- pub fn TryAcquireSRWLockExclusive(srwlock: *mut RTL_SRWLOCK) -> BOOLEAN;
+ pub fn TryAcquireSRWLockExclusive(srwlock: *mut SRWLOCK) -> BOOLEAN;
+}
+#[link(name = "kernel32")]
+extern "system" {
+ pub fn TryAcquireSRWLockShared(srwlock: *mut SRWLOCK) -> BOOLEAN;
}
#[link(name = "kernel32")]
extern "system" {
- pub fn TryAcquireSRWLockShared(srwlock: *mut RTL_SRWLOCK) -> BOOLEAN;
+ pub fn UpdateProcThreadAttribute(
+ lpattributelist: LPPROC_THREAD_ATTRIBUTE_LIST,
+ dwflags: u32,
+ attribute: usize,
+ lpvalue: *const ::core::ffi::c_void,
+ cbsize: usize,
+ lppreviousvalue: *mut ::core::ffi::c_void,
+ lpreturnsize: *const usize,
+ ) -> BOOL;
}
#[link(name = "kernel32")]
extern "system" {
@@ -549,19 +575,19 @@ extern "system" {
lphandles: *const HANDLE,
bwaitall: BOOL,
dwmilliseconds: u32,
- ) -> WIN32_ERROR;
+ ) -> WAIT_EVENT;
}
#[link(name = "kernel32")]
extern "system" {
- pub fn WaitForSingleObject(hhandle: HANDLE, dwmilliseconds: u32) -> WIN32_ERROR;
+ pub fn WaitForSingleObject(hhandle: HANDLE, dwmilliseconds: u32) -> WAIT_EVENT;
}
#[link(name = "kernel32")]
extern "system" {
- pub fn WakeAllConditionVariable(conditionvariable: *mut RTL_CONDITION_VARIABLE) -> ();
+ pub fn WakeAllConditionVariable(conditionvariable: *mut CONDITION_VARIABLE) -> ();
}
#[link(name = "kernel32")]
extern "system" {
- pub fn WakeConditionVariable(conditionvariable: *mut RTL_CONDITION_VARIABLE) -> ();
+ pub fn WakeConditionVariable(conditionvariable: *mut CONDITION_VARIABLE) -> ();
}
#[link(name = "kernel32")]
extern "system" {
@@ -822,6 +848,7 @@ impl ::core::clone::Clone for ADDRINFOA {
pub const AF_INET: ADDRESS_FAMILY = 2u16;
pub const AF_INET6: ADDRESS_FAMILY = 23u16;
pub const AF_UNSPEC: ADDRESS_FAMILY = 0u16;
+pub const ALL_PROCESSOR_GROUPS: u32 = 65535u32;
#[repr(C)]
pub union ARM64_NT_NEON128 {
pub Anonymous: ARM64_NT_NEON128_0,
@@ -874,7 +901,17 @@ impl ::core::clone::Clone for BY_HANDLE_FILE_INFORMATION {
}
pub const CALLBACK_CHUNK_FINISHED: LPPROGRESS_ROUTINE_CALLBACK_REASON = 0u32;
pub const CALLBACK_STREAM_SWITCH: LPPROGRESS_ROUTINE_CALLBACK_REASON = 1u32;
-pub type COMPARESTRING_RESULT = u32;
+pub type COMPARESTRING_RESULT = i32;
+#[repr(C)]
+pub struct CONDITION_VARIABLE {
+ pub Ptr: *mut ::core::ffi::c_void,
+}
+impl ::core::marker::Copy for CONDITION_VARIABLE {}
+impl ::core::clone::Clone for CONDITION_VARIABLE {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
pub type CONSOLE_MODE = u32;
#[repr(C)]
pub struct CONSOLE_READCONSOLE_CONTROL {
@@ -892,7 +929,7 @@ impl ::core::clone::Clone for CONSOLE_READCONSOLE_CONTROL {
#[repr(C)]
#[cfg(target_arch = "aarch64")]
pub struct CONTEXT {
- pub ContextFlags: u32,
+ pub ContextFlags: CONTEXT_FLAGS,
pub Cpsr: u32,
pub Anonymous: CONTEXT_0,
pub Sp: u64,
@@ -979,7 +1016,7 @@ pub struct CONTEXT {
pub P4Home: u64,
pub P5Home: u64,
pub P6Home: u64,
- pub ContextFlags: u32,
+ pub ContextFlags: CONTEXT_FLAGS,
pub MxCsr: u32,
pub SegCs: u16,
pub SegDs: u16,
@@ -1075,7 +1112,7 @@ impl ::core::clone::Clone for CONTEXT_0_0 {
#[repr(C)]
#[cfg(target_arch = "x86")]
pub struct CONTEXT {
- pub ContextFlags: u32,
+ pub ContextFlags: CONTEXT_FLAGS,
pub Dr0: u32,
pub Dr1: u32,
pub Dr2: u32,
@@ -1109,6 +1146,7 @@ impl ::core::clone::Clone for CONTEXT {
*self
}
}
+pub type CONTEXT_FLAGS = u32;
pub const CP_UTF8: u32 = 65001u32;
pub const CREATE_ALWAYS: FILE_CREATION_DISPOSITION = 2u32;
pub const CREATE_BREAKAWAY_FROM_JOB: PROCESS_CREATION_FLAGS = 16777216u32;
@@ -1126,9 +1164,9 @@ pub const CREATE_SEPARATE_WOW_VDM: PROCESS_CREATION_FLAGS = 2048u32;
pub const CREATE_SHARED_WOW_VDM: PROCESS_CREATION_FLAGS = 4096u32;
pub const CREATE_SUSPENDED: PROCESS_CREATION_FLAGS = 4u32;
pub const CREATE_UNICODE_ENVIRONMENT: PROCESS_CREATION_FLAGS = 1024u32;
-pub const CSTR_EQUAL: COMPARESTRING_RESULT = 2u32;
-pub const CSTR_GREATER_THAN: COMPARESTRING_RESULT = 3u32;
-pub const CSTR_LESS_THAN: COMPARESTRING_RESULT = 1u32;
+pub const CSTR_EQUAL: COMPARESTRING_RESULT = 2i32;
+pub const CSTR_GREATER_THAN: COMPARESTRING_RESULT = 3i32;
+pub const CSTR_LESS_THAN: COMPARESTRING_RESULT = 1i32;
pub const DEBUG_ONLY_THIS_PROCESS: PROCESS_CREATION_FLAGS = 2u32;
pub const DEBUG_PROCESS: PROCESS_CREATION_FLAGS = 1u32;
pub const DELETE: FILE_ACCESS_RIGHTS = 65536u32;
@@ -3344,7 +3382,6 @@ pub const FileRenameInfoEx: FILE_INFO_BY_HANDLE_CLASS = 22i32;
pub const FileStandardInfo: FILE_INFO_BY_HANDLE_CLASS = 1i32;
pub const FileStorageInfo: FILE_INFO_BY_HANDLE_CLASS = 16i32;
pub const FileStreamInfo: FILE_INFO_BY_HANDLE_CLASS = 7i32;
-pub type FindFileHandle = *mut ::core::ffi::c_void;
pub type GENERIC_ACCESS_RIGHTS = u32;
pub const GENERIC_ALL: GENERIC_ACCESS_RIGHTS = 268435456u32;
pub const GENERIC_EXECUTE: GENERIC_ACCESS_RIGHTS = 536870912u32;
@@ -3358,6 +3395,12 @@ pub struct GUID {
pub data3: u16,
pub data4: [u8; 8],
}
+impl ::core::marker::Copy for GUID {}
+impl ::core::clone::Clone for GUID {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
impl GUID {
pub const fn from_u128(uuid: u128) -> Self {
Self {
@@ -3368,12 +3411,6 @@ impl GUID {
}
}
}
-impl ::core::marker::Copy for GUID {}
-impl ::core::clone::Clone for GUID {
- fn clone(&self) -> Self {
- *self
- }
-}
pub type HANDLE = *mut ::core::ffi::c_void;
pub type HANDLE_FLAGS = u32;
pub const HANDLE_FLAG_INHERIT: HANDLE_FLAGS = 1u32;
@@ -3406,6 +3443,16 @@ impl ::core::clone::Clone for IN6_ADDR_0 {
pub const INFINITE: u32 = 4294967295u32;
pub const INHERIT_CALLER_PRIORITY: PROCESS_CREATION_FLAGS = 131072u32;
pub const INHERIT_PARENT_AFFINITY: PROCESS_CREATION_FLAGS = 65536u32;
+#[repr(C)]
+pub union INIT_ONCE {
+ pub Ptr: *mut ::core::ffi::c_void,
+}
+impl ::core::marker::Copy for INIT_ONCE {}
+impl ::core::clone::Clone for INIT_ONCE {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
pub const INIT_ONCE_INIT_FAILED: u32 = 4u32;
pub const INVALID_FILE_ATTRIBUTES: u32 = 4294967295u32;
pub const INVALID_HANDLE_VALUE: HANDLE = ::core::ptr::invalid_mut(-1i32 as _);
@@ -3567,6 +3614,7 @@ pub type LPOVERLAPPED_COMPLETION_ROUTINE = ::core::option::Option<
lpoverlapped: *mut OVERLAPPED,
) -> (),
>;
+pub type LPPROC_THREAD_ATTRIBUTE_LIST = *mut ::core::ffi::c_void;
pub type LPPROGRESS_ROUTINE = ::core::option::Option<
unsafe extern "system" fn(
totalfilesize: i64,
@@ -3633,10 +3681,10 @@ pub type NTSTATUS = i32;
pub struct OBJECT_ATTRIBUTES {
pub Length: u32,
pub RootDirectory: HANDLE,
- pub ObjectName: *mut UNICODE_STRING,
+ pub ObjectName: *const UNICODE_STRING,
pub Attributes: u32,
- pub SecurityDescriptor: *mut ::core::ffi::c_void,
- pub SecurityQualityOfService: *mut ::core::ffi::c_void,
+ pub SecurityDescriptor: *const ::core::ffi::c_void,
+ pub SecurityQualityOfService: *const ::core::ffi::c_void,
}
impl ::core::marker::Copy for OBJECT_ATTRIBUTES {}
impl ::core::clone::Clone for OBJECT_ATTRIBUTES {
@@ -3686,8 +3734,8 @@ pub type PCSTR = *const u8;
pub type PCWSTR = *const u16;
pub type PIO_APC_ROUTINE = ::core::option::Option<
unsafe extern "system" fn(
- apccontext: *const ::core::ffi::c_void,
- iostatusblock: *const IO_STATUS_BLOCK,
+ apccontext: *mut ::core::ffi::c_void,
+ iostatusblock: *mut IO_STATUS_BLOCK,
reserved: u32,
) -> (),
>;
@@ -3729,36 +3777,6 @@ pub type PSTR = *mut u8;
pub type PWSTR = *mut u16;
pub const READ_CONTROL: FILE_ACCESS_RIGHTS = 131072u32;
pub const REALTIME_PRIORITY_CLASS: PROCESS_CREATION_FLAGS = 256u32;
-#[repr(C)]
-pub struct RTL_CONDITION_VARIABLE {
- pub Ptr: *mut ::core::ffi::c_void,
-}
-impl ::core::marker::Copy for RTL_CONDITION_VARIABLE {}
-impl ::core::clone::Clone for RTL_CONDITION_VARIABLE {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-pub union RTL_RUN_ONCE {
- pub Ptr: *mut ::core::ffi::c_void,
-}
-impl ::core::marker::Copy for RTL_RUN_ONCE {}
-impl ::core::clone::Clone for RTL_RUN_ONCE {
- fn clone(&self) -> Self {
- *self
- }
-}
-#[repr(C)]
-pub struct RTL_SRWLOCK {
- pub Ptr: *mut ::core::ffi::c_void,
-}
-impl ::core::marker::Copy for RTL_SRWLOCK {}
-impl ::core::clone::Clone for RTL_SRWLOCK {
- fn clone(&self) -> Self {
- *self
- }
-}
pub const SD_BOTH: WINSOCK_SHUTDOWN_HOW = 2i32;
pub const SD_RECEIVE: WINSOCK_SHUTDOWN_HOW = 0i32;
pub const SD_SEND: WINSOCK_SHUTDOWN_HOW = 1i32;
@@ -3795,10 +3813,7 @@ impl ::core::clone::Clone for SOCKADDR {
*self
}
}
-#[cfg(target_pointer_width = "32")]
-pub type SOCKET = u32;
-#[cfg(target_pointer_width = "64")]
-pub type SOCKET = u64;
+pub type SOCKET = usize;
pub const SOCKET_ERROR: i32 = -1i32;
pub const SOCK_DGRAM: WINSOCK_SOCKET_TYPE = 2i32;
pub const SOCK_RAW: WINSOCK_SOCKET_TYPE = 3i32;
@@ -3812,6 +3827,16 @@ pub const SO_LINGER: i32 = 128i32;
pub const SO_RCVTIMEO: i32 = 4102i32;
pub const SO_SNDTIMEO: i32 = 4101i32;
pub const SPECIFIC_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 65535u32;
+#[repr(C)]
+pub struct SRWLOCK {
+ pub Ptr: *mut ::core::ffi::c_void,
+}
+impl ::core::marker::Copy for SRWLOCK {}
+impl ::core::clone::Clone for SRWLOCK {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
pub const STACK_SIZE_PARAM_IS_A_RESERVATION: THREAD_CREATION_FLAGS = 65536u32;
pub const STANDARD_RIGHTS_ALL: FILE_ACCESS_RIGHTS = 2031616u32;
pub const STANDARD_RIGHTS_EXECUTE: FILE_ACCESS_RIGHTS = 131072u32;
@@ -3833,6 +3858,17 @@ pub const STARTF_USESHOWWINDOW: STARTUPINFOW_FLAGS = 1u32;
pub const STARTF_USESIZE: STARTUPINFOW_FLAGS = 2u32;
pub const STARTF_USESTDHANDLES: STARTUPINFOW_FLAGS = 256u32;
#[repr(C)]
+pub struct STARTUPINFOEXW {
+ pub StartupInfo: STARTUPINFOW,
+ pub lpAttributeList: LPPROC_THREAD_ATTRIBUTE_LIST,
+}
+impl ::core::marker::Copy for STARTUPINFOEXW {}
+impl ::core::clone::Clone for STARTUPINFOEXW {
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+#[repr(C)]
pub struct STARTUPINFOW {
pub cb: u32,
pub lpReserved: PWSTR,
@@ -3971,12 +4007,13 @@ impl ::core::clone::Clone for UNICODE_STRING {
pub const VOLUME_NAME_DOS: GETFINALPATHNAMEBYHANDLE_FLAGS = 0u32;
pub const VOLUME_NAME_GUID: GETFINALPATHNAMEBYHANDLE_FLAGS = 1u32;
pub const VOLUME_NAME_NONE: GETFINALPATHNAMEBYHANDLE_FLAGS = 4u32;
-pub const WAIT_ABANDONED: WIN32_ERROR = 128u32;
-pub const WAIT_ABANDONED_0: WIN32_ERROR = 128u32;
-pub const WAIT_FAILED: WIN32_ERROR = 4294967295u32;
-pub const WAIT_IO_COMPLETION: WIN32_ERROR = 192u32;
-pub const WAIT_OBJECT_0: WIN32_ERROR = 0u32;
-pub const WAIT_TIMEOUT: WIN32_ERROR = 258u32;
+pub const WAIT_ABANDONED: WAIT_EVENT = 128u32;
+pub const WAIT_ABANDONED_0: WAIT_EVENT = 128u32;
+pub type WAIT_EVENT = u32;
+pub const WAIT_FAILED: WAIT_EVENT = 4294967295u32;
+pub const WAIT_IO_COMPLETION: WAIT_EVENT = 192u32;
+pub const WAIT_OBJECT_0: WAIT_EVENT = 0u32;
+pub const WAIT_TIMEOUT: WAIT_EVENT = 258u32;
pub const WC_ERR_INVALID_CHARS: u32 = 128u32;
pub type WIN32_ERROR = u32;
#[repr(C)]
diff --git a/library/std/src/sys/windows/handle.rs b/library/std/src/sys/windows/handle.rs
index 84c1fbde3..56d0d6c08 100644
--- a/library/std/src/sys/windows/handle.rs
+++ b/library/std/src/sys/windows/handle.rs
@@ -143,13 +143,8 @@ impl Handle {
) -> io::Result<Option<usize>> {
let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD;
let mut amt = 0;
- let res = cvt(c::ReadFile(
- self.as_raw_handle(),
- buf.as_ptr() as c::LPVOID,
- len,
- &mut amt,
- overlapped,
- ));
+ let res =
+ cvt(c::ReadFile(self.as_raw_handle(), buf.as_mut_ptr(), len, &mut amt, overlapped));
match res {
Ok(_) => Ok(Some(amt as usize)),
Err(e) => {
diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs
index bcc172b0f..b609ad247 100644
--- a/library/std/src/sys/windows/mod.rs
+++ b/library/std/src/sys/windows/mod.rs
@@ -60,6 +60,11 @@ pub unsafe fn cleanup() {
net::cleanup();
}
+#[inline]
+pub fn is_interrupted(_errno: i32) -> bool {
+ false
+}
+
pub fn decode_error_kind(errno: i32) -> ErrorKind {
use ErrorKind::*;
diff --git a/library/std/src/sys/windows/net.rs b/library/std/src/sys/windows/net.rs
index 1ae42cb7e..abdcab424 100644
--- a/library/std/src/sys/windows/net.rs
+++ b/library/std/src/sys/windows/net.rs
@@ -117,7 +117,7 @@ impl Socket {
};
if socket != c::INVALID_SOCKET {
- unsafe { Ok(Self::from_raw_socket(socket)) }
+ unsafe { Ok(Self::from_raw(socket)) }
} else {
let error = unsafe { c::WSAGetLastError() };
@@ -133,7 +133,7 @@ impl Socket {
}
unsafe {
- let socket = Self::from_raw_socket(socket);
+ let socket = Self::from_raw(socket);
socket.0.set_no_inherit()?;
Ok(socket)
}
@@ -144,7 +144,7 @@ impl Socket {
self.set_nonblocking(true)?;
let result = {
let (addr, len) = addr.into_inner();
- let result = unsafe { c::connect(self.as_raw_socket(), addr.as_ptr(), len) };
+ let result = unsafe { c::connect(self.as_raw(), addr.as_ptr(), len) };
cvt(result).map(drop)
};
self.set_nonblocking(false)?;
@@ -170,7 +170,7 @@ impl Socket {
let fds = {
let mut fds = unsafe { mem::zeroed::<c::fd_set>() };
fds.fd_count = 1;
- fds.fd_array[0] = self.as_raw_socket();
+ fds.fd_array[0] = self.as_raw();
fds
};
@@ -202,11 +202,11 @@ impl Socket {
}
pub fn accept(&self, storage: *mut c::SOCKADDR, len: *mut c_int) -> io::Result<Socket> {
- let socket = unsafe { c::accept(self.as_raw_socket(), storage, len) };
+ let socket = unsafe { c::accept(self.as_raw(), storage, len) };
match socket {
c::INVALID_SOCKET => Err(last_error()),
- _ => unsafe { Ok(Self::from_raw_socket(socket)) },
+ _ => unsafe { Ok(Self::from_raw(socket)) },
}
}
@@ -218,9 +218,8 @@ impl Socket {
// On unix when a socket is shut down all further reads return 0, so we
// do the same on windows to map a shut down socket to returning EOF.
let length = cmp::min(buf.capacity(), i32::MAX as usize) as i32;
- let result = unsafe {
- c::recv(self.as_raw_socket(), buf.as_mut().as_mut_ptr() as *mut _, length, flags)
- };
+ let result =
+ unsafe { c::recv(self.as_raw(), buf.as_mut().as_mut_ptr() as *mut _, length, flags) };
match result {
c::SOCKET_ERROR => {
@@ -257,7 +256,7 @@ impl Socket {
let mut flags = 0;
let result = unsafe {
c::WSARecv(
- self.as_raw_socket(),
+ self.as_raw(),
bufs.as_mut_ptr() as *mut c::WSABUF,
length,
&mut nread,
@@ -305,7 +304,7 @@ impl Socket {
// do the same on windows to map a shut down socket to returning EOF.
let result = unsafe {
c::recvfrom(
- self.as_raw_socket(),
+ self.as_raw(),
buf.as_mut_ptr() as *mut _,
length,
flags,
@@ -341,7 +340,7 @@ impl Socket {
let mut nwritten = 0;
let result = unsafe {
c::WSASend(
- self.as_raw_socket(),
+ self.as_raw(),
bufs.as_ptr() as *const c::WSABUF as *mut _,
length,
&mut nwritten,
@@ -392,14 +391,14 @@ impl Socket {
Shutdown::Read => c::SD_RECEIVE,
Shutdown::Both => c::SD_BOTH,
};
- let result = unsafe { c::shutdown(self.as_raw_socket(), how) };
+ let result = unsafe { c::shutdown(self.as_raw(), how) };
cvt(result).map(drop)
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
let mut nonblocking = nonblocking as c_ulong;
let result =
- unsafe { c::ioctlsocket(self.as_raw_socket(), c::FIONBIO as c_int, &mut nonblocking) };
+ unsafe { c::ioctlsocket(self.as_raw(), c::FIONBIO as c_int, &mut nonblocking) };
cvt(result).map(drop)
}
@@ -433,8 +432,15 @@ impl Socket {
}
// This is used by sys_common code to abstract over Windows and Unix.
- pub fn as_raw(&self) -> RawSocket {
- self.as_inner().as_raw_socket()
+ pub fn as_raw(&self) -> c::SOCKET {
+ debug_assert_eq!(mem::size_of::<c::SOCKET>(), mem::size_of::<RawSocket>());
+ debug_assert_eq!(mem::align_of::<c::SOCKET>(), mem::align_of::<RawSocket>());
+ self.as_inner().as_raw_socket() as c::SOCKET
+ }
+ pub unsafe fn from_raw(raw: c::SOCKET) -> Self {
+ debug_assert_eq!(mem::size_of::<c::SOCKET>(), mem::size_of::<RawSocket>());
+ debug_assert_eq!(mem::align_of::<c::SOCKET>(), mem::align_of::<RawSocket>());
+ Self::from_raw_socket(raw as RawSocket)
}
}
diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs
index 4708657a9..237854fac 100644
--- a/library/std/src/sys/windows/os_str.rs
+++ b/library/std/src/sys/windows/os_str.rs
@@ -64,12 +64,12 @@ impl fmt::Display for Slice {
impl Buf {
#[inline]
- pub fn into_os_str_bytes(self) -> Vec<u8> {
+ pub fn into_encoded_bytes(self) -> Vec<u8> {
self.inner.into_bytes()
}
#[inline]
- pub unsafe fn from_os_str_bytes_unchecked(s: Vec<u8>) -> Self {
+ pub unsafe fn from_encoded_bytes_unchecked(s: Vec<u8>) -> Self {
Self { inner: Wtf8Buf::from_bytes_unchecked(s) }
}
@@ -162,12 +162,12 @@ impl Buf {
impl Slice {
#[inline]
- pub fn as_os_str_bytes(&self) -> &[u8] {
+ pub fn as_encoded_bytes(&self) -> &[u8] {
self.inner.as_bytes()
}
#[inline]
- pub unsafe fn from_os_str_bytes_unchecked(s: &[u8]) -> &Slice {
+ pub unsafe fn from_encoded_bytes_unchecked(s: &[u8]) -> &Slice {
mem::transmute(Wtf8::from_bytes_unchecked(s))
}
diff --git a/library/std/src/sys/windows/path.rs b/library/std/src/sys/windows/path.rs
index c9c2d10e6..8c0e07b35 100644
--- a/library/std/src/sys/windows/path.rs
+++ b/library/std/src/sys/windows/path.rs
@@ -22,12 +22,12 @@ pub fn is_verbatim_sep(b: u8) -> bool {
/// Returns true if `path` looks like a lone filename.
pub(crate) fn is_file_name(path: &OsStr) -> bool {
- !path.as_os_str_bytes().iter().copied().any(is_sep_byte)
+ !path.as_encoded_bytes().iter().copied().any(is_sep_byte)
}
pub(crate) fn has_trailing_slash(path: &OsStr) -> bool {
- let is_verbatim = path.as_os_str_bytes().starts_with(br"\\?\");
+ let is_verbatim = path.as_encoded_bytes().starts_with(br"\\?\");
let is_separator = if is_verbatim { is_verbatim_sep } else { is_sep_byte };
- if let Some(&c) = path.as_os_str_bytes().last() { is_separator(c) } else { false }
+ if let Some(&c) = path.as_encoded_bytes().last() { is_separator(c) } else { false }
}
/// Appends a suffix to a path.
@@ -49,7 +49,7 @@ impl<'a, const LEN: usize> PrefixParser<'a, LEN> {
fn get_prefix(path: &OsStr) -> [u8; LEN] {
let mut prefix = [0; LEN];
// SAFETY: Only ASCII characters are modified.
- for (i, &ch) in path.as_os_str_bytes().iter().take(LEN).enumerate() {
+ for (i, &ch) in path.as_encoded_bytes().iter().take(LEN).enumerate() {
prefix[i] = if ch == b'/' { b'\\' } else { ch };
}
prefix
@@ -82,7 +82,7 @@ impl<'a> PrefixParserSlice<'a, '_> {
}
fn prefix_bytes(&self) -> &'a [u8] {
- &self.path.as_os_str_bytes()[..self.index]
+ &self.path.as_encoded_bytes()[..self.index]
}
fn finish(self) -> &'a OsStr {
@@ -90,7 +90,7 @@ impl<'a> PrefixParserSlice<'a, '_> {
// &[u8] and back. This is safe to do because (1) we only look at ASCII
// contents of the encoding and (2) new &OsStr values are produced only
// from ASCII-bounded slices of existing &OsStr values.
- unsafe { OsStr::from_os_str_bytes_unchecked(&self.path.as_os_str_bytes()[self.index..]) }
+ unsafe { OsStr::from_encoded_bytes_unchecked(&self.path.as_encoded_bytes()[self.index..]) }
}
}
@@ -162,7 +162,7 @@ fn parse_drive(path: &OsStr) -> Option<u8> {
drive.is_ascii_alphabetic()
}
- match path.as_os_str_bytes() {
+ match path.as_encoded_bytes() {
[drive, b':', ..] if is_valid_drive_letter(drive) => Some(drive.to_ascii_uppercase()),
_ => None,
}
@@ -171,7 +171,7 @@ fn parse_drive(path: &OsStr) -> Option<u8> {
// Parses a drive prefix exactly, e.g. "C:"
fn parse_drive_exact(path: &OsStr) -> Option<u8> {
// only parse two bytes: the drive letter and the drive separator
- if path.as_os_str_bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) {
+ if path.as_encoded_bytes().get(2).map(|&x| is_sep_byte(x)).unwrap_or(true) {
parse_drive(path)
} else {
None
@@ -185,15 +185,15 @@ fn parse_drive_exact(path: &OsStr) -> Option<u8> {
fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
let separator = if verbatim { is_verbatim_sep } else { is_sep_byte };
- match path.as_os_str_bytes().iter().position(|&x| separator(x)) {
+ match path.as_encoded_bytes().iter().position(|&x| separator(x)) {
Some(separator_start) => {
let separator_end = separator_start + 1;
- let component = &path.as_os_str_bytes()[..separator_start];
+ let component = &path.as_encoded_bytes()[..separator_start];
// Panic safe
// The max `separator_end` is `bytes.len()` and `bytes[bytes.len()..]` is a valid index.
- let path = &path.as_os_str_bytes()[separator_end..];
+ let path = &path.as_encoded_bytes()[separator_end..];
// SAFETY: `path` is a valid wtf8 encoded slice and each of the separators ('/', '\')
// is encoded in a single byte, therefore `bytes[separator_start]` and
@@ -201,8 +201,8 @@ fn parse_next_component(path: &OsStr, verbatim: bool) -> (&OsStr, &OsStr) {
// `bytes[..separator_start]` and `bytes[separator_end..]` are valid wtf8 slices.
unsafe {
(
- OsStr::from_os_str_bytes_unchecked(component),
- OsStr::from_os_str_bytes_unchecked(path),
+ OsStr::from_encoded_bytes_unchecked(component),
+ OsStr::from_encoded_bytes_unchecked(path),
)
}
}
@@ -323,7 +323,7 @@ pub(crate) fn absolute(path: &Path) -> io::Result<PathBuf> {
// Verbatim paths should not be modified.
if prefix.map(|x| x.is_verbatim()).unwrap_or(false) {
// NULs in verbatim paths are rejected for consistency.
- if path.as_os_str_bytes().contains(&0) {
+ if path.as_encoded_bytes().contains(&0) {
return Err(io::const_io_error!(
io::ErrorKind::InvalidInput,
"strings passed to WinAPI cannot contain NULs",
diff --git a/library/std/src/sys/windows/pipe.rs b/library/std/src/sys/windows/pipe.rs
index d07147ecc..7624e746f 100644
--- a/library/std/src/sys/windows/pipe.rs
+++ b/library/std/src/sys/windows/pipe.rs
@@ -12,7 +12,7 @@ use crate::sys::c;
use crate::sys::fs::{File, OpenOptions};
use crate::sys::handle::Handle;
use crate::sys::hashmap_random_keys;
-use crate::sys_common::IntoInner;
+use crate::sys_common::{FromInner, IntoInner};
////////////////////////////////////////////////////////////////////////////////
// Anonymous pipes
@@ -28,6 +28,12 @@ impl IntoInner<Handle> for AnonPipe {
}
}
+impl FromInner<Handle> for AnonPipe {
+ fn from_inner(inner: Handle) -> AnonPipe {
+ Self { inner }
+ }
+}
+
pub struct Pipes {
pub ours: AnonPipe,
pub theirs: AnonPipe,
diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs
index 2dd0c67ac..cd5bf7f15 100644
--- a/library/std/src/sys/windows/process.rs
+++ b/library/std/src/sys/windows/process.rs
@@ -11,6 +11,7 @@ use crate::ffi::{OsStr, OsString};
use crate::fmt;
use crate::io::{self, Error, ErrorKind};
use crate::mem;
+use crate::mem::MaybeUninit;
use crate::num::NonZeroI32;
use crate::os::windows::ffi::{OsStrExt, OsStringExt};
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle, FromRawHandle, IntoRawHandle};
@@ -166,10 +167,12 @@ pub struct Command {
stdout: Option<Stdio>,
stderr: Option<Stdio>,
force_quotes_enabled: bool,
+ proc_thread_attributes: BTreeMap<usize, ProcThreadAttributeValue>,
}
pub enum Stdio {
Inherit,
+ InheritSpecific { from_stdio_id: c::DWORD },
Null,
MakePipe,
Pipe(AnonPipe),
@@ -195,6 +198,7 @@ impl Command {
stdout: None,
stderr: None,
force_quotes_enabled: false,
+ proc_thread_attributes: Default::default(),
}
}
@@ -245,6 +249,17 @@ impl Command {
self.cwd.as_ref().map(|cwd| Path::new(cwd))
}
+ pub unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
+ &mut self,
+ attribute: usize,
+ value: T,
+ ) {
+ self.proc_thread_attributes.insert(
+ attribute,
+ ProcThreadAttributeValue { size: mem::size_of::<T>(), data: Box::new(value) },
+ );
+ }
+
pub fn spawn(
&mut self,
default: Stdio,
@@ -308,7 +323,6 @@ impl Command {
let stderr = stderr.to_handle(c::STD_ERROR_HANDLE, &mut pipes.stderr)?;
let mut si = zeroed_startupinfo();
- si.cb = mem::size_of::<c::STARTUPINFOW>() as c::DWORD;
// If at least one of stdin, stdout or stderr are set (i.e. are non null)
// then set the `hStd` fields in `STARTUPINFO`.
@@ -322,6 +336,27 @@ impl Command {
si.hStdError = stderr.as_raw_handle();
}
+ let si_ptr: *mut c::STARTUPINFOW;
+
+ let mut proc_thread_attribute_list;
+ let mut si_ex;
+
+ if !self.proc_thread_attributes.is_empty() {
+ si.cb = mem::size_of::<c::STARTUPINFOEXW>() as u32;
+ flags |= c::EXTENDED_STARTUPINFO_PRESENT;
+
+ proc_thread_attribute_list =
+ make_proc_thread_attribute_list(&self.proc_thread_attributes)?;
+ si_ex = c::STARTUPINFOEXW {
+ StartupInfo: si,
+ lpAttributeList: proc_thread_attribute_list.0.as_mut_ptr() as _,
+ };
+ si_ptr = &mut si_ex as *mut _ as _;
+ } else {
+ si.cb = mem::size_of::<c::STARTUPINFOW>() as c::DWORD;
+ si_ptr = &mut si as *mut _ as _;
+ }
+
unsafe {
cvt(c::CreateProcessW(
program.as_ptr(),
@@ -332,7 +367,7 @@ impl Command {
flags,
envp,
dirp,
- &si,
+ si_ptr,
&mut pi,
))
}?;
@@ -395,7 +430,7 @@ fn resolve_exe<'a>(
// Test if the file name has the `exe` extension.
// This does a case-insensitive `ends_with`.
let has_exe_suffix = if exe_path.len() >= EXE_SUFFIX.len() {
- exe_path.as_os_str_bytes()[exe_path.len() - EXE_SUFFIX.len()..]
+ exe_path.as_encoded_bytes()[exe_path.len() - EXE_SUFFIX.len()..]
.eq_ignore_ascii_case(EXE_SUFFIX.as_bytes())
} else {
false
@@ -425,7 +460,7 @@ fn resolve_exe<'a>(
// From the `CreateProcessW` docs:
// > If the file name does not contain an extension, .exe is appended.
// Note that this rule only applies when searching paths.
- let has_extension = exe_path.as_os_str_bytes().contains(&b'.');
+ let has_extension = exe_path.as_encoded_bytes().contains(&b'.');
// Search the directories given by `search_paths`.
let result = search_paths(parent_paths, child_paths, |mut path| {
@@ -521,17 +556,19 @@ fn program_exists(path: &Path) -> Option<Vec<u16>> {
impl Stdio {
fn to_handle(&self, stdio_id: c::DWORD, pipe: &mut Option<AnonPipe>) -> io::Result<Handle> {
- match *self {
- Stdio::Inherit => match stdio::get_handle(stdio_id) {
- Ok(io) => unsafe {
- let io = Handle::from_raw_handle(io);
- let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS);
- io.into_raw_handle();
- ret
- },
- // If no stdio handle is available, then propagate the null value.
- Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) },
+ let use_stdio_id = |stdio_id| match stdio::get_handle(stdio_id) {
+ Ok(io) => unsafe {
+ let io = Handle::from_raw_handle(io);
+ let ret = io.duplicate(0, true, c::DUPLICATE_SAME_ACCESS);
+ io.into_raw_handle();
+ ret
},
+ // If no stdio handle is available, then propagate the null value.
+ Err(..) => unsafe { Ok(Handle::from_raw_handle(ptr::null_mut())) },
+ };
+ match *self {
+ Stdio::Inherit => use_stdio_id(stdio_id),
+ Stdio::InheritSpecific { from_stdio_id } => use_stdio_id(from_stdio_id),
Stdio::MakePipe => {
let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
@@ -579,6 +616,18 @@ impl From<File> for Stdio {
}
}
+impl From<io::Stdout> for Stdio {
+ fn from(_: io::Stdout) -> Stdio {
+ Stdio::InheritSpecific { from_stdio_id: c::STD_OUTPUT_HANDLE }
+ }
+}
+
+impl From<io::Stderr> for Stdio {
+ fn from(_: io::Stderr) -> Stdio {
+ Stdio::InheritSpecific { from_stdio_id: c::STD_ERROR_HANDLE }
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// Processes
////////////////////////////////////////////////////////////////////////////////
@@ -831,6 +880,80 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec<u16>)> {
}
}
+struct ProcThreadAttributeList(Box<[MaybeUninit<u8>]>);
+
+impl Drop for ProcThreadAttributeList {
+ fn drop(&mut self) {
+ let lp_attribute_list = self.0.as_mut_ptr() as _;
+ unsafe { c::DeleteProcThreadAttributeList(lp_attribute_list) }
+ }
+}
+
+/// Wrapper around the value data to be used as a Process Thread Attribute.
+struct ProcThreadAttributeValue {
+ data: Box<dyn Send + Sync>,
+ size: usize,
+}
+
+fn make_proc_thread_attribute_list(
+ attributes: &BTreeMap<usize, ProcThreadAttributeValue>,
+) -> io::Result<ProcThreadAttributeList> {
+ // To initialize our ProcThreadAttributeList, we need to determine
+ // how many bytes to allocate for it. The Windows API simplifies this process
+ // by allowing us to call `InitializeProcThreadAttributeList` with
+ // a null pointer to retrieve the required size.
+ let mut required_size = 0;
+ let Ok(attribute_count) = attributes.len().try_into() else {
+ return Err(io::const_io_error!(
+ ErrorKind::InvalidInput,
+ "maximum number of ProcThreadAttributes exceeded",
+ ));
+ };
+ unsafe {
+ c::InitializeProcThreadAttributeList(
+ ptr::null_mut(),
+ attribute_count,
+ 0,
+ &mut required_size,
+ )
+ };
+
+ let mut proc_thread_attribute_list = ProcThreadAttributeList(
+ vec![MaybeUninit::uninit(); required_size as usize].into_boxed_slice(),
+ );
+
+ // Once we've allocated the necessary memory, it's safe to invoke
+ // `InitializeProcThreadAttributeList` to properly initialize the list.
+ cvt(unsafe {
+ c::InitializeProcThreadAttributeList(
+ proc_thread_attribute_list.0.as_mut_ptr() as *mut _,
+ attribute_count,
+ 0,
+ &mut required_size,
+ )
+ })?;
+
+ // # Add our attributes to the buffer.
+ // It's theoretically possible for the attribute count to exceed a u32 value.
+ // Therefore, we ensure that we don't add more attributes than the buffer was initialized for.
+ for (&attribute, value) in attributes.iter().take(attribute_count as usize) {
+ let value_ptr = &*value.data as *const (dyn Send + Sync) as _;
+ cvt(unsafe {
+ c::UpdateProcThreadAttribute(
+ proc_thread_attribute_list.0.as_mut_ptr() as _,
+ 0,
+ attribute,
+ value_ptr,
+ value.size,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ )
+ })?;
+ }
+
+ Ok(proc_thread_attribute_list)
+}
+
pub struct CommandArgs<'a> {
iter: crate::slice::Iter<'a, Arg>,
}
diff --git a/library/std/src/sys/xous/alloc.rs b/library/std/src/sys/xous/alloc.rs
new file mode 100644
index 000000000..b3a3e691e
--- /dev/null
+++ b/library/std/src/sys/xous/alloc.rs
@@ -0,0 +1,62 @@
+use crate::alloc::{GlobalAlloc, Layout, System};
+
+static mut DLMALLOC: dlmalloc::Dlmalloc = dlmalloc::Dlmalloc::new();
+
+#[stable(feature = "alloc_system_type", since = "1.28.0")]
+unsafe impl GlobalAlloc for System {
+ #[inline]
+ unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
+ // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
+ // Calling malloc() is safe because preconditions on this function match the trait method preconditions.
+ let _lock = lock::lock();
+ unsafe { DLMALLOC.malloc(layout.size(), layout.align()) }
+ }
+
+ #[inline]
+ unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
+ // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
+ // Calling calloc() is safe because preconditions on this function match the trait method preconditions.
+ let _lock = lock::lock();
+ unsafe { DLMALLOC.calloc(layout.size(), layout.align()) }
+ }
+
+ #[inline]
+ unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
+ // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
+ // Calling free() is safe because preconditions on this function match the trait method preconditions.
+ let _lock = lock::lock();
+ unsafe { DLMALLOC.free(ptr, layout.size(), layout.align()) }
+ }
+
+ #[inline]
+ unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
+ // SAFETY: DLMALLOC access is guaranteed to be safe because the lock gives us unique and non-reentrant access.
+ // Calling realloc() is safe because preconditions on this function match the trait method preconditions.
+ let _lock = lock::lock();
+ unsafe { DLMALLOC.realloc(ptr, layout.size(), layout.align(), new_size) }
+ }
+}
+
+mod lock {
+ use crate::sync::atomic::{AtomicI32, Ordering::SeqCst};
+
+ static LOCKED: AtomicI32 = AtomicI32::new(0);
+
+ pub struct DropLock;
+
+ pub fn lock() -> DropLock {
+ loop {
+ if LOCKED.swap(1, SeqCst) == 0 {
+ return DropLock;
+ }
+ crate::os::xous::ffi::do_yield();
+ }
+ }
+
+ impl Drop for DropLock {
+ fn drop(&mut self) {
+ let r = LOCKED.swap(0, SeqCst);
+ debug_assert_eq!(r, 1);
+ }
+ }
+}
diff --git a/library/std/src/sys/xous/locks/condvar.rs b/library/std/src/sys/xous/locks/condvar.rs
new file mode 100644
index 000000000..1bb38dfa3
--- /dev/null
+++ b/library/std/src/sys/xous/locks/condvar.rs
@@ -0,0 +1,111 @@
+use super::mutex::Mutex;
+use crate::os::xous::ffi::{blocking_scalar, scalar};
+use crate::os::xous::services::ticktimer_server;
+use crate::sync::Mutex as StdMutex;
+use crate::time::Duration;
+
+// The implementation is inspired by Andrew D. Birrell's paper
+// "Implementing Condition Variables with Semaphores"
+
+pub struct Condvar {
+ counter: StdMutex<usize>,
+}
+
+unsafe impl Send for Condvar {}
+unsafe impl Sync for Condvar {}
+
+impl Condvar {
+ #[inline]
+ #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+ pub const fn new() -> Condvar {
+ Condvar { counter: StdMutex::new(0) }
+ }
+
+ pub fn notify_one(&self) {
+ let mut counter = self.counter.lock().unwrap();
+ if *counter <= 0 {
+ return;
+ } else {
+ *counter -= 1;
+ }
+ let result = blocking_scalar(
+ ticktimer_server(),
+ crate::os::xous::services::TicktimerScalar::NotifyCondition(self.index(), 1).into(),
+ );
+ drop(counter);
+ result.expect("failure to send NotifyCondition command");
+ }
+
+ pub fn notify_all(&self) {
+ let mut counter = self.counter.lock().unwrap();
+ if *counter <= 0 {
+ return;
+ }
+ let result = blocking_scalar(
+ ticktimer_server(),
+ crate::os::xous::services::TicktimerScalar::NotifyCondition(self.index(), *counter)
+ .into(),
+ );
+ *counter = 0;
+ drop(counter);
+
+ result.expect("failure to send NotifyCondition command");
+ }
+
+ fn index(&self) -> usize {
+ self as *const Condvar as usize
+ }
+
+ pub unsafe fn wait(&self, mutex: &Mutex) {
+ let mut counter = self.counter.lock().unwrap();
+ *counter += 1;
+ unsafe { mutex.unlock() };
+ drop(counter);
+
+ let result = blocking_scalar(
+ ticktimer_server(),
+ crate::os::xous::services::TicktimerScalar::WaitForCondition(self.index(), 0).into(),
+ );
+ unsafe { mutex.lock() };
+
+ result.expect("Ticktimer: failure to send WaitForCondition command");
+ }
+
+ pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
+ let mut counter = self.counter.lock().unwrap();
+ *counter += 1;
+ unsafe { mutex.unlock() };
+ drop(counter);
+
+ let mut millis = dur.as_millis() as usize;
+ if millis == 0 {
+ millis = 1;
+ }
+
+ let result = blocking_scalar(
+ ticktimer_server(),
+ crate::os::xous::services::TicktimerScalar::WaitForCondition(self.index(), millis)
+ .into(),
+ );
+ unsafe { mutex.lock() };
+
+ let result = result.expect("Ticktimer: failure to send WaitForCondition command")[0] == 0;
+
+ // If we awoke due to a timeout, decrement the wake count, as that would not have
+ // been done in the `notify()` call.
+ if !result {
+ *self.counter.lock().unwrap() -= 1;
+ }
+ result
+ }
+}
+
+impl Drop for Condvar {
+ fn drop(&mut self) {
+ scalar(
+ ticktimer_server(),
+ crate::os::xous::services::TicktimerScalar::FreeCondition(self.index()).into(),
+ )
+ .ok();
+ }
+}
diff --git a/library/std/src/sys/xous/locks/mod.rs b/library/std/src/sys/xous/locks/mod.rs
new file mode 100644
index 000000000..f3c5c5d9f
--- /dev/null
+++ b/library/std/src/sys/xous/locks/mod.rs
@@ -0,0 +1,7 @@
+mod condvar;
+mod mutex;
+mod rwlock;
+
+pub use condvar::*;
+pub use mutex::*;
+pub use rwlock::*;
diff --git a/library/std/src/sys/xous/locks/mutex.rs b/library/std/src/sys/xous/locks/mutex.rs
new file mode 100644
index 000000000..ea51776d5
--- /dev/null
+++ b/library/std/src/sys/xous/locks/mutex.rs
@@ -0,0 +1,116 @@
+use crate::os::xous::ffi::{blocking_scalar, do_yield, scalar};
+use crate::os::xous::services::ticktimer_server;
+use crate::sync::atomic::{AtomicBool, AtomicUsize, Ordering::Relaxed, Ordering::SeqCst};
+
+pub struct Mutex {
+ /// The "locked" value indicates how many threads are waiting on this
+ /// Mutex. Possible values are:
+ /// 0: The lock is unlocked
+ /// 1: The lock is locked and uncontended
+ /// >=2: The lock is locked and contended
+ ///
+ /// A lock is "contended" when there is more than one thread waiting
+ /// for a lock, or it is locked for long periods of time. Rather than
+ /// spinning, these locks send a Message to the ticktimer server
+ /// requesting that they be woken up when a lock is unlocked.
+ locked: AtomicUsize,
+
+ /// Whether this Mutex ever was contended, and therefore made a trip
+ /// to the ticktimer server. If this was never set, then we were never
+ /// on the slow path and can skip deregistering the mutex.
+ contended: AtomicBool,
+}
+
+impl Mutex {
+ #[inline]
+ #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+ pub const fn new() -> Mutex {
+ Mutex { locked: AtomicUsize::new(0), contended: AtomicBool::new(false) }
+ }
+
+ fn index(&self) -> usize {
+ self as *const Mutex as usize
+ }
+
+ #[inline]
+ pub unsafe fn lock(&self) {
+ // Try multiple times to acquire the lock without resorting to the ticktimer
+ // server. For locks that are held for a short amount of time, this will
+ // result in the ticktimer server never getting invoked. The `locked` value
+ // will be either 0 or 1.
+ for _attempts in 0..3 {
+ if unsafe { self.try_lock() } {
+ return;
+ }
+ do_yield();
+ }
+
+ // Try one more time to lock. If the lock is released between the previous code and
+ // here, then the inner `locked` value will be 1 at the end of this. If it was not
+ // locked, then the value will be more than 1, for example if there are multiple other
+ // threads waiting on this lock.
+ if unsafe { self.try_lock_or_poison() } {
+ return;
+ }
+
+ // When this mutex is dropped, we will need to deregister it with the server.
+ self.contended.store(true, Relaxed);
+
+ // The lock is now "contended". When the lock is released, a Message will get sent to the
+ // ticktimer server to wake it up. Note that this may already have happened, so the actual
+ // value of `lock` may be anything (0, 1, 2, ...).
+ blocking_scalar(
+ ticktimer_server(),
+ crate::os::xous::services::TicktimerScalar::LockMutex(self.index()).into(),
+ )
+ .expect("failure to send LockMutex command");
+ }
+
+ #[inline]
+ pub unsafe fn unlock(&self) {
+ let prev = self.locked.fetch_sub(1, SeqCst);
+
+ // If the previous value was 1, then this was a "fast path" unlock, so no
+ // need to involve the Ticktimer server
+ if prev == 1 {
+ return;
+ }
+
+ // If it was 0, then something has gone seriously wrong and the counter
+ // has just wrapped around.
+ if prev == 0 {
+ panic!("mutex lock count underflowed");
+ }
+
+ // Unblock one thread that is waiting on this message.
+ scalar(
+ ticktimer_server(),
+ crate::os::xous::services::TicktimerScalar::UnlockMutex(self.index()).into(),
+ )
+ .expect("failure to send UnlockMutex command");
+ }
+
+ #[inline]
+ pub unsafe fn try_lock(&self) -> bool {
+ self.locked.compare_exchange(0, 1, SeqCst, SeqCst).is_ok()
+ }
+
+ #[inline]
+ pub unsafe fn try_lock_or_poison(&self) -> bool {
+ self.locked.fetch_add(1, SeqCst) == 0
+ }
+}
+
+impl Drop for Mutex {
+ fn drop(&mut self) {
+ // If there was Mutex contention, then we involved the ticktimer. Free
+ // the resources associated with this Mutex as it is deallocated.
+ if self.contended.load(Relaxed) {
+ scalar(
+ ticktimer_server(),
+ crate::os::xous::services::TicktimerScalar::FreeMutex(self.index()).into(),
+ )
+ .ok();
+ }
+ }
+}
diff --git a/library/std/src/sys/xous/locks/rwlock.rs b/library/std/src/sys/xous/locks/rwlock.rs
new file mode 100644
index 000000000..618da758a
--- /dev/null
+++ b/library/std/src/sys/xous/locks/rwlock.rs
@@ -0,0 +1,72 @@
+use crate::os::xous::ffi::do_yield;
+use crate::sync::atomic::{AtomicIsize, Ordering::SeqCst};
+
+pub struct RwLock {
+ /// The "mode" value indicates how many threads are waiting on this
+ /// Mutex. Possible values are:
+ /// -1: The lock is locked for writing
+ /// 0: The lock is unlocked
+ /// >=1: The lock is locked for reading
+ ///
+ /// This currently spins waiting for the lock to be freed. An
+ /// optimization would be to involve the ticktimer server to
+ /// coordinate unlocks.
+ mode: AtomicIsize,
+}
+
+unsafe impl Send for RwLock {}
+unsafe impl Sync for RwLock {}
+
+impl RwLock {
+ #[inline]
+ #[rustc_const_stable(feature = "const_locks", since = "1.63.0")]
+ pub const fn new() -> RwLock {
+ RwLock { mode: AtomicIsize::new(0) }
+ }
+
+ #[inline]
+ pub unsafe fn read(&self) {
+ while !unsafe { self.try_read() } {
+ do_yield();
+ }
+ }
+
+ #[inline]
+ pub unsafe fn try_read(&self) -> bool {
+ // Non-atomically determine the current value.
+ let current = self.mode.load(SeqCst);
+
+ // If it's currently locked for writing, then we cannot read.
+ if current < 0 {
+ return false;
+ }
+
+ // Attempt to lock. If the `current` value has changed, then this
+ // operation will fail and we will not obtain the lock even if we
+ // could potentially keep it.
+ let new = current + 1;
+ self.mode.compare_exchange(current, new, SeqCst, SeqCst).is_ok()
+ }
+
+ #[inline]
+ pub unsafe fn write(&self) {
+ while !unsafe { self.try_write() } {
+ do_yield();
+ }
+ }
+
+ #[inline]
+ pub unsafe fn try_write(&self) -> bool {
+ self.mode.compare_exchange(0, -1, SeqCst, SeqCst).is_ok()
+ }
+
+ #[inline]
+ pub unsafe fn read_unlock(&self) {
+ self.mode.fetch_sub(1, SeqCst);
+ }
+
+ #[inline]
+ pub unsafe fn write_unlock(&self) {
+ assert_eq!(self.mode.compare_exchange(-1, 0, SeqCst, SeqCst), Ok(-1));
+ }
+}
diff --git a/library/std/src/sys/xous/mod.rs b/library/std/src/sys/xous/mod.rs
new file mode 100644
index 000000000..6d5c218d1
--- /dev/null
+++ b/library/std/src/sys/xous/mod.rs
@@ -0,0 +1,37 @@
+#![deny(unsafe_op_in_unsafe_fn)]
+
+pub mod alloc;
+#[path = "../unsupported/args.rs"]
+pub mod args;
+#[path = "../unix/cmath.rs"]
+pub mod cmath;
+#[path = "../unsupported/env.rs"]
+pub mod env;
+#[path = "../unsupported/fs.rs"]
+pub mod fs;
+#[path = "../unsupported/io.rs"]
+pub mod io;
+pub mod locks;
+#[path = "../unsupported/net.rs"]
+pub mod net;
+#[path = "../unsupported/once.rs"]
+pub mod once;
+pub mod os;
+#[path = "../unix/os_str.rs"]
+pub mod os_str;
+#[path = "../unix/path.rs"]
+pub mod path;
+#[path = "../unsupported/pipe.rs"]
+pub mod pipe;
+#[path = "../unsupported/process.rs"]
+pub mod process;
+pub mod stdio;
+pub mod thread;
+pub mod thread_local_key;
+#[path = "../unsupported/thread_parking.rs"]
+pub mod thread_parking;
+pub mod time;
+
+#[path = "../unsupported/common.rs"]
+mod common;
+pub use common::*;
diff --git a/library/std/src/sys/xous/os.rs b/library/std/src/sys/xous/os.rs
new file mode 100644
index 000000000..3d19fa4b3
--- /dev/null
+++ b/library/std/src/sys/xous/os.rs
@@ -0,0 +1,147 @@
+use super::unsupported;
+use crate::error::Error as StdError;
+use crate::ffi::{OsStr, OsString};
+use crate::fmt;
+use crate::io;
+use crate::marker::PhantomData;
+use crate::os::xous::ffi::Error as XousError;
+use crate::path::{self, PathBuf};
+
+#[cfg(not(test))]
+mod c_compat {
+ use crate::os::xous::ffi::exit;
+ extern "C" {
+ fn main() -> u32;
+ }
+
+ #[no_mangle]
+ pub extern "C" fn abort() {
+ exit(1);
+ }
+
+ #[no_mangle]
+ pub extern "C" fn _start() {
+ exit(unsafe { main() });
+ }
+
+ // This function is needed by the panic runtime. The symbol is named in
+ // pre-link args for the target specification, so keep that in sync.
+ #[no_mangle]
+ // NB. used by both libunwind and libpanic_abort
+ pub extern "C" fn __rust_abort() -> ! {
+ exit(101);
+ }
+}
+
+pub fn errno() -> i32 {
+ 0
+}
+
+pub fn error_string(errno: i32) -> String {
+ Into::<XousError>::into(errno).to_string()
+}
+
+pub fn getcwd() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub fn chdir(_: &path::Path) -> io::Result<()> {
+ unsupported()
+}
+
+pub struct SplitPaths<'a>(!, PhantomData<&'a ()>);
+
+pub fn split_paths(_unparsed: &OsStr) -> SplitPaths<'_> {
+ panic!("unsupported")
+}
+
+impl<'a> Iterator for SplitPaths<'a> {
+ type Item = PathBuf;
+ fn next(&mut self) -> Option<PathBuf> {
+ self.0
+ }
+}
+
+#[derive(Debug)]
+pub struct JoinPathsError;
+
+pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
+where
+ I: Iterator<Item = T>,
+ T: AsRef<OsStr>,
+{
+ Err(JoinPathsError)
+}
+
+impl fmt::Display for JoinPathsError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ "not supported on this platform yet".fmt(f)
+ }
+}
+
+impl StdError for JoinPathsError {
+ #[allow(deprecated)]
+ fn description(&self) -> &str {
+ "not supported on this platform yet"
+ }
+}
+
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub struct Env(!);
+
+impl Env {
+ // FIXME(https://github.com/rust-lang/rust/issues/114583): Remove this when <OsStr as Debug>::fmt matches <str as Debug>::fmt.
+ pub fn str_debug(&self) -> impl fmt::Debug + '_ {
+ let Self(inner) = self;
+ match *inner {}
+ }
+}
+
+impl fmt::Debug for Env {
+ fn fmt(&self, _: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let Self(inner) = self;
+ match *inner {}
+ }
+}
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> {
+ self.0
+ }
+}
+
+pub fn env() -> Env {
+ panic!("not supported on this platform")
+}
+
+pub fn getenv(_: &OsStr) -> Option<OsString> {
+ None
+}
+
+pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot set env vars on this platform"))
+}
+
+pub fn unsetenv(_: &OsStr) -> io::Result<()> {
+ Err(io::const_io_error!(io::ErrorKind::Unsupported, "cannot unset env vars on this platform"))
+}
+
+pub fn temp_dir() -> PathBuf {
+ panic!("no filesystem on this platform")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ None
+}
+
+pub fn exit(code: i32) -> ! {
+ crate::os::xous::ffi::exit(code as u32);
+}
+
+pub fn getpid() -> u32 {
+ panic!("no pids on this platform")
+}
diff --git a/library/std/src/sys/xous/stdio.rs b/library/std/src/sys/xous/stdio.rs
new file mode 100644
index 000000000..2ac694641
--- /dev/null
+++ b/library/std/src/sys/xous/stdio.rs
@@ -0,0 +1,131 @@
+use crate::io;
+
+pub struct Stdin;
+pub struct Stdout {}
+pub struct Stderr;
+
+use crate::os::xous::ffi::{lend, try_lend, try_scalar, Connection};
+use crate::os::xous::services::{log_server, try_connect, LogScalar};
+
+impl Stdin {
+ pub const fn new() -> Stdin {
+ Stdin
+ }
+}
+
+impl io::Read for Stdin {
+ fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
+ Ok(0)
+ }
+}
+
+impl Stdout {
+ pub const fn new() -> Stdout {
+ Stdout {}
+ }
+}
+
+impl io::Write for Stdout {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ #[repr(align(4096))]
+ struct LendBuffer([u8; 4096]);
+ let mut lend_buffer = LendBuffer([0u8; 4096]);
+ let connection = log_server();
+ for chunk in buf.chunks(lend_buffer.0.len()) {
+ for (dest, src) in lend_buffer.0.iter_mut().zip(chunk) {
+ *dest = *src;
+ }
+ lend(connection, 1, &lend_buffer.0, 0, chunk.len()).unwrap();
+ }
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+impl Stderr {
+ pub const fn new() -> Stderr {
+ Stderr
+ }
+}
+
+impl io::Write for Stderr {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ #[repr(align(4096))]
+ struct LendBuffer([u8; 4096]);
+ let mut lend_buffer = LendBuffer([0u8; 4096]);
+ let connection = log_server();
+ for chunk in buf.chunks(lend_buffer.0.len()) {
+ for (dest, src) in lend_buffer.0.iter_mut().zip(chunk) {
+ *dest = *src;
+ }
+ lend(connection, 1, &lend_buffer.0, 0, chunk.len()).unwrap();
+ }
+ Ok(buf.len())
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+pub const STDIN_BUF_SIZE: usize = 0;
+
+pub fn is_ebadf(_err: &io::Error) -> bool {
+ true
+}
+
+#[derive(Copy, Clone)]
+pub struct PanicWriter {
+ log: Connection,
+ gfx: Option<Connection>,
+}
+
+impl io::Write for PanicWriter {
+ fn write(&mut self, s: &[u8]) -> core::result::Result<usize, io::Error> {
+ for c in s.chunks(core::mem::size_of::<usize>() * 4) {
+ // Text is grouped into 4x `usize` words. The id is 1100 plus
+ // the number of characters in this message.
+ // Ignore errors since we're already panicking.
+ try_scalar(self.log, LogScalar::AppendPanicMessage(&c).into()).ok();
+ }
+
+ // Serialize the text to the graphics panic handler, only if we were able
+ // to acquire a connection to it. Text length is encoded in the `valid` field,
+ // the data itself in the buffer. Typically several messages are require to
+ // fully transmit the entire panic message.
+ if let Some(gfx) = self.gfx {
+ #[repr(C, align(4096))]
+ struct Request([u8; 4096]);
+ let mut request = Request([0u8; 4096]);
+ for (&s, d) in s.iter().zip(request.0.iter_mut()) {
+ *d = s;
+ }
+ try_lend(gfx, 0 /* AppendPanicText */, &request.0, 0, s.len()).ok();
+ }
+ Ok(s.len())
+ }
+
+ // Tests show that this does not seem to be reliably called at the end of a panic
+ // print, so, we can't rely on this to e.g. trigger a graphics update.
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+pub fn panic_output() -> Option<impl io::Write> {
+ // Generally this won't fail because every server has already connected, so
+ // this is likely to succeed.
+ let log = log_server();
+
+ // Send the "We're panicking" message (1000).
+ try_scalar(log, LogScalar::BeginPanic.into()).ok();
+
+ // This is will fail in the case that the connection table is full, or if the
+ // graphics server is not running. Most servers do not already have this connection.
+ let gfx = try_connect("panic-to-screen!");
+
+ Some(PanicWriter { log, gfx })
+}
diff --git a/library/std/src/sys/xous/thread.rs b/library/std/src/sys/xous/thread.rs
new file mode 100644
index 000000000..78c68de7b
--- /dev/null
+++ b/library/std/src/sys/xous/thread.rs
@@ -0,0 +1,144 @@
+use crate::ffi::CStr;
+use crate::io;
+use crate::num::NonZeroUsize;
+use crate::os::xous::ffi::{
+ blocking_scalar, create_thread, do_yield, join_thread, map_memory, update_memory_flags,
+ MemoryFlags, Syscall, ThreadId,
+};
+use crate::os::xous::services::{ticktimer_server, TicktimerScalar};
+use crate::time::Duration;
+use core::arch::asm;
+
+pub struct Thread {
+ tid: ThreadId,
+}
+
+pub const DEFAULT_MIN_STACK_SIZE: usize = 131072;
+const MIN_STACK_SIZE: usize = 4096;
+pub const GUARD_PAGE_SIZE: usize = 4096;
+
+impl Thread {
+ // unsafe: see thread::Builder::spawn_unchecked for safety requirements
+ pub unsafe fn new(stack: usize, p: Box<dyn FnOnce()>) -> io::Result<Thread> {
+ let p = Box::into_raw(Box::new(p));
+ let mut stack_size = crate::cmp::max(stack, MIN_STACK_SIZE);
+
+ if (stack_size & 4095) != 0 {
+ stack_size = (stack_size + 4095) & !4095;
+ }
+
+ // Allocate the whole thing, then divide it up after the fact. This ensures that
+ // even if there's a context switch during this function, the whole stack plus
+ // guard pages will remain contiguous.
+ let stack_plus_guard_pages: &mut [u8] = unsafe {
+ map_memory(
+ None,
+ None,
+ GUARD_PAGE_SIZE + stack_size + GUARD_PAGE_SIZE,
+ MemoryFlags::R | MemoryFlags::W | MemoryFlags::X,
+ )
+ }
+ .map_err(|code| io::Error::from_raw_os_error(code as i32))?;
+
+ // No access to this page. Note: Write-only pages are illegal, and will
+ // cause an access violation.
+ unsafe {
+ update_memory_flags(&mut stack_plus_guard_pages[0..GUARD_PAGE_SIZE], MemoryFlags::W)
+ .map_err(|code| io::Error::from_raw_os_error(code as i32))?
+ };
+
+ // No access to this page. Note: Write-only pages are illegal, and will
+ // cause an access violation.
+ unsafe {
+ update_memory_flags(
+ &mut stack_plus_guard_pages[(GUARD_PAGE_SIZE + stack_size)..],
+ MemoryFlags::W,
+ )
+ .map_err(|code| io::Error::from_raw_os_error(code as i32))?
+ };
+
+ let guard_page_pre = stack_plus_guard_pages.as_ptr() as usize;
+ let tid = create_thread(
+ thread_start as *mut usize,
+ &mut stack_plus_guard_pages[GUARD_PAGE_SIZE..(stack_size + GUARD_PAGE_SIZE)],
+ p as usize,
+ guard_page_pre,
+ stack_size,
+ 0,
+ )
+ .map_err(|code| io::Error::from_raw_os_error(code as i32))?;
+
+ extern "C" fn thread_start(main: *mut usize, guard_page_pre: usize, stack_size: usize) {
+ unsafe {
+ // Finally, let's run some code.
+ Box::from_raw(main as *mut Box<dyn FnOnce()>)();
+ }
+
+ // Destroy TLS, which will free the TLS page and call the destructor for
+ // any thread local storage.
+ unsafe {
+ crate::sys::thread_local_key::destroy_tls();
+ }
+
+ // Deallocate the stack memory, along with the guard pages. Afterwards,
+ // exit the thread by returning to the magic address 0xff80_3000usize,
+ // which tells the kernel to deallocate this thread.
+ let mapped_memory_base = guard_page_pre;
+ let mapped_memory_length = GUARD_PAGE_SIZE + stack_size + GUARD_PAGE_SIZE;
+ unsafe {
+ asm!(
+ "ecall",
+ "ret",
+ in("a0") Syscall::UnmapMemory as usize,
+ in("a1") mapped_memory_base,
+ in("a2") mapped_memory_length,
+ in("ra") 0xff80_3000usize,
+ options(nomem, nostack, noreturn)
+ );
+ }
+ }
+
+ Ok(Thread { tid })
+ }
+
+ pub fn yield_now() {
+ do_yield();
+ }
+
+ pub fn set_name(_name: &CStr) {
+ // nope
+ }
+
+ pub fn sleep(dur: Duration) {
+ // Because the sleep server works on units of `usized milliseconds`, split
+ // the messages up into these chunks. This means we may run into issues
+ // if you try to sleep a thread for more than 49 days on a 32-bit system.
+ let mut millis = dur.as_millis();
+ while millis > 0 {
+ let sleep_duration =
+ if millis > (usize::MAX as _) { usize::MAX } else { millis as usize };
+ blocking_scalar(ticktimer_server(), TicktimerScalar::SleepMs(sleep_duration).into())
+ .expect("failed to send message to ticktimer server");
+ millis -= sleep_duration as u128;
+ }
+ }
+
+ pub fn join(self) {
+ join_thread(self.tid).unwrap();
+ }
+}
+
+pub fn available_parallelism() -> io::Result<NonZeroUsize> {
+ // We're unicore right now.
+ Ok(unsafe { NonZeroUsize::new_unchecked(1) })
+}
+
+pub mod guard {
+ pub type Guard = !;
+ pub unsafe fn current() -> Option<Guard> {
+ None
+ }
+ pub unsafe fn init() -> Option<Guard> {
+ None
+ }
+}
diff --git a/library/std/src/sys/xous/thread_local_key.rs b/library/std/src/sys/xous/thread_local_key.rs
new file mode 100644
index 000000000..3771ea657
--- /dev/null
+++ b/library/std/src/sys/xous/thread_local_key.rs
@@ -0,0 +1,190 @@
+use crate::mem::ManuallyDrop;
+use crate::ptr;
+use crate::sync::atomic::AtomicPtr;
+use crate::sync::atomic::AtomicUsize;
+use crate::sync::atomic::Ordering::SeqCst;
+use core::arch::asm;
+
+use crate::os::xous::ffi::{map_memory, unmap_memory, MemoryFlags};
+
+/// Thread Local Storage
+///
+/// Currently, we are limited to 1023 TLS entries. The entries
+/// live in a page of memory that's unique per-process, and is
+/// stored in the `$tp` register. If this register is 0, then
+/// TLS has not been initialized and thread cleanup can be skipped.
+///
+/// The index into this register is the `key`. This key is identical
+/// between all threads, but indexes a different offset within this
+/// pointer.
+pub type Key = usize;
+
+pub type Dtor = unsafe extern "C" fn(*mut u8);
+
+const TLS_MEMORY_SIZE: usize = 4096;
+
+/// TLS keys start at `1` to mimic POSIX.
+static TLS_KEY_INDEX: AtomicUsize = AtomicUsize::new(1);
+
+fn tls_ptr_addr() -> *mut usize {
+ let mut tp: usize;
+ unsafe {
+ asm!(
+ "mv {}, tp",
+ out(reg) tp,
+ );
+ }
+ core::ptr::from_exposed_addr_mut::<usize>(tp)
+}
+
+/// Create an area of memory that's unique per thread. This area will
+/// contain all thread local pointers.
+fn tls_ptr() -> *mut usize {
+ let mut tp = tls_ptr_addr();
+
+ // If the TP register is `0`, then this thread hasn't initialized
+ // its TLS yet. Allocate a new page to store this memory.
+ if tp.is_null() {
+ tp = unsafe {
+ map_memory(
+ None,
+ None,
+ TLS_MEMORY_SIZE / core::mem::size_of::<usize>(),
+ MemoryFlags::R | MemoryFlags::W,
+ )
+ }
+ .expect("Unable to allocate memory for thread local storage")
+ .as_mut_ptr();
+
+ unsafe {
+ // Key #0 is currently unused.
+ (tp).write_volatile(0);
+
+ // Set the thread's `$tp` register
+ asm!(
+ "mv tp, {}",
+ in(reg) tp as usize,
+ );
+ }
+ }
+ tp
+}
+
+/// Allocate a new TLS key. These keys are shared among all threads.
+fn tls_alloc() -> usize {
+ TLS_KEY_INDEX.fetch_add(1, SeqCst)
+}
+
+#[inline]
+pub unsafe fn create(dtor: Option<Dtor>) -> Key {
+ let key = tls_alloc();
+ if let Some(f) = dtor {
+ unsafe { register_dtor(key, f) };
+ }
+ key
+}
+
+#[inline]
+pub unsafe fn set(key: Key, value: *mut u8) {
+ assert!((key < 1022) && (key >= 1));
+ unsafe { tls_ptr().add(key).write_volatile(value as usize) };
+}
+
+#[inline]
+pub unsafe fn get(key: Key) -> *mut u8 {
+ assert!((key < 1022) && (key >= 1));
+ core::ptr::from_exposed_addr_mut::<u8>(unsafe { tls_ptr().add(key).read_volatile() })
+}
+
+#[inline]
+pub unsafe fn destroy(_key: Key) {
+ panic!("can't destroy keys on Xous");
+}
+
+// -------------------------------------------------------------------------
+// Dtor registration (stolen from Windows)
+//
+// Xous has no native support for running destructors so we manage our own
+// list of destructors to keep track of how to destroy keys. We then install a
+// callback later to get invoked whenever a thread exits, running all
+// appropriate destructors.
+//
+// Currently unregistration from this list is not supported. A destructor can be
+// registered but cannot be unregistered. There's various simplifying reasons
+// for doing this, the big ones being:
+//
+// 1. Currently we don't even support deallocating TLS keys, so normal operation
+// doesn't need to deallocate a destructor.
+// 2. There is no point in time where we know we can unregister a destructor
+// because it could always be getting run by some remote thread.
+//
+// Typically processes have a statically known set of TLS keys which is pretty
+// small, and we'd want to keep this memory alive for the whole process anyway
+// really.
+//
+// Perhaps one day we can fold the `Box` here into a static allocation,
+// expanding the `StaticKey` structure to contain not only a slot for the TLS
+// key but also a slot for the destructor queue on windows. An optimization for
+// another day!
+
+static DTORS: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut());
+
+struct Node {
+ dtor: Dtor,
+ key: Key,
+ next: *mut Node,
+}
+
+unsafe fn register_dtor(key: Key, dtor: Dtor) {
+ let mut node = ManuallyDrop::new(Box::new(Node { key, dtor, next: ptr::null_mut() }));
+
+ let mut head = DTORS.load(SeqCst);
+ loop {
+ node.next = head;
+ match DTORS.compare_exchange(head, &mut **node, SeqCst, SeqCst) {
+ Ok(_) => return, // nothing to drop, we successfully added the node to the list
+ Err(cur) => head = cur,
+ }
+ }
+}
+
+pub unsafe fn destroy_tls() {
+ let tp = tls_ptr_addr();
+
+ // If the pointer address is 0, then this thread has no TLS.
+ if tp.is_null() {
+ return;
+ }
+ unsafe { run_dtors() };
+
+ // Finally, free the TLS array
+ unsafe {
+ unmap_memory(core::slice::from_raw_parts_mut(
+ tp,
+ TLS_MEMORY_SIZE / core::mem::size_of::<usize>(),
+ ))
+ .unwrap()
+ };
+}
+
+unsafe fn run_dtors() {
+ let mut any_run = true;
+ for _ in 0..5 {
+ if !any_run {
+ break;
+ }
+ any_run = false;
+ let mut cur = DTORS.load(SeqCst);
+ while !cur.is_null() {
+ let ptr = unsafe { get((*cur).key) };
+
+ if !ptr.is_null() {
+ unsafe { set((*cur).key, ptr::null_mut()) };
+ unsafe { ((*cur).dtor)(ptr as *mut _) };
+ any_run = true;
+ }
+
+ unsafe { cur = (*cur).next };
+ }
+ }
+}
diff --git a/library/std/src/sys/xous/time.rs b/library/std/src/sys/xous/time.rs
new file mode 100644
index 000000000..4e4ae67ef
--- /dev/null
+++ b/library/std/src/sys/xous/time.rs
@@ -0,0 +1,57 @@
+use crate::os::xous::ffi::blocking_scalar;
+use crate::os::xous::services::{
+ systime_server, ticktimer_server, SystimeScalar::GetUtcTimeMs, TicktimerScalar::ElapsedMs,
+};
+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 {
+ let result = blocking_scalar(ticktimer_server(), ElapsedMs.into())
+ .expect("failed to request elapsed_ms");
+ let lower = result[0];
+ let upper = result[1];
+ Instant { 0: Duration::from_millis(lower as u64 | (upper as u64) << 32) }
+ }
+
+ 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> {
+ self.0.checked_add(*other).map(Instant)
+ }
+
+ pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
+ self.0.checked_sub(*other).map(Instant)
+ }
+}
+
+impl SystemTime {
+ pub fn now() -> SystemTime {
+ let result = blocking_scalar(systime_server(), GetUtcTimeMs.into())
+ .expect("failed to request utc time in ms");
+ let lower = result[0];
+ let upper = result[1];
+ SystemTime { 0: Duration::from_millis((upper as u64) << 32 | lower as u64) }
+ }
+
+ 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)?))
+ }
+}