summaryrefslogtreecommitdiffstats
path: root/library/std
diff options
context:
space:
mode:
Diffstat (limited to 'library/std')
-rw-r--r--library/std/Cargo.toml10
-rw-r--r--library/std/build.rs4
-rw-r--r--library/std/primitive_docs/box_into_raw.md1
-rw-r--r--library/std/primitive_docs/fs_file.md1
-rw-r--r--library/std/primitive_docs/io_bufread.md1
-rw-r--r--library/std/primitive_docs/io_read.md1
-rw-r--r--library/std/primitive_docs/io_seek.md1
-rw-r--r--library/std/primitive_docs/io_write.md1
-rw-r--r--library/std/primitive_docs/net_tosocketaddrs.md1
-rw-r--r--library/std/primitive_docs/process_exit.md1
-rw-r--r--library/std/primitive_docs/string_string.md1
-rw-r--r--library/std/src/alloc.rs26
-rw-r--r--library/std/src/f32.rs5
-rw-r--r--library/std/src/f64.rs5
-rw-r--r--library/std/src/ffi/mod.rs4
-rw-r--r--library/std/src/ffi/os_str.rs68
-rw-r--r--library/std/src/fs.rs17
-rw-r--r--library/std/src/io/buffered/bufwriter.rs2
-rw-r--r--library/std/src/io/copy.rs51
-rw-r--r--library/std/src/io/copy/tests.rs12
-rw-r--r--library/std/src/io/error.rs25
-rw-r--r--library/std/src/io/error/repr_bitpacked.rs3
-rw-r--r--library/std/src/io/mod.rs99
-rw-r--r--library/std/src/keyword_docs.rs10
-rw-r--r--library/std/src/lib.rs37
-rw-r--r--library/std/src/macros.rs12
-rw-r--r--library/std/src/net/tcp.rs2
-rw-r--r--library/std/src/net/udp.rs2
-rw-r--r--library/std/src/num.rs2
-rw-r--r--library/std/src/os/fd/owned.rs12
-rw-r--r--library/std/src/os/fd/raw.rs5
-rw-r--r--library/std/src/os/fortanix_sgx/io.rs23
-rw-r--r--library/std/src/os/hurd/fs.rs348
-rw-r--r--library/std/src/os/hurd/mod.rs6
-rw-r--r--library/std/src/os/hurd/raw.rs33
-rw-r--r--library/std/src/os/mod.rs6
-rw-r--r--library/std/src/os/solid/io.rs22
-rw-r--r--library/std/src/os/uefi/env.rs92
-rw-r--r--library/std/src/os/uefi/mod.rs8
-rw-r--r--library/std/src/os/unix/fs.rs6
-rw-r--r--library/std/src/os/unix/io/mod.rs16
-rw-r--r--library/std/src/os/unix/mod.rs2
-rw-r--r--library/std/src/os/unix/net/tests.rs2
-rw-r--r--library/std/src/os/unix/process.rs42
-rw-r--r--library/std/src/os/wasi/fs.rs4
-rw-r--r--library/std/src/os/windows/io/mod.rs10
-rw-r--r--library/std/src/os/windows/io/raw.rs6
-rw-r--r--library/std/src/os/windows/io/socket.rs8
-rw-r--r--library/std/src/os/windows/process.rs108
-rw-r--r--library/std/src/os/xous/ffi.rs647
-rw-r--r--library/std/src/os/xous/ffi/definitions.rs283
-rw-r--r--library/std/src/os/xous/ffi/definitions/memoryflags.rs176
-rw-r--r--library/std/src/os/xous/mod.rs17
-rw-r--r--library/std/src/os/xous/services.rs132
-rw-r--r--library/std/src/os/xous/services/log.rs63
-rw-r--r--library/std/src/os/xous/services/systime.rs28
-rw-r--r--library/std/src/os/xous/services/ticktimer.rs42
-rw-r--r--library/std/src/panicking.rs74
-rw-r--r--library/std/src/path.rs34
-rw-r--r--library/std/src/primitive_docs.rs1593
-rw-r--r--library/std/src/process.rs210
-rw-r--r--library/std/src/process/tests.rs132
-rw-r--r--library/std/src/sync/mpsc/mod.rs15
-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
-rw-r--r--library/std/src/sys_common/mod.rs2
-rw-r--r--library/std/src/sys_common/net.rs1
-rw-r--r--library/std/src/sys_common/process.rs4
-rw-r--r--library/std/src/sys_common/thread_info.rs37
-rw-r--r--library/std/src/thread/mod.rs82
-rw-r--r--library/std/src/time.rs26
-rw-r--r--library/std/tests/env.rs20
133 files changed, 5229 insertions, 2179 deletions
diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml
index 33c9c6e63..965132bde 100644
--- a/library/std/Cargo.toml
+++ b/library/std/Cargo.toml
@@ -17,7 +17,7 @@ cfg-if = { version = "1.0", features = ['rustc-dep-of-std'] }
panic_unwind = { path = "../panic_unwind", optional = true }
panic_abort = { path = "../panic_abort" }
core = { path = "../core", public = true }
-libc = { version = "0.2.146", default-features = false, features = ['rustc-dep-of-std'], public = true }
+libc = { version = "0.2.148", default-features = false, features = ['rustc-dep-of-std'], public = true }
compiler_builtins = { version = "0.1.100" }
profiler_builtins = { path = "../profiler_builtins", optional = true }
unwind = { path = "../unwind" }
@@ -36,8 +36,8 @@ object = { version = "0.32.0", default-features = false, optional = true, featur
rand = { version = "0.8.5", default-features = false, features = ["alloc"] }
rand_xorshift = "0.3.0"
-[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
-dlmalloc = { version = "0.2.3", features = ['rustc-dep-of-std'] }
+[target.'cfg(any(all(target_family = "wasm", target_os = "unknown"), target_os = "xous", all(target_vendor = "fortanix", target_env = "sgx")))'.dependencies]
+dlmalloc = { version = "0.2.4", features = ['rustc-dep-of-std'] }
[target.x86_64-fortanix-unknown-sgx.dependencies]
fortanix-sgx-abi = { version = "0.5.0", features = ['rustc-dep-of-std'], public = true }
@@ -48,6 +48,10 @@ hermit-abi = { version = "0.3.2", features = ['rustc-dep-of-std'], public = true
[target.'cfg(target_os = "wasi")'.dependencies]
wasi = { version = "0.11.0", features = ['rustc-dep-of-std'], default-features = false }
+[target.'cfg(target_os = "uefi")'.dependencies]
+r-efi = { version = "4.2.0", features = ['rustc-dep-of-std']}
+r-efi-alloc = { version = "1.0.0", features = ['rustc-dep-of-std']}
+
[features]
backtrace = [
"gimli-symbolize",
diff --git a/library/std/build.rs b/library/std/build.rs
index ddf6e84d8..36516978b 100644
--- a/library/std/build.rs
+++ b/library/std/build.rs
@@ -37,6 +37,9 @@ fn main() {
|| target.contains("nintendo-3ds")
|| target.contains("vita")
|| target.contains("nto")
+ || target.contains("xous")
+ || target.contains("hurd")
+ || target.contains("uefi")
// See src/bootstrap/synthetic_targets.rs
|| env::var("RUSTC_BOOTSTRAP_SYNTHETIC_TARGET").is_ok()
{
@@ -49,7 +52,6 @@ fn main() {
// - mipsel-sony-psp
// - nvptx64-nvidia-cuda
// - arch=avr
- // - uefi (x86_64-unknown-uefi, i686-unknown-uefi)
// - JSON targets
// - Any new targets that have not been explicitly added above.
println!("cargo:rustc-cfg=feature=\"restricted-std\"");
diff --git a/library/std/primitive_docs/box_into_raw.md b/library/std/primitive_docs/box_into_raw.md
deleted file mode 100644
index 307b9c85b..000000000
--- a/library/std/primitive_docs/box_into_raw.md
+++ /dev/null
@@ -1 +0,0 @@
-Box::into_raw
diff --git a/library/std/primitive_docs/fs_file.md b/library/std/primitive_docs/fs_file.md
deleted file mode 100644
index 13e454083..000000000
--- a/library/std/primitive_docs/fs_file.md
+++ /dev/null
@@ -1 +0,0 @@
-fs::File
diff --git a/library/std/primitive_docs/io_bufread.md b/library/std/primitive_docs/io_bufread.md
deleted file mode 100644
index bb688e3a5..000000000
--- a/library/std/primitive_docs/io_bufread.md
+++ /dev/null
@@ -1 +0,0 @@
-io::BufRead
diff --git a/library/std/primitive_docs/io_read.md b/library/std/primitive_docs/io_read.md
deleted file mode 100644
index 5118d7c48..000000000
--- a/library/std/primitive_docs/io_read.md
+++ /dev/null
@@ -1 +0,0 @@
-io::Read
diff --git a/library/std/primitive_docs/io_seek.md b/library/std/primitive_docs/io_seek.md
deleted file mode 100644
index 122e6df77..000000000
--- a/library/std/primitive_docs/io_seek.md
+++ /dev/null
@@ -1 +0,0 @@
-io::Seek
diff --git a/library/std/primitive_docs/io_write.md b/library/std/primitive_docs/io_write.md
deleted file mode 100644
index 15dfc907a..000000000
--- a/library/std/primitive_docs/io_write.md
+++ /dev/null
@@ -1 +0,0 @@
-io::Write
diff --git a/library/std/primitive_docs/net_tosocketaddrs.md b/library/std/primitive_docs/net_tosocketaddrs.md
deleted file mode 100644
index a01f318e8..000000000
--- a/library/std/primitive_docs/net_tosocketaddrs.md
+++ /dev/null
@@ -1 +0,0 @@
-net::ToSocketAddrs
diff --git a/library/std/primitive_docs/process_exit.md b/library/std/primitive_docs/process_exit.md
deleted file mode 100644
index 565a71375..000000000
--- a/library/std/primitive_docs/process_exit.md
+++ /dev/null
@@ -1 +0,0 @@
-process::exit
diff --git a/library/std/primitive_docs/string_string.md b/library/std/primitive_docs/string_string.md
deleted file mode 100644
index ce7815ff9..000000000
--- a/library/std/primitive_docs/string_string.md
+++ /dev/null
@@ -1 +0,0 @@
-string::String
diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs
index 1eae7fa6a..bb786bd59 100644
--- a/library/std/src/alloc.rs
+++ b/library/std/src/alloc.rs
@@ -290,15 +290,29 @@ static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
/// Registers a custom allocation error hook, replacing any that was previously registered.
///
-/// The allocation error hook is invoked when an infallible memory allocation fails, before
-/// the runtime aborts. The default hook prints a message to standard error,
-/// but this behavior can be customized with the [`set_alloc_error_hook`] and
-/// [`take_alloc_error_hook`] functions.
+/// The allocation error hook is invoked when an infallible memory allocation fails — that is,
+/// as a consequence of calling [`handle_alloc_error`] — before the runtime aborts.
///
-/// The hook is provided with a `Layout` struct which contains information
+/// The allocation error hook is a global resource. [`take_alloc_error_hook`] may be used to
+/// retrieve a previously registered hook and wrap or discard it.
+///
+/// # What the provided `hook` function should expect
+///
+/// The hook function is provided with a [`Layout`] struct which contains information
/// about the allocation that failed.
///
-/// The allocation error hook is a global resource.
+/// The hook function may choose to panic or abort; in the event that it returns normally, this
+/// will cause an immediate abort.
+///
+/// Since [`take_alloc_error_hook`] is a safe function that allows retrieving the hook, the hook
+/// function must be _sound_ to call even if no memory allocations were attempted.
+///
+/// # The default hook
+///
+/// The default hook, used if [`set_alloc_error_hook`] is never called, prints a message to
+/// standard error (and then returns, causing the runtime to abort the process).
+/// Compiler options may cause it to panic instead, and the default behavior may be changed
+/// to panicking in future versions of Rust.
///
/// # Examples
///
diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs
index a659b552f..c35061757 100644
--- a/library/std/src/f32.rs
+++ b/library/std/src/f32.rs
@@ -822,6 +822,7 @@ impl f32 {
///
/// assert!(abs_difference < 1e-10);
/// ```
+ #[doc(alias = "log1p")]
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -988,7 +989,9 @@ impl f32 {
unsafe { cmath::tgammaf(self) }
}
- /// Returns the natural logarithm of the gamma function.
+ /// Natural logarithm of the absolute value of the gamma function
+ ///
+ /// The integer part of the tuple indicates the sign of the gamma function.
///
/// # Examples
///
diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs
index 721e1fb75..e4b7bfeeb 100644
--- a/library/std/src/f64.rs
+++ b/library/std/src/f64.rs
@@ -822,6 +822,7 @@ impl f64 {
///
/// assert!(abs_difference < 1e-20);
/// ```
+ #[doc(alias = "log1p")]
#[rustc_allow_incoherent_impl]
#[must_use = "method returns a new number and does not mutate the original value"]
#[stable(feature = "rust1", since = "1.0.0")]
@@ -988,7 +989,9 @@ impl f64 {
unsafe { cmath::tgamma(self) }
}
- /// Returns the natural logarithm of the gamma function.
+ /// Natural logarithm of the absolute value of the gamma function
+ ///
+ /// The integer part of the tuple indicates the sign of the gamma function.
///
/// # Examples
///
diff --git a/library/std/src/ffi/mod.rs b/library/std/src/ffi/mod.rs
index ee9f6ed08..97e78d177 100644
--- a/library/std/src/ffi/mod.rs
+++ b/library/std/src/ffi/mod.rs
@@ -132,8 +132,8 @@
//! On all platforms, [`OsStr`] consists of a sequence of bytes that is encoded as a superset of
//! UTF-8; see [`OsString`] for more details on its encoding on different platforms.
//!
-//! For limited, inexpensive conversions from and to bytes, see [`OsStr::as_os_str_bytes`] and
-//! [`OsStr::from_os_str_bytes_unchecked`].
+//! For limited, inexpensive conversions from and to bytes, see [`OsStr::as_encoded_bytes`] and
+//! [`OsStr::from_encoded_bytes_unchecked`].
//!
//! [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
//! [Unicode code point]: https://www.unicode.org/glossary/#code_point
diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs
index 43cecb19b..fa9d48771 100644
--- a/library/std/src/ffi/os_str.rs
+++ b/library/std/src/ffi/os_str.rs
@@ -154,36 +154,34 @@ impl OsString {
/// # Safety
///
/// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of
- /// validated UTF-8 and bytes from [`OsStr::as_os_str_bytes`] from within the same rust version
+ /// validated UTF-8 and bytes from [`OsStr::as_encoded_bytes`] from within the same rust version
/// built for the same target platform. For example, reconstructing an `OsString` from bytes sent
/// over the network or stored in a file will likely violate these safety rules.
///
- /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_os_str_bytes`] can be
+ /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_encoded_bytes`] can be
/// split either immediately before or immediately after any valid non-empty UTF-8 substring.
///
/// # Example
///
/// ```
- /// #![feature(os_str_bytes)]
- ///
/// use std::ffi::OsStr;
///
/// let os_str = OsStr::new("Mary had a little lamb");
- /// let bytes = os_str.as_os_str_bytes();
+ /// let bytes = os_str.as_encoded_bytes();
/// let words = bytes.split(|b| *b == b' ');
/// let words: Vec<&OsStr> = words.map(|word| {
/// // SAFETY:
- /// // - Each `word` only contains content that originated from `OsStr::as_os_str_bytes`
+ /// // - Each `word` only contains content that originated from `OsStr::as_encoded_bytes`
/// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring
- /// unsafe { OsStr::from_os_str_bytes_unchecked(word) }
+ /// unsafe { OsStr::from_encoded_bytes_unchecked(word) }
/// }).collect();
/// ```
///
/// [conversions]: super#conversions
#[inline]
- #[unstable(feature = "os_str_bytes", issue = "111544")]
- pub unsafe fn from_os_str_bytes_unchecked(bytes: Vec<u8>) -> Self {
- OsString { inner: Buf::from_os_str_bytes_unchecked(bytes) }
+ #[stable(feature = "os_str_bytes", since = "1.74.0")]
+ pub unsafe fn from_encoded_bytes_unchecked(bytes: Vec<u8>) -> Self {
+ OsString { inner: Buf::from_encoded_bytes_unchecked(bytes) }
}
/// Converts to an [`OsStr`] slice.
@@ -205,7 +203,7 @@ impl OsString {
}
/// Converts the `OsString` into a byte slice. To convert the byte slice back into an
- /// `OsString`, use the [`OsStr::from_os_str_bytes_unchecked`] function.
+ /// `OsString`, use the [`OsStr::from_encoded_bytes_unchecked`] function.
///
/// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8.
/// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit
@@ -219,9 +217,9 @@ impl OsString {
///
/// [`std::ffi`]: crate::ffi
#[inline]
- #[unstable(feature = "os_str_bytes", issue = "111544")]
- pub fn into_os_str_bytes(self) -> Vec<u8> {
- self.inner.into_os_str_bytes()
+ #[stable(feature = "os_str_bytes", since = "1.74.0")]
+ pub fn into_encoded_bytes(self) -> Vec<u8> {
+ self.inner.into_encoded_bytes()
}
/// Converts the `OsString` into a [`String`] if it contains valid Unicode data.
@@ -745,36 +743,34 @@ impl OsStr {
/// # Safety
///
/// As the encoding is unspecified, callers must pass in bytes that originated as a mixture of
- /// validated UTF-8 and bytes from [`OsStr::as_os_str_bytes`] from within the same rust version
+ /// validated UTF-8 and bytes from [`OsStr::as_encoded_bytes`] from within the same rust version
/// built for the same target platform. For example, reconstructing an `OsStr` from bytes sent
/// over the network or stored in a file will likely violate these safety rules.
///
- /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_os_str_bytes`] can be
+ /// Due to the encoding being self-synchronizing, the bytes from [`OsStr::as_encoded_bytes`] can be
/// split either immediately before or immediately after any valid non-empty UTF-8 substring.
///
/// # Example
///
/// ```
- /// #![feature(os_str_bytes)]
- ///
/// use std::ffi::OsStr;
///
/// let os_str = OsStr::new("Mary had a little lamb");
- /// let bytes = os_str.as_os_str_bytes();
+ /// let bytes = os_str.as_encoded_bytes();
/// let words = bytes.split(|b| *b == b' ');
/// let words: Vec<&OsStr> = words.map(|word| {
/// // SAFETY:
- /// // - Each `word` only contains content that originated from `OsStr::as_os_str_bytes`
+ /// // - Each `word` only contains content that originated from `OsStr::as_encoded_bytes`
/// // - Only split with ASCII whitespace which is a non-empty UTF-8 substring
- /// unsafe { OsStr::from_os_str_bytes_unchecked(word) }
+ /// unsafe { OsStr::from_encoded_bytes_unchecked(word) }
/// }).collect();
/// ```
///
/// [conversions]: super#conversions
#[inline]
- #[unstable(feature = "os_str_bytes", issue = "111544")]
- pub unsafe fn from_os_str_bytes_unchecked(bytes: &[u8]) -> &Self {
- Self::from_inner(Slice::from_os_str_bytes_unchecked(bytes))
+ #[stable(feature = "os_str_bytes", since = "1.74.0")]
+ pub unsafe fn from_encoded_bytes_unchecked(bytes: &[u8]) -> &Self {
+ Self::from_inner(Slice::from_encoded_bytes_unchecked(bytes))
}
#[inline]
@@ -948,7 +944,7 @@ impl OsStr {
}
/// Converts an OS string slice to a byte slice. To convert the byte slice back into an OS
- /// string slice, use the [`OsStr::from_os_str_bytes_unchecked`] function.
+ /// string slice, use the [`OsStr::from_encoded_bytes_unchecked`] function.
///
/// The byte encoding is an unspecified, platform-specific, self-synchronizing superset of UTF-8.
/// By being a self-synchronizing superset of UTF-8, this encoding is also a superset of 7-bit
@@ -962,9 +958,9 @@ impl OsStr {
///
/// [`std::ffi`]: crate::ffi
#[inline]
- #[unstable(feature = "os_str_bytes", issue = "111544")]
- pub fn as_os_str_bytes(&self) -> &[u8] {
- self.inner.as_os_str_bytes()
+ #[stable(feature = "os_str_bytes", since = "1.74.0")]
+ pub fn as_encoded_bytes(&self) -> &[u8] {
+ self.inner.as_encoded_bytes()
}
/// Converts this string to its ASCII lower case equivalent in-place.
@@ -1270,7 +1266,7 @@ impl Default for &OsStr {
impl PartialEq for OsStr {
#[inline]
fn eq(&self, other: &OsStr) -> bool {
- self.as_os_str_bytes().eq(other.as_os_str_bytes())
+ self.as_encoded_bytes().eq(other.as_encoded_bytes())
}
}
@@ -1297,23 +1293,23 @@ impl Eq for OsStr {}
impl PartialOrd for OsStr {
#[inline]
fn partial_cmp(&self, other: &OsStr) -> Option<cmp::Ordering> {
- self.as_os_str_bytes().partial_cmp(other.as_os_str_bytes())
+ self.as_encoded_bytes().partial_cmp(other.as_encoded_bytes())
}
#[inline]
fn lt(&self, other: &OsStr) -> bool {
- self.as_os_str_bytes().lt(other.as_os_str_bytes())
+ self.as_encoded_bytes().lt(other.as_encoded_bytes())
}
#[inline]
fn le(&self, other: &OsStr) -> bool {
- self.as_os_str_bytes().le(other.as_os_str_bytes())
+ self.as_encoded_bytes().le(other.as_encoded_bytes())
}
#[inline]
fn gt(&self, other: &OsStr) -> bool {
- self.as_os_str_bytes().gt(other.as_os_str_bytes())
+ self.as_encoded_bytes().gt(other.as_encoded_bytes())
}
#[inline]
fn ge(&self, other: &OsStr) -> bool {
- self.as_os_str_bytes().ge(other.as_os_str_bytes())
+ self.as_encoded_bytes().ge(other.as_encoded_bytes())
}
}
@@ -1332,7 +1328,7 @@ impl PartialOrd<str> for OsStr {
impl Ord for OsStr {
#[inline]
fn cmp(&self, other: &OsStr) -> cmp::Ordering {
- self.as_os_str_bytes().cmp(other.as_os_str_bytes())
+ self.as_encoded_bytes().cmp(other.as_encoded_bytes())
}
}
@@ -1382,7 +1378,7 @@ impl_cmp!(Cow<'a, OsStr>, OsString);
impl Hash for OsStr {
#[inline]
fn hash<H: Hasher>(&self, state: &mut H) {
- self.as_os_str_bytes().hash(state)
+ self.as_encoded_bytes().hash(state)
}
}
diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs
index 4094e3780..73cce35ac 100644
--- a/library/std/src/fs.rs
+++ b/library/std/src/fs.rs
@@ -8,7 +8,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![deny(unsafe_op_in_unsafe_fn)]
-#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))]
mod tests;
use crate::ffi::OsString;
@@ -233,8 +233,8 @@ pub struct DirBuilder {
/// This function will return an error if `path` does not already exist.
/// Other errors may also be returned according to [`OpenOptions::open`].
///
-/// It will also return an error if it encounters while reading an error
-/// of a kind other than [`io::ErrorKind::Interrupted`].
+/// While reading from the file, this function handles [`io::ErrorKind::Interrupted`]
+/// with automatic retries. See [io::Read] documentation for details.
///
/// # Examples
///
@@ -271,9 +271,11 @@ pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
/// This function will return an error if `path` does not already exist.
/// Other errors may also be returned according to [`OpenOptions::open`].
///
-/// It will also return an error if it encounters while reading an error
-/// of a kind other than [`io::ErrorKind::Interrupted`],
-/// or if the contents of the file are not valid UTF-8.
+/// If the contents of the file are not valid UTF-8, then an error will also be
+/// returned.
+///
+/// While reading from the file, this function handles [`io::ErrorKind::Interrupted`]
+/// with automatic retries. See [io::Read] documentation for details.
///
/// # Examples
///
@@ -745,14 +747,17 @@ fn buffer_capacity_required(mut file: &File) -> Option<usize> {
#[stable(feature = "rust1", since = "1.0.0")]
impl Read for &File {
+ #[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.inner.read(buf)
}
+ #[inline]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
self.inner.read_vectored(bufs)
}
+ #[inline]
fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
self.inner.read_buf(cursor)
}
diff --git a/library/std/src/io/buffered/bufwriter.rs b/library/std/src/io/buffered/bufwriter.rs
index 0f04f2911..95ba82e1e 100644
--- a/library/std/src/io/buffered/bufwriter.rs
+++ b/library/std/src/io/buffered/bufwriter.rs
@@ -237,7 +237,7 @@ impl<W: ?Sized + Write> BufWriter<W> {
));
}
Ok(n) => guard.consume(n),
- Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
diff --git a/library/std/src/io/copy.rs b/library/std/src/io/copy.rs
index 3322940d2..eafd078a7 100644
--- a/library/std/src/io/copy.rs
+++ b/library/std/src/io/copy.rs
@@ -1,6 +1,5 @@
-use super::{BorrowedBuf, BufReader, BufWriter, ErrorKind, Read, Result, Write, DEFAULT_BUF_SIZE};
+use super::{BorrowedBuf, BufReader, BufWriter, Read, Result, Write, DEFAULT_BUF_SIZE};
use crate::alloc::Allocator;
-use crate::cmp;
use crate::collections::VecDeque;
use crate::io::IoSlice;
use crate::mem::MaybeUninit;
@@ -30,6 +29,7 @@ mod tests;
///
/// [`read`]: Read::read
/// [`write`]: Write::write
+/// [`ErrorKind::Interrupted`]: crate::io::ErrorKind::Interrupted
///
/// # Examples
///
@@ -163,7 +163,7 @@ where
// from adding I: Read
match self.read(&mut []) {
Ok(_) => {}
- Err(e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(e) if e.is_interrupted() => continue,
Err(e) => return Err(e),
}
let buf = self.buffer();
@@ -243,7 +243,7 @@ impl<I: Write + ?Sized> BufferedWriterSpec for BufWriter<I> {
// Read again if the buffer still has enough capacity, as BufWriter itself would do
// This will occur if the reader returns short reads
}
- Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
} else {
@@ -254,47 +254,6 @@ impl<I: Write + ?Sized> BufferedWriterSpec for BufWriter<I> {
}
}
-impl<A: Allocator> BufferedWriterSpec for Vec<u8, A> {
- fn buffer_size(&self) -> usize {
- cmp::max(DEFAULT_BUF_SIZE, self.capacity() - self.len())
- }
-
- fn copy_from<R: Read + ?Sized>(&mut self, reader: &mut R) -> Result<u64> {
- let mut bytes = 0;
-
- // avoid allocating before we have determined that there's anything to read
- if self.capacity() == 0 {
- bytes = stack_buffer_copy(&mut reader.take(DEFAULT_BUF_SIZE as u64), self)?;
- if bytes == 0 {
- return Ok(0);
- }
- }
-
- loop {
- self.reserve(DEFAULT_BUF_SIZE);
- let mut buf: BorrowedBuf<'_> = self.spare_capacity_mut().into();
- match reader.read_buf(buf.unfilled()) {
- Ok(()) => {}
- Err(e) if e.kind() == ErrorKind::Interrupted => continue,
- Err(e) => return Err(e),
- };
-
- let read = buf.filled().len();
- if read == 0 {
- break;
- }
-
- // SAFETY: BorrowedBuf guarantees all of its filled bytes are init
- // and the number of read bytes can't exceed the spare capacity since
- // that's what the buffer is borrowing from.
- unsafe { self.set_len(self.len() + read) };
- bytes += read as u64;
- }
-
- Ok(bytes)
- }
-}
-
fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
reader: &mut R,
writer: &mut W,
@@ -307,7 +266,7 @@ fn stack_buffer_copy<R: Read + ?Sized, W: Write + ?Sized>(
loop {
match reader.read_buf(buf.unfilled()) {
Ok(()) => {}
- Err(e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(e) if e.is_interrupted() => continue,
Err(e) => return Err(e),
};
diff --git a/library/std/src/io/copy/tests.rs b/library/std/src/io/copy/tests.rs
index af137eaf8..d9998e87c 100644
--- a/library/std/src/io/copy/tests.rs
+++ b/library/std/src/io/copy/tests.rs
@@ -81,18 +81,6 @@ fn copy_specializes_bufreader() {
}
#[test]
-fn copy_specializes_to_vec() {
- let cap = 123456;
- let mut source = ShortReader { cap, observed_buffer: 0, read_size: 1337 };
- let mut sink = Vec::new();
- assert_eq!(cap as u64, io::copy(&mut source, &mut sink).unwrap());
- assert!(
- source.observed_buffer > DEFAULT_BUF_SIZE,
- "expected a large buffer to be provided to the reader"
- );
-}
-
-#[test]
fn copy_specializes_from_vecdeque() {
let mut source = VecDeque::with_capacity(100 * 1024);
for _ in 0..20 * 1024 {
diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs
index 34c0ce9dc..b63091dea 100644
--- a/library/std/src/io/error.rs
+++ b/library/std/src/io/error.rs
@@ -1,14 +1,14 @@
#[cfg(test)]
mod tests;
-#[cfg(target_pointer_width = "64")]
+#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
mod repr_bitpacked;
-#[cfg(target_pointer_width = "64")]
+#[cfg(all(target_pointer_width = "64", not(target_os = "uefi")))]
use repr_bitpacked::Repr;
-#[cfg(not(target_pointer_width = "64"))]
+#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
mod repr_unpacked;
-#[cfg(not(target_pointer_width = "64"))]
+#[cfg(any(not(target_pointer_width = "64"), target_os = "uefi"))]
use repr_unpacked::Repr;
use crate::error;
@@ -102,7 +102,7 @@ enum ErrorData<C> {
///
/// [`into`]: Into::into
#[unstable(feature = "raw_os_error_ty", issue = "107792")]
-pub type RawOsError = i32;
+pub type RawOsError = sys::RawOsError;
// `#[repr(align(4))]` is probably redundant, it should have that value or
// higher already. We include it just because repr_bitpacked.rs's encoding
@@ -511,6 +511,7 @@ impl Error {
/// let eof_error = Error::from(ErrorKind::UnexpectedEof);
/// ```
#[stable(feature = "rust1", since = "1.0.0")]
+ #[inline(never)]
pub fn new<E>(kind: ErrorKind, error: E) -> Error
where
E: Into<Box<dyn error::Error + Send + Sync>>,
@@ -527,8 +528,6 @@ impl Error {
/// # Examples
///
/// ```
- /// #![feature(io_error_other)]
- ///
/// use std::io::Error;
///
/// // errors can be created from strings
@@ -537,7 +536,7 @@ impl Error {
/// // errors can also be created from other errors
/// let custom_error2 = Error::other(custom_error);
/// ```
- #[unstable(feature = "io_error_other", issue = "91946")]
+ #[stable(feature = "io_error_other", since = "1.74.0")]
pub fn other<E>(error: E) -> Error
where
E: Into<Box<dyn error::Error + Send + Sync>>,
@@ -916,6 +915,16 @@ impl Error {
ErrorData::SimpleMessage(m) => m.kind,
}
}
+
+ #[inline]
+ pub(crate) fn is_interrupted(&self) -> bool {
+ match self.repr.data() {
+ ErrorData::Os(code) => sys::is_interrupted(code),
+ ErrorData::Custom(c) => c.kind == ErrorKind::Interrupted,
+ ErrorData::Simple(kind) => kind == ErrorKind::Interrupted,
+ ErrorData::SimpleMessage(m) => m.kind == ErrorKind::Interrupted,
+ }
+ }
}
impl fmt::Debug for Repr {
diff --git a/library/std/src/io/error/repr_bitpacked.rs b/library/std/src/io/error/repr_bitpacked.rs
index f94f88bac..6e7366b36 100644
--- a/library/std/src/io/error/repr_bitpacked.rs
+++ b/library/std/src/io/error/repr_bitpacked.rs
@@ -374,9 +374,6 @@ static_assert!((TAG_MASK + 1).is_power_of_two());
static_assert!(align_of::<SimpleMessage>() >= TAG_MASK + 1);
static_assert!(align_of::<Custom>() >= TAG_MASK + 1);
-// `RawOsError` must be an alias for `i32`.
-const _: fn(RawOsError) -> i32 = |os| os;
-
static_assert!(@usize_eq: TAG_MASK & TAG_SIMPLE_MESSAGE, TAG_SIMPLE_MESSAGE);
static_assert!(@usize_eq: TAG_MASK & TAG_CUSTOM, TAG_CUSTOM);
static_assert!(@usize_eq: TAG_MASK & TAG_OS, TAG_OS);
diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs
index 71d91f213..604b795cd 100644
--- a/library/std/src/io/mod.rs
+++ b/library/std/src/io/mod.rs
@@ -5,7 +5,7 @@
//! the [`Read`] and [`Write`] traits, which provide the
//! most general interface for reading and writing input and output.
//!
-//! # Read and Write
+//! ## Read and Write
//!
//! Because they are traits, [`Read`] and [`Write`] are implemented by a number
//! of other types, and you can implement them for your types too. As such,
@@ -238,6 +238,47 @@
//! contract. The implementation of many of these functions are subject to change over
//! time and may call fewer or more syscalls/library functions.
//!
+//! ## I/O Safety
+//!
+//! Rust follows an I/O safety discipline that is comparable to its memory safety discipline. This
+//! means that file descriptors can be *exclusively owned*. (Here, "file descriptor" is meant to
+//! subsume similar concepts that exist across a wide range of operating systems even if they might
+//! use a different name, such as "handle".) An exclusively owned file descriptor is one that no
+//! other code is allowed to access in any way, but the owner is allowed to access and even close
+//! it any time. A type that owns its file descriptor should usually close it in its `drop`
+//! function. Types like [`File`] own their file descriptor. Similarly, file descriptors
+//! can be *borrowed*, granting the temporary right to perform operations on this file descriptor.
+//! This indicates that the file descriptor will not be closed for the lifetime of the borrow, but
+//! it does *not* imply any right to close this file descriptor, since it will likely be owned by
+//! someone else.
+//!
+//! The platform-specific parts of the Rust standard library expose types that reflect these
+//! concepts, see [`os::unix`] and [`os::windows`].
+//!
+//! To uphold I/O safety, it is crucial that no code acts on file descriptors it does not own or
+//! borrow, and no code closes file descriptors it does not own. In other words, a safe function
+//! that takes a regular integer, treats it as a file descriptor, and acts on it, is *unsound*.
+//!
+//! Not upholding I/O safety and acting on a file descriptor without proof of ownership can lead to
+//! misbehavior and even Undefined Behavior in code that relies on ownership of its file
+//! descriptors: a closed file descriptor could be re-allocated, so the original owner of that file
+//! descriptor is now working on the wrong file. Some code might even rely on fully encapsulating
+//! its file descriptors with no operations being performed by any other part of the program.
+//!
+//! Note that exclusive ownership of a file descriptor does *not* imply exclusive ownership of the
+//! underlying kernel object that the file descriptor references (also called "file description" on
+//! some operating systems). File descriptors basically work like [`Arc`]: when you receive an owned
+//! file descriptor, you cannot know whether there are any other file descriptors that reference the
+//! same kernel object. However, when you create a new kernel object, you know that you are holding
+//! the only reference to it. Just be careful not to lend it to anyone, since they can obtain a
+//! clone and then you can no longer know what the reference count is! In that sense, [`OwnedFd`] is
+//! like `Arc` and [`BorrowedFd<'a>`] is like `&'a Arc` (and similar for the Windows types). In
+//! particular, given a `BorrowedFd<'a>`, you are not allowed to close the file descriptor -- just
+//! like how, given a `&'a Arc`, you are not allowed to decrement the reference count and
+//! potentially free the underlying object. There is no equivalent to `Box` for file descriptors in
+//! the standard library (that would be a type that guarantees that the reference count is `1`),
+//! however, it would be possible for a crate to define a type with those semantics.
+//!
//! [`File`]: crate::fs::File
//! [`TcpStream`]: crate::net::TcpStream
//! [`io::stdout`]: stdout
@@ -245,6 +286,11 @@
//! [`?` operator]: ../../book/appendix-02-operators.html
//! [`Result`]: crate::result::Result
//! [`.unwrap()`]: crate::result::Result::unwrap
+//! [`os::unix`]: ../os/unix/io/index.html
+//! [`os::windows`]: ../os/windows/io/index.html
+//! [`OwnedFd`]: ../os/fd/struct.OwnedFd.html
+//! [`BorrowedFd<'a>`]: ../os/fd/struct.BorrowedFd.html
+//! [`Arc`]: crate::sync::Arc
#![stable(feature = "rust1", since = "1.0.0")]
@@ -390,7 +436,7 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
let mut cursor = read_buf.unfilled();
match r.read_buf(cursor.reborrow()) {
Ok(()) => {}
- Err(e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(e) if e.is_interrupted() => continue,
Err(e) => return Err(e),
}
@@ -421,7 +467,7 @@ pub(crate) fn default_read_to_end<R: Read + ?Sized>(
buf.extend_from_slice(&probe[..n]);
break;
}
- Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(ref e) if e.is_interrupted() => continue,
Err(e) => return Err(e),
}
}
@@ -470,7 +516,7 @@ pub(crate) fn default_read_exact<R: Read + ?Sized>(this: &mut R, mut buf: &mut [
let tmp = buf;
buf = &mut tmp[n..];
}
- Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
@@ -860,7 +906,7 @@ pub trait Read {
let prev_written = cursor.written();
match self.read_buf(cursor.reborrow()) {
Ok(()) => {}
- Err(e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(e) if e.is_interrupted() => continue,
Err(e) => return Err(e),
}
@@ -1190,22 +1236,22 @@ impl<'a> IoSliceMut<'a> {
pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) {
// Number of buffers to remove.
let mut remove = 0;
- // Total length of all the to be removed buffers.
- let mut accumulated_len = 0;
+ // Remaining length before reaching n.
+ let mut left = n;
for buf in bufs.iter() {
- if accumulated_len + buf.len() > n {
- break;
- } else {
- accumulated_len += buf.len();
+ if let Some(remainder) = left.checked_sub(buf.len()) {
+ left = remainder;
remove += 1;
+ } else {
+ break;
}
}
*bufs = &mut take(bufs)[remove..];
if bufs.is_empty() {
- assert!(n == accumulated_len, "advancing io slices beyond their length");
+ assert!(left == 0, "advancing io slices beyond their length");
} else {
- bufs[0].advance(n - accumulated_len)
+ bufs[0].advance(left);
}
}
}
@@ -1333,22 +1379,25 @@ impl<'a> IoSlice<'a> {
pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) {
// Number of buffers to remove.
let mut remove = 0;
- // Total length of all the to be removed buffers.
- let mut accumulated_len = 0;
+ // Remaining length before reaching n. This prevents overflow
+ // that could happen if the length of slices in `bufs` were instead
+ // accumulated. Those slice may be aliased and, if they are large
+ // enough, their added length may overflow a `usize`.
+ let mut left = n;
for buf in bufs.iter() {
- if accumulated_len + buf.len() > n {
- break;
- } else {
- accumulated_len += buf.len();
+ if let Some(remainder) = left.checked_sub(buf.len()) {
+ left = remainder;
remove += 1;
+ } else {
+ break;
}
}
*bufs = &mut take(bufs)[remove..];
if bufs.is_empty() {
- assert!(n == accumulated_len, "advancing io slices beyond their length");
+ assert!(left == 0, "advancing io slices beyond their length");
} else {
- bufs[0].advance(n - accumulated_len)
+ bufs[0].advance(left);
}
}
}
@@ -1579,7 +1628,7 @@ pub trait Write {
));
}
Ok(n) => buf = &buf[n..],
- Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
@@ -1647,7 +1696,7 @@ pub trait Write {
));
}
Ok(n) => IoSlice::advance_slices(&mut bufs, n),
- Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
@@ -1943,7 +1992,7 @@ fn read_until<R: BufRead + ?Sized>(r: &mut R, delim: u8, buf: &mut Vec<u8>) -> R
let (done, used) = {
let available = match r.fill_buf() {
Ok(n) => n,
- Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(ref e) if e.is_interrupted() => continue,
Err(e) => return Err(e),
};
match memchr::memchr(delim, available) {
@@ -2734,7 +2783,7 @@ impl<R: Read> Iterator for Bytes<R> {
return match self.inner.read(slice::from_mut(&mut byte)) {
Ok(0) => None,
Ok(..) => Some(Ok(byte)),
- Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
+ Err(ref e) if e.is_interrupted() => continue,
Err(e) => Some(Err(e)),
};
}
diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs
index eb46f4e54..873bfb621 100644
--- a/library/std/src/keyword_docs.rs
+++ b/library/std/src/keyword_docs.rs
@@ -1820,7 +1820,7 @@ mod true_keyword {}
#[doc(keyword = "type")]
//
-/// Define an alias for an existing type.
+/// Define an [alias] for an existing type.
///
/// The syntax is `type Name = ExistingType;`.
///
@@ -1838,6 +1838,13 @@ mod true_keyword {}
/// assert_eq!(m, k);
/// ```
///
+/// A type can be generic:
+///
+/// ```rust
+/// # use std::sync::{Arc, Mutex};
+/// type ArcMutex<T> = Arc<Mutex<T>>;
+/// ```
+///
/// In traits, `type` is used to declare an [associated type]:
///
/// ```rust
@@ -1860,6 +1867,7 @@ mod true_keyword {}
///
/// [`trait`]: keyword.trait.html
/// [associated type]: ../reference/items/associated-items.html#associated-types
+/// [alias]: ../reference/items/type-aliases.html
mod type_keyword {}
#[doc(keyword = "unsafe")]
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 0ccbb16b1..f1f0f8b16 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -152,6 +152,31 @@
//! contains further primitive shared memory types, including [`atomic`] and
//! [`mpsc`], which contains the channel types for message passing.
//!
+//! # Use before and after `main()`
+//!
+//! Many parts of the standard library are expected to work before and after `main()`;
+//! but this is not guaranteed or ensured by tests. It is recommended that you write your own tests
+//! and run them on each platform you wish to support.
+//! This means that use of `std` before/after main, especially of features that interact with the
+//! OS or global state, is exempted from stability and portability guarantees and instead only
+//! provided on a best-effort basis. Nevertheless bug reports are appreciated.
+//!
+//! On the other hand `core` and `alloc` are most likely to work in such environments with
+//! the caveat that any hookable behavior such as panics, oom handling or allocators will also
+//! depend on the compatibility of the hooks.
+//!
+//! Some features may also behave differently outside main, e.g. stdio could become unbuffered,
+//! some panics might turn into aborts, backtraces might not get symbolicated or similar.
+//!
+//! Non-exhaustive list of known limitations:
+//!
+//! - after-main use of thread-locals, which also affects additional features:
+//! - [`thread::current()`]
+//! - [`thread::scope()`]
+//! - [`sync::mpsc`]
+//! - before-main stdio file descriptors are not guaranteed to be open on unix platforms
+//!
+//!
//! [I/O]: io
//! [`MIN`]: i32::MIN
//! [`MAX`]: i32::MAX
@@ -187,7 +212,6 @@
//! [rust-discord]: https://discord.gg/rust-lang
//! [array]: prim@array
//! [slice]: prim@slice
-
// To run std tests without x.py without ending up with two copies of std, Miri needs to be
// able to "empty" this crate. See <https://github.com/rust-lang/miri-test-libstd/issues/4>.
// rustc itself never sets the feature, so this line has no effect there.
@@ -220,10 +244,10 @@
#![warn(missing_debug_implementations)]
#![allow(explicit_outlives_requirements)]
#![allow(unused_lifetimes)]
-#![cfg_attr(not(bootstrap), allow(internal_features))]
+#![allow(internal_features)]
#![deny(rustc::existing_doc_keyword)]
#![deny(fuzzy_provenance_casts)]
-#![cfg_attr(not(bootstrap), allow(rustdoc::redundant_explicit_links))]
+#![allow(rustdoc::redundant_explicit_links)]
// Ensure that std can be linked against panic_abort despite compiled with `-C panic=unwind`
#![deny(ffi_unwind_calls)]
// std may use features in a platform-specific way
@@ -236,6 +260,7 @@
feature(slice_index_methods, coerce_unsized, sgx_platform)
)]
#![cfg_attr(windows, feature(round_char_boundary))]
+#![cfg_attr(target_os = "xous", feature(slice_ptr_len))]
//
// Language features:
// tidy-alphabetical-start
@@ -351,7 +376,6 @@
#![feature(get_many_mut)]
#![feature(lazy_cell)]
#![feature(log_syntax)]
-#![feature(saturating_int_impl)]
#![feature(stdsimd)]
#![feature(test)]
#![feature(trace_macros)]
@@ -641,13 +665,16 @@ pub use core::{
)]
pub use core::concat_bytes;
+#[unstable(feature = "cfg_match", issue = "115585")]
+pub use core::cfg_match;
+
#[stable(feature = "core_primitive", since = "1.43.0")]
pub use core::primitive;
// Include a number of private modules that exist solely to provide
// the rustdoc documentation for primitive types. Using `include!`
// because rustdoc only looks for these modules at the crate level.
-include!("primitive_docs.rs");
+include!("../../core/src/primitive_docs.rs");
// Include a number of private modules that exist solely to provide
// the rustdoc documentation for the existing keywords. Using `include!`
diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs
index ba1b8cbfa..34b8b6b97 100644
--- a/library/std/src/macros.rs
+++ b/library/std/src/macros.rs
@@ -41,6 +41,9 @@ macro_rules! panic {
/// Use `print!` only for the primary output of your program. Use
/// [`eprint!`] instead to print error and progress messages.
///
+/// See [the formatting documentation in `std::fmt`](../std/fmt/index.html)
+/// for details of the macro argument syntax.
+///
/// [flush]: crate::io::Write::flush
/// [`println!`]: crate::println
/// [`eprint!`]: crate::eprint
@@ -103,6 +106,9 @@ macro_rules! print {
/// Use `println!` only for the primary output of your program. Use
/// [`eprintln!`] instead to print error and progress messages.
///
+/// See [the formatting documentation in `std::fmt`](../std/fmt/index.html)
+/// for details of the macro argument syntax.
+///
/// [`std::fmt`]: crate::fmt
/// [`eprintln!`]: crate::eprintln
/// [lock]: crate::io::Stdout
@@ -150,6 +156,9 @@ macro_rules! println {
/// [`io::stderr`]: crate::io::stderr
/// [`io::stdout`]: crate::io::stdout
///
+/// See [the formatting documentation in `std::fmt`](../std/fmt/index.html)
+/// for details of the macro argument syntax.
+///
/// # Panics
///
/// Panics if writing to `io::stderr` fails.
@@ -181,6 +190,9 @@ macro_rules! eprint {
/// Use `eprintln!` only for error and progress messages. Use `println!`
/// instead for the primary output of your program.
///
+/// See [the formatting documentation in `std::fmt`](../std/fmt/index.html)
+/// for details of the macro argument syntax.
+///
/// [`io::stderr`]: crate::io::stderr
/// [`io::stdout`]: crate::io::stdout
/// [`println!`]: crate::println
diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs
index 32fd54c8e..9667d5f92 100644
--- a/library/std/src/net/tcp.rs
+++ b/library/std/src/net/tcp.rs
@@ -1,6 +1,6 @@
#![deny(unsafe_op_in_unsafe_fn)]
-#[cfg(all(test, not(target_os = "emscripten")))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_os = "xous"))))]
mod tests;
use crate::io::prelude::*;
diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs
index 5ca4ed832..227e418b7 100644
--- a/library/std/src/net/udp.rs
+++ b/library/std/src/net/udp.rs
@@ -1,4 +1,4 @@
-#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))]
mod tests;
use crate::fmt;
diff --git a/library/std/src/num.rs b/library/std/src/num.rs
index 46064bd28..3cd5fa458 100644
--- a/library/std/src/num.rs
+++ b/library/std/src/num.rs
@@ -12,7 +12,7 @@ mod tests;
#[cfg(test)]
mod benches;
-#[unstable(feature = "saturating_int_impl", issue = "87920")]
+#[stable(feature = "saturating_int_impl", since = "1.74.0")]
pub use core::num::Saturating;
#[stable(feature = "rust1", since = "1.0.0")]
pub use core::num::Wrapping;
diff --git a/library/std/src/os/fd/owned.rs b/library/std/src/os/fd/owned.rs
index 2180d2974..81106d6c6 100644
--- a/library/std/src/os/fd/owned.rs
+++ b/library/std/src/os/fd/owned.rs
@@ -15,8 +15,9 @@ use crate::sys_common::{AsInner, FromInner, IntoInner};
/// A borrowed file descriptor.
///
-/// This has a lifetime parameter to tie it to the lifetime of something that
-/// owns the file descriptor.
+/// This has a lifetime parameter to tie it to the lifetime of something that owns the file
+/// descriptor. For the duration of that lifetime, it is guaranteed that nobody will close the file
+/// descriptor.
///
/// This uses `repr(transparent)` and has the representation of a host file
/// descriptor, so it can be used in FFI in places where a file descriptor is
@@ -42,7 +43,8 @@ pub struct BorrowedFd<'fd> {
/// An owned file descriptor.
///
-/// This closes the file descriptor on drop.
+/// This closes the file descriptor on drop. It is guaranteed that nobody else will close the file
+/// descriptor.
///
/// This uses `repr(transparent)` and has the representation of a host file
/// descriptor, so it can be used in FFI in places where a file descriptor is
@@ -155,7 +157,9 @@ impl FromRawFd for OwnedFd {
/// # Safety
///
/// The resource pointed to by `fd` must be open and suitable for assuming
- /// ownership. The resource must not require any cleanup other than `close`.
+ /// [ownership][io-safety]. The resource must not require any cleanup other than `close`.
+ ///
+ /// [io-safety]: io#io-safety
#[inline]
unsafe fn from_raw_fd(fd: RawFd) -> Self {
assert_ne!(fd, u32::MAX as RawFd);
diff --git a/library/std/src/os/fd/raw.rs b/library/std/src/os/fd/raw.rs
index 592e072ad..ef896ea95 100644
--- a/library/std/src/os/fd/raw.rs
+++ b/library/std/src/os/fd/raw.rs
@@ -84,7 +84,10 @@ pub trait FromRawFd {
///
/// # Safety
///
- /// The `fd` passed in must be a valid and open file descriptor.
+ /// The `fd` passed in must be an [owned file descriptor][io-safety];
+ /// in particular, it must be open.
+ ///
+ /// [io-safety]: io#io-safety
///
/// # Example
///
diff --git a/library/std/src/os/fortanix_sgx/io.rs b/library/std/src/os/fortanix_sgx/io.rs
index 7223ade68..7e57435b6 100644
--- a/library/std/src/os/fortanix_sgx/io.rs
+++ b/library/std/src/os/fortanix_sgx/io.rs
@@ -31,15 +31,22 @@ pub trait FromRawFd {
/// Constructs a new instance of `Self` from the given raw file
/// descriptor and metadata.
///
- /// This function **consumes ownership** of the specified file
- /// descriptor. The returned object will take responsibility for closing
- /// it when the object goes out of scope.
+ /// This function is typically used to **consume ownership** of the
+ /// specified file descriptor. When used in this way, the returned object
+ /// will take responsibility for closing it when the object goes out of
+ /// scope.
///
- /// This function is also unsafe as the primitives currently returned
- /// have the contract that they are the sole owner of the file
- /// descriptor they are wrapping. Usage of this function could
- /// accidentally allow violating this contract which can cause memory
- /// unsafety in code that relies on it being true.
+ /// However, consuming ownership is not strictly required. Use a
+ /// [`From<OwnedFd>::from`] implementation for an API which strictly
+ /// consumes ownership.
+ ///
+ /// # Safety
+ ///
+ /// The `fd` passed in must be an [owned file descriptor][io-safety];
+ /// in particular, it must be open.
+ // FIXME: say something about `metadata`.
+ ///
+ /// [io-safety]: io#io-safety
#[unstable(feature = "sgx_platform", issue = "56975")]
unsafe fn from_raw_fd(fd: RawFd, metadata: Self::Metadata) -> Self;
}
diff --git a/library/std/src/os/hurd/fs.rs b/library/std/src/os/hurd/fs.rs
new file mode 100644
index 000000000..00ff1560f
--- /dev/null
+++ b/library/std/src/os/hurd/fs.rs
@@ -0,0 +1,348 @@
+//! Hurd-specific extensions to primitives in the [`std::fs`] module.
+//!
+//! [`std::fs`]: crate::fs
+
+#![stable(feature = "metadata_ext", since = "1.1.0")]
+
+use crate::fs::Metadata;
+use crate::sys_common::AsInner;
+
+/// OS-specific extensions to [`fs::Metadata`].
+///
+/// [`fs::Metadata`]: crate::fs::Metadata
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+pub trait MetadataExt {
+ /// Returns the device ID on which this file resides.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_dev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_dev(&self) -> u64;
+ /// Returns the inode number.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ino());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ino(&self) -> u64;
+ /// Returns the file type and mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mode());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mode(&self) -> u32;
+ /// Returns the number of hard links to file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_nlink());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_nlink(&self) -> u64;
+ /// Returns the user ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_uid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_uid(&self) -> u32;
+ /// Returns the group ID of the file owner.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_gid());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_gid(&self) -> u32;
+ /// Returns the device ID that this file represents. Only relevant for special file.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_rdev());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_rdev(&self) -> u64;
+ /// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
+ ///
+ /// The size of a symbolic link is the length of the pathname it contains,
+ /// without a terminating null byte.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_size());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_size(&self) -> u64;
+ /// Returns the last access time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime(&self) -> i64;
+ /// Returns the last access time of the file, in nanoseconds since [`st_atime`].
+ ///
+ /// [`st_atime`]: Self::st_atime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_atime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_atime_nsec(&self) -> i64;
+ /// Returns the last modification time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime(&self) -> i64;
+ /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`].
+ ///
+ /// [`st_mtime`]: Self::st_mtime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_mtime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_mtime_nsec(&self) -> i64;
+ /// Returns the last status change time of the file, in seconds since Unix Epoch.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime(&self) -> i64;
+ /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`].
+ ///
+ /// [`st_ctime`]: Self::st_ctime
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_ctime_nsec());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_ctime_nsec(&self) -> i64;
+ /// Returns the "preferred" block size for efficient filesystem I/O.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blksize());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blksize(&self) -> u64;
+ /// Returns the number of blocks allocated to the file, 512-byte units.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::fs;
+ /// use std::io;
+ /// use std::os::hurd::fs::MetadataExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let meta = fs::metadata("some_file")?;
+ /// println!("{}", meta.st_blocks());
+ /// Ok(())
+ /// }
+ /// ```
+ #[stable(feature = "metadata_ext2", since = "1.8.0")]
+ fn st_blocks(&self) -> u64;
+}
+
+#[stable(feature = "metadata_ext", since = "1.1.0")]
+impl MetadataExt for Metadata {
+ fn st_dev(&self) -> u64 {
+ self.as_inner().as_inner().st_fsid as u64
+ }
+ fn st_ino(&self) -> u64 {
+ self.as_inner().as_inner().st_ino as u64
+ }
+ fn st_mode(&self) -> u32 {
+ self.as_inner().as_inner().st_mode as u32
+ }
+ fn st_nlink(&self) -> u64 {
+ self.as_inner().as_inner().st_nlink as u64
+ }
+ fn st_uid(&self) -> u32 {
+ self.as_inner().as_inner().st_uid as u32
+ }
+ fn st_gid(&self) -> u32 {
+ self.as_inner().as_inner().st_gid as u32
+ }
+ fn st_rdev(&self) -> u64 {
+ self.as_inner().as_inner().st_rdev as u64
+ }
+ fn st_size(&self) -> u64 {
+ self.as_inner().as_inner().st_size as u64
+ }
+ fn st_atime(&self) -> i64 {
+ self.as_inner().as_inner().st_atim.tv_sec as i64
+ }
+ fn st_atime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_atim.tv_nsec as i64
+ }
+ fn st_mtime(&self) -> i64 {
+ self.as_inner().as_inner().st_mtim.tv_sec as i64
+ }
+ fn st_mtime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_mtim.tv_nsec as i64
+ }
+ fn st_ctime(&self) -> i64 {
+ self.as_inner().as_inner().st_ctim.tv_sec as i64
+ }
+ fn st_ctime_nsec(&self) -> i64 {
+ self.as_inner().as_inner().st_ctim.tv_nsec as i64
+ }
+ fn st_blksize(&self) -> u64 {
+ self.as_inner().as_inner().st_blksize as u64
+ }
+ fn st_blocks(&self) -> u64 {
+ self.as_inner().as_inner().st_blocks as u64
+ }
+}
diff --git a/library/std/src/os/hurd/mod.rs b/library/std/src/os/hurd/mod.rs
new file mode 100644
index 000000000..aee86c7f6
--- /dev/null
+++ b/library/std/src/os/hurd/mod.rs
@@ -0,0 +1,6 @@
+//! Hurd-specific definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+
+pub mod fs;
+pub mod raw;
diff --git a/library/std/src/os/hurd/raw.rs b/library/std/src/os/hurd/raw.rs
new file mode 100644
index 000000000..fa2666635
--- /dev/null
+++ b/library/std/src/os/hurd/raw.rs
@@ -0,0 +1,33 @@
+//! Hurd-specific raw type definitions
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![deprecated(
+ since = "1.8.0",
+ note = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions"
+)]
+#![allow(deprecated)]
+
+use crate::os::raw::{c_long, c_uint, c_ulong};
+
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blkcnt_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type blksize_t = c_long;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type dev_t = c_ulong;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type ino_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type mode_t = c_uint;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type nlink_t = c_ulong;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type off_t = u64;
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub type time_t = c_long;
+
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub type pthread_t = c_long;
diff --git a/library/std/src/os/mod.rs b/library/std/src/os/mod.rs
index 634c3cc4a..11ad21515 100644
--- a/library/std/src/os/mod.rs
+++ b/library/std/src/os/mod.rs
@@ -117,6 +117,8 @@ pub mod haiku;
pub mod hermit;
#[cfg(target_os = "horizon")]
pub mod horizon;
+#[cfg(target_os = "hurd")]
+pub mod hurd;
#[cfg(target_os = "illumos")]
pub mod illumos;
#[cfg(target_os = "ios")]
@@ -140,12 +142,16 @@ pub mod solid;
#[cfg(target_os = "tvos")]
#[path = "ios/mod.rs"]
pub(crate) mod tvos;
+#[cfg(target_os = "uefi")]
+pub mod uefi;
#[cfg(target_os = "vita")]
pub mod vita;
#[cfg(target_os = "vxworks")]
pub mod vxworks;
#[cfg(target_os = "watchos")]
pub(crate) mod watchos;
+#[cfg(target_os = "xous")]
+pub mod xous;
#[cfg(any(unix, target_os = "wasi", doc))]
pub mod fd;
diff --git a/library/std/src/os/solid/io.rs b/library/std/src/os/solid/io.rs
index 33cc5a015..f82034663 100644
--- a/library/std/src/os/solid/io.rs
+++ b/library/std/src/os/solid/io.rs
@@ -27,15 +27,21 @@ pub trait FromRawFd {
/// Constructs a new instance of `Self` from the given raw file
/// descriptor.
///
- /// This function **consumes ownership** of the specified file
- /// descriptor. The returned object will take responsibility for closing
- /// it when the object goes out of scope.
+ /// This function is typically used to **consume ownership** of the
+ /// specified file descriptor. When used in this way, the returned object
+ /// will take responsibility for closing it when the object goes out of
+ /// scope.
///
- /// This function is also unsafe as the primitives currently returned
- /// have the contract that they are the sole owner of the file
- /// descriptor they are wrapping. Usage of this function could
- /// accidentally allow violating this contract which can cause memory
- /// unsafety in code that relies on it being true.
+ /// However, consuming ownership is not strictly required. Use a
+ /// [`From<OwnedFd>::from`] implementation for an API which strictly
+ /// consumes ownership.
+ ///
+ /// # Safety
+ ///
+ /// The `fd` passed in must be an [owned file descriptor][io-safety];
+ /// in particular, it must be open.
+ ///
+ /// [io-safety]: io#io-safety
unsafe fn from_raw_fd(fd: RawFd) -> Self;
}
diff --git a/library/std/src/os/uefi/env.rs b/library/std/src/os/uefi/env.rs
new file mode 100644
index 000000000..5d082e7c1
--- /dev/null
+++ b/library/std/src/os/uefi/env.rs
@@ -0,0 +1,92 @@
+//! UEFI-specific extensions to the primitives in `std::env` module
+
+#![unstable(feature = "uefi_std", issue = "100499")]
+
+use crate::sync::atomic::{AtomicBool, AtomicPtr, Ordering};
+use crate::{ffi::c_void, ptr::NonNull};
+
+static SYSTEM_TABLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
+static IMAGE_HANDLE: AtomicPtr<c_void> = AtomicPtr::new(crate::ptr::null_mut());
+// Flag to check if BootServices are still valid.
+// Start with assuming that they are not available
+static BOOT_SERVICES_FLAG: AtomicBool = AtomicBool::new(false);
+
+/// Initializes the global System Table and Image Handle pointers.
+///
+/// The standard library requires access to the UEFI System Table and the Application Image Handle
+/// to operate. Those are provided to UEFI Applications via their application entry point. By
+/// calling `init_globals()`, those pointers are retained by the standard library for future use.
+/// Thus this function must be called before any of the standard library services are used.
+///
+/// The pointers are never exposed to any entity outside of this application and it is guaranteed
+/// that, once the application exited, these pointers are never dereferenced again.
+///
+/// Callers are required to ensure the pointers are valid for the entire lifetime of this
+/// application. In particular, UEFI Boot Services must not be exited while an application with the
+/// standard library is loaded.
+///
+/// # SAFETY
+/// Calling this function more than once will panic
+pub(crate) unsafe fn init_globals(handle: NonNull<c_void>, system_table: NonNull<c_void>) {
+ IMAGE_HANDLE
+ .compare_exchange(
+ crate::ptr::null_mut(),
+ handle.as_ptr(),
+ Ordering::Release,
+ Ordering::Acquire,
+ )
+ .unwrap();
+ SYSTEM_TABLE
+ .compare_exchange(
+ crate::ptr::null_mut(),
+ system_table.as_ptr(),
+ Ordering::Release,
+ Ordering::Acquire,
+ )
+ .unwrap();
+ BOOT_SERVICES_FLAG.store(true, Ordering::Release)
+}
+
+/// Get the SystemTable Pointer.
+/// If you want to use `BootServices` then please use [`boot_services`] as it performs some
+/// additional checks.
+///
+/// Note: This function panics if the System Table or Image Handle is not initialized
+pub fn system_table() -> NonNull<c_void> {
+ try_system_table().unwrap()
+}
+
+/// Get the ImageHandle Pointer.
+///
+/// Note: This function panics if the System Table or Image Handle is not initialized
+pub fn image_handle() -> NonNull<c_void> {
+ try_image_handle().unwrap()
+}
+
+/// Get the BootServices Pointer.
+/// This function also checks if `ExitBootServices` has already been called.
+pub fn boot_services() -> Option<NonNull<c_void>> {
+ if BOOT_SERVICES_FLAG.load(Ordering::Acquire) {
+ let system_table: NonNull<r_efi::efi::SystemTable> = try_system_table()?.cast();
+ let boot_services = unsafe { (*system_table.as_ptr()).boot_services };
+ NonNull::new(boot_services).map(|x| x.cast())
+ } else {
+ None
+ }
+}
+
+/// Get the SystemTable Pointer.
+/// This function is mostly intended for places where panic is not an option
+pub(crate) fn try_system_table() -> Option<NonNull<c_void>> {
+ NonNull::new(SYSTEM_TABLE.load(Ordering::Acquire))
+}
+
+/// Get the SystemHandle Pointer.
+/// This function is mostly intended for places where panicking is not an option
+pub(crate) fn try_image_handle() -> Option<NonNull<c_void>> {
+ NonNull::new(IMAGE_HANDLE.load(Ordering::Acquire))
+}
+
+pub(crate) fn disable_boot_services() {
+ BOOT_SERVICES_FLAG.store(false, Ordering::Release)
+}
diff --git a/library/std/src/os/uefi/mod.rs b/library/std/src/os/uefi/mod.rs
new file mode 100644
index 000000000..8ef05eee1
--- /dev/null
+++ b/library/std/src/os/uefi/mod.rs
@@ -0,0 +1,8 @@
+//! Platform-specific extensions to `std` for UEFI.
+
+#![unstable(feature = "uefi_std", issue = "100499")]
+#![doc(cfg(target_os = "uefi"))]
+
+pub mod env;
+#[path = "../windows/ffi.rs"]
+pub mod ffi;
diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs
index 029de8fbf..0eb4e88cf 100644
--- a/library/std/src/os/unix/fs.rs
+++ b/library/std/src/os/unix/fs.rs
@@ -123,7 +123,7 @@ pub trait FileExt {
buf = &mut tmp[n..];
offset += n as u64;
}
- Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
@@ -155,7 +155,7 @@ pub trait FileExt {
/// flag fail to respect the offset parameter, always appending to the end
/// of the file instead.
///
- /// It is possible to inadvertantly set this flag, like in the example below.
+ /// It is possible to inadvertently set this flag, like in the example below.
/// Therefore, it is important to be vigilant while changing options to mitigate
/// unexpected behaviour.
///
@@ -258,7 +258,7 @@ pub trait FileExt {
buf = &buf[n..];
offset += n as u64
}
- Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
diff --git a/library/std/src/os/unix/io/mod.rs b/library/std/src/os/unix/io/mod.rs
index 25b5dbff1..827278f8b 100644
--- a/library/std/src/os/unix/io/mod.rs
+++ b/library/std/src/os/unix/io/mod.rs
@@ -6,7 +6,8 @@
//!
//! This module provides three types for representing file descriptors,
//! with different ownership properties: raw, borrowed, and owned, which are
-//! analogous to types used for representing pointers:
+//! analogous to types used for representing pointers. These types reflect concepts of [I/O
+//! safety][io-safety] on Unix.
//!
//! | Type | Analogous to |
//! | ------------------ | ------------ |
@@ -17,8 +18,8 @@
//! Like raw pointers, `RawFd` values are primitive values. And in new code,
//! they should be considered unsafe to do I/O on (analogous to dereferencing
//! them). Rust did not always provide this guidance, so existing code in the
-//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe. Once the
-//! `io_safety` feature is stable, libraries will be encouraged to migrate,
+//! Rust ecosystem often doesn't mark `RawFd` usage as unsafe.
+//! Libraries are encouraged to migrate,
//! either by adding `unsafe` to APIs that dereference `RawFd` values, or by
//! using to `BorrowedFd` or `OwnedFd` instead.
//!
@@ -54,6 +55,8 @@
//! Like boxes, `OwnedFd` values conceptually own the resource they point to,
//! and free (close) it when they are dropped.
//!
+//! See the [`io` module docs][io-safety] for a general explanation of I/O safety.
+//!
//! ## `/proc/self/mem` and similar OS features
//!
//! Some platforms have special files, such as `/proc/self/mem`, which
@@ -65,15 +68,16 @@
//! to be opened and read from or written must be `unsafe`. Rust's safety guarantees
//! only cover what the program itself can do, and not what entities outside
//! the program can do to it. `/proc/self/mem` is considered to be such an
-//! external entity, along with debugging interfaces, and people with physical access to
-//! the hardware. This is true even in cases where the program is controlling
-//! the external entity.
+//! external entity, along with `/proc/self/fd/*`, debugging interfaces, and people with physical
+//! access to the hardware. This is true even in cases where the program is controlling the external
+//! entity.
//!
//! If you desire to comprehensively prevent programs from reaching out and
//! causing external entities to reach back in and violate memory safety, it's
//! necessary to use *sandboxing*, which is outside the scope of `std`.
//!
//! [`BorrowedFd<'a>`]: crate::os::unix::io::BorrowedFd
+//! [io-safety]: crate::io#io-safety
#![stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/os/unix/mod.rs b/library/std/src/os/unix/mod.rs
index 401ec1e7a..3724e90af 100644
--- a/library/std/src/os/unix/mod.rs
+++ b/library/std/src/os/unix/mod.rs
@@ -53,6 +53,8 @@ mod platform {
pub use crate::os::haiku::*;
#[cfg(target_os = "horizon")]
pub use crate::os::horizon::*;
+ #[cfg(target_os = "hurd")]
+ pub use crate::os::hurd::*;
#[cfg(target_os = "illumos")]
pub use crate::os::illumos::*;
#[cfg(target_os = "ios")]
diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs
index 3d4302e66..6a6af9efd 100644
--- a/library/std/src/os/unix/net/tests.rs
+++ b/library/std/src/os/unix/net/tests.rs
@@ -662,7 +662,7 @@ fn test_send_vectored_fds_unix_stream() {
}
}
-#[cfg(any(target_os = "android", target_os = "linux", target_os = "freebsd"))]
+#[cfg(any(target_os = "android", target_os = "linux"))]
#[test]
#[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets
fn test_send_vectored_with_ancillary_to_unix_datagram() {
diff --git a/library/std/src/os/unix/process.rs b/library/std/src/os/unix/process.rs
index 2b40b672d..ac5510304 100644
--- a/library/std/src/os/unix/process.rs
+++ b/library/std/src/os/unix/process.rs
@@ -434,6 +434,20 @@ impl From<crate::process::ChildStdin> for OwnedFd {
}
}
+/// Create a `ChildStdin` from the provided `OwnedFd`.
+///
+/// The provided file descriptor must point to a pipe
+/// with the `CLOEXEC` flag set.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedFd> for process::ChildStdin {
+ #[inline]
+ fn from(fd: OwnedFd) -> process::ChildStdin {
+ let fd = sys::fd::FileDesc::from_inner(fd);
+ let pipe = sys::pipe::AnonPipe::from_inner(fd);
+ process::ChildStdin::from_inner(pipe)
+ }
+}
+
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for crate::process::ChildStdout {
#[inline]
@@ -450,6 +464,20 @@ impl From<crate::process::ChildStdout> for OwnedFd {
}
}
+/// Create a `ChildStdout` from the provided `OwnedFd`.
+///
+/// The provided file descriptor must point to a pipe
+/// with the `CLOEXEC` flag set.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedFd> for process::ChildStdout {
+ #[inline]
+ fn from(fd: OwnedFd) -> process::ChildStdout {
+ let fd = sys::fd::FileDesc::from_inner(fd);
+ let pipe = sys::pipe::AnonPipe::from_inner(fd);
+ process::ChildStdout::from_inner(pipe)
+ }
+}
+
#[stable(feature = "io_safety", since = "1.63.0")]
impl AsFd for crate::process::ChildStderr {
#[inline]
@@ -466,6 +494,20 @@ impl From<crate::process::ChildStderr> for OwnedFd {
}
}
+/// Create a `ChildStderr` from the provided `OwnedFd`.
+///
+/// The provided file descriptor must point to a pipe
+/// with the `CLOEXEC` flag set.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedFd> for process::ChildStderr {
+ #[inline]
+ fn from(fd: OwnedFd) -> process::ChildStderr {
+ let fd = sys::fd::FileDesc::from_inner(fd);
+ let pipe = sys::pipe::AnonPipe::from_inner(fd);
+ process::ChildStderr::from_inner(pipe)
+ }
+}
+
/// Returns the OS-assigned process identifier associated with this process's parent.
#[must_use]
#[stable(feature = "unix_ppid", since = "1.27.0")]
diff --git a/library/std/src/os/wasi/fs.rs b/library/std/src/os/wasi/fs.rs
index 160c8f1ec..3da8c8355 100644
--- a/library/std/src/os/wasi/fs.rs
+++ b/library/std/src/os/wasi/fs.rs
@@ -82,7 +82,7 @@ pub trait FileExt {
buf = &mut tmp[n..];
offset += n as u64;
}
- Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
@@ -162,7 +162,7 @@ pub trait FileExt {
buf = &buf[n..];
offset += n as u64
}
- Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(ref e) if e.is_interrupted() => {}
Err(e) => return Err(e),
}
}
diff --git a/library/std/src/os/windows/io/mod.rs b/library/std/src/os/windows/io/mod.rs
index e2a401fb6..3d3ae3878 100644
--- a/library/std/src/os/windows/io/mod.rs
+++ b/library/std/src/os/windows/io/mod.rs
@@ -6,7 +6,8 @@
//!
//! This module provides three types for representing raw handles and sockets
//! with different ownership properties: raw, borrowed, and owned, which are
-//! analogous to types used for representing pointers:
+//! analogous to types used for representing pointers. These types reflect concepts of [I/O
+//! safety][io-safety] on Windows.
//!
//! | Type | Analogous to |
//! | ---------------------- | ------------ |
@@ -23,8 +24,8 @@
//! And in new code, they should be considered unsafe to do I/O on (analogous
//! to dereferencing them). Rust did not always provide this guidance, so
//! existing code in the Rust ecosystem often doesn't mark `RawHandle` and
-//! `RawSocket` usage as unsafe. Once the `io_safety` feature is stable,
-//! libraries will be encouraged to migrate, either by adding `unsafe` to APIs
+//! `RawSocket` usage as unsafe.
+//! Libraries are encouraged to migrate, either by adding `unsafe` to APIs
//! that dereference `RawHandle` and `RawSocket` values, or by using to
//! `BorrowedHandle`, `BorrowedSocket`, `OwnedHandle`, or `OwnedSocket`.
//!
@@ -45,8 +46,11 @@
//! Like boxes, `OwnedHandle` and `OwnedSocket` values conceptually own the
//! resource they point to, and free (close) it when they are dropped.
//!
+//! See the [`io` module docs][io-safety] for a general explanation of I/O safety.
+//!
//! [`BorrowedHandle<'a>`]: crate::os::windows::io::BorrowedHandle
//! [`BorrowedSocket<'a>`]: crate::os::windows::io::BorrowedSocket
+//! [io-safety]: crate::io#io-safety
#![stable(feature = "rust1", since = "1.0.0")]
diff --git a/library/std/src/os/windows/io/raw.rs b/library/std/src/os/windows/io/raw.rs
index 1759e2e7f..770583a9c 100644
--- a/library/std/src/os/windows/io/raw.rs
+++ b/library/std/src/os/windows/io/raw.rs
@@ -62,7 +62,7 @@ pub trait FromRawHandle {
/// # Safety
///
/// The `handle` passed in must:
- /// - be a valid an open handle,
+ /// - be an [owned handle][io-safety]; in particular, it must be open.
/// - be a handle for a resource that may be freed via [`CloseHandle`]
/// (as opposed to `RegCloseKey` or other close functions).
///
@@ -71,6 +71,7 @@ pub trait FromRawHandle {
///
/// [`CloseHandle`]: https://docs.microsoft.com/en-us/windows/win32/api/handleapi/nf-handleapi-closehandle
/// [here]: https://devblogs.microsoft.com/oldnewthing/20040302-00/?p=40443
+ /// [io-safety]: io#io-safety
#[stable(feature = "from_raw_os", since = "1.1.0")]
unsafe fn from_raw_handle(handle: RawHandle) -> Self;
}
@@ -207,10 +208,11 @@ pub trait FromRawSocket {
/// # Safety
///
/// The `socket` passed in must:
- /// - be a valid an open socket,
+ /// - be an [owned socket][io-safety]; in particular, it must be open.
/// - be a socket that may be freed via [`closesocket`].
///
/// [`closesocket`]: https://docs.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-closesocket
+ /// [io-safety]: io#io-safety
#[stable(feature = "from_raw_os", since = "1.1.0")]
unsafe fn from_raw_socket(sock: RawSocket) -> Self;
}
diff --git a/library/std/src/os/windows/io/socket.rs b/library/std/src/os/windows/io/socket.rs
index 6359835ca..c80b9e284 100644
--- a/library/std/src/os/windows/io/socket.rs
+++ b/library/std/src/os/windows/io/socket.rs
@@ -116,7 +116,7 @@ impl BorrowedSocket<'_> {
let mut info = unsafe { mem::zeroed::<sys::c::WSAPROTOCOL_INFOW>() };
let result = unsafe {
sys::c::WSADuplicateSocketW(
- self.as_raw_socket(),
+ self.as_raw_socket() as sys::c::SOCKET,
sys::c::GetCurrentProcessId(),
&mut info,
)
@@ -134,7 +134,7 @@ impl BorrowedSocket<'_> {
};
if socket != sys::c::INVALID_SOCKET {
- unsafe { Ok(OwnedSocket::from_raw_socket(socket)) }
+ unsafe { Ok(OwnedSocket::from_raw_socket(socket as RawSocket)) }
} else {
let error = unsafe { sys::c::WSAGetLastError() };
@@ -158,7 +158,7 @@ impl BorrowedSocket<'_> {
}
unsafe {
- let socket = OwnedSocket::from_raw_socket(socket);
+ let socket = OwnedSocket::from_raw_socket(socket as RawSocket);
socket.set_no_inherit()?;
Ok(socket)
}
@@ -211,7 +211,7 @@ impl Drop for OwnedSocket {
#[inline]
fn drop(&mut self) {
unsafe {
- let _ = sys::c::closesocket(self.socket);
+ let _ = sys::c::closesocket(self.socket as sys::c::SOCKET);
}
}
}
diff --git a/library/std/src/os/windows/process.rs b/library/std/src/os/windows/process.rs
index 073168cf2..d00e79476 100644
--- a/library/std/src/os/windows/process.rs
+++ b/library/std/src/os/windows/process.rs
@@ -106,6 +106,45 @@ impl IntoRawHandle for process::ChildStderr {
}
}
+/// Create a `ChildStdin` from the provided `OwnedHandle`.
+///
+/// The provided handle must be asynchronous, as reading and
+/// writing from and to it is implemented using asynchronous APIs.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedHandle> for process::ChildStdin {
+ fn from(handle: OwnedHandle) -> process::ChildStdin {
+ let handle = sys::handle::Handle::from_inner(handle);
+ let pipe = sys::pipe::AnonPipe::from_inner(handle);
+ process::ChildStdin::from_inner(pipe)
+ }
+}
+
+/// Create a `ChildStdout` from the provided `OwnedHandle`.
+///
+/// The provided handle must be asynchronous, as reading and
+/// writing from and to it is implemented using asynchronous APIs.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedHandle> for process::ChildStdout {
+ fn from(handle: OwnedHandle) -> process::ChildStdout {
+ let handle = sys::handle::Handle::from_inner(handle);
+ let pipe = sys::pipe::AnonPipe::from_inner(handle);
+ process::ChildStdout::from_inner(pipe)
+ }
+}
+
+/// Create a `ChildStderr` from the provided `OwnedHandle`.
+///
+/// The provided handle must be asynchronous, as reading and
+/// writing from and to it is implemented using asynchronous APIs.
+#[stable(feature = "child_stream_from_fd", since = "1.74.0")]
+impl From<OwnedHandle> for process::ChildStderr {
+ fn from(handle: OwnedHandle) -> process::ChildStderr {
+ let handle = sys::handle::Handle::from_inner(handle);
+ let pipe = sys::pipe::AnonPipe::from_inner(handle);
+ process::ChildStderr::from_inner(pipe)
+ }
+}
+
/// Windows-specific extensions to [`process::ExitStatus`].
///
/// This trait is sealed: it cannot be implemented outside the standard library.
@@ -192,6 +231,66 @@ pub trait CommandExt: Sealed {
/// ```
#[unstable(feature = "windows_process_extensions_async_pipes", issue = "98289")]
fn async_pipes(&mut self, always_async: bool) -> &mut process::Command;
+
+ /// Sets a raw attribute on the command, providing extended configuration options for Windows processes.
+ ///
+ /// This method allows you to specify custom attributes for a child process on Windows systems using raw attribute values.
+ /// Raw attributes provide extended configurability for process creation, but their usage can be complex and potentially unsafe.
+ ///
+ /// The `attribute` parameter specifies the raw attribute to be set, while the `value` parameter holds the value associated with that attribute.
+ /// Please refer to the [`windows-rs`](https://microsoft.github.io/windows-docs-rs/doc/windows/) documentation or the [`Win32 API documentation`](https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-updateprocthreadattribute) for detailed information about available attributes and their meanings.
+ ///
+ /// # Note
+ ///
+ /// The maximum number of raw attributes is the value of [`u32::MAX`].
+ /// If this limit is exceeded, the call to [`process::Command::spawn`] will return an `Error` indicating that the maximum number of attributes has been exceeded.
+ /// # Safety
+ ///
+ /// The usage of raw attributes is potentially unsafe and should be done with caution. Incorrect attribute values or improper configuration can lead to unexpected behavior or errors.
+ ///
+ /// # Example
+ ///
+ /// The following example demonstrates how to create a child process with a specific parent process ID using a raw attribute.
+ ///
+ /// ```rust
+ /// #![feature(windows_process_extensions_raw_attribute)]
+ /// use std::os::windows::{process::CommandExt, io::AsRawHandle};
+ /// use std::process::Command;
+ ///
+ /// # struct ProcessDropGuard(std::process::Child);
+ /// # impl Drop for ProcessDropGuard {
+ /// # fn drop(&mut self) {
+ /// # let _ = self.0.kill();
+ /// # }
+ /// # }
+ ///
+ /// let parent = Command::new("cmd").spawn()?;
+ ///
+ /// let mut child_cmd = Command::new("cmd");
+ ///
+ /// const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
+ ///
+ /// unsafe {
+ /// child_cmd.raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.as_raw_handle() as isize);
+ /// }
+ /// #
+ /// # let parent = ProcessDropGuard(parent);
+ ///
+ /// let mut child = child_cmd.spawn()?;
+ ///
+ /// # child.kill()?;
+ /// # Ok::<(), std::io::Error>(())
+ /// ```
+ ///
+ /// # Safety Note
+ ///
+ /// Remember that improper use of raw attributes can lead to undefined behavior or security vulnerabilities. Always consult the documentation and ensure proper attribute values are used.
+ #[unstable(feature = "windows_process_extensions_raw_attribute", issue = "114854")]
+ unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
+ &mut self,
+ attribute: usize,
+ value: T,
+ ) -> &mut process::Command;
}
#[stable(feature = "windows_process_extensions", since = "1.16.0")]
@@ -219,6 +318,15 @@ impl CommandExt for process::Command {
let _ = always_async;
self
}
+
+ unsafe fn raw_attribute<T: Copy + Send + Sync + 'static>(
+ &mut self,
+ attribute: usize,
+ value: T,
+ ) -> &mut process::Command {
+ self.as_inner_mut().raw_attribute(attribute, value);
+ self
+ }
}
#[unstable(feature = "windows_process_extensions_main_thread_handle", issue = "96723")]
diff --git a/library/std/src/os/xous/ffi.rs b/library/std/src/os/xous/ffi.rs
new file mode 100644
index 000000000..8be7fbb10
--- /dev/null
+++ b/library/std/src/os/xous/ffi.rs
@@ -0,0 +1,647 @@
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![stable(feature = "rust1", since = "1.0.0")]
+
+#[path = "../unix/ffi/os_str.rs"]
+mod os_str;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use self::os_str::{OsStrExt, OsStringExt};
+
+mod definitions;
+#[stable(feature = "rust1", since = "1.0.0")]
+pub use definitions::*;
+
+fn lend_mut_impl(
+ connection: Connection,
+ opcode: usize,
+ data: &mut [u8],
+ arg1: usize,
+ arg2: usize,
+ blocking: bool,
+) -> Result<(usize, usize), Error> {
+ let mut a0 = if blocking { Syscall::SendMessage } else { Syscall::TrySendMessage } as usize;
+ let mut a1: usize = connection.try_into().unwrap();
+ let mut a2 = InvokeType::LendMut as usize;
+ let a3 = opcode;
+ let a4 = data.as_mut_ptr() as usize;
+ let a5 = data.len();
+ let a6 = arg1;
+ let a7 = arg2;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::MemoryReturned as usize {
+ Ok((a1, a2))
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+pub(crate) fn lend_mut(
+ connection: Connection,
+ opcode: usize,
+ data: &mut [u8],
+ arg1: usize,
+ arg2: usize,
+) -> Result<(usize, usize), Error> {
+ lend_mut_impl(connection, opcode, data, arg1, arg2, true)
+}
+
+pub(crate) fn try_lend_mut(
+ connection: Connection,
+ opcode: usize,
+ data: &mut [u8],
+ arg1: usize,
+ arg2: usize,
+) -> Result<(usize, usize), Error> {
+ lend_mut_impl(connection, opcode, data, arg1, arg2, false)
+}
+
+fn lend_impl(
+ connection: Connection,
+ opcode: usize,
+ data: &[u8],
+ arg1: usize,
+ arg2: usize,
+ blocking: bool,
+) -> Result<(usize, usize), Error> {
+ let mut a0 = if blocking { Syscall::SendMessage } else { Syscall::TrySendMessage } as usize;
+ let a1: usize = connection.try_into().unwrap();
+ let a2 = InvokeType::Lend as usize;
+ let a3 = opcode;
+ let a4 = data.as_ptr() as usize;
+ let a5 = data.len();
+ let mut a6 = arg1;
+ let mut a7 = arg2;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1 => _,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6,
+ inlateout("a7") a7,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::MemoryReturned as usize {
+ Ok((a6, a7))
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+pub(crate) fn lend(
+ connection: Connection,
+ opcode: usize,
+ data: &[u8],
+ arg1: usize,
+ arg2: usize,
+) -> Result<(usize, usize), Error> {
+ lend_impl(connection, opcode, data, arg1, arg2, true)
+}
+
+pub(crate) fn try_lend(
+ connection: Connection,
+ opcode: usize,
+ data: &[u8],
+ arg1: usize,
+ arg2: usize,
+) -> Result<(usize, usize), Error> {
+ lend_impl(connection, opcode, data, arg1, arg2, false)
+}
+
+fn scalar_impl(connection: Connection, args: [usize; 5], blocking: bool) -> Result<(), Error> {
+ let mut a0 = if blocking { Syscall::SendMessage } else { Syscall::TrySendMessage } as usize;
+ let mut a1: usize = connection.try_into().unwrap();
+ let a2 = InvokeType::Scalar as usize;
+ let a3 = args[0];
+ let a4 = args[1];
+ let a5 = args[2];
+ let a6 = args[3];
+ let a7 = args[4];
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::Ok as usize {
+ Ok(())
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+pub(crate) fn scalar(connection: Connection, args: [usize; 5]) -> Result<(), Error> {
+ scalar_impl(connection, args, true)
+}
+
+pub(crate) fn try_scalar(connection: Connection, args: [usize; 5]) -> Result<(), Error> {
+ scalar_impl(connection, args, false)
+}
+
+fn blocking_scalar_impl(
+ connection: Connection,
+ args: [usize; 5],
+ blocking: bool,
+) -> Result<[usize; 5], Error> {
+ let mut a0 = if blocking { Syscall::SendMessage } else { Syscall::TrySendMessage } as usize;
+ let mut a1: usize = connection.try_into().unwrap();
+ let mut a2 = InvokeType::BlockingScalar as usize;
+ let mut a3 = args[0];
+ let mut a4 = args[1];
+ let mut a5 = args[2];
+ let a6 = args[3];
+ let a7 = args[4];
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2,
+ inlateout("a3") a3,
+ inlateout("a4") a4,
+ inlateout("a5") a5,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::Scalar1 as usize {
+ Ok([a1, 0, 0, 0, 0])
+ } else if result == SyscallResult::Scalar2 as usize {
+ Ok([a1, a2, 0, 0, 0])
+ } else if result == SyscallResult::Scalar5 as usize {
+ Ok([a1, a2, a3, a4, a5])
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+pub(crate) fn blocking_scalar(
+ connection: Connection,
+ args: [usize; 5],
+) -> Result<[usize; 5], Error> {
+ blocking_scalar_impl(connection, args, true)
+}
+
+pub(crate) fn try_blocking_scalar(
+ connection: Connection,
+ args: [usize; 5],
+) -> Result<[usize; 5], Error> {
+ blocking_scalar_impl(connection, args, false)
+}
+
+fn connect_impl(address: ServerAddress, blocking: bool) -> Result<Connection, Error> {
+ let a0 = if blocking { Syscall::Connect } else { Syscall::TryConnect } as usize;
+ let address: [u32; 4] = address.into();
+ let a1: usize = address[0].try_into().unwrap();
+ let a2: usize = address[1].try_into().unwrap();
+ let a3: usize = address[2].try_into().unwrap();
+ let a4: usize = address[3].try_into().unwrap();
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ let mut result: usize;
+ let mut value: usize;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0 => result,
+ inlateout("a1") a1 => value,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+ if result == SyscallResult::ConnectionId as usize {
+ Ok(value.try_into().unwrap())
+ } else if result == SyscallResult::Error as usize {
+ Err(value.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Connect to a Xous server represented by the specified `address`.
+///
+/// The current thread will block until the server is available. Returns
+/// an error if the server cannot accept any more connections.
+pub(crate) fn connect(address: ServerAddress) -> Result<Connection, Error> {
+ connect_impl(address, true)
+}
+
+/// Attempt to connect to a Xous server represented by the specified `address`.
+///
+/// If the server does not exist then None is returned.
+pub(crate) fn try_connect(address: ServerAddress) -> Result<Option<Connection>, Error> {
+ match connect_impl(address, false) {
+ Ok(conn) => Ok(Some(conn)),
+ Err(Error::ServerNotFound) => Ok(None),
+ Err(e) => Err(e),
+ }
+}
+
+/// Terminate the current process and return the specified code to the parent process.
+pub(crate) fn exit(return_code: u32) -> ! {
+ let a0 = Syscall::TerminateProcess as usize;
+ let a1 = return_code as usize;
+ let a2 = 0;
+ let a3 = 0;
+ let a4 = 0;
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ in("a0") a0,
+ in("a1") a1,
+ in("a2") a2,
+ in("a3") a3,
+ in("a4") a4,
+ in("a5") a5,
+ in("a6") a6,
+ in("a7") a7,
+ )
+ };
+ unreachable!();
+}
+
+/// Suspend the current thread and allow another thread to run. This thread may
+/// continue executing again immediately if there are no other threads available
+/// to run on the system.
+pub(crate) fn do_yield() {
+ let a0 = Syscall::Yield as usize;
+ let a1 = 0;
+ let a2 = 0;
+ let a3 = 0;
+ let a4 = 0;
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0 => _,
+ inlateout("a1") a1 => _,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+}
+
+/// Allocate memory from the system. An optional physical and/or virtual address
+/// may be specified in order to ensure memory is allocated at specific offsets,
+/// otherwise the kernel will select an address.
+///
+/// # Safety
+///
+/// This function is safe unless a virtual address is specified. In that case,
+/// the kernel will return an alias to the existing range. This violates Rust's
+/// pointer uniqueness guarantee.
+pub(crate) unsafe fn map_memory<T>(
+ phys: Option<core::ptr::NonNull<T>>,
+ virt: Option<core::ptr::NonNull<T>>,
+ count: usize,
+ flags: MemoryFlags,
+) -> Result<&'static mut [T], Error> {
+ let mut a0 = Syscall::MapMemory as usize;
+ let mut a1 = phys.map(|p| p.as_ptr() as usize).unwrap_or_default();
+ let mut a2 = virt.map(|p| p.as_ptr() as usize).unwrap_or_default();
+ let a3 = count * core::mem::size_of::<T>();
+ let a4 = flags.bits();
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::MemoryRange as usize {
+ let start = core::ptr::from_exposed_addr_mut::<T>(a1);
+ let len = a2 / core::mem::size_of::<T>();
+ let end = unsafe { start.add(len) };
+ Ok(unsafe { core::slice::from_raw_parts_mut(start, len) })
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Destroy the given memory, returning it to the compiler.
+///
+/// Safety: The memory pointed to by `range` should not be used after this
+/// function returns, even if this function returns Err().
+pub(crate) unsafe fn unmap_memory<T>(range: *mut [T]) -> Result<(), Error> {
+ let mut a0 = Syscall::UnmapMemory as usize;
+ let mut a1 = range.as_mut_ptr() as usize;
+ let a2 = range.len();
+ let a3 = 0;
+ let a4 = 0;
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::Ok as usize {
+ Ok(())
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Adjust the memory flags for the given range. This can be used to remove flags
+/// from a given region in order to harden memory access. Note that flags may
+/// only be removed and may never be added.
+///
+/// Safety: The memory pointed to by `range` may become inaccessible or have its
+/// mutability removed. It is up to the caller to ensure that the flags specified
+/// by `new_flags` are upheld, otherwise the program will crash.
+pub(crate) unsafe fn update_memory_flags<T>(
+ range: *mut [T],
+ new_flags: MemoryFlags,
+) -> Result<(), Error> {
+ let mut a0 = Syscall::UpdateMemoryFlags as usize;
+ let mut a1 = range.as_mut_ptr() as usize;
+ let a2 = range.len();
+ let a3 = new_flags.bits();
+ let a4 = 0; // Process ID is currently None
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::Ok as usize {
+ Ok(())
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Create a thread with a given stack and up to four arguments
+pub(crate) fn create_thread(
+ start: *mut usize,
+ stack: *mut [u8],
+ arg0: usize,
+ arg1: usize,
+ arg2: usize,
+ arg3: usize,
+) -> Result<ThreadId, Error> {
+ let mut a0 = Syscall::CreateThread as usize;
+ let mut a1 = start as usize;
+ let a2 = stack.as_mut_ptr() as usize;
+ let a3 = stack.len();
+ let a4 = arg0;
+ let a5 = arg1;
+ let a6 = arg2;
+ let a7 = arg3;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::ThreadId as usize {
+ Ok(a1.into())
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Wait for the given thread to terminate and return the exit code from that thread.
+pub(crate) fn join_thread(thread_id: ThreadId) -> Result<usize, Error> {
+ let mut a0 = Syscall::JoinThread as usize;
+ let mut a1 = thread_id.into();
+ let a2 = 0;
+ let a3 = 0;
+ let a4 = 0;
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::Scalar1 as usize {
+ Ok(a1)
+ } else if result == SyscallResult::Scalar2 as usize {
+ Ok(a1)
+ } else if result == SyscallResult::Scalar5 as usize {
+ Ok(a1)
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Get the current thread's ID
+pub(crate) fn thread_id() -> Result<ThreadId, Error> {
+ let mut a0 = Syscall::GetThreadId as usize;
+ let mut a1 = 0;
+ let a2 = 0;
+ let a3 = 0;
+ let a4 = 0;
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::ThreadId as usize {
+ Ok(a1.into())
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
+
+/// Adjust the given `knob` limit to match the new value `new`. The current value must
+/// match the `current` in order for this to take effect.
+///
+/// The new value is returned as a result of this call. If the call fails, then the old
+/// value is returned. In either case, this function returns successfully.
+///
+/// An error is generated if the `knob` is not a valid limit, or if the call
+/// would not succeed.
+pub(crate) fn adjust_limit(knob: Limits, current: usize, new: usize) -> Result<usize, Error> {
+ let mut a0 = Syscall::JoinThread as usize;
+ let mut a1 = knob as usize;
+ let a2 = current;
+ let a3 = new;
+ let a4 = 0;
+ let a5 = 0;
+ let a6 = 0;
+ let a7 = 0;
+
+ unsafe {
+ core::arch::asm!(
+ "ecall",
+ inlateout("a0") a0,
+ inlateout("a1") a1,
+ inlateout("a2") a2 => _,
+ inlateout("a3") a3 => _,
+ inlateout("a4") a4 => _,
+ inlateout("a5") a5 => _,
+ inlateout("a6") a6 => _,
+ inlateout("a7") a7 => _,
+ )
+ };
+
+ let result = a0;
+
+ if result == SyscallResult::Scalar2 as usize && a1 == knob as usize {
+ Ok(a2)
+ } else if result == SyscallResult::Scalar5 as usize && a1 == knob as usize {
+ Ok(a1)
+ } else if result == SyscallResult::Error as usize {
+ Err(a1.into())
+ } else {
+ Err(Error::InternalError)
+ }
+}
diff --git a/library/std/src/os/xous/ffi/definitions.rs b/library/std/src/os/xous/ffi/definitions.rs
new file mode 100644
index 000000000..345005bcc
--- /dev/null
+++ b/library/std/src/os/xous/ffi/definitions.rs
@@ -0,0 +1,283 @@
+mod memoryflags;
+pub(crate) use memoryflags::*;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+/// Indicates a particular syscall number as used by the Xous kernel.
+#[derive(Copy, Clone)]
+#[repr(usize)]
+pub enum Syscall {
+ MapMemory = 2,
+ Yield = 3,
+ UpdateMemoryFlags = 12,
+ ReceiveMessage = 15,
+ SendMessage = 16,
+ Connect = 17,
+ CreateThread = 18,
+ UnmapMemory = 19,
+ ReturnMemory = 20,
+ TerminateProcess = 22,
+ TrySendMessage = 24,
+ TryConnect = 25,
+ GetThreadId = 32,
+ JoinThread = 36,
+ AdjustProcessLimit = 38,
+ ReturnScalar = 40,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+/// Copies of these invocation types here for when we're running
+/// in environments without libxous.
+#[derive(Copy, Clone)]
+#[repr(usize)]
+pub enum SyscallResult {
+ Ok = 0,
+ Error = 1,
+ MemoryRange = 3,
+ ConnectionId = 7,
+ Message = 9,
+ ThreadId = 10,
+ Scalar1 = 14,
+ Scalar2 = 15,
+ MemoryReturned = 18,
+ Scalar5 = 20,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Copy, Clone)]
+/// A list of all known errors that may be returned by the Xous kernel.
+#[repr(usize)]
+pub enum Error {
+ NoError = 0,
+ BadAlignment = 1,
+ BadAddress = 2,
+ OutOfMemory = 3,
+ MemoryInUse = 4,
+ InterruptNotFound = 5,
+ InterruptInUse = 6,
+ InvalidString = 7,
+ ServerExists = 8,
+ ServerNotFound = 9,
+ ProcessNotFound = 10,
+ ProcessNotChild = 11,
+ ProcessTerminated = 12,
+ Timeout = 13,
+ InternalError = 14,
+ ServerQueueFull = 15,
+ ThreadNotAvailable = 16,
+ UnhandledSyscall = 17,
+ InvalidSyscall = 18,
+ ShareViolation = 19,
+ InvalidThread = 20,
+ InvalidPid = 21,
+ UnknownError = 22,
+ AccessDenied = 23,
+ UseBeforeInit = 24,
+ DoubleFree = 25,
+ DebugInProgress = 26,
+ InvalidLimit = 27,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<usize> for Error {
+ fn from(src: usize) -> Self {
+ match src {
+ 0 => Self::NoError,
+ 1 => Self::BadAlignment,
+ 2 => Self::BadAddress,
+ 3 => Self::OutOfMemory,
+ 4 => Self::MemoryInUse,
+ 5 => Self::InterruptNotFound,
+ 6 => Self::InterruptInUse,
+ 7 => Self::InvalidString,
+ 8 => Self::ServerExists,
+ 9 => Self::ServerNotFound,
+ 10 => Self::ProcessNotFound,
+ 11 => Self::ProcessNotChild,
+ 12 => Self::ProcessTerminated,
+ 13 => Self::Timeout,
+ 14 => Self::InternalError,
+ 15 => Self::ServerQueueFull,
+ 16 => Self::ThreadNotAvailable,
+ 17 => Self::UnhandledSyscall,
+ 18 => Self::InvalidSyscall,
+ 19 => Self::ShareViolation,
+ 20 => Self::InvalidThread,
+ 21 => Self::InvalidPid,
+ 23 => Self::AccessDenied,
+ 24 => Self::UseBeforeInit,
+ 25 => Self::DoubleFree,
+ 26 => Self::DebugInProgress,
+ 27 => Self::InvalidLimit,
+ 22 | _ => Self::UnknownError,
+ }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<i32> for Error {
+ fn from(src: i32) -> Self {
+ let Ok(src) = core::convert::TryInto::<usize>::try_into(src) else {
+ return Self::UnknownError;
+ };
+ src.into()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::fmt::Display for Error {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(
+ f,
+ "{}",
+ match self {
+ Error::NoError => "no error occurred",
+ Error::BadAlignment => "memory was not properly aligned",
+ Error::BadAddress => "an invalid address was supplied",
+ Error::OutOfMemory => "the process or service has run out of memory",
+ Error::MemoryInUse => "the requested address is in use",
+ Error::InterruptNotFound =>
+ "the requested interrupt does not exist on this platform",
+ Error::InterruptInUse => "the requested interrupt is currently in use",
+ Error::InvalidString => "the specified string was not formatted correctly",
+ Error::ServerExists => "a server with that address already exists",
+ Error::ServerNotFound => "the requetsed server could not be found",
+ Error::ProcessNotFound => "the target process does not exist",
+ Error::ProcessNotChild =>
+ "the requested operation can only be done on child processes",
+ Error::ProcessTerminated => "the target process has crashed",
+ Error::Timeout => "the requested operation timed out",
+ Error::InternalError => "an internal error occurred",
+ Error::ServerQueueFull => "the server has too many pending messages",
+ Error::ThreadNotAvailable => "the specified thread does not exist",
+ Error::UnhandledSyscall => "the kernel did not recognize that syscall",
+ Error::InvalidSyscall => "the syscall had incorrect parameters",
+ Error::ShareViolation => "an attempt was made to share memory twice",
+ Error::InvalidThread => "tried to resume a thread that was not ready",
+ Error::InvalidPid => "kernel attempted to use a pid that was not valid",
+ Error::AccessDenied => "no permission to perform the requested operation",
+ Error::UseBeforeInit => "attempt to use a service before initialization finished",
+ Error::DoubleFree => "the requested resource was freed twice",
+ Error::DebugInProgress => "kernel attempted to activate a thread being debugged",
+ Error::InvalidLimit => "process attempted to adjust an invalid limit",
+ Error::UnknownError => "an unknown error occurred",
+ }
+ )
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::fmt::Debug for Error {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ write!(f, "{}", self)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl crate::error::Error for Error {}
+
+/// Indicates the type of Message that is sent when making a `SendMessage` syscall.
+#[derive(Copy, Clone)]
+#[repr(usize)]
+pub(crate) enum InvokeType {
+ LendMut = 1,
+ Lend = 2,
+ Move = 3,
+ Scalar = 4,
+ BlockingScalar = 5,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug, Copy, Clone)]
+/// A representation of a connection to a Xous service.
+pub struct Connection(u32);
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl From<u32> for Connection {
+ fn from(src: u32) -> Connection {
+ Connection(src)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl TryFrom<usize> for Connection {
+ type Error = core::num::TryFromIntError;
+ fn try_from(src: usize) -> Result<Self, Self::Error> {
+ Ok(Connection(src.try_into()?))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Into<u32> for Connection {
+ fn into(self) -> u32 {
+ self.0
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl TryInto<usize> for Connection {
+ type Error = core::num::TryFromIntError;
+ fn try_into(self) -> Result<usize, Self::Error> {
+ self.0.try_into()
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+#[derive(Debug)]
+pub enum ServerAddressError {
+ InvalidLength,
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct ServerAddress([u32; 4]);
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl TryFrom<&str> for ServerAddress {
+ type Error = ServerAddressError;
+ fn try_from(value: &str) -> Result<Self, Self::Error> {
+ let b = value.as_bytes();
+ if b.len() == 0 || b.len() > 16 {
+ return Err(Self::Error::InvalidLength);
+ }
+
+ let mut this_temp = [0u8; 16];
+ for (dest, src) in this_temp.iter_mut().zip(b.iter()) {
+ *dest = *src;
+ }
+
+ let mut this = [0u32; 4];
+ for (dest, src) in this.iter_mut().zip(this_temp.chunks_exact(4)) {
+ *dest = u32::from_le_bytes(src.try_into().unwrap());
+ }
+ Ok(ServerAddress(this))
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl Into<[u32; 4]> for ServerAddress {
+ fn into(self) -> [u32; 4] {
+ self.0
+ }
+}
+
+#[derive(Debug, Copy, Clone)]
+pub(crate) struct ThreadId(usize);
+
+impl From<usize> for ThreadId {
+ fn from(src: usize) -> ThreadId {
+ ThreadId(src)
+ }
+}
+
+impl Into<usize> for ThreadId {
+ fn into(self) -> usize {
+ self.0
+ }
+}
+
+#[derive(Copy, Clone)]
+#[repr(usize)]
+/// Limits that can be passed to `AdjustLimit`
+pub(crate) enum Limits {
+ HeapMaximum = 1,
+ HeapSize = 2,
+}
diff --git a/library/std/src/os/xous/ffi/definitions/memoryflags.rs b/library/std/src/os/xous/ffi/definitions/memoryflags.rs
new file mode 100644
index 000000000..af9de3cbf
--- /dev/null
+++ b/library/std/src/os/xous/ffi/definitions/memoryflags.rs
@@ -0,0 +1,176 @@
+/// Flags to be passed to the MapMemory struct.
+/// Note that it is an error to have memory be
+/// writable and not readable.
+#[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash, Debug)]
+#[stable(feature = "rust1", since = "1.0.0")]
+pub struct MemoryFlags {
+ bits: usize,
+}
+
+impl MemoryFlags {
+ /// Free this memory
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const FREE: Self = Self { bits: 0b0000_0000 };
+
+ /// Immediately allocate this memory. Otherwise it will
+ /// be demand-paged. This is implicitly set when `phys`
+ /// is not 0.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const RESERVE: Self = Self { bits: 0b0000_0001 };
+
+ /// Allow the CPU to read from this page.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const R: Self = Self { bits: 0b0000_0010 };
+
+ /// Allow the CPU to write to this page.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const W: Self = Self { bits: 0b0000_0100 };
+
+ /// Allow the CPU to execute from this page.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub const X: Self = Self { bits: 0b0000_1000 };
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn bits(&self) -> usize {
+ self.bits
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn from_bits(raw: usize) -> Option<MemoryFlags> {
+ if raw > 16 { None } else { Some(MemoryFlags { bits: raw }) }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn is_empty(&self) -> bool {
+ self.bits == 0
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn empty() -> MemoryFlags {
+ MemoryFlags { bits: 0 }
+ }
+
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub fn all() -> MemoryFlags {
+ MemoryFlags { bits: 15 }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::fmt::Binary for MemoryFlags {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::fmt::Binary::fmt(&self.bits, f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::fmt::Octal for MemoryFlags {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::fmt::Octal::fmt(&self.bits, f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::fmt::LowerHex for MemoryFlags {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::fmt::LowerHex::fmt(&self.bits, f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::fmt::UpperHex for MemoryFlags {
+ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
+ core::fmt::UpperHex::fmt(&self.bits, f)
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::BitOr for MemoryFlags {
+ type Output = Self;
+
+ /// Returns the union of the two sets of flags.
+ #[inline]
+ fn bitor(self, other: MemoryFlags) -> Self {
+ Self { bits: self.bits | other.bits }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::BitOrAssign for MemoryFlags {
+ /// Adds the set of flags.
+ #[inline]
+ fn bitor_assign(&mut self, other: Self) {
+ self.bits |= other.bits;
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::BitXor for MemoryFlags {
+ type Output = Self;
+
+ /// Returns the left flags, but with all the right flags toggled.
+ #[inline]
+ fn bitxor(self, other: Self) -> Self {
+ Self { bits: self.bits ^ other.bits }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::BitXorAssign for MemoryFlags {
+ /// Toggles the set of flags.
+ #[inline]
+ fn bitxor_assign(&mut self, other: Self) {
+ self.bits ^= other.bits;
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::BitAnd for MemoryFlags {
+ type Output = Self;
+
+ /// Returns the intersection between the two sets of flags.
+ #[inline]
+ fn bitand(self, other: Self) -> Self {
+ Self { bits: self.bits & other.bits }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::BitAndAssign for MemoryFlags {
+ /// Disables all flags disabled in the set.
+ #[inline]
+ fn bitand_assign(&mut self, other: Self) {
+ self.bits &= other.bits;
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::Sub for MemoryFlags {
+ type Output = Self;
+
+ /// Returns the set difference of the two sets of flags.
+ #[inline]
+ fn sub(self, other: Self) -> Self {
+ Self { bits: self.bits & !other.bits }
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::SubAssign for MemoryFlags {
+ /// Disables all flags enabled in the set.
+ #[inline]
+ fn sub_assign(&mut self, other: Self) {
+ self.bits &= !other.bits;
+ }
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl core::ops::Not for MemoryFlags {
+ type Output = Self;
+
+ /// Returns the complement of this set of flags.
+ #[inline]
+ fn not(self) -> Self {
+ Self { bits: !self.bits } & MemoryFlags { bits: 15 }
+ }
+}
diff --git a/library/std/src/os/xous/mod.rs b/library/std/src/os/xous/mod.rs
new file mode 100644
index 000000000..153694a89
--- /dev/null
+++ b/library/std/src/os/xous/mod.rs
@@ -0,0 +1,17 @@
+#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(target_os = "xous"))]
+
+pub mod ffi;
+
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod services;
+
+/// A prelude for conveniently writing platform-specific code.
+///
+/// Includes all extension traits, and some important type definitions.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub mod prelude {
+ #[doc(no_inline)]
+ #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::ffi::{OsStrExt, OsStringExt};
+}
diff --git a/library/std/src/os/xous/services.rs b/library/std/src/os/xous/services.rs
new file mode 100644
index 000000000..5c219f1fb
--- /dev/null
+++ b/library/std/src/os/xous/services.rs
@@ -0,0 +1,132 @@
+use crate::os::xous::ffi::Connection;
+use core::sync::atomic::{AtomicU32, Ordering};
+
+mod log;
+pub(crate) use log::*;
+
+mod systime;
+pub(crate) use systime::*;
+
+mod ticktimer;
+pub(crate) use ticktimer::*;
+
+mod ns {
+ const NAME_MAX_LENGTH: usize = 64;
+ use crate::os::xous::ffi::{lend_mut, Connection};
+ // By making this repr(C), the layout of this struct becomes well-defined
+ // and no longer shifts around.
+ // By marking it as `align(4096)` we define that it will be page-aligned,
+ // meaning it can be sent between processes. We make sure to pad out the
+ // entire struct so that memory isn't leaked to the name server.
+ #[repr(C, align(4096))]
+ struct ConnectRequest {
+ data: [u8; 4096],
+ }
+
+ impl ConnectRequest {
+ pub fn new(name: &str) -> Self {
+ let mut cr = ConnectRequest { data: [0u8; 4096] };
+ let name_bytes = name.as_bytes();
+
+ // Copy the string into our backing store.
+ for (&src_byte, dest_byte) in name_bytes.iter().zip(&mut cr.data[0..NAME_MAX_LENGTH]) {
+ *dest_byte = src_byte;
+ }
+
+ // Set the string length to the length of the passed-in String,
+ // or the maximum possible length. Which ever is smaller.
+ for (&src_byte, dest_byte) in (name.len().min(NAME_MAX_LENGTH) as u32)
+ .to_le_bytes()
+ .iter()
+ .zip(&mut cr.data[NAME_MAX_LENGTH..])
+ {
+ *dest_byte = src_byte;
+ }
+ cr
+ }
+ }
+
+ pub fn connect_with_name_impl(name: &str, blocking: bool) -> Option<Connection> {
+ let mut request = ConnectRequest::new(name);
+ let opcode = if blocking {
+ 6 /* BlockingConnect */
+ } else {
+ 7 /* TryConnect */
+ };
+ let cid = if blocking { super::name_server() } else { super::try_name_server()? };
+
+ lend_mut(cid, opcode, &mut request.data, 0, name.len().min(NAME_MAX_LENGTH))
+ .expect("unable to perform lookup");
+
+ // Read the result code back from the nameserver
+ let result = u32::from_le_bytes(request.data[0..4].try_into().unwrap());
+ if result == 0 {
+ // If the result was successful, then the CID is stored in the next 4 bytes
+ Some(u32::from_le_bytes(request.data[4..8].try_into().unwrap()).into())
+ } else {
+ None
+ }
+ }
+
+ pub fn connect_with_name(name: &str) -> Option<Connection> {
+ connect_with_name_impl(name, true)
+ }
+
+ pub fn try_connect_with_name(name: &str) -> Option<Connection> {
+ connect_with_name_impl(name, false)
+ }
+}
+
+/// Attempt to connect to a server by name. If the server does not exist, this will
+/// block until the server is created.
+///
+/// Note that this is different from connecting to a server by address. Server
+/// addresses are always 16 bytes long, whereas server names are arbitrary-length
+/// strings up to 64 bytes in length.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn connect(name: &str) -> Option<Connection> {
+ ns::connect_with_name(name)
+}
+
+/// Attempt to connect to a server by name. If the server does not exist, this will
+/// immediately return `None`.
+///
+/// Note that this is different from connecting to a server by address. Server
+/// addresses are always 16 bytes long, whereas server names are arbitrary-length
+/// strings.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub fn try_connect(name: &str) -> Option<Connection> {
+ ns::try_connect_with_name(name)
+}
+
+static NAME_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
+
+/// Return a `Connection` to the name server. If the name server has not been started,
+/// then this call will block until the name server has been started. The `Connection`
+/// will be shared among all connections in a process, so it is safe to call this
+/// multiple times.
+pub(crate) fn name_server() -> Connection {
+ let cid = NAME_SERVER_CONNECTION.load(Ordering::Relaxed);
+ if cid != 0 {
+ return cid.into();
+ }
+
+ let cid = crate::os::xous::ffi::connect("xous-name-server".try_into().unwrap()).unwrap();
+ NAME_SERVER_CONNECTION.store(cid.into(), Ordering::Relaxed);
+ cid
+}
+
+fn try_name_server() -> Option<Connection> {
+ let cid = NAME_SERVER_CONNECTION.load(Ordering::Relaxed);
+ if cid != 0 {
+ return Some(cid.into());
+ }
+
+ if let Ok(Some(cid)) = crate::os::xous::ffi::try_connect("xous-name-server".try_into().unwrap())
+ {
+ NAME_SERVER_CONNECTION.store(cid.into(), Ordering::Relaxed);
+ Some(cid)
+ } else {
+ None
+ }
+}
diff --git a/library/std/src/os/xous/services/log.rs b/library/std/src/os/xous/services/log.rs
new file mode 100644
index 000000000..e6bae929e
--- /dev/null
+++ b/library/std/src/os/xous/services/log.rs
@@ -0,0 +1,63 @@
+use crate::os::xous::ffi::Connection;
+use core::sync::atomic::{AtomicU32, Ordering};
+
+/// Group `usize` bytes into a `usize` and return it, beginning
+/// from `offset` * sizeof(usize) bytes from the start. For example,
+/// `group_or_null([1,2,3,4,5,6,7,8], 1)` on a 32-bit system will
+/// return a usize with 5678 packed into it.
+fn group_or_null(data: &[u8], offset: usize) -> usize {
+ let start = offset * core::mem::size_of::<usize>();
+ let mut out_array = [0u8; core::mem::size_of::<usize>()];
+ if start < data.len() {
+ for (dest, src) in out_array.iter_mut().zip(&data[start..]) {
+ *dest = *src;
+ }
+ }
+ usize::from_le_bytes(out_array)
+}
+
+pub(crate) enum LogScalar<'a> {
+ /// A panic occurred, and a panic log is forthcoming
+ BeginPanic,
+
+ /// Some number of bytes will be appended to the log message
+ AppendPanicMessage(&'a [u8]),
+}
+
+impl<'a> Into<[usize; 5]> for LogScalar<'a> {
+ fn into(self) -> [usize; 5] {
+ match self {
+ LogScalar::BeginPanic => [1000, 0, 0, 0, 0],
+ LogScalar::AppendPanicMessage(c) =>
+ // 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.
+ {
+ [
+ 1100 + c.len(),
+ group_or_null(&c, 0),
+ group_or_null(&c, 1),
+ group_or_null(&c, 2),
+ group_or_null(&c, 3),
+ ]
+ }
+ }
+ }
+}
+
+/// Return a `Connection` to the log server, which is used for printing messages to
+/// the console and reporting panics. If the log server has not yet started, this
+/// will block until the server is running. It is safe to call this multiple times,
+/// because the address is shared among all threads in a process.
+pub(crate) fn log_server() -> Connection {
+ static LOG_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
+
+ let cid = LOG_SERVER_CONNECTION.load(Ordering::Relaxed);
+ if cid != 0 {
+ return cid.into();
+ }
+
+ let cid = crate::os::xous::ffi::connect("xous-log-server ".try_into().unwrap()).unwrap();
+ LOG_SERVER_CONNECTION.store(cid.into(), Ordering::Relaxed);
+ cid
+}
diff --git a/library/std/src/os/xous/services/systime.rs b/library/std/src/os/xous/services/systime.rs
new file mode 100644
index 000000000..bbb875c69
--- /dev/null
+++ b/library/std/src/os/xous/services/systime.rs
@@ -0,0 +1,28 @@
+use crate::os::xous::ffi::{connect, Connection};
+use core::sync::atomic::{AtomicU32, Ordering};
+
+pub(crate) enum SystimeScalar {
+ GetUtcTimeMs,
+}
+
+impl Into<[usize; 5]> for SystimeScalar {
+ fn into(self) -> [usize; 5] {
+ match self {
+ SystimeScalar::GetUtcTimeMs => [3, 0, 0, 0, 0],
+ }
+ }
+}
+
+/// Return a `Connection` to the systime server. This server is used for reporting the
+/// realtime clock.
+pub(crate) fn systime_server() -> Connection {
+ static SYSTIME_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
+ let cid = SYSTIME_SERVER_CONNECTION.load(Ordering::Relaxed);
+ if cid != 0 {
+ return cid.into();
+ }
+
+ let cid = connect("timeserverpublic".try_into().unwrap()).unwrap();
+ SYSTIME_SERVER_CONNECTION.store(cid.into(), Ordering::Relaxed);
+ cid
+}
diff --git a/library/std/src/os/xous/services/ticktimer.rs b/library/std/src/os/xous/services/ticktimer.rs
new file mode 100644
index 000000000..7759303fd
--- /dev/null
+++ b/library/std/src/os/xous/services/ticktimer.rs
@@ -0,0 +1,42 @@
+use crate::os::xous::ffi::Connection;
+use core::sync::atomic::{AtomicU32, Ordering};
+
+pub(crate) enum TicktimerScalar {
+ ElapsedMs,
+ SleepMs(usize),
+ LockMutex(usize /* cookie */),
+ UnlockMutex(usize /* cookie */),
+ WaitForCondition(usize /* cookie */, usize /* timeout (ms) */),
+ NotifyCondition(usize /* cookie */, usize /* count */),
+ FreeMutex(usize /* cookie */),
+ FreeCondition(usize /* cookie */),
+}
+
+impl Into<[usize; 5]> for TicktimerScalar {
+ fn into(self) -> [usize; 5] {
+ match self {
+ TicktimerScalar::ElapsedMs => [0, 0, 0, 0, 0],
+ TicktimerScalar::SleepMs(msecs) => [1, msecs, 0, 0, 0],
+ TicktimerScalar::LockMutex(cookie) => [6, cookie, 0, 0, 0],
+ TicktimerScalar::UnlockMutex(cookie) => [7, cookie, 0, 0, 0],
+ TicktimerScalar::WaitForCondition(cookie, timeout_ms) => [8, cookie, timeout_ms, 0, 0],
+ TicktimerScalar::NotifyCondition(cookie, count) => [9, cookie, count, 0, 0],
+ TicktimerScalar::FreeMutex(cookie) => [10, cookie, 0, 0, 0],
+ TicktimerScalar::FreeCondition(cookie) => [11, cookie, 0, 0, 0],
+ }
+ }
+}
+
+/// Return a `Connection` to the ticktimer server. This server is used for synchronization
+/// primitives such as sleep, Mutex, and Condvar.
+pub(crate) fn ticktimer_server() -> Connection {
+ static TICKTIMER_SERVER_CONNECTION: AtomicU32 = AtomicU32::new(0);
+ let cid = TICKTIMER_SERVER_CONNECTION.load(Ordering::Relaxed);
+ if cid != 0 {
+ return cid.into();
+ }
+
+ let cid = crate::os::xous::ffi::connect("ticktimer-server".try_into().unwrap()).unwrap();
+ TICKTIMER_SERVER_CONNECTION.store(cid.into(), Ordering::Relaxed);
+ cid
+}
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index a0c21f704..d7a2baa1f 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -10,7 +10,7 @@
#![deny(unsafe_op_in_unsafe_fn)]
use crate::panic::BacktraceStyle;
-use core::panic::{BoxMeUp, Location, PanicInfo};
+use core::panic::{Location, PanicInfo, PanicPayload};
use crate::any::Any;
use crate::fmt;
@@ -47,9 +47,9 @@ extern "C" {
}
extern "Rust" {
- /// `BoxMeUp` lazily performs allocation only when needed (this avoids
+ /// `PanicPayload` lazily performs allocation only when needed (this avoids
/// allocations when using the "abort" panic runtime).
- fn __rust_start_panic(payload: &mut dyn BoxMeUp) -> u32;
+ fn __rust_start_panic(payload: &mut dyn PanicPayload) -> u32;
}
/// This function is called by the panic runtime if FFI code catches a Rust
@@ -238,7 +238,9 @@ where
fn default_hook(info: &PanicInfo<'_>) {
// If this is a double panic, make sure that we print a backtrace
// for this panic. Otherwise only print it if logging is enabled.
- let backtrace = if panic_count::get_count() >= 2 {
+ let backtrace = if info.force_no_backtrace() {
+ None
+ } else if panic_count::get_count() >= 2 {
BacktraceStyle::full()
} else {
crate::panic::get_backtrace_style()
@@ -278,7 +280,7 @@ fn default_hook(info: &PanicInfo<'_>) {
);
}
}
- // If backtraces aren't supported, do nothing.
+ // If backtraces aren't supported or are forced-off, do nothing.
None => {}
}
};
@@ -541,14 +543,14 @@ pub fn panicking() -> bool {
#[cfg(not(test))]
#[panic_handler]
pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
- struct PanicPayload<'a> {
+ struct FormatStringPayload<'a> {
inner: &'a fmt::Arguments<'a>,
string: Option<String>,
}
- impl<'a> PanicPayload<'a> {
- fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> {
- PanicPayload { inner, string: None }
+ impl<'a> FormatStringPayload<'a> {
+ fn new(inner: &'a fmt::Arguments<'a>) -> Self {
+ Self { inner, string: None }
}
fn fill(&mut self) -> &mut String {
@@ -564,7 +566,7 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
}
}
- unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
+ unsafe impl<'a> PanicPayload for FormatStringPayload<'a> {
fn take_box(&mut self) -> *mut (dyn Any + Send) {
// We do two allocations here, unfortunately. But (a) they're required with the current
// scheme, and (b) we don't handle panic + OOM properly anyway (see comment in
@@ -578,9 +580,9 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
}
}
- struct StrPanicPayload(&'static str);
+ struct StaticStrPayload(&'static str);
- unsafe impl BoxMeUp for StrPanicPayload {
+ unsafe impl PanicPayload for StaticStrPayload {
fn take_box(&mut self) -> *mut (dyn Any + Send) {
Box::into_raw(Box::new(self.0))
}
@@ -593,14 +595,23 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
let loc = info.location().unwrap(); // The current implementation always returns Some
let msg = info.message().unwrap(); // The current implementation always returns Some
crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
+ // FIXME: can we just pass `info` along rather than taking it apart here, only to have
+ // `rust_panic_with_hook` construct a new `PanicInfo`?
if let Some(msg) = msg.as_str() {
- rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind());
+ rust_panic_with_hook(
+ &mut StaticStrPayload(msg),
+ info.message(),
+ loc,
+ info.can_unwind(),
+ info.force_no_backtrace(),
+ );
} else {
rust_panic_with_hook(
- &mut PanicPayload::new(msg),
+ &mut FormatStringPayload::new(msg),
info.message(),
loc,
info.can_unwind(),
+ info.force_no_backtrace(),
);
}
})
@@ -625,20 +636,26 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
let loc = Location::caller();
return crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
- rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc, true)
+ rust_panic_with_hook(
+ &mut Payload::new(msg),
+ None,
+ loc,
+ /* can_unwind */ true,
+ /* force_no_backtrace */ false,
+ )
});
- struct PanicPayload<A> {
+ struct Payload<A> {
inner: Option<A>,
}
- impl<A: Send + 'static> PanicPayload<A> {
- fn new(inner: A) -> PanicPayload<A> {
- PanicPayload { inner: Some(inner) }
+ impl<A: Send + 'static> Payload<A> {
+ fn new(inner: A) -> Payload<A> {
+ Payload { inner: Some(inner) }
}
}
- unsafe impl<A: Send + 'static> BoxMeUp for PanicPayload<A> {
+ unsafe impl<A: Send + 'static> PanicPayload for Payload<A> {
fn take_box(&mut self) -> *mut (dyn Any + Send) {
// Note that this should be the only allocation performed in this code path. Currently
// this means that panic!() on OOM will invoke this code path, but then again we're not
@@ -667,10 +684,11 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
/// panics, panic hooks, and finally dispatching to the panic runtime to either
/// abort or unwind.
fn rust_panic_with_hook(
- payload: &mut dyn BoxMeUp,
+ payload: &mut dyn PanicPayload,
message: Option<&fmt::Arguments<'_>>,
location: &Location<'_>,
can_unwind: bool,
+ force_no_backtrace: bool,
) -> ! {
let must_abort = panic_count::increase(true);
@@ -685,14 +703,20 @@ fn rust_panic_with_hook(
panic_count::MustAbort::AlwaysAbort => {
// Unfortunately, this does not print a backtrace, because creating
// a `Backtrace` will allocate, which we must to avoid here.
- let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
+ let panicinfo = PanicInfo::internal_constructor(
+ message,
+ location,
+ can_unwind,
+ force_no_backtrace,
+ );
rtprintpanic!("{panicinfo}\npanicked after panic::always_abort(), aborting.\n");
}
}
crate::sys::abort_internal();
}
- let mut info = PanicInfo::internal_constructor(message, location, can_unwind);
+ let mut info =
+ PanicInfo::internal_constructor(message, location, can_unwind, force_no_backtrace);
let hook = HOOK.read().unwrap_or_else(PoisonError::into_inner);
match *hook {
// Some platforms (like wasm) know that printing to stderr won't ever actually
@@ -736,7 +760,7 @@ pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
struct RewrapBox(Box<dyn Any + Send>);
- unsafe impl BoxMeUp for RewrapBox {
+ unsafe impl PanicPayload for RewrapBox {
fn take_box(&mut self) -> *mut (dyn Any + Send) {
Box::into_raw(mem::replace(&mut self.0, Box::new(())))
}
@@ -753,7 +777,7 @@ pub fn rust_panic_without_hook(payload: Box<dyn Any + Send>) -> ! {
/// yer breakpoints.
#[inline(never)]
#[cfg_attr(not(test), rustc_std_internal_symbol)]
-fn rust_panic(msg: &mut dyn BoxMeUp) -> ! {
+fn rust_panic(msg: &mut dyn PanicPayload) -> ! {
let code = unsafe { __rust_start_panic(msg) };
rtabort!("failed to initiate panic, error {code}")
}
diff --git a/library/std/src/path.rs b/library/std/src/path.rs
index 5842c096f..60562f64c 100644
--- a/library/std/src/path.rs
+++ b/library/std/src/path.rs
@@ -193,7 +193,7 @@ impl<'a> Prefix<'a> {
fn len(&self) -> usize {
use self::Prefix::*;
fn os_str_len(s: &OsStr) -> usize {
- s.as_os_str_bytes().len()
+ s.as_encoded_bytes().len()
}
match *self {
Verbatim(x) => 4 + os_str_len(x),
@@ -316,7 +316,7 @@ fn has_physical_root(s: &[u8], prefix: Option<Prefix<'_>>) -> bool {
// basic workhorse for splitting stem and extension
fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
- if file.as_os_str_bytes() == b".." {
+ if file.as_encoded_bytes() == b".." {
return (Some(file), None);
}
@@ -324,7 +324,7 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
// 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.
- let mut iter = file.as_os_str_bytes().rsplitn(2, |b| *b == b'.');
+ let mut iter = file.as_encoded_bytes().rsplitn(2, |b| *b == b'.');
let after = iter.next();
let before = iter.next();
if before == Some(b"") {
@@ -332,15 +332,15 @@ fn rsplit_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) {
} else {
unsafe {
(
- before.map(|s| OsStr::from_os_str_bytes_unchecked(s)),
- after.map(|s| OsStr::from_os_str_bytes_unchecked(s)),
+ before.map(|s| OsStr::from_encoded_bytes_unchecked(s)),
+ after.map(|s| OsStr::from_encoded_bytes_unchecked(s)),
)
}
}
}
fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) {
- let slice = file.as_os_str_bytes();
+ let slice = file.as_encoded_bytes();
if slice == b".." {
return (file, None);
}
@@ -357,8 +357,8 @@ fn split_file_at_dot(file: &OsStr) -> (&OsStr, Option<&OsStr>) {
let after = &slice[i + 1..];
unsafe {
(
- OsStr::from_os_str_bytes_unchecked(before),
- Some(OsStr::from_os_str_bytes_unchecked(after)),
+ OsStr::from_encoded_bytes_unchecked(before),
+ Some(OsStr::from_encoded_bytes_unchecked(after)),
)
}
}
@@ -739,7 +739,7 @@ impl<'a> Components<'a> {
// separately via `include_cur_dir`
b".." => Some(Component::ParentDir),
b"" => None,
- _ => Some(Component::Normal(unsafe { OsStr::from_os_str_bytes_unchecked(comp) })),
+ _ => Some(Component::Normal(unsafe { OsStr::from_encoded_bytes_unchecked(comp) })),
}
}
@@ -896,7 +896,7 @@ impl<'a> Iterator for Components<'a> {
let raw = &self.path[..self.prefix_len()];
self.path = &self.path[self.prefix_len()..];
return Some(Component::Prefix(PrefixComponent {
- raw: unsafe { OsStr::from_os_str_bytes_unchecked(raw) },
+ raw: unsafe { OsStr::from_encoded_bytes_unchecked(raw) },
parsed: self.prefix.unwrap(),
}));
}
@@ -968,7 +968,7 @@ impl<'a> DoubleEndedIterator for Components<'a> {
State::Prefix if self.prefix_len() > 0 => {
self.back = State::Done;
return Some(Component::Prefix(PrefixComponent {
- raw: unsafe { OsStr::from_os_str_bytes_unchecked(self.path) },
+ raw: unsafe { OsStr::from_encoded_bytes_unchecked(self.path) },
parsed: self.prefix.unwrap(),
}));
}
@@ -1477,17 +1477,17 @@ impl PathBuf {
fn _set_extension(&mut self, extension: &OsStr) -> bool {
let file_stem = match self.file_stem() {
None => return false,
- Some(f) => f.as_os_str_bytes(),
+ Some(f) => f.as_encoded_bytes(),
};
// truncate until right after the file stem
let end_file_stem = file_stem[file_stem.len()..].as_ptr().addr();
- let start = self.inner.as_os_str_bytes().as_ptr().addr();
+ let start = self.inner.as_encoded_bytes().as_ptr().addr();
let v = self.as_mut_vec();
v.truncate(end_file_stem.wrapping_sub(start));
// add the new extension, if any
- let new = extension.as_os_str_bytes();
+ let new = extension.as_encoded_bytes();
if !new.is_empty() {
v.reserve_exact(new.len() + 1);
v.push(b'.');
@@ -2007,11 +2007,11 @@ impl Path {
// The following (private!) function allows construction of a path from a u8
// slice, which is only safe when it is known to follow the OsStr encoding.
unsafe fn from_u8_slice(s: &[u8]) -> &Path {
- unsafe { Path::new(OsStr::from_os_str_bytes_unchecked(s)) }
+ unsafe { Path::new(OsStr::from_encoded_bytes_unchecked(s)) }
}
// The following (private!) function reveals the byte encoding used for OsStr.
fn as_u8_slice(&self) -> &[u8] {
- self.inner.as_os_str_bytes()
+ self.inner.as_encoded_bytes()
}
/// Directly wraps a string slice as a `Path` slice.
@@ -2609,7 +2609,7 @@ impl Path {
fn _with_extension(&self, extension: &OsStr) -> PathBuf {
let self_len = self.as_os_str().len();
- let self_bytes = self.as_os_str().as_os_str_bytes();
+ let self_bytes = self.as_os_str().as_encoded_bytes();
let (new_capacity, slice_to_copy) = match self.extension() {
None => {
diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs
deleted file mode 100644
index 80289ca08..000000000
--- a/library/std/src/primitive_docs.rs
+++ /dev/null
@@ -1,1593 +0,0 @@
-// `library/{std,core}/src/primitive_docs.rs` should have the same contents.
-// These are different files so that relative links work properly without
-// having to have `CARGO_PKG_NAME` set, but conceptually they should always be the same.
-#[rustc_doc_primitive = "bool"]
-#[doc(alias = "true")]
-#[doc(alias = "false")]
-/// The boolean type.
-///
-/// The `bool` represents a value, which could only be either [`true`] or [`false`]. If you cast
-/// a `bool` into an integer, [`true`] will be 1 and [`false`] will be 0.
-///
-/// # Basic usage
-///
-/// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc.,
-/// which allow us to perform boolean operations using `&`, `|` and `!`.
-///
-/// [`if`] requires a `bool` value as its conditional. [`assert!`], which is an
-/// important macro in testing, checks whether an expression is [`true`] and panics
-/// if it isn't.
-///
-/// ```
-/// let bool_val = true & false | false;
-/// assert!(!bool_val);
-/// ```
-///
-/// [`true`]: ../std/keyword.true.html
-/// [`false`]: ../std/keyword.false.html
-/// [`BitAnd`]: ops::BitAnd
-/// [`BitOr`]: ops::BitOr
-/// [`Not`]: ops::Not
-/// [`if`]: ../std/keyword.if.html
-///
-/// # Examples
-///
-/// A trivial example of the usage of `bool`:
-///
-/// ```
-/// let praise_the_borrow_checker = true;
-///
-/// // using the `if` conditional
-/// if praise_the_borrow_checker {
-/// println!("oh, yeah!");
-/// } else {
-/// println!("what?!!");
-/// }
-///
-/// // ... or, a match pattern
-/// match praise_the_borrow_checker {
-/// true => println!("keep praising!"),
-/// false => println!("you should praise!"),
-/// }
-/// ```
-///
-/// Also, since `bool` implements the [`Copy`] trait, we don't
-/// have to worry about the move semantics (just like the integer and float primitives).
-///
-/// Now an example of `bool` cast to integer type:
-///
-/// ```
-/// assert_eq!(true as i32, 1);
-/// assert_eq!(false as i32, 0);
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_bool {}
-
-#[rustc_doc_primitive = "never"]
-#[doc(alias = "!")]
-//
-/// The `!` type, also called "never".
-///
-/// `!` represents the type of computations which never resolve to any value at all. For example,
-/// the [`exit`] function `fn exit(code: i32) -> !` exits the process without ever returning, and
-/// so returns `!`.
-///
-/// `break`, `continue` and `return` expressions also have type `!`. For example we are allowed to
-/// write:
-///
-/// ```
-/// #![feature(never_type)]
-/// # fn foo() -> u32 {
-/// let x: ! = {
-/// return 123
-/// };
-/// # }
-/// ```
-///
-/// Although the `let` is pointless here, it illustrates the meaning of `!`. Since `x` is never
-/// assigned a value (because `return` returns from the entire function), `x` can be given type
-/// `!`. We could also replace `return 123` with a `panic!` or a never-ending `loop` and this code
-/// would still be valid.
-///
-/// A more realistic usage of `!` is in this code:
-///
-/// ```
-/// # fn get_a_number() -> Option<u32> { None }
-/// # loop {
-/// let num: u32 = match get_a_number() {
-/// Some(num) => num,
-/// None => break,
-/// };
-/// # }
-/// ```
-///
-/// Both match arms must produce values of type [`u32`], but since `break` never produces a value
-/// at all we know it can never produce a value which isn't a [`u32`]. This illustrates another
-/// behaviour of the `!` type - expressions with type `!` will coerce into any other type.
-///
-/// [`u32`]: prim@u32
-#[doc = concat!("[`exit`]: ", include_str!("../primitive_docs/process_exit.md"))]
-///
-/// # `!` and generics
-///
-/// ## Infallible errors
-///
-/// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`]
-/// trait:
-///
-/// ```
-/// trait FromStr: Sized {
-/// type Err;
-/// fn from_str(s: &str) -> Result<Self, Self::Err>;
-/// }
-/// ```
-///
-/// When implementing this trait for [`String`] we need to pick a type for [`Err`]. And since
-/// converting a string into a string will never result in an error, the appropriate type is `!`.
-/// (Currently the type actually used is an enum with no variants, though this is only because `!`
-/// was added to Rust at a later date and it may change in the future.) With an [`Err`] type of
-/// `!`, if we have to call [`String::from_str`] for some reason the result will be a
-/// [`Result<String, !>`] which we can unpack like this:
-///
-/// ```
-/// #![feature(exhaustive_patterns)]
-/// use std::str::FromStr;
-/// let Ok(s) = String::from_str("hello");
-/// ```
-///
-/// Since the [`Err`] variant contains a `!`, it can never occur. If the `exhaustive_patterns`
-/// feature is present this means we can exhaustively match on [`Result<T, !>`] by just taking the
-/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain
-/// enum variants from generic types like `Result`.
-///
-/// ## Infinite loops
-///
-/// While [`Result<T, !>`] is very useful for removing errors, `!` can also be used to remove
-/// successes as well. If we think of [`Result<T, !>`] as "if this function returns, it has not
-/// errored," we get a very intuitive idea of [`Result<!, E>`] as well: if the function returns, it
-/// *has* errored.
-///
-/// For example, consider the case of a simple web server, which can be simplified to:
-///
-/// ```ignore (hypothetical-example)
-/// loop {
-/// let (client, request) = get_request().expect("disconnected");
-/// let response = request.process();
-/// response.send(client);
-/// }
-/// ```
-///
-/// Currently, this isn't ideal, because we simply panic whenever we fail to get a new connection.
-/// Instead, we'd like to keep track of this error, like this:
-///
-/// ```ignore (hypothetical-example)
-/// loop {
-/// match get_request() {
-/// Err(err) => break err,
-/// Ok((client, request)) => {
-/// let response = request.process();
-/// response.send(client);
-/// },
-/// }
-/// }
-/// ```
-///
-/// Now, when the server disconnects, we exit the loop with an error instead of panicking. While it
-/// might be intuitive to simply return the error, we might want to wrap it in a [`Result<!, E>`]
-/// instead:
-///
-/// ```ignore (hypothetical-example)
-/// fn server_loop() -> Result<!, ConnectionError> {
-/// loop {
-/// let (client, request) = get_request()?;
-/// let response = request.process();
-/// response.send(client);
-/// }
-/// }
-/// ```
-///
-/// Now, we can use `?` instead of `match`, and the return type makes a lot more sense: if the loop
-/// ever stops, it means that an error occurred. We don't even have to wrap the loop in an `Ok`
-/// because `!` coerces to `Result<!, ConnectionError>` automatically.
-///
-/// [`String::from_str`]: str::FromStr::from_str
-#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))]
-/// [`FromStr`]: str::FromStr
-///
-/// # `!` and traits
-///
-/// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl`
-/// which doesn't `panic!`. The reason is that functions returning an `impl Trait` where `!`
-/// does not have an `impl` of `Trait` cannot diverge as their only possible code path. In other
-/// words, they can't return `!` from every code path. As an example, this code doesn't compile:
-///
-/// ```compile_fail
-/// use std::ops::Add;
-///
-/// fn foo() -> impl Add<u32> {
-/// unimplemented!()
-/// }
-/// ```
-///
-/// But this code does:
-///
-/// ```
-/// use std::ops::Add;
-///
-/// fn foo() -> impl Add<u32> {
-/// if true {
-/// unimplemented!()
-/// } else {
-/// 0
-/// }
-/// }
-/// ```
-///
-/// The reason is that, in the first example, there are many possible types that `!` could coerce
-/// to, because many types implement `Add<u32>`. However, in the second example,
-/// the `else` branch returns a `0`, which the compiler infers from the return type to be of type
-/// `u32`. Since `u32` is a concrete type, `!` can and will be coerced to it. See issue [#36375]
-/// for more information on this quirk of `!`.
-///
-/// [#36375]: https://github.com/rust-lang/rust/issues/36375
-///
-/// As it turns out, though, most traits can have an `impl` for `!`. Take [`Debug`]
-/// for example:
-///
-/// ```
-/// #![feature(never_type)]
-/// # use std::fmt;
-/// # trait Debug {
-/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result;
-/// # }
-/// impl Debug for ! {
-/// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
-/// *self
-/// }
-/// }
-/// ```
-///
-/// Once again we're using `!`'s ability to coerce into any other type, in this case
-/// [`fmt::Result`]. Since this method takes a `&!` as an argument we know that it can never be
-/// called (because there is no value of type `!` for it to be called with). Writing `*self`
-/// essentially tells the compiler "We know that this code can never be run, so just treat the
-/// entire function body as having type [`fmt::Result`]". This pattern can be used a lot when
-/// implementing traits for `!`. Generally, any trait which only has methods which take a `self`
-/// parameter should have such an impl.
-///
-/// On the other hand, one trait which would not be appropriate to implement is [`Default`]:
-///
-/// ```
-/// trait Default {
-/// fn default() -> Self;
-/// }
-/// ```
-///
-/// Since `!` has no values, it has no default value either. It's true that we could write an
-/// `impl` for this which simply panics, but the same is true for any type (we could `impl
-/// Default` for (eg.) [`File`] by just making [`default()`] panic.)
-///
-#[doc = concat!("[`File`]: ", include_str!("../primitive_docs/fs_file.md"))]
-/// [`Debug`]: fmt::Debug
-/// [`default()`]: Default::default
-///
-#[unstable(feature = "never_type", issue = "35121")]
-mod prim_never {}
-
-#[rustc_doc_primitive = "char"]
-#[allow(rustdoc::invalid_rust_codeblocks)]
-/// A character type.
-///
-/// The `char` type represents a single character. More specifically, since
-/// 'character' isn't a well-defined concept in Unicode, `char` is a '[Unicode
-/// scalar value]'.
-///
-/// This documentation describes a number of methods and trait implementations on the
-/// `char` type. For technical reasons, there is additional, separate
-/// documentation in [the `std::char` module](char/index.html) as well.
-///
-/// # Validity
-///
-/// A `char` is a '[Unicode scalar value]', which is any '[Unicode code point]'
-/// other than a [surrogate code point]. This has a fixed numerical definition:
-/// code points are in the range 0 to 0x10FFFF, inclusive.
-/// Surrogate code points, used by UTF-16, are in the range 0xD800 to 0xDFFF.
-///
-/// No `char` may be constructed, whether as a literal or at runtime, that is not a
-/// Unicode scalar value:
-///
-/// ```compile_fail
-/// // Each of these is a compiler error
-/// ['\u{D800}', '\u{DFFF}', '\u{110000}'];
-/// ```
-///
-/// ```should_panic
-/// // Panics; from_u32 returns None.
-/// char::from_u32(0xDE01).unwrap();
-/// ```
-///
-/// ```no_run
-/// // Undefined behaviour
-/// let _ = unsafe { char::from_u32_unchecked(0x110000) };
-/// ```
-///
-/// USVs are also the exact set of values that may be encoded in UTF-8. Because
-/// `char` values are USVs and `str` values are valid UTF-8, it is safe to store
-/// any `char` in a `str` or read any character from a `str` as a `char`.
-///
-/// The gap in valid `char` values is understood by the compiler, so in the
-/// below example the two ranges are understood to cover the whole range of
-/// possible `char` values and there is no error for a [non-exhaustive match].
-///
-/// ```
-/// let c: char = 'a';
-/// match c {
-/// '\0' ..= '\u{D7FF}' => false,
-/// '\u{E000}' ..= '\u{10FFFF}' => true,
-/// };
-/// ```
-///
-/// All USVs are valid `char` values, but not all of them represent a real
-/// character. Many USVs are not currently assigned to a character, but may be
-/// in the future ("reserved"); some will never be a character
-/// ("noncharacters"); and some may be given different meanings by different
-/// users ("private use").
-///
-/// [Unicode code point]: https://www.unicode.org/glossary/#code_point
-/// [Unicode scalar value]: https://www.unicode.org/glossary/#unicode_scalar_value
-/// [non-exhaustive match]: ../book/ch06-02-match.html#matches-are-exhaustive
-/// [surrogate code point]: https://www.unicode.org/glossary/#surrogate_code_point
-///
-/// # Representation
-///
-/// `char` is always four bytes in size. This is a different representation than
-/// a given character would have as part of a [`String`]. For example:
-///
-/// ```
-/// let v = vec!['h', 'e', 'l', 'l', 'o'];
-///
-/// // five elements times four bytes for each element
-/// assert_eq!(20, v.len() * std::mem::size_of::<char>());
-///
-/// let s = String::from("hello");
-///
-/// // five elements times one byte per element
-/// assert_eq!(5, s.len() * std::mem::size_of::<u8>());
-/// ```
-///
-#[doc = concat!("[`String`]: ", include_str!("../primitive_docs/string_string.md"))]
-///
-/// As always, remember that a human intuition for 'character' might not map to
-/// Unicode's definitions. For example, despite looking similar, the 'é'
-/// character is one Unicode code point while 'é' is two Unicode code points:
-///
-/// ```
-/// let mut chars = "é".chars();
-/// // U+00e9: 'latin small letter e with acute'
-/// assert_eq!(Some('\u{00e9}'), chars.next());
-/// assert_eq!(None, chars.next());
-///
-/// let mut chars = "é".chars();
-/// // U+0065: 'latin small letter e'
-/// assert_eq!(Some('\u{0065}'), chars.next());
-/// // U+0301: 'combining acute accent'
-/// assert_eq!(Some('\u{0301}'), chars.next());
-/// assert_eq!(None, chars.next());
-/// ```
-///
-/// This means that the contents of the first string above _will_ fit into a
-/// `char` while the contents of the second string _will not_. Trying to create
-/// a `char` literal with the contents of the second string gives an error:
-///
-/// ```text
-/// error: character literal may only contain one codepoint: 'é'
-/// let c = 'é';
-/// ^^^
-/// ```
-///
-/// Another implication of the 4-byte fixed size of a `char` is that
-/// per-`char` processing can end up using a lot more memory:
-///
-/// ```
-/// let s = String::from("love: ❤️");
-/// let v: Vec<char> = s.chars().collect();
-///
-/// assert_eq!(12, std::mem::size_of_val(&s[..]));
-/// assert_eq!(32, std::mem::size_of_val(&v[..]));
-/// ```
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_char {}
-
-#[rustc_doc_primitive = "unit"]
-#[doc(alias = "(")]
-#[doc(alias = ")")]
-#[doc(alias = "()")]
-//
-/// The `()` type, also called "unit".
-///
-/// The `()` type has exactly one value `()`, and is used when there
-/// is no other meaningful value that could be returned. `()` is most
-/// commonly seen implicitly: functions without a `-> ...` implicitly
-/// have return type `()`, that is, these are equivalent:
-///
-/// ```rust
-/// fn long() -> () {}
-///
-/// fn short() {}
-/// ```
-///
-/// The semicolon `;` can be used to discard the result of an
-/// expression at the end of a block, making the expression (and thus
-/// the block) evaluate to `()`. For example,
-///
-/// ```rust
-/// fn returns_i64() -> i64 {
-/// 1i64
-/// }
-/// fn returns_unit() {
-/// 1i64;
-/// }
-///
-/// let is_i64 = {
-/// returns_i64()
-/// };
-/// let is_unit = {
-/// returns_i64();
-/// };
-/// ```
-///
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_unit {}
-
-// Required to make auto trait impls render.
-// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
-#[doc(hidden)]
-impl () {}
-
-// Fake impl that's only really used for docs.
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Clone for () {
- fn clone(&self) -> Self {
- loop {}
- }
-}
-
-// Fake impl that's only really used for docs.
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-impl Copy for () {
- // empty
-}
-
-#[rustc_doc_primitive = "pointer"]
-#[doc(alias = "ptr")]
-#[doc(alias = "*")]
-#[doc(alias = "*const")]
-#[doc(alias = "*mut")]
-//
-/// Raw, unsafe pointers, `*const T`, and `*mut T`.
-///
-/// *[See also the `std::ptr` module](ptr).*
-///
-/// Working with raw pointers in Rust is uncommon, typically limited to a few patterns.
-/// Raw pointers can be unaligned or [`null`]. However, when a raw pointer is
-/// dereferenced (using the `*` operator), it must be non-null and aligned.
-///
-/// Storing through a raw pointer using `*ptr = data` calls `drop` on the old value, so
-/// [`write`] must be used if the type has drop glue and memory is not already
-/// initialized - otherwise `drop` would be called on the uninitialized memory.
-///
-/// Use the [`null`] and [`null_mut`] functions to create null pointers, and the
-/// [`is_null`] method of the `*const T` and `*mut T` types to check for null.
-/// The `*const T` and `*mut T` types also define the [`offset`] method, for
-/// pointer math.
-///
-/// # Common ways to create raw pointers
-///
-/// ## 1. Coerce a reference (`&T`) or mutable reference (`&mut T`).
-///
-/// ```
-/// let my_num: i32 = 10;
-/// let my_num_ptr: *const i32 = &my_num;
-/// let mut my_speed: i32 = 88;
-/// let my_speed_ptr: *mut i32 = &mut my_speed;
-/// ```
-///
-/// To get a pointer to a boxed value, dereference the box:
-///
-/// ```
-/// let my_num: Box<i32> = Box::new(10);
-/// let my_num_ptr: *const i32 = &*my_num;
-/// let mut my_speed: Box<i32> = Box::new(88);
-/// let my_speed_ptr: *mut i32 = &mut *my_speed;
-/// ```
-///
-/// This does not take ownership of the original allocation
-/// and requires no resource management later,
-/// but you must not use the pointer after its lifetime.
-///
-/// ## 2. Consume a box (`Box<T>`).
-///
-/// The [`into_raw`] function consumes a box and returns
-/// the raw pointer. It doesn't destroy `T` or deallocate any memory.
-///
-/// ```
-/// let my_speed: Box<i32> = Box::new(88);
-/// let my_speed: *mut i32 = Box::into_raw(my_speed);
-///
-/// // By taking ownership of the original `Box<T>` though
-/// // we are obligated to put it together later to be destroyed.
-/// unsafe {
-/// drop(Box::from_raw(my_speed));
-/// }
-/// ```
-///
-/// Note that here the call to [`drop`] is for clarity - it indicates
-/// that we are done with the given value and it should be destroyed.
-///
-/// ## 3. Create it using `ptr::addr_of!`
-///
-/// Instead of coercing a reference to a raw pointer, you can use the macros
-/// [`ptr::addr_of!`] (for `*const T`) and [`ptr::addr_of_mut!`] (for `*mut T`).
-/// These macros allow you to create raw pointers to fields to which you cannot
-/// create a reference (without causing undefined behaviour), such as an
-/// unaligned field. This might be necessary if packed structs or uninitialized
-/// memory is involved.
-///
-/// ```
-/// #[derive(Debug, Default, Copy, Clone)]
-/// #[repr(C, packed)]
-/// struct S {
-/// aligned: u8,
-/// unaligned: u32,
-/// }
-/// let s = S::default();
-/// let p = std::ptr::addr_of!(s.unaligned); // not allowed with coercion
-/// ```
-///
-/// ## 4. Get it from C.
-///
-/// ```
-/// # #![feature(rustc_private)]
-/// #[allow(unused_extern_crates)]
-/// extern crate libc;
-///
-/// use std::mem;
-///
-/// unsafe {
-/// let my_num: *mut i32 = libc::malloc(mem::size_of::<i32>()) as *mut i32;
-/// if my_num.is_null() {
-/// panic!("failed to allocate memory");
-/// }
-/// libc::free(my_num as *mut libc::c_void);
-/// }
-/// ```
-///
-/// Usually you wouldn't literally use `malloc` and `free` from Rust,
-/// but C APIs hand out a lot of pointers generally, so are a common source
-/// of raw pointers in Rust.
-///
-/// [`null`]: ptr::null
-/// [`null_mut`]: ptr::null_mut
-/// [`is_null`]: pointer::is_null
-/// [`offset`]: pointer::offset
-#[doc = concat!("[`into_raw`]: ", include_str!("../primitive_docs/box_into_raw.md"))]
-/// [`write`]: ptr::write
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_pointer {}
-
-#[rustc_doc_primitive = "array"]
-#[doc(alias = "[]")]
-#[doc(alias = "[T;N]")] // unfortunately, rustdoc doesn't have fuzzy search for aliases
-#[doc(alias = "[T; N]")]
-/// A fixed-size array, denoted `[T; N]`, for the element type, `T`, and the
-/// non-negative compile-time constant size, `N`.
-///
-/// There are two syntactic forms for creating an array:
-///
-/// * A list with each element, i.e., `[x, y, z]`.
-/// * A repeat expression `[expr; N]` where `N` is how many times to repeat `expr` in the array. `expr` must either be:
-///
-/// * A value of a type implementing the [`Copy`] trait
-/// * A `const` value
-///
-/// Note that `[expr; 0]` is allowed, and produces an empty array.
-/// This will still evaluate `expr`, however, and immediately drop the resulting value, so
-/// be mindful of side effects.
-///
-/// Arrays of *any* size implement the following traits if the element type allows it:
-///
-/// - [`Copy`]
-/// - [`Clone`]
-/// - [`Debug`]
-/// - [`IntoIterator`] (implemented for `[T; N]`, `&[T; N]` and `&mut [T; N]`)
-/// - [`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`]
-/// - [`Hash`]
-/// - [`AsRef`], [`AsMut`]
-/// - [`Borrow`], [`BorrowMut`]
-///
-/// Arrays of sizes from 0 to 32 (inclusive) implement the [`Default`] trait
-/// if the element type allows it. As a stopgap, trait implementations are
-/// statically generated up to size 32.
-///
-/// Arrays of sizes from 1 to 12 (inclusive) implement [`From<Tuple>`], where `Tuple`
-/// is a homogenous [prim@tuple] of appropriate length.
-///
-/// Arrays coerce to [slices (`[T]`)][slice], so a slice method may be called on
-/// an array. Indeed, this provides most of the API for working with arrays.
-///
-/// Slices have a dynamic size and do not coerce to arrays. Instead, use
-/// `slice.try_into().unwrap()` or `<ArrayType>::try_from(slice).unwrap()`.
-///
-/// Array's `try_from(slice)` implementations (and the corresponding `slice.try_into()`
-/// array implementations) succeed if the input slice length is the same as the result
-/// array length. They optimize especially well when the optimizer can easily determine
-/// the slice length, e.g. `<[u8; 4]>::try_from(&slice[4..8]).unwrap()`. Array implements
-/// [TryFrom](crate::convert::TryFrom) returning:
-///
-/// - `[T; N]` copies from the slice's elements
-/// - `&[T; N]` references the original slice's elements
-/// - `&mut [T; N]` references the original slice's elements
-///
-/// You can move elements out of an array with a [slice pattern]. If you want
-/// one element, see [`mem::replace`].
-///
-/// # Examples
-///
-/// ```
-/// let mut array: [i32; 3] = [0; 3];
-///
-/// array[1] = 1;
-/// array[2] = 2;
-///
-/// assert_eq!([1, 2], &array[1..]);
-///
-/// // This loop prints: 0 1 2
-/// for x in array {
-/// print!("{x} ");
-/// }
-/// ```
-///
-/// You can also iterate over reference to the array's elements:
-///
-/// ```
-/// let array: [i32; 3] = [0; 3];
-///
-/// for x in &array { }
-/// ```
-///
-/// You can use `<ArrayType>::try_from(slice)` or `slice.try_into()` to get an array from
-/// a slice:
-///
-/// ```
-/// let bytes: [u8; 3] = [1, 0, 2];
-/// assert_eq!(1, u16::from_le_bytes(<[u8; 2]>::try_from(&bytes[0..2]).unwrap()));
-/// assert_eq!(512, u16::from_le_bytes(bytes[1..3].try_into().unwrap()));
-/// ```
-///
-/// You can use a [slice pattern] to move elements out of an array:
-///
-/// ```
-/// fn move_away(_: String) { /* Do interesting things. */ }
-///
-/// let [john, roa] = ["John".to_string(), "Roa".to_string()];
-/// move_away(john);
-/// move_away(roa);
-/// ```
-///
-/// Arrays can be created from homogenous tuples of appropriate length:
-///
-/// ```
-/// let tuple: (u32, u32, u32) = (1, 2, 3);
-/// let array: [u32; 3] = tuple.into();
-/// ```
-///
-/// # Editions
-///
-/// Prior to Rust 1.53, arrays did not implement [`IntoIterator`] by value, so the method call
-/// `array.into_iter()` auto-referenced into a [slice iterator](slice::iter). Right now, the old
-/// behavior is preserved in the 2015 and 2018 editions of Rust for compatibility, ignoring
-/// [`IntoIterator`] by value. In the future, the behavior on the 2015 and 2018 edition
-/// might be made consistent to the behavior of later editions.
-///
-/// ```rust,edition2018
-/// // Rust 2015 and 2018:
-///
-/// # #![allow(array_into_iter)] // override our `deny(warnings)`
-/// let array: [i32; 3] = [0; 3];
-///
-/// // This creates a slice iterator, producing references to each value.
-/// for item in array.into_iter().enumerate() {
-/// let (i, x): (usize, &i32) = item;
-/// println!("array[{i}] = {x}");
-/// }
-///
-/// // The `array_into_iter` lint suggests this change for future compatibility:
-/// for item in array.iter().enumerate() {
-/// let (i, x): (usize, &i32) = item;
-/// println!("array[{i}] = {x}");
-/// }
-///
-/// // You can explicitly iterate an array by value using `IntoIterator::into_iter`
-/// for item in IntoIterator::into_iter(array).enumerate() {
-/// let (i, x): (usize, i32) = item;
-/// println!("array[{i}] = {x}");
-/// }
-/// ```
-///
-/// Starting in the 2021 edition, `array.into_iter()` uses `IntoIterator` normally to iterate
-/// by value, and `iter()` should be used to iterate by reference like previous editions.
-///
-/// ```rust,edition2021
-/// // Rust 2021:
-///
-/// let array: [i32; 3] = [0; 3];
-///
-/// // This iterates by reference:
-/// for item in array.iter().enumerate() {
-/// let (i, x): (usize, &i32) = item;
-/// println!("array[{i}] = {x}");
-/// }
-///
-/// // This iterates by value:
-/// for item in array.into_iter().enumerate() {
-/// let (i, x): (usize, i32) = item;
-/// println!("array[{i}] = {x}");
-/// }
-/// ```
-///
-/// Future language versions might start treating the `array.into_iter()`
-/// syntax on editions 2015 and 2018 the same as on edition 2021. So code using
-/// those older editions should still be written with this change in mind, to
-/// prevent breakage in the future. The safest way to accomplish this is to
-/// avoid the `into_iter` syntax on those editions. If an edition update is not
-/// viable/desired, there are multiple alternatives:
-/// * use `iter`, equivalent to the old behavior, creating references
-/// * use [`IntoIterator::into_iter`], equivalent to the post-2021 behavior (Rust 1.53+)
-/// * replace `for ... in array.into_iter() {` with `for ... in array {`,
-/// equivalent to the post-2021 behavior (Rust 1.53+)
-///
-/// ```rust,edition2018
-/// // Rust 2015 and 2018:
-///
-/// let array: [i32; 3] = [0; 3];
-///
-/// // This iterates by reference:
-/// for item in array.iter() {
-/// let x: &i32 = item;
-/// println!("{x}");
-/// }
-///
-/// // This iterates by value:
-/// for item in IntoIterator::into_iter(array) {
-/// let x: i32 = item;
-/// println!("{x}");
-/// }
-///
-/// // This iterates by value:
-/// for item in array {
-/// let x: i32 = item;
-/// println!("{x}");
-/// }
-///
-/// // IntoIter can also start a chain.
-/// // This iterates by value:
-/// for item in IntoIterator::into_iter(array).enumerate() {
-/// let (i, x): (usize, i32) = item;
-/// println!("array[{i}] = {x}");
-/// }
-/// ```
-///
-/// [slice]: prim@slice
-/// [`Debug`]: fmt::Debug
-/// [`Hash`]: hash::Hash
-/// [`Borrow`]: borrow::Borrow
-/// [`BorrowMut`]: borrow::BorrowMut
-/// [slice pattern]: ../reference/patterns.html#slice-patterns
-/// [`From<Tuple>`]: convert::From
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_array {}
-
-#[rustc_doc_primitive = "slice"]
-#[doc(alias = "[")]
-#[doc(alias = "]")]
-#[doc(alias = "[]")]
-/// A dynamically-sized view into a contiguous sequence, `[T]`. Contiguous here
-/// means that elements are laid out so that every element is the same
-/// distance from its neighbors.
-///
-/// *[See also the `std::slice` module](crate::slice).*
-///
-/// Slices are a view into a block of memory represented as a pointer and a
-/// length.
-///
-/// ```
-/// // slicing a Vec
-/// let vec = vec![1, 2, 3];
-/// let int_slice = &vec[..];
-/// // coercing an array to a slice
-/// let str_slice: &[&str] = &["one", "two", "three"];
-/// ```
-///
-/// Slices are either mutable or shared. The shared slice type is `&[T]`,
-/// while the mutable slice type is `&mut [T]`, where `T` represents the element
-/// type. For example, you can mutate the block of memory that a mutable slice
-/// points to:
-///
-/// ```
-/// let mut x = [1, 2, 3];
-/// let x = &mut x[..]; // Take a full slice of `x`.
-/// x[1] = 7;
-/// assert_eq!(x, &[1, 7, 3]);
-/// ```
-///
-/// As slices store the length of the sequence they refer to, they have twice
-/// the size of pointers to [`Sized`](marker/trait.Sized.html) types.
-/// Also see the reference on
-/// [dynamically sized types](../reference/dynamically-sized-types.html).
-///
-/// ```
-/// # use std::rc::Rc;
-/// let pointer_size = std::mem::size_of::<&u8>();
-/// assert_eq!(2 * pointer_size, std::mem::size_of::<&[u8]>());
-/// assert_eq!(2 * pointer_size, std::mem::size_of::<*const [u8]>());
-/// assert_eq!(2 * pointer_size, std::mem::size_of::<Box<[u8]>>());
-/// assert_eq!(2 * pointer_size, std::mem::size_of::<Rc<[u8]>>());
-/// ```
-///
-/// ## Trait Implementations
-///
-/// Some traits are implemented for slices if the element type implements
-/// that trait. This includes [`Eq`], [`Hash`] and [`Ord`].
-///
-/// ## Iteration
-///
-/// The slices implement `IntoIterator`. The iterator yields references to the
-/// slice elements.
-///
-/// ```
-/// let numbers: &[i32] = &[0, 1, 2];
-/// for n in numbers {
-/// println!("{n} is a number!");
-/// }
-/// ```
-///
-/// The mutable slice yields mutable references to the elements:
-///
-/// ```
-/// let mut scores: &mut [i32] = &mut [7, 8, 9];
-/// for score in scores {
-/// *score += 1;
-/// }
-/// ```
-///
-/// This iterator yields mutable references to the slice's elements, so while
-/// the element type of the slice is `i32`, the element type of the iterator is
-/// `&mut i32`.
-///
-/// * [`.iter`] and [`.iter_mut`] are the explicit methods to return the default
-/// iterators.
-/// * Further methods that return iterators are [`.split`], [`.splitn`],
-/// [`.chunks`], [`.windows`] and more.
-///
-/// [`Hash`]: core::hash::Hash
-/// [`.iter`]: slice::iter
-/// [`.iter_mut`]: slice::iter_mut
-/// [`.split`]: slice::split
-/// [`.splitn`]: slice::splitn
-/// [`.chunks`]: slice::chunks
-/// [`.windows`]: slice::windows
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_slice {}
-
-#[rustc_doc_primitive = "str"]
-/// String slices.
-///
-/// *[See also the `std::str` module](crate::str).*
-///
-/// The `str` type, also called a 'string slice', is the most primitive string
-/// type. It is usually seen in its borrowed form, `&str`. It is also the type
-/// of string literals, `&'static str`.
-///
-/// String slices are always valid UTF-8.
-///
-/// # Basic Usage
-///
-/// String literals are string slices:
-///
-/// ```
-/// let hello_world = "Hello, World!";
-/// ```
-///
-/// Here we have declared a string slice initialized with a string literal.
-/// String literals have a static lifetime, which means the string `hello_world`
-/// is guaranteed to be valid for the duration of the entire program.
-/// We can explicitly specify `hello_world`'s lifetime as well:
-///
-/// ```
-/// let hello_world: &'static str = "Hello, world!";
-/// ```
-///
-/// # Representation
-///
-/// A `&str` is made up of two components: a pointer to some bytes, and a
-/// length. You can look at these with the [`as_ptr`] and [`len`] methods:
-///
-/// ```
-/// use std::slice;
-/// use std::str;
-///
-/// let story = "Once upon a time...";
-///
-/// let ptr = story.as_ptr();
-/// let len = story.len();
-///
-/// // story has nineteen bytes
-/// assert_eq!(19, len);
-///
-/// // We can re-build a str out of ptr and len. This is all unsafe because
-/// // we are responsible for making sure the two components are valid:
-/// let s = unsafe {
-/// // First, we build a &[u8]...
-/// let slice = slice::from_raw_parts(ptr, len);
-///
-/// // ... and then convert that slice into a string slice
-/// str::from_utf8(slice)
-/// };
-///
-/// assert_eq!(s, Ok(story));
-/// ```
-///
-/// [`as_ptr`]: str::as_ptr
-/// [`len`]: str::len
-///
-/// Note: This example shows the internals of `&str`. `unsafe` should not be
-/// used to get a string slice under normal circumstances. Use `as_str`
-/// instead.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_str {}
-
-#[rustc_doc_primitive = "tuple"]
-#[doc(alias = "(")]
-#[doc(alias = ")")]
-#[doc(alias = "()")]
-//
-/// A finite heterogeneous sequence, `(T, U, ..)`.
-///
-/// Let's cover each of those in turn:
-///
-/// Tuples are *finite*. In other words, a tuple has a length. Here's a tuple
-/// of length `3`:
-///
-/// ```
-/// ("hello", 5, 'c');
-/// ```
-///
-/// 'Length' is also sometimes called 'arity' here; each tuple of a different
-/// length is a different, distinct type.
-///
-/// Tuples are *heterogeneous*. This means that each element of the tuple can
-/// have a different type. In that tuple above, it has the type:
-///
-/// ```
-/// # let _:
-/// (&'static str, i32, char)
-/// # = ("hello", 5, 'c');
-/// ```
-///
-/// Tuples are a *sequence*. This means that they can be accessed by position;
-/// this is called 'tuple indexing', and it looks like this:
-///
-/// ```rust
-/// let tuple = ("hello", 5, 'c');
-///
-/// assert_eq!(tuple.0, "hello");
-/// assert_eq!(tuple.1, 5);
-/// assert_eq!(tuple.2, 'c');
-/// ```
-///
-/// The sequential nature of the tuple applies to its implementations of various
-/// traits. For example, in [`PartialOrd`] and [`Ord`], the elements are compared
-/// sequentially until the first non-equal set is found.
-///
-/// For more about tuples, see [the book](../book/ch03-02-data-types.html#the-tuple-type).
-///
-// Hardcoded anchor in src/librustdoc/html/format.rs
-// linked to as `#trait-implementations-1`
-/// # Trait implementations
-///
-/// In this documentation the shorthand `(T₁, T₂, …, Tₙ)` is used to represent tuples of varying
-/// length. When that is used, any trait bound expressed on `T` applies to each element of the
-/// tuple independently. Note that this is a convenience notation to avoid repetitive
-/// documentation, not valid Rust syntax.
-///
-/// Due to a temporary restriction in Rust’s type system, the following traits are only
-/// implemented on tuples of arity 12 or less. In the future, this may change:
-///
-/// * [`PartialEq`]
-/// * [`Eq`]
-/// * [`PartialOrd`]
-/// * [`Ord`]
-/// * [`Debug`]
-/// * [`Default`]
-/// * [`Hash`]
-/// * [`From<[T; N]>`][from]
-///
-/// [from]: convert::From
-/// [`Debug`]: fmt::Debug
-/// [`Hash`]: hash::Hash
-///
-/// The following traits are implemented for tuples of any length. These traits have
-/// implementations that are automatically generated by the compiler, so are not limited by
-/// missing language features.
-///
-/// * [`Clone`]
-/// * [`Copy`]
-/// * [`Send`]
-/// * [`Sync`]
-/// * [`Unpin`]
-/// * [`UnwindSafe`]
-/// * [`RefUnwindSafe`]
-///
-/// [`UnwindSafe`]: panic::UnwindSafe
-/// [`RefUnwindSafe`]: panic::RefUnwindSafe
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```
-/// let tuple = ("hello", 5, 'c');
-///
-/// assert_eq!(tuple.0, "hello");
-/// ```
-///
-/// Tuples are often used as a return type when you want to return more than
-/// one value:
-///
-/// ```
-/// fn calculate_point() -> (i32, i32) {
-/// // Don't do a calculation, that's not the point of the example
-/// (4, 5)
-/// }
-///
-/// let point = calculate_point();
-///
-/// assert_eq!(point.0, 4);
-/// assert_eq!(point.1, 5);
-///
-/// // Combining this with patterns can be nicer.
-///
-/// let (x, y) = calculate_point();
-///
-/// assert_eq!(x, 4);
-/// assert_eq!(y, 5);
-/// ```
-///
-/// Homogenous tuples can be created from arrays of appropriate length:
-///
-/// ```
-/// let array: [u32; 3] = [1, 2, 3];
-/// let tuple: (u32, u32, u32) = array.into();
-/// ```
-///
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_tuple {}
-
-// Required to make auto trait impls render.
-// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
-#[doc(hidden)]
-impl<T> (T,) {}
-
-// Fake impl that's only really used for docs.
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(fake_variadic)]
-/// This trait is implemented on arbitrary-length tuples.
-impl<T: Clone> Clone for (T,) {
- fn clone(&self) -> Self {
- loop {}
- }
-}
-
-// Fake impl that's only really used for docs.
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(fake_variadic)]
-/// This trait is implemented on arbitrary-length tuples.
-impl<T: Copy> Copy for (T,) {
- // empty
-}
-
-#[rustc_doc_primitive = "f32"]
-/// A 32-bit floating point type (specifically, the "binary32" type defined in IEEE 754-2008).
-///
-/// This type can represent a wide range of decimal numbers, like `3.5`, `27`,
-/// `-113.75`, `0.0078125`, `34359738368`, `0`, `-1`. So unlike integer types
-/// (such as `i32`), floating point types can represent non-integer numbers,
-/// too.
-///
-/// However, being able to represent this wide range of numbers comes at the
-/// cost of precision: floats can only represent some of the real numbers and
-/// calculation with floats round to a nearby representable number. For example,
-/// `5.0` and `1.0` can be exactly represented as `f32`, but `1.0 / 5.0` results
-/// in `0.20000000298023223876953125` since `0.2` cannot be exactly represented
-/// as `f32`. Note, however, that printing floats with `println` and friends will
-/// often discard insignificant digits: `println!("{}", 1.0f32 / 5.0f32)` will
-/// print `0.2`.
-///
-/// Additionally, `f32` can represent some special values:
-///
-/// - −0.0: IEEE 754 floating point numbers have a bit that indicates their sign, so −0.0 is a
-/// possible value. For comparison −0.0 = +0.0, but floating point operations can carry
-/// the sign bit through arithmetic operations. This means −0.0 × +0.0 produces −0.0 and
-/// a negative number rounded to a value smaller than a float can represent also produces −0.0.
-/// - [∞](#associatedconstant.INFINITY) and
-/// [−∞](#associatedconstant.NEG_INFINITY): these result from calculations
-/// like `1.0 / 0.0`.
-/// - [NaN (not a number)](#associatedconstant.NAN): this value results from
-/// calculations like `(-1.0).sqrt()`. NaN has some potentially unexpected
-/// behavior:
-/// - It is not equal to any float, including itself! This is the reason `f32`
-/// doesn't implement the `Eq` trait.
-/// - It is also neither smaller nor greater than any float, making it
-/// impossible to sort by the default comparison operation, which is the
-/// reason `f32` doesn't implement the `Ord` trait.
-/// - It is also considered *infectious* as almost all calculations where one
-/// of the operands is NaN will also result in NaN. The explanations on this
-/// page only explicitly document behavior on NaN operands if this default
-/// is deviated from.
-/// - Lastly, there are multiple bit patterns that are considered NaN.
-/// Rust does not currently guarantee that the bit patterns of NaN are
-/// preserved over arithmetic operations, and they are not guaranteed to be
-/// portable or even fully deterministic! This means that there may be some
-/// surprising results upon inspecting the bit patterns,
-/// as the same calculations might produce NaNs with different bit patterns.
-///
-/// When the number resulting from a primitive operation (addition,
-/// subtraction, multiplication, or division) on this type is not exactly
-/// representable as `f32`, it is rounded according to the roundTiesToEven
-/// direction defined in IEEE 754-2008. That means:
-///
-/// - The result is the representable value closest to the true value, if there
-/// is a unique closest representable value.
-/// - If the true value is exactly half-way between two representable values,
-/// the result is the one with an even least-significant binary digit.
-/// - If the true value's magnitude is ≥ `f32::MAX` + 2<sup>(`f32::MAX_EXP` −
-/// `f32::MANTISSA_DIGITS` − 1)</sup>, the result is ∞ or −∞ (preserving the
-/// true value's sign).
-///
-/// For more information on floating point numbers, see [Wikipedia][wikipedia].
-///
-/// *[See also the `std::f32::consts` module](crate::f32::consts).*
-///
-/// [wikipedia]: https://en.wikipedia.org/wiki/Single-precision_floating-point_format
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_f32 {}
-
-#[rustc_doc_primitive = "f64"]
-/// A 64-bit floating point type (specifically, the "binary64" type defined in IEEE 754-2008).
-///
-/// This type is very similar to [`f32`], but has increased
-/// precision by using twice as many bits. Please see [the documentation for
-/// `f32`][`f32`] or [Wikipedia on double precision
-/// values][wikipedia] for more information.
-///
-/// *[See also the `std::f64::consts` module](crate::f64::consts).*
-///
-/// [`f32`]: prim@f32
-/// [wikipedia]: https://en.wikipedia.org/wiki/Double-precision_floating-point_format
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_f64 {}
-
-#[rustc_doc_primitive = "i8"]
-//
-/// The 8-bit signed integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_i8 {}
-
-#[rustc_doc_primitive = "i16"]
-//
-/// The 16-bit signed integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_i16 {}
-
-#[rustc_doc_primitive = "i32"]
-//
-/// The 32-bit signed integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_i32 {}
-
-#[rustc_doc_primitive = "i64"]
-//
-/// The 64-bit signed integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_i64 {}
-
-#[rustc_doc_primitive = "i128"]
-//
-/// The 128-bit signed integer type.
-#[stable(feature = "i128", since = "1.26.0")]
-mod prim_i128 {}
-
-#[rustc_doc_primitive = "u8"]
-//
-/// The 8-bit unsigned integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_u8 {}
-
-#[rustc_doc_primitive = "u16"]
-//
-/// The 16-bit unsigned integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_u16 {}
-
-#[rustc_doc_primitive = "u32"]
-//
-/// The 32-bit unsigned integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_u32 {}
-
-#[rustc_doc_primitive = "u64"]
-//
-/// The 64-bit unsigned integer type.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_u64 {}
-
-#[rustc_doc_primitive = "u128"]
-//
-/// The 128-bit unsigned integer type.
-#[stable(feature = "i128", since = "1.26.0")]
-mod prim_u128 {}
-
-#[rustc_doc_primitive = "isize"]
-//
-/// The pointer-sized signed integer type.
-///
-/// The size of this primitive is how many bytes it takes to reference any
-/// location in memory. For example, on a 32 bit target, this is 4 bytes
-/// and on a 64 bit target, this is 8 bytes.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_isize {}
-
-#[rustc_doc_primitive = "usize"]
-//
-/// The pointer-sized unsigned integer type.
-///
-/// The size of this primitive is how many bytes it takes to reference any
-/// location in memory. For example, on a 32 bit target, this is 4 bytes
-/// and on a 64 bit target, this is 8 bytes.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_usize {}
-
-#[rustc_doc_primitive = "reference"]
-#[doc(alias = "&")]
-#[doc(alias = "&mut")]
-//
-/// References, `&T` and `&mut T`.
-///
-/// A reference represents a borrow of some owned value. You can get one by using the `&` or `&mut`
-/// operators on a value, or by using a [`ref`](../std/keyword.ref.html) or
-/// <code>[ref](../std/keyword.ref.html) [mut](../std/keyword.mut.html)</code> pattern.
-///
-/// For those familiar with pointers, a reference is just a pointer that is assumed to be
-/// aligned, not null, and pointing to memory containing a valid value of `T` - for example,
-/// <code>&[bool]</code> can only point to an allocation containing the integer values `1`
-/// ([`true`](../std/keyword.true.html)) or `0` ([`false`](../std/keyword.false.html)), but
-/// creating a <code>&[bool]</code> that points to an allocation containing
-/// the value `3` causes undefined behaviour.
-/// In fact, <code>[Option]\<&T></code> has the same memory representation as a
-/// nullable but aligned pointer, and can be passed across FFI boundaries as such.
-///
-/// In most cases, references can be used much like the original value. Field access, method
-/// calling, and indexing work the same (save for mutability rules, of course). In addition, the
-/// comparison operators transparently defer to the referent's implementation, allowing references
-/// to be compared the same as owned values.
-///
-/// References have a lifetime attached to them, which represents the scope for which the borrow is
-/// valid. A lifetime is said to "outlive" another one if its representative scope is as long or
-/// longer than the other. The `'static` lifetime is the longest lifetime, which represents the
-/// total life of the program. For example, string literals have a `'static` lifetime because the
-/// text data is embedded into the binary of the program, rather than in an allocation that needs
-/// to be dynamically managed.
-///
-/// `&mut T` references can be freely coerced into `&T` references with the same referent type, and
-/// references with longer lifetimes can be freely coerced into references with shorter ones.
-///
-/// Reference equality by address, instead of comparing the values pointed to, is accomplished via
-/// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while
-/// [`PartialEq`] compares values.
-///
-/// ```
-/// use std::ptr;
-///
-/// let five = 5;
-/// let other_five = 5;
-/// let five_ref = &five;
-/// let same_five_ref = &five;
-/// let other_five_ref = &other_five;
-///
-/// assert!(five_ref == same_five_ref);
-/// assert!(five_ref == other_five_ref);
-///
-/// assert!(ptr::eq(five_ref, same_five_ref));
-/// assert!(!ptr::eq(five_ref, other_five_ref));
-/// ```
-///
-/// For more information on how to use references, see [the book's section on "References and
-/// Borrowing"][book-refs].
-///
-/// [book-refs]: ../book/ch04-02-references-and-borrowing.html
-///
-/// # Trait implementations
-///
-/// The following traits are implemented for all `&T`, regardless of the type of its referent:
-///
-/// * [`Copy`]
-/// * [`Clone`] \(Note that this will not defer to `T`'s `Clone` implementation if it exists!)
-/// * [`Deref`]
-/// * [`Borrow`]
-/// * [`fmt::Pointer`]
-///
-/// [`Deref`]: ops::Deref
-/// [`Borrow`]: borrow::Borrow
-///
-/// `&mut T` references get all of the above except `Copy` and `Clone` (to prevent creating
-/// multiple simultaneous mutable borrows), plus the following, regardless of the type of its
-/// referent:
-///
-/// * [`DerefMut`]
-/// * [`BorrowMut`]
-///
-/// [`DerefMut`]: ops::DerefMut
-/// [`BorrowMut`]: borrow::BorrowMut
-/// [bool]: prim@bool
-///
-/// The following traits are implemented on `&T` references if the underlying `T` also implements
-/// that trait:
-///
-/// * All the traits in [`std::fmt`] except [`fmt::Pointer`] (which is implemented regardless of the type of its referent) and [`fmt::Write`]
-/// * [`PartialOrd`]
-/// * [`Ord`]
-/// * [`PartialEq`]
-/// * [`Eq`]
-/// * [`AsRef`]
-/// * [`Fn`] \(in addition, `&T` references get [`FnMut`] and [`FnOnce`] if `T: Fn`)
-/// * [`Hash`]
-/// * [`ToSocketAddrs`]
-/// * [`Send`] \(`&T` references also require <code>T: [Sync]</code>)
-/// * [`Sync`]
-///
-/// [`std::fmt`]: fmt
-/// [`Hash`]: hash::Hash
-#[doc = concat!("[`ToSocketAddrs`]: ", include_str!("../primitive_docs/net_tosocketaddrs.md"))]
-///
-/// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T`
-/// implements that trait:
-///
-/// * [`AsMut`]
-/// * [`FnMut`] \(in addition, `&mut T` references get [`FnOnce`] if `T: FnMut`)
-/// * [`fmt::Write`]
-/// * [`Iterator`]
-/// * [`DoubleEndedIterator`]
-/// * [`ExactSizeIterator`]
-/// * [`FusedIterator`]
-/// * [`TrustedLen`]
-/// * [`io::Write`]
-/// * [`Read`]
-/// * [`Seek`]
-/// * [`BufRead`]
-///
-/// [`FusedIterator`]: iter::FusedIterator
-/// [`TrustedLen`]: iter::TrustedLen
-#[doc = concat!("[`Seek`]: ", include_str!("../primitive_docs/io_seek.md"))]
-#[doc = concat!("[`BufRead`]: ", include_str!("../primitive_docs/io_bufread.md"))]
-#[doc = concat!("[`Read`]: ", include_str!("../primitive_docs/io_read.md"))]
-#[doc = concat!("[`io::Write`]: ", include_str!("../primitive_docs/io_write.md"))]
-///
-/// Note that due to method call deref coercion, simply calling a trait method will act like they
-/// work on references as well as they do on owned values! The implementations described here are
-/// meant for generic contexts, where the final type `T` is a type parameter or otherwise not
-/// locally known.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_ref {}
-
-#[rustc_doc_primitive = "fn"]
-//
-/// Function pointers, like `fn(usize) -> bool`.
-///
-/// *See also the traits [`Fn`], [`FnMut`], and [`FnOnce`].*
-///
-/// Function pointers are pointers that point to *code*, not data. They can be called
-/// just like functions. Like references, function pointers are, among other things, assumed to
-/// not be null, so if you want to pass a function pointer over FFI and be able to accommodate null
-/// pointers, make your type [`Option<fn()>`](core::option#options-and-pointers-nullable-pointers)
-/// with your required signature.
-///
-/// ### Safety
-///
-/// Plain function pointers are obtained by casting either plain functions, or closures that don't
-/// capture an environment:
-///
-/// ```
-/// fn add_one(x: usize) -> usize {
-/// x + 1
-/// }
-///
-/// let ptr: fn(usize) -> usize = add_one;
-/// assert_eq!(ptr(5), 6);
-///
-/// let clos: fn(usize) -> usize = |x| x + 5;
-/// assert_eq!(clos(5), 10);
-/// ```
-///
-/// In addition to varying based on their signature, function pointers come in two flavors: safe
-/// and unsafe. Plain `fn()` function pointers can only point to safe functions,
-/// while `unsafe fn()` function pointers can point to safe or unsafe functions.
-///
-/// ```
-/// fn add_one(x: usize) -> usize {
-/// x + 1
-/// }
-///
-/// unsafe fn add_one_unsafely(x: usize) -> usize {
-/// x + 1
-/// }
-///
-/// let safe_ptr: fn(usize) -> usize = add_one;
-///
-/// //ERROR: mismatched types: expected normal fn, found unsafe fn
-/// //let bad_ptr: fn(usize) -> usize = add_one_unsafely;
-///
-/// let unsafe_ptr: unsafe fn(usize) -> usize = add_one_unsafely;
-/// let really_safe_ptr: unsafe fn(usize) -> usize = add_one;
-/// ```
-///
-/// ### ABI
-///
-/// On top of that, function pointers can vary based on what ABI they use. This
-/// is achieved by adding the `extern` keyword before the type, followed by the
-/// ABI in question. The default ABI is "Rust", i.e., `fn()` is the exact same
-/// type as `extern "Rust" fn()`. A pointer to a function with C ABI would have
-/// type `extern "C" fn()`.
-///
-/// `extern "ABI" { ... }` blocks declare functions with ABI "ABI". The default
-/// here is "C", i.e., functions declared in an `extern {...}` block have "C"
-/// ABI.
-///
-/// For more information and a list of supported ABIs, see [the nomicon's
-/// section on foreign calling conventions][nomicon-abi].
-///
-/// [nomicon-abi]: ../nomicon/ffi.html#foreign-calling-conventions
-///
-/// ### Variadic functions
-///
-/// Extern function declarations with the "C" or "cdecl" ABIs can also be *variadic*, allowing them
-/// to be called with a variable number of arguments. Normal Rust functions, even those with an
-/// `extern "ABI"`, cannot be variadic. For more information, see [the nomicon's section on
-/// variadic functions][nomicon-variadic].
-///
-/// [nomicon-variadic]: ../nomicon/ffi.html#variadic-functions
-///
-/// ### Creating function pointers
-///
-/// When `bar` is the name of a function, then the expression `bar` is *not* a
-/// function pointer. Rather, it denotes a value of an unnameable type that
-/// uniquely identifies the function `bar`. The value is zero-sized because the
-/// type already identifies the function. This has the advantage that "calling"
-/// the value (it implements the `Fn*` traits) does not require dynamic
-/// dispatch.
-///
-/// This zero-sized type *coerces* to a regular function pointer. For example:
-///
-/// ```rust
-/// use std::mem;
-///
-/// fn bar(x: i32) {}
-///
-/// let not_bar_ptr = bar; // `not_bar_ptr` is zero-sized, uniquely identifying `bar`
-/// assert_eq!(mem::size_of_val(&not_bar_ptr), 0);
-///
-/// let bar_ptr: fn(i32) = not_bar_ptr; // force coercion to function pointer
-/// assert_eq!(mem::size_of_val(&bar_ptr), mem::size_of::<usize>());
-///
-/// let footgun = &bar; // this is a shared reference to the zero-sized type identifying `bar`
-/// ```
-///
-/// The last line shows that `&bar` is not a function pointer either. Rather, it
-/// is a reference to the function-specific ZST. `&bar` is basically never what you
-/// want when `bar` is a function.
-///
-/// ### Casting to and from integers
-///
-/// You cast function pointers directly to integers:
-///
-/// ```rust
-/// let fnptr: fn(i32) -> i32 = |x| x+2;
-/// let fnptr_addr = fnptr as usize;
-/// ```
-///
-/// However, a direct cast back is not possible. You need to use `transmute`:
-///
-/// ```rust
-/// # #[cfg(not(miri))] { // FIXME: use strict provenance APIs once they are stable, then remove this `cfg`
-/// # let fnptr: fn(i32) -> i32 = |x| x+2;
-/// # let fnptr_addr = fnptr as usize;
-/// let fnptr = fnptr_addr as *const ();
-/// let fnptr: fn(i32) -> i32 = unsafe { std::mem::transmute(fnptr) };
-/// assert_eq!(fnptr(40), 42);
-/// # }
-/// ```
-///
-/// Crucially, we `as`-cast to a raw pointer before `transmute`ing to a function pointer.
-/// This avoids an integer-to-pointer `transmute`, which can be problematic.
-/// Transmuting between raw pointers and function pointers (i.e., two pointer types) is fine.
-///
-/// Note that all of this is not portable to platforms where function pointers and data pointers
-/// have different sizes.
-///
-/// ### Trait implementations
-///
-/// In this documentation the shorthand `fn (T₁, T₂, …, Tₙ)` is used to represent non-variadic
-/// function pointers of varying length. Note that this is a convenience notation to avoid
-/// repetitive documentation, not valid Rust syntax.
-///
-/// Due to a temporary restriction in Rust's type system, these traits are only implemented on
-/// functions that take 12 arguments or less, with the `"Rust"` and `"C"` ABIs. In the future, this
-/// may change:
-///
-/// * [`PartialEq`]
-/// * [`Eq`]
-/// * [`PartialOrd`]
-/// * [`Ord`]
-/// * [`Hash`]
-/// * [`Pointer`]
-/// * [`Debug`]
-///
-/// The following traits are implemented for function pointers with any number of arguments and
-/// any ABI. These traits have implementations that are automatically generated by the compiler,
-/// so are not limited by missing language features:
-///
-/// * [`Clone`]
-/// * [`Copy`]
-/// * [`Send`]
-/// * [`Sync`]
-/// * [`Unpin`]
-/// * [`UnwindSafe`]
-/// * [`RefUnwindSafe`]
-///
-/// [`Hash`]: hash::Hash
-/// [`Pointer`]: fmt::Pointer
-/// [`UnwindSafe`]: panic::UnwindSafe
-/// [`RefUnwindSafe`]: panic::RefUnwindSafe
-///
-/// In addition, all *safe* function pointers implement [`Fn`], [`FnMut`], and [`FnOnce`], because
-/// these traits are specially known to the compiler.
-#[stable(feature = "rust1", since = "1.0.0")]
-mod prim_fn {}
-
-// Required to make auto trait impls render.
-// See src/librustdoc/passes/collect_trait_impls.rs:collect_trait_impls
-#[doc(hidden)]
-impl<Ret, T> fn(T) -> Ret {}
-
-// Fake impl that's only really used for docs.
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(fake_variadic)]
-/// This trait is implemented on function pointers with any number of arguments.
-impl<Ret, T> Clone for fn(T) -> Ret {
- fn clone(&self) -> Self {
- loop {}
- }
-}
-
-// Fake impl that's only really used for docs.
-#[cfg(doc)]
-#[stable(feature = "rust1", since = "1.0.0")]
-#[doc(fake_variadic)]
-/// This trait is implemented on function pointers with any number of arguments.
-impl<Ret, T> Copy for fn(T) -> Ret {
- // empty
-}
diff --git a/library/std/src/process.rs b/library/std/src/process.rs
index 7380b45b0..8c1497613 100644
--- a/library/std/src/process.rs
+++ b/library/std/src/process.rs
@@ -12,9 +12,9 @@
//! use std::process::Command;
//!
//! let output = Command::new("echo")
-//! .arg("Hello world")
-//! .output()
-//! .expect("Failed to execute command");
+//! .arg("Hello world")
+//! .output()
+//! .expect("Failed to execute command");
//!
//! assert_eq!(b"Hello world\n", output.stdout.as_slice());
//! ```
@@ -101,7 +101,7 @@
#![stable(feature = "process", since = "1.0.0")]
#![deny(unsafe_op_in_unsafe_fn)]
-#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx"))))]
+#[cfg(all(test, not(any(target_os = "emscripten", target_env = "sgx", target_os = "xous"))))]
mod tests;
use crate::io::prelude::*;
@@ -154,12 +154,11 @@ use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
/// use std::process::Command;
///
/// let mut child = Command::new("/bin/cat")
-/// .arg("file.txt")
-/// .spawn()
-/// .expect("failed to execute child");
+/// .arg("file.txt")
+/// .spawn()
+/// .expect("failed to execute child");
///
-/// let ecode = child.wait()
-/// .expect("failed to wait on child");
+/// let ecode = child.wait().expect("failed to wait on child");
///
/// assert!(ecode.success());
/// ```
@@ -481,15 +480,15 @@ impl fmt::Debug for ChildStderr {
///
/// let output = if cfg!(target_os = "windows") {
/// Command::new("cmd")
-/// .args(["/C", "echo hello"])
-/// .output()
-/// .expect("failed to execute process")
+/// .args(["/C", "echo hello"])
+/// .output()
+/// .expect("failed to execute process")
/// } else {
/// Command::new("sh")
-/// .arg("-c")
-/// .arg("echo hello")
-/// .output()
-/// .expect("failed to execute process")
+/// .arg("-c")
+/// .arg("echo hello")
+/// .output()
+/// .expect("failed to execute process")
/// };
///
/// let hello = output.stdout;
@@ -502,8 +501,7 @@ impl fmt::Debug for ChildStderr {
/// use std::process::Command;
///
/// let mut echo_hello = Command::new("sh");
-/// echo_hello.arg("-c")
-/// .arg("echo hello");
+/// echo_hello.arg("-c").arg("echo hello");
/// let hello_1 = echo_hello.output().expect("failed to execute process");
/// let hello_2 = echo_hello.output().expect("failed to execute process");
/// ```
@@ -576,8 +574,8 @@ impl Command {
/// use std::process::Command;
///
/// Command::new("sh")
- /// .spawn()
- /// .expect("sh command failed to start");
+ /// .spawn()
+ /// .expect("sh command failed to start");
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn new<S: AsRef<OsStr>>(program: S) -> Command {
@@ -620,10 +618,10 @@ impl Command {
/// use std::process::Command;
///
/// Command::new("ls")
- /// .arg("-l")
- /// .arg("-a")
- /// .spawn()
- /// .expect("ls command failed to start");
+ /// .arg("-l")
+ /// .arg("-a")
+ /// .spawn()
+ /// .expect("ls command failed to start");
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn arg<S: AsRef<OsStr>>(&mut self, arg: S) -> &mut Command {
@@ -650,9 +648,9 @@ impl Command {
/// use std::process::Command;
///
/// Command::new("ls")
- /// .args(["-l", "-a"])
- /// .spawn()
- /// .expect("ls command failed to start");
+ /// .args(["-l", "-a"])
+ /// .spawn()
+ /// .expect("ls command failed to start");
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn args<I, S>(&mut self, args: I) -> &mut Command
@@ -688,9 +686,9 @@ impl Command {
/// use std::process::Command;
///
/// Command::new("ls")
- /// .env("PATH", "/bin")
- /// .spawn()
- /// .expect("ls command failed to start");
+ /// .env("PATH", "/bin")
+ /// .spawn()
+ /// .expect("ls command failed to start");
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn env<K, V>(&mut self, key: K, val: V) -> &mut Command
@@ -731,12 +729,12 @@ impl Command {
/// ).collect();
///
/// Command::new("printenv")
- /// .stdin(Stdio::null())
- /// .stdout(Stdio::inherit())
- /// .env_clear()
- /// .envs(&filtered_env)
- /// .spawn()
- /// .expect("printenv failed to start");
+ /// .stdin(Stdio::null())
+ /// .stdout(Stdio::inherit())
+ /// .env_clear()
+ /// .envs(&filtered_env)
+ /// .spawn()
+ /// .expect("printenv failed to start");
/// ```
#[stable(feature = "command_envs", since = "1.19.0")]
pub fn envs<I, K, V>(&mut self, vars: I) -> &mut Command
@@ -772,9 +770,9 @@ impl Command {
/// use std::process::Command;
///
/// Command::new("ls")
- /// .env_remove("PATH")
- /// .spawn()
- /// .expect("ls command failed to start");
+ /// .env_remove("PATH")
+ /// .spawn()
+ /// .expect("ls command failed to start");
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn env_remove<K: AsRef<OsStr>>(&mut self, key: K) -> &mut Command {
@@ -789,7 +787,7 @@ impl Command {
/// or [`Command::envs`]. In addition, it will prevent the spawned child process from inheriting
/// any environment variable from its parent process.
///
- /// After calling [`Command::env_remove`], the iterator from [`Command::get_envs`] will be
+ /// After calling [`Command::env_clear`], the iterator from [`Command::get_envs`] will be
/// empty.
///
/// You can use [`Command::env_remove`] to clear a single mapping.
@@ -802,9 +800,9 @@ impl Command {
/// use std::process::Command;
///
/// Command::new("ls")
- /// .env_clear()
- /// .spawn()
- /// .expect("ls command failed to start");
+ /// .env_clear()
+ /// .spawn()
+ /// .expect("ls command failed to start");
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn env_clear(&mut self) -> &mut Command {
@@ -830,9 +828,9 @@ impl Command {
/// use std::process::Command;
///
/// Command::new("ls")
- /// .current_dir("/bin")
- /// .spawn()
- /// .expect("ls command failed to start");
+ /// .current_dir("/bin")
+ /// .spawn()
+ /// .expect("ls command failed to start");
/// ```
///
/// [`canonicalize`]: crate::fs::canonicalize
@@ -861,9 +859,9 @@ impl Command {
/// use std::process::{Command, Stdio};
///
/// Command::new("ls")
- /// .stdin(Stdio::null())
- /// .spawn()
- /// .expect("ls command failed to start");
+ /// .stdin(Stdio::null())
+ /// .spawn()
+ /// .expect("ls command failed to start");
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn stdin<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
@@ -890,9 +888,9 @@ impl Command {
/// use std::process::{Command, Stdio};
///
/// Command::new("ls")
- /// .stdout(Stdio::null())
- /// .spawn()
- /// .expect("ls command failed to start");
+ /// .stdout(Stdio::null())
+ /// .spawn()
+ /// .expect("ls command failed to start");
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn stdout<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
@@ -919,9 +917,9 @@ impl Command {
/// use std::process::{Command, Stdio};
///
/// Command::new("ls")
- /// .stderr(Stdio::null())
- /// .spawn()
- /// .expect("ls command failed to start");
+ /// .stderr(Stdio::null())
+ /// .spawn()
+ /// .expect("ls command failed to start");
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn stderr<T: Into<Stdio>>(&mut self, cfg: T) -> &mut Command {
@@ -941,8 +939,8 @@ impl Command {
/// use std::process::Command;
///
/// Command::new("ls")
- /// .spawn()
- /// .expect("ls command failed to start");
+ /// .spawn()
+ /// .expect("ls command failed to start");
/// ```
#[stable(feature = "process", since = "1.0.0")]
pub fn spawn(&mut self) -> io::Result<Child> {
@@ -963,9 +961,9 @@ impl Command {
/// use std::process::Command;
/// use std::io::{self, Write};
/// let output = Command::new("/bin/cat")
- /// .arg("file.txt")
- /// .output()
- /// .expect("failed to execute process");
+ /// .arg("file.txt")
+ /// .output()
+ /// .expect("failed to execute process");
///
/// println!("status: {}", output.status);
/// io::stdout().write_all(&output.stdout).unwrap();
@@ -990,9 +988,9 @@ impl Command {
/// use std::process::Command;
///
/// let status = Command::new("/bin/cat")
- /// .arg("file.txt")
- /// .status()
- /// .expect("failed to execute process");
+ /// .arg("file.txt")
+ /// .status()
+ /// .expect("failed to execute process");
///
/// println!("process finished with: {status}");
///
@@ -1501,6 +1499,66 @@ impl From<fs::File> for Stdio {
}
}
+#[stable(feature = "stdio_from_stdio", since = "1.74.0")]
+impl From<io::Stdout> for Stdio {
+ /// Redirect command stdout/stderr to our stdout
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// #![feature(exit_status_error)]
+ /// use std::io;
+ /// use std::process::Command;
+ ///
+ /// # fn test() -> Result<(), Box<dyn std::error::Error>> {
+ /// let output = Command::new("whoami")
+ // "whoami" is a command which exists on both Unix and Windows,
+ // and which succeeds, producing some stdout output but no stderr.
+ /// .stdout(io::stdout())
+ /// .output()?;
+ /// output.status.exit_ok()?;
+ /// assert!(output.stdout.is_empty());
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # if cfg!(unix) {
+ /// # test().unwrap();
+ /// # }
+ /// ```
+ fn from(inherit: io::Stdout) -> Stdio {
+ Stdio::from_inner(inherit.into())
+ }
+}
+
+#[stable(feature = "stdio_from_stdio", since = "1.74.0")]
+impl From<io::Stderr> for Stdio {
+ /// Redirect command stdout/stderr to our stderr
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// #![feature(exit_status_error)]
+ /// use std::io;
+ /// use std::process::Command;
+ ///
+ /// # fn test() -> Result<(), Box<dyn std::error::Error>> {
+ /// let output = Command::new("whoami")
+ /// .stdout(io::stderr())
+ /// .output()?;
+ /// output.status.exit_ok()?;
+ /// assert!(output.stdout.is_empty());
+ /// # Ok(())
+ /// # }
+ /// #
+ /// # if cfg!(unix) {
+ /// # test().unwrap();
+ /// # }
+ /// ```
+ fn from(inherit: io::Stderr) -> Stdio {
+ Stdio::from_inner(inherit.into())
+ }
+}
+
/// Describes the result of a process after it has terminated.
///
/// This `struct` is used to represent the exit status or other termination of a child process.
@@ -1558,9 +1616,9 @@ impl ExitStatus {
/// use std::process::Command;
///
/// let status = Command::new("ls")
- /// .arg("/dev/nonexistent")
- /// .status()
- /// .expect("ls could not be executed");
+ /// .arg("/dev/nonexistent")
+ /// .status()
+ /// .expect("ls could not be executed");
///
/// println!("ls: {status}");
/// status.exit_ok().expect_err("/dev/nonexistent could be listed!");
@@ -1580,9 +1638,9 @@ impl ExitStatus {
/// use std::process::Command;
///
/// let status = Command::new("mkdir")
- /// .arg("projects")
- /// .status()
- /// .expect("failed to execute mkdir");
+ /// .arg("projects")
+ /// .status()
+ /// .expect("failed to execute mkdir");
///
/// if status.success() {
/// println!("'projects/' directory created");
@@ -1613,13 +1671,13 @@ impl ExitStatus {
/// use std::process::Command;
///
/// let status = Command::new("mkdir")
- /// .arg("projects")
- /// .status()
- /// .expect("failed to execute mkdir");
+ /// .arg("projects")
+ /// .status()
+ /// .expect("failed to execute mkdir");
///
/// match status.code() {
/// Some(code) => println!("Exited with status code: {code}"),
- /// None => println!("Process terminated by signal")
+ /// None => println!("Process terminated by signal")
/// }
/// ```
#[must_use]
@@ -1749,9 +1807,9 @@ impl ExitStatusError {
}
#[unstable(feature = "exit_status_error", issue = "84908")]
-impl Into<ExitStatus> for ExitStatusError {
- fn into(self) -> ExitStatus {
- ExitStatus(self.0.into())
+impl From<ExitStatusError> for ExitStatus {
+ fn from(error: ExitStatusError) -> Self {
+ Self(error.0.into())
}
}
diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs
index 366b59146..07d4de5c1 100644
--- a/library/std/src/process/tests.rs
+++ b/library/std/src/process/tests.rs
@@ -434,6 +434,91 @@ fn test_creation_flags() {
assert!(events > 0);
}
+/// Tests proc thread attributes by spawning a process with a custom parent process,
+/// then comparing the parent process ID with the expected parent process ID.
+#[test]
+#[cfg(windows)]
+fn test_proc_thread_attributes() {
+ use crate::mem;
+ use crate::os::windows::io::AsRawHandle;
+ use crate::os::windows::process::CommandExt;
+ use crate::sys::c::{CloseHandle, BOOL, HANDLE};
+ use crate::sys::cvt;
+
+ #[repr(C)]
+ #[allow(non_snake_case)]
+ struct PROCESSENTRY32W {
+ dwSize: u32,
+ cntUsage: u32,
+ th32ProcessID: u32,
+ th32DefaultHeapID: usize,
+ th32ModuleID: u32,
+ cntThreads: u32,
+ th32ParentProcessID: u32,
+ pcPriClassBase: i32,
+ dwFlags: u32,
+ szExeFile: [u16; 260],
+ }
+
+ extern "system" {
+ fn CreateToolhelp32Snapshot(dwflags: u32, th32processid: u32) -> HANDLE;
+ fn Process32First(hsnapshot: HANDLE, lppe: *mut PROCESSENTRY32W) -> BOOL;
+ fn Process32Next(hsnapshot: HANDLE, lppe: *mut PROCESSENTRY32W) -> BOOL;
+ }
+
+ const PROC_THREAD_ATTRIBUTE_PARENT_PROCESS: usize = 0x00020000;
+ const TH32CS_SNAPPROCESS: u32 = 0x00000002;
+
+ struct ProcessDropGuard(crate::process::Child);
+
+ impl Drop for ProcessDropGuard {
+ fn drop(&mut self) {
+ let _ = self.0.kill();
+ }
+ }
+
+ let parent = ProcessDropGuard(Command::new("cmd").spawn().unwrap());
+
+ let mut child_cmd = Command::new("cmd");
+
+ unsafe {
+ child_cmd
+ .raw_attribute(PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, parent.0.as_raw_handle() as isize);
+ }
+
+ let child = ProcessDropGuard(child_cmd.spawn().unwrap());
+
+ let h_snapshot = unsafe { CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0) };
+
+ let mut process_entry = PROCESSENTRY32W {
+ dwSize: mem::size_of::<PROCESSENTRY32W>() as u32,
+ cntUsage: 0,
+ th32ProcessID: 0,
+ th32DefaultHeapID: 0,
+ th32ModuleID: 0,
+ cntThreads: 0,
+ th32ParentProcessID: 0,
+ pcPriClassBase: 0,
+ dwFlags: 0,
+ szExeFile: [0; 260],
+ };
+
+ unsafe { cvt(Process32First(h_snapshot, &mut process_entry as *mut _)) }.unwrap();
+
+ loop {
+ if child.0.id() == process_entry.th32ProcessID {
+ break;
+ }
+ unsafe { cvt(Process32Next(h_snapshot, &mut process_entry as *mut _)) }.unwrap();
+ }
+
+ unsafe { cvt(CloseHandle(h_snapshot)) }.unwrap();
+
+ assert_eq!(parent.0.id(), process_entry.th32ParentProcessID);
+
+ drop(child)
+}
+
#[test]
fn test_command_implements_send_sync() {
fn take_send_sync_type<T: Send + Sync>(_: T) {}
@@ -452,7 +537,7 @@ fn env_empty() {
#[test]
#[cfg(not(windows))]
#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)]
-fn main() {
+fn debug_print() {
const PIDFD: &'static str =
if cfg!(target_os = "linux") { " create_pidfd: false,\n" } else { "" };
@@ -541,6 +626,51 @@ fn main() {
{PIDFD}}}"#
)
);
+
+ let mut command_with_removed_env = Command::new("boring-name");
+ command_with_removed_env.env_remove("FOO").env_remove("BAR");
+ assert_eq!(format!("{command_with_removed_env:?}"), r#"env -u BAR -u FOO "boring-name""#);
+ assert_eq!(
+ format!("{command_with_removed_env:#?}"),
+ format!(
+ r#"Command {{
+ program: "boring-name",
+ args: [
+ "boring-name",
+ ],
+ env: CommandEnv {{
+ clear: false,
+ vars: {{
+ "BAR": None,
+ "FOO": None,
+ }},
+ }},
+{PIDFD}}}"#
+ )
+ );
+
+ let mut command_with_cleared_env = Command::new("boring-name");
+ command_with_cleared_env.env_clear().env("BAR", "val").env_remove("FOO");
+ assert_eq!(format!("{command_with_cleared_env:?}"), r#"env -i BAR="val" "boring-name""#);
+ assert_eq!(
+ format!("{command_with_cleared_env:#?}"),
+ format!(
+ r#"Command {{
+ program: "boring-name",
+ args: [
+ "boring-name",
+ ],
+ env: CommandEnv {{
+ clear: true,
+ vars: {{
+ "BAR": Some(
+ "val",
+ ),
+ }},
+ }},
+{PIDFD}}}"#
+ )
+ );
}
// See issue #91991
diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs
index f92bb1a4b..d353c7bd5 100644
--- a/library/std/src/sync/mpsc/mod.rs
+++ b/library/std/src/sync/mpsc/mod.rs
@@ -626,11 +626,6 @@ impl<T> Clone for Sender<T> {
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Drop for Sender<T> {
- fn drop(&mut self) {}
-}
-
#[stable(feature = "mpsc_debug", since = "1.8.0")]
impl<T> fmt::Debug for Sender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -755,11 +750,6 @@ impl<T> Clone for SyncSender<T> {
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Drop for SyncSender<T> {
- fn drop(&mut self) {}
-}
-
#[stable(feature = "mpsc_debug", since = "1.8.0")]
impl<T> fmt::Debug for SyncSender<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -1096,11 +1086,6 @@ impl<T> IntoIterator for Receiver<T> {
}
}
-#[stable(feature = "rust1", since = "1.0.0")]
-impl<T> Drop for Receiver<T> {
- fn drop(&mut self) {}
-}
-
#[stable(feature = "mpsc_debug", since = "1.8.0")]
impl<T> fmt::Debug for Receiver<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
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)?))
+ }
+}
diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs
index e9c727cbb..e18638f2a 100644
--- a/library/std/src/sys_common/mod.rs
+++ b/library/std/src/sys_common/mod.rs
@@ -44,8 +44,10 @@ cfg_if::cfg_if! {
cfg_if::cfg_if! {
if #[cfg(any(target_os = "l4re",
+ target_os = "uefi",
feature = "restricted-std",
all(target_family = "wasm", not(target_os = "emscripten")),
+ target_os = "xous",
all(target_vendor = "fortanix", target_env = "sgx")))] {
pub use crate::sys::net;
} else {
diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs
index 2976a9f57..4f5b17dea 100644
--- a/library/std/src/sys_common/net.rs
+++ b/library/std/src/sys_common/net.rs
@@ -32,6 +32,7 @@ cfg_if::cfg_if! {
cfg_if::cfg_if! {
if #[cfg(any(
target_os = "linux", target_os = "android",
+ target_os = "hurd",
target_os = "dragonfly", target_os = "freebsd",
target_os = "openbsd", target_os = "netbsd",
target_os = "haiku", target_os = "nto"))] {
diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs
index 18883048d..4d295cf0f 100644
--- a/library/std/src/sys_common/process.rs
+++ b/library/std/src/sys_common/process.rs
@@ -80,6 +80,10 @@ impl CommandEnv {
self.vars.clear();
}
+ pub fn does_clear(&self) -> bool {
+ self.clear
+ }
+
pub fn have_changed_path(&self) -> bool {
self.saw_path || self.clear
}
diff --git a/library/std/src/sys_common/thread_info.rs b/library/std/src/sys_common/thread_info.rs
index 88d937a7d..8d51732e0 100644
--- a/library/std/src/sys_common/thread_info.rs
+++ b/library/std/src/sys_common/thread_info.rs
@@ -1,46 +1,51 @@
#![allow(dead_code)] // stack_guard isn't used right now on all platforms
-use crate::cell::RefCell;
+use crate::cell::OnceCell;
use crate::sys::thread::guard::Guard;
use crate::thread::Thread;
struct ThreadInfo {
- stack_guard: Option<Guard>,
- thread: Thread,
+ stack_guard: OnceCell<Guard>,
+ thread: OnceCell<Thread>,
}
-thread_local! { static THREAD_INFO: RefCell<Option<ThreadInfo>> = const { RefCell::new(None) } }
+thread_local! {
+ static THREAD_INFO: ThreadInfo = const { ThreadInfo {
+ stack_guard: OnceCell::new(),
+ thread: OnceCell::new()
+ } };
+}
impl ThreadInfo {
fn with<R, F>(f: F) -> Option<R>
where
- F: FnOnce(&mut ThreadInfo) -> R,
+ F: FnOnce(&Thread, &OnceCell<Guard>) -> R,
{
THREAD_INFO
.try_with(move |thread_info| {
- let mut thread_info = thread_info.borrow_mut();
- let thread_info = thread_info.get_or_insert_with(|| ThreadInfo {
- stack_guard: None,
- thread: Thread::new(None),
- });
- f(thread_info)
+ let thread = thread_info.thread.get_or_init(|| Thread::new(None));
+ f(thread, &thread_info.stack_guard)
})
.ok()
}
}
pub fn current_thread() -> Option<Thread> {
- ThreadInfo::with(|info| info.thread.clone())
+ ThreadInfo::with(|thread, _| thread.clone())
}
pub fn stack_guard() -> Option<Guard> {
- ThreadInfo::with(|info| info.stack_guard.clone()).and_then(|o| o)
+ ThreadInfo::with(|_, guard| guard.get().cloned()).flatten()
}
+/// Set new thread info, panicking if it has already been initialized
+#[allow(unreachable_code, unreachable_patterns)] // some platforms don't use stack_guard
pub fn set(stack_guard: Option<Guard>, thread: Thread) {
THREAD_INFO.with(move |thread_info| {
- let mut thread_info = thread_info.borrow_mut();
- rtassert!(thread_info.is_none());
- *thread_info = Some(ThreadInfo { stack_guard, thread });
+ rtassert!(thread_info.stack_guard.get().is_none() && thread_info.thread.get().is_none());
+ if let Some(guard) = stack_guard {
+ thread_info.stack_guard.set(guard).unwrap();
+ }
+ thread_info.thread.set(thread).unwrap();
});
}
diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs
index e4581c2de..7b26068c2 100644
--- a/library/std/src/thread/mod.rs
+++ b/library/std/src/thread/mod.rs
@@ -178,7 +178,7 @@ use crate::sys_common::thread;
use crate::sys_common::thread_info;
use crate::sys_common::thread_parking::Parker;
use crate::sys_common::{AsInner, IntoInner};
-use crate::time::Duration;
+use crate::time::{Duration, Instant};
#[stable(feature = "scoped_threads", since = "1.63.0")]
mod scoped;
@@ -872,6 +872,86 @@ pub fn sleep(dur: Duration) {
imp::Thread::sleep(dur)
}
+/// Puts the current thread to sleep until the specified deadline has passed.
+///
+/// The thread may still be asleep after the deadline specified due to
+/// scheduling specifics or platform-dependent functionality. It will never
+/// wake before.
+///
+/// This function is blocking, and should not be used in `async` functions.
+///
+/// # Platform-specific behavior
+///
+/// This function uses [`sleep`] internally, see its platform-specific behaviour.
+///
+///
+/// # Examples
+///
+/// A simple game loop that limits the game to 60 frames per second.
+///
+/// ```no_run
+/// #![feature(thread_sleep_until)]
+/// # use std::time::{Duration, Instant};
+/// # use std::thread;
+/// #
+/// # fn update() {}
+/// # fn render() {}
+/// #
+/// let max_fps = 60.0;
+/// let frame_time = Duration::from_secs_f32(1.0/max_fps);
+/// let mut next_frame = Instant::now();
+/// loop {
+/// thread::sleep_until(next_frame);
+/// next_frame += frame_time;
+/// update();
+/// render();
+/// }
+/// ```
+///
+/// A slow api we must not call too fast and which takes a few
+/// tries before succeeding. By using `sleep_until` the time the
+/// api call takes does not influence when we retry or when we give up
+///
+/// ```no_run
+/// #![feature(thread_sleep_until)]
+/// # use std::time::{Duration, Instant};
+/// # use std::thread;
+/// #
+/// # enum Status {
+/// # Ready(usize),
+/// # Waiting,
+/// # }
+/// # fn slow_web_api_call() -> Status { Status::Ready(42) }
+/// #
+/// # const MAX_DURATION: Duration = Duration::from_secs(10);
+/// #
+/// # fn try_api_call() -> Result<usize, ()> {
+/// let deadline = Instant::now() + MAX_DURATION;
+/// let delay = Duration::from_millis(250);
+/// let mut next_attempt = Instant::now();
+/// loop {
+/// if Instant::now() > deadline {
+/// break Err(());
+/// }
+/// if let Status::Ready(data) = slow_web_api_call() {
+/// break Ok(data);
+/// }
+///
+/// next_attempt = deadline.min(next_attempt + delay);
+/// thread::sleep_until(next_attempt);
+/// }
+/// # }
+/// # let _data = try_api_call();
+/// ```
+#[unstable(feature = "thread_sleep_until", issue = "113752")]
+pub fn sleep_until(deadline: Instant) {
+ let now = Instant::now();
+
+ if let Some(delay) = deadline.checked_duration_since(now) {
+ sleep(delay);
+ }
+}
+
/// Used to ensure that `park` and `park_timeout` do not unwind, as that can
/// cause undefined behaviour if not handled correctly (see #102398 for context).
struct PanicGuard;
diff --git a/library/std/src/time.rs b/library/std/src/time.rs
index 00e2857a1..005d8c767 100644
--- a/library/std/src/time.rs
+++ b/library/std/src/time.rs
@@ -58,6 +58,8 @@ pub use core::time::TryFromFloatSecsError;
/// some seconds may be longer than others). An instant may jump forwards or
/// experience time dilation (slow down or speed up), but it will never go
/// backwards.
+/// As part of this non-guarantee it is also not specified whether system suspends count as
+/// elapsed time or not. The behavior varies across platforms and rust versions.
///
/// Instants are opaque types that can only be compared to one another. There is
/// no method to get "the number of seconds" from an instant. Instead, it only
@@ -176,6 +178,14 @@ pub struct Instant(time::Instant);
/// The size of a `SystemTime` struct may vary depending on the target operating
/// system.
///
+/// A `SystemTime` does not count leap seconds.
+/// `SystemTime::now()`'s behaviour around a leap second
+/// is the same as the operating system's wall clock.
+/// The precise behaviour near a leap second
+/// (e.g. whether the clock appears to run slow or fast, or stop, or jump)
+/// depends on platform and configuration,
+/// so should not be relied on.
+///
/// Example:
///
/// ```no_run
@@ -461,6 +471,9 @@ impl fmt::Debug for Instant {
impl SystemTime {
/// An anchor in time which can be used to create new `SystemTime` instances or
/// learn about where in time a `SystemTime` lies.
+ //
+ // NOTE! this documentation is duplicated, here and in std::time::UNIX_EPOCH.
+ // The two copies are not quite identical, because of the difference in naming.
///
/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with
/// respect to the system clock. Using `duration_since` on an existing
@@ -468,6 +481,11 @@ impl SystemTime {
/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a
/// `SystemTime` instance to represent another fixed point in time.
///
+ /// `duration_since(UNIX_EPOCH).unwrap().as_secs()` returns
+ /// the number of non-leap seconds since the start of 1970 UTC.
+ /// This is a POSIX `time_t` (as a `u64`),
+ /// and is the same time representation as used in many Internet protocols.
+ ///
/// # Examples
///
/// ```no_run
@@ -617,6 +635,9 @@ impl fmt::Debug for SystemTime {
/// An anchor in time which can be used to create new `SystemTime` instances or
/// learn about where in time a `SystemTime` lies.
+//
+// NOTE! this documentation is duplicated, here and in SystemTime::UNIX_EPOCH.
+// The two copies are not quite identical, because of the difference in naming.
///
/// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with
/// respect to the system clock. Using `duration_since` on an existing
@@ -624,6 +645,11 @@ impl fmt::Debug for SystemTime {
/// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a
/// [`SystemTime`] instance to represent another fixed point in time.
///
+/// `duration_since(UNIX_EPOCH).unwrap().as_secs()` returns
+/// the number of non-leap seconds since the start of 1970 UTC.
+/// This is a POSIX `time_t` (as a `u64`),
+/// and is the same time representation as used in many Internet protocols.
+///
/// # Examples
///
/// ```no_run
diff --git a/library/std/tests/env.rs b/library/std/tests/env.rs
index 96b4f372b..a1ca85c21 100644
--- a/library/std/tests/env.rs
+++ b/library/std/tests/env.rs
@@ -5,6 +5,7 @@ use rand::distributions::{Alphanumeric, DistString};
mod common;
use common::test_rng;
+use std::thread;
#[track_caller]
fn make_rand_name() -> OsString {
@@ -140,3 +141,22 @@ fn env_home_dir() {
}
}
}
+
+#[test] // miri shouldn't detect any data race in this fn
+#[cfg_attr(any(not(miri), target_os = "emscripten"), ignore)]
+fn test_env_get_set_multithreaded() {
+ let getter = thread::spawn(|| {
+ for _ in 0..100 {
+ let _ = var_os("foo");
+ }
+ });
+
+ let setter = thread::spawn(|| {
+ for _ in 0..100 {
+ set_var("foo", "bar");
+ }
+ });
+
+ let _ = getter.join();
+ let _ = setter.join();
+}