summaryrefslogtreecommitdiffstats
path: root/library/std/src/sys
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src/sys')
-rw-r--r--library/std/src/sys/common/alloc.rs1
-rw-r--r--library/std/src/sys/hermit/args.rs2
-rw-r--r--library/std/src/sys/hermit/fd.rs77
-rw-r--r--library/std/src/sys/hermit/fs.rs57
-rw-r--r--library/std/src/sys/hermit/mod.rs92
-rw-r--r--library/std/src/sys/hermit/net.rs639
-rw-r--r--library/std/src/sys/hermit/os.rs2
-rw-r--r--library/std/src/sys/hermit/thread.rs4
-rw-r--r--library/std/src/sys/hermit/thread_local_dtor.rs23
-rw-r--r--library/std/src/sys/hermit/time.rs98
-rw-r--r--library/std/src/sys/itron/thread.rs2
-rw-r--r--library/std/src/sys/itron/thread_parking.rs37
-rw-r--r--library/std/src/sys/itron/wait_flag.rs72
-rw-r--r--library/std/src/sys/solid/mod.rs4
-rw-r--r--library/std/src/sys/solid/thread_local_dtor.rs32
-rw-r--r--library/std/src/sys/unix/args.rs31
-rw-r--r--library/std/src/sys/unix/env.rs11
-rw-r--r--library/std/src/sys/unix/fd.rs203
-rw-r--r--library/std/src/sys/unix/fs.rs92
-rw-r--r--library/std/src/sys/unix/locks/pthread_condvar.rs11
-rw-r--r--library/std/src/sys/unix/mod.rs2
-rw-r--r--library/std/src/sys/unix/net.rs2
-rw-r--r--library/std/src/sys/unix/os.rs12
-rw-r--r--library/std/src/sys/unix/process/process_unix.rs74
-rw-r--r--library/std/src/sys/unix/thread.rs17
-rw-r--r--library/std/src/sys/unix/thread_local_dtor.rs36
-rw-r--r--library/std/src/sys/unix/thread_parking/pthread.rs9
-rw-r--r--library/std/src/sys/unix/time.rs22
-rw-r--r--library/std/src/sys/unsupported/once.rs11
-rw-r--r--library/std/src/sys/wasi/os.rs8
-rw-r--r--library/std/src/sys/windows/args.rs11
-rw-r--r--library/std/src/sys/windows/c.rs40
-rw-r--r--library/std/src/sys/windows/fs.rs9
-rw-r--r--library/std/src/sys/windows/io.rs32
-rw-r--r--library/std/src/sys/windows/stdio.rs75
-rw-r--r--library/std/src/sys/windows/thread.rs2
-rw-r--r--library/std/src/sys/windows/thread_parking.rs2
37 files changed, 1155 insertions, 699 deletions
diff --git a/library/std/src/sys/common/alloc.rs b/library/std/src/sys/common/alloc.rs
index 3edbe7280..403a5e627 100644
--- a/library/std/src/sys/common/alloc.rs
+++ b/library/std/src/sys/common/alloc.rs
@@ -7,6 +7,7 @@ use crate::ptr;
#[cfg(any(
target_arch = "x86",
target_arch = "arm",
+ target_arch = "m68k",
target_arch = "mips",
target_arch = "powerpc",
target_arch = "powerpc64",
diff --git a/library/std/src/sys/hermit/args.rs b/library/std/src/sys/hermit/args.rs
index afcae6c90..220a76e4b 100644
--- a/library/std/src/sys/hermit/args.rs
+++ b/library/std/src/sys/hermit/args.rs
@@ -1,6 +1,6 @@
use crate::ffi::{c_char, CStr, OsString};
use crate::fmt;
-use crate::os::unix::ffi::OsStringExt;
+use crate::os::hermit::ffi::OsStringExt;
use crate::ptr;
use crate::sync::atomic::{
AtomicIsize, AtomicPtr,
diff --git a/library/std/src/sys/hermit/fd.rs b/library/std/src/sys/hermit/fd.rs
index c400f5f2c..3a2cdd301 100644
--- a/library/std/src/sys/hermit/fd.rs
+++ b/library/std/src/sys/hermit/fd.rs
@@ -1,36 +1,23 @@
#![unstable(reason = "not public", issue = "none", feature = "fd")]
use crate::io::{self, Read};
-use crate::mem;
+use crate::os::hermit::io::{FromRawFd, OwnedFd, RawFd};
use crate::sys::cvt;
use crate::sys::hermit::abi;
use crate::sys::unsupported;
-use crate::sys_common::AsInner;
+use crate::sys_common::{AsInner, FromInner, IntoInner};
+
+use crate::os::hermit::io::*;
#[derive(Debug)]
pub struct FileDesc {
- fd: i32,
+ fd: OwnedFd,
}
impl FileDesc {
- pub fn new(fd: i32) -> FileDesc {
- FileDesc { fd }
- }
-
- pub fn raw(&self) -> i32 {
- self.fd
- }
-
- /// Extracts the actual file descriptor without closing it.
- pub fn into_raw(self) -> i32 {
- let fd = self.fd;
- mem::forget(self);
- fd
- }
-
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
- let result = unsafe { abi::read(self.fd, buf.as_mut_ptr(), buf.len()) };
- cvt(result as i32)
+ let result = cvt(unsafe { abi::read(self.fd.as_raw_fd(), buf.as_mut_ptr(), buf.len()) })?;
+ Ok(result as usize)
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
@@ -39,8 +26,8 @@ impl FileDesc {
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
- let result = unsafe { abi::write(self.fd, buf.as_ptr(), buf.len()) };
- cvt(result as i32)
+ let result = cvt(unsafe { abi::write(self.fd.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
+ Ok(result as usize)
}
pub fn duplicate(&self) -> io::Result<FileDesc> {
@@ -69,19 +56,45 @@ impl<'a> Read for &'a FileDesc {
}
}
-impl AsInner<i32> for FileDesc {
- fn as_inner(&self) -> &i32 {
+impl IntoInner<OwnedFd> for FileDesc {
+ fn into_inner(self) -> OwnedFd {
+ self.fd
+ }
+}
+
+impl FromInner<OwnedFd> for FileDesc {
+ fn from_inner(owned_fd: OwnedFd) -> Self {
+ Self { fd: owned_fd }
+ }
+}
+
+impl FromRawFd for FileDesc {
+ unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+ Self { fd: FromRawFd::from_raw_fd(raw_fd) }
+ }
+}
+
+impl AsInner<OwnedFd> for FileDesc {
+ fn as_inner(&self) -> &OwnedFd {
&self.fd
}
}
-impl Drop for FileDesc {
- fn drop(&mut self) {
- // Note that errors are ignored when closing a file descriptor. The
- // reason for this is that if an error occurs we don't actually know if
- // the file descriptor was closed or not, and if we retried (for
- // something like EINTR), we might close another valid file descriptor
- // (opened after we closed ours.
- let _ = unsafe { abi::close(self.fd) };
+impl AsFd for FileDesc {
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.fd.as_fd()
+ }
+}
+
+impl AsRawFd for FileDesc {
+ #[inline]
+ fn as_raw_fd(&self) -> RawFd {
+ self.fd.as_raw_fd()
+ }
+}
+
+impl IntoRawFd for FileDesc {
+ fn into_raw_fd(self) -> RawFd {
+ self.fd.into_raw_fd()
}
}
diff --git a/library/std/src/sys/hermit/fs.rs b/library/std/src/sys/hermit/fs.rs
index 6fb92c037..c966f2177 100644
--- a/library/std/src/sys/hermit/fs.rs
+++ b/library/std/src/sys/hermit/fs.rs
@@ -3,14 +3,17 @@ use crate::fmt;
use crate::hash::{Hash, Hasher};
use crate::io::{self, Error, ErrorKind};
use crate::io::{BorrowedCursor, IoSlice, IoSliceMut, SeekFrom};
+use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, RawFd};
use crate::path::{Path, PathBuf};
use crate::sys::common::small_c_string::run_path_with_cstr;
use crate::sys::cvt;
-use crate::sys::hermit::abi;
-use crate::sys::hermit::abi::{O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY};
+use crate::sys::hermit::abi::{
+ self, O_APPEND, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY,
+};
use crate::sys::hermit::fd::FileDesc;
use crate::sys::time::SystemTime;
use crate::sys::unsupported;
+use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner};
pub use crate::sys_common::fs::{copy, try_exists};
//pub use crate::sys_common::fs::remove_dir_all;
@@ -283,7 +286,7 @@ impl File {
}
let fd = unsafe { cvt(abi::open(path.as_ptr(), flags, mode))? };
- Ok(File(FileDesc::new(fd as i32)))
+ Ok(File(unsafe { FileDesc::from_raw_fd(fd as i32) }))
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
@@ -363,6 +366,54 @@ impl DirBuilder {
}
}
+impl AsInner<FileDesc> for File {
+ fn as_inner(&self) -> &FileDesc {
+ &self.0
+ }
+}
+
+impl AsInnerMut<FileDesc> for File {
+ fn as_inner_mut(&mut self) -> &mut FileDesc {
+ &mut self.0
+ }
+}
+
+impl IntoInner<FileDesc> for File {
+ fn into_inner(self) -> FileDesc {
+ self.0
+ }
+}
+
+impl FromInner<FileDesc> for File {
+ fn from_inner(file_desc: FileDesc) -> Self {
+ Self(file_desc)
+ }
+}
+
+impl AsFd for File {
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.0.as_fd()
+ }
+}
+
+impl AsRawFd for File {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_raw_fd()
+ }
+}
+
+impl IntoRawFd for File {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_raw_fd()
+ }
+}
+
+impl FromRawFd for File {
+ unsafe fn from_raw_fd(raw_fd: RawFd) -> Self {
+ Self(FromRawFd::from_raw_fd(raw_fd))
+ }
+}
+
pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
unsupported()
}
diff --git a/library/std/src/sys/hermit/mod.rs b/library/std/src/sys/hermit/mod.rs
index 6811fadb0..d34a4cfed 100644
--- a/library/std/src/sys/hermit/mod.rs
+++ b/library/std/src/sys/hermit/mod.rs
@@ -13,7 +13,7 @@
//! compiling for wasm. That way it's a compile time error for something that's
//! guaranteed to be a runtime error!
-#![allow(unsafe_op_in_unsafe_fn)]
+#![allow(missing_docs, nonstandard_style, unsafe_op_in_unsafe_fn)]
use crate::intrinsics;
use crate::os::raw::c_char;
@@ -57,9 +57,7 @@ pub mod locks {
}
use crate::io::ErrorKind;
-
-#[allow(unused_extern_crates)]
-pub extern crate hermit_abi as abi;
+use crate::os::hermit::abi;
pub fn unsupported<T>() -> crate::io::Result<T> {
Err(unsupported_err())
@@ -72,11 +70,6 @@ pub fn unsupported_err() -> crate::io::Error {
)
}
-#[no_mangle]
-pub extern "C" fn floor(x: f64) -> f64 {
- unsafe { intrinsics::floorf64(x) }
-}
-
pub fn abort_internal() -> ! {
unsafe {
abi::abort();
@@ -131,25 +124,72 @@ pub unsafe extern "C" fn runtime_entry(
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno {
- x if x == 13 as i32 => ErrorKind::PermissionDenied,
- x if x == 98 as i32 => ErrorKind::AddrInUse,
- x if x == 99 as i32 => ErrorKind::AddrNotAvailable,
- x if x == 11 as i32 => ErrorKind::WouldBlock,
- x if x == 103 as i32 => ErrorKind::ConnectionAborted,
- x if x == 111 as i32 => ErrorKind::ConnectionRefused,
- x if x == 104 as i32 => ErrorKind::ConnectionReset,
- x if x == 17 as i32 => ErrorKind::AlreadyExists,
- x if x == 4 as i32 => ErrorKind::Interrupted,
- x if x == 22 as i32 => ErrorKind::InvalidInput,
- x if x == 2 as i32 => ErrorKind::NotFound,
- x if x == 107 as i32 => ErrorKind::NotConnected,
- x if x == 1 as i32 => ErrorKind::PermissionDenied,
- x if x == 32 as i32 => ErrorKind::BrokenPipe,
- x if x == 110 as i32 => ErrorKind::TimedOut,
+ abi::errno::EACCES => ErrorKind::PermissionDenied,
+ abi::errno::EADDRINUSE => ErrorKind::AddrInUse,
+ abi::errno::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
+ abi::errno::EAGAIN => ErrorKind::WouldBlock,
+ abi::errno::ECONNABORTED => ErrorKind::ConnectionAborted,
+ abi::errno::ECONNREFUSED => ErrorKind::ConnectionRefused,
+ abi::errno::ECONNRESET => ErrorKind::ConnectionReset,
+ abi::errno::EEXIST => ErrorKind::AlreadyExists,
+ abi::errno::EINTR => ErrorKind::Interrupted,
+ abi::errno::EINVAL => ErrorKind::InvalidInput,
+ abi::errno::ENOENT => ErrorKind::NotFound,
+ abi::errno::ENOTCONN => ErrorKind::NotConnected,
+ abi::errno::EPERM => ErrorKind::PermissionDenied,
+ abi::errno::EPIPE => ErrorKind::BrokenPipe,
+ abi::errno::ETIMEDOUT => ErrorKind::TimedOut,
_ => ErrorKind::Uncategorized,
}
}
-pub fn cvt(result: i32) -> crate::io::Result<usize> {
- if result < 0 { Err(crate::io::Error::from_raw_os_error(-result)) } else { Ok(result as usize) }
+#[doc(hidden)]
+pub trait IsNegative {
+ fn is_negative(&self) -> bool;
+ fn negate(&self) -> i32;
+}
+
+macro_rules! impl_is_negative {
+ ($($t:ident)*) => ($(impl IsNegative for $t {
+ fn is_negative(&self) -> bool {
+ *self < 0
+ }
+
+ fn negate(&self) -> i32 {
+ i32::try_from(-(*self)).unwrap()
+ }
+ })*)
+}
+
+impl IsNegative for i32 {
+ fn is_negative(&self) -> bool {
+ *self < 0
+ }
+
+ fn negate(&self) -> i32 {
+ -(*self)
+ }
+}
+impl_is_negative! { i8 i16 i64 isize }
+
+pub fn cvt<T: IsNegative>(t: T) -> crate::io::Result<T> {
+ if t.is_negative() {
+ let e = decode_error_kind(t.negate());
+ Err(crate::io::Error::from(e))
+ } else {
+ Ok(t)
+ }
+}
+
+pub fn cvt_r<T, F>(mut f: F) -> crate::io::Result<T>
+where
+ T: IsNegative,
+ F: FnMut() -> T,
+{
+ loop {
+ match cvt(f()) {
+ Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
+ other => return other,
+ }
+ }
}
diff --git a/library/std/src/sys/hermit/net.rs b/library/std/src/sys/hermit/net.rs
index 8a13879d8..5fb6281aa 100644
--- a/library/std/src/sys/hermit/net.rs
+++ b/library/std/src/sys/hermit/net.rs
@@ -1,490 +1,353 @@
-use crate::fmt;
-use crate::io::{self, ErrorKind, IoSlice, IoSliceMut};
-use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
-use crate::str;
-use crate::sync::Arc;
-use crate::sys::hermit::abi;
-use crate::sys::hermit::abi::IpAddress::{Ipv4, Ipv6};
-use crate::sys::unsupported;
-use crate::sys_common::AsInner;
+#![allow(dead_code)]
+
+use crate::cmp;
+use crate::io::{self, IoSlice, IoSliceMut};
+use crate::mem;
+use crate::net::{Shutdown, SocketAddr};
+use crate::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
+use crate::sys::hermit::fd::FileDesc;
+use crate::sys::time::Instant;
+use crate::sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
+use crate::sys_common::{AsInner, FromInner, IntoInner};
use crate::time::Duration;
-/// Checks whether the HermitCore's socket interface has been started already, and
-/// if not, starts it.
-pub fn init() -> io::Result<()> {
- if abi::network_init() < 0 {
- return Err(io::const_io_error!(
- ErrorKind::Uncategorized,
- "Unable to initialize network interface",
- ));
- }
-
- Ok(())
-}
-
-#[derive(Debug, Clone)]
-pub struct Socket(abi::Handle);
-
-impl AsInner<abi::Handle> for Socket {
- fn as_inner(&self) -> &abi::Handle {
- &self.0
- }
-}
+use core::ffi::c_int;
-impl Drop for Socket {
- fn drop(&mut self) {
- let _ = abi::tcpstream::close(self.0);
- }
-}
+#[allow(unused_extern_crates)]
+pub extern crate hermit_abi as netc;
-// Arc is used to count the number of used sockets.
-// Only if all sockets are released, the drop
-// method will close the socket.
-#[derive(Clone)]
-pub struct TcpStream(Arc<Socket>);
-
-impl TcpStream {
- pub fn connect(addr: io::Result<&SocketAddr>) -> io::Result<TcpStream> {
- let addr = addr?;
-
- match abi::tcpstream::connect(addr.ip().to_string().as_bytes(), addr.port(), None) {
- Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
- _ => Err(io::const_io_error!(
- ErrorKind::Uncategorized,
- "Unable to initiate a connection on a socket",
- )),
- }
- }
+pub use crate::sys::{cvt, cvt_r};
- pub fn connect_timeout(saddr: &SocketAddr, duration: Duration) -> io::Result<TcpStream> {
- match abi::tcpstream::connect(
- saddr.ip().to_string().as_bytes(),
- saddr.port(),
- Some(duration.as_millis() as u64),
- ) {
- Ok(handle) => Ok(TcpStream(Arc::new(Socket(handle)))),
- _ => Err(io::const_io_error!(
- ErrorKind::Uncategorized,
- "Unable to initiate a connection on a socket",
- )),
- }
- }
+pub type wrlen_t = usize;
- pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
- abi::tcpstream::set_read_timeout(*self.0.as_inner(), duration.map(|d| d.as_millis() as u64))
- .map_err(|_| {
- io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value")
- })
+pub fn cvt_gai(err: i32) -> io::Result<()> {
+ if err == 0 {
+ return Ok(());
}
- pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
- abi::tcpstream::set_write_timeout(
- *self.0.as_inner(),
- duration.map(|d| d.as_millis() as u64),
- )
- .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "Unable to set timeout value"))
- }
+ let detail = "";
- pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
- let duration = abi::tcpstream::get_read_timeout(*self.0.as_inner()).map_err(|_| {
- io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
- })?;
+ Err(io::Error::new(
+ io::ErrorKind::Uncategorized,
+ &format!("failed to lookup address information: {detail}")[..],
+ ))
+}
- Ok(duration.map(|d| Duration::from_millis(d)))
+/// 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 write_timeout(&self) -> io::Result<Option<Duration>> {
- let duration = abi::tcpstream::get_write_timeout(*self.0.as_inner()).map_err(|_| {
- io::const_io_error!(ErrorKind::Uncategorized, "Unable to determine timeout value")
- })?;
+#[derive(Debug)]
+pub struct Socket(FileDesc);
- Ok(duration.map(|d| Duration::from_millis(d)))
+impl Socket {
+ pub fn new(addr: &SocketAddr, ty: i32) -> io::Result<Socket> {
+ let fam = match *addr {
+ SocketAddr::V4(..) => netc::AF_INET,
+ SocketAddr::V6(..) => netc::AF_INET6,
+ };
+ Socket::new_raw(fam, ty)
}
- pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
- abi::tcpstream::peek(*self.0.as_inner(), buf)
- .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peek failed"))
+ pub fn new_raw(fam: i32, ty: i32) -> io::Result<Socket> {
+ let fd = cvt(unsafe { netc::socket(fam, ty, 0) })?;
+ Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
}
- pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> {
- self.read_vectored(&mut [IoSliceMut::new(buffer)])
+ pub fn new_pair(_fam: i32, _ty: i32) -> io::Result<(Socket, Socket)> {
+ unimplemented!()
}
- pub fn read_vectored(&self, ioslice: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- let mut size: usize = 0;
-
- for i in ioslice.iter_mut() {
- let ret = abi::tcpstream::read(*self.0.as_inner(), &mut i[0..]).map_err(|_| {
- io::const_io_error!(ErrorKind::Uncategorized, "Unable to read on socket")
- })?;
+ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
+ self.set_nonblocking(true)?;
+ let r = unsafe {
+ let (addr, len) = addr.into_inner();
+ cvt(netc::connect(self.as_raw_fd(), addr.as_ptr(), len))
+ };
+ self.set_nonblocking(false)?;
- if ret != 0 {
- size += ret;
- }
+ match r {
+ Ok(_) => return Ok(()),
+ // there's no ErrorKind for EINPROGRESS :(
+ Err(ref e) if e.raw_os_error() == Some(netc::errno::EINPROGRESS) => {}
+ Err(e) => return Err(e),
}
- Ok(size)
- }
-
- #[inline]
- pub fn is_read_vectored(&self) -> bool {
- true
- }
-
- pub fn write(&self, buffer: &[u8]) -> io::Result<usize> {
- self.write_vectored(&[IoSlice::new(buffer)])
- }
+ let mut pollfd = netc::pollfd { fd: self.as_raw_fd(), events: netc::POLLOUT, revents: 0 };
- pub fn write_vectored(&self, ioslice: &[IoSlice<'_>]) -> io::Result<usize> {
- let mut size: usize = 0;
-
- for i in ioslice.iter() {
- size += abi::tcpstream::write(*self.0.as_inner(), i).map_err(|_| {
- io::const_io_error!(ErrorKind::Uncategorized, "Unable to write on socket")
- })?;
+ if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout",
+ ));
}
- Ok(size)
- }
-
- #[inline]
- pub fn is_write_vectored(&self) -> bool {
- true
- }
-
- pub fn peer_addr(&self) -> io::Result<SocketAddr> {
- let (ipaddr, port) = abi::tcpstream::peer_addr(*self.0.as_inner())
- .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"))?;
+ let start = Instant::now();
- let saddr = match ipaddr {
- Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
- Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
- _ => {
- return Err(io::const_io_error!(ErrorKind::Uncategorized, "peer_addr failed"));
+ loop {
+ let elapsed = start.elapsed();
+ if elapsed >= timeout {
+ return Err(io::const_io_error!(io::ErrorKind::TimedOut, "connection timed out"));
}
- };
-
- Ok(saddr)
- }
-
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- unsupported()
- }
-
- pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
- abi::tcpstream::shutdown(*self.0.as_inner(), how as i32)
- .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to shutdown socket"))
- }
-
- pub fn duplicate(&self) -> io::Result<TcpStream> {
- Ok(self.clone())
- }
-
- pub fn set_linger(&self, _linger: Option<Duration>) -> io::Result<()> {
- unsupported()
- }
-
- pub fn linger(&self) -> io::Result<Option<Duration>> {
- unsupported()
- }
-
- pub fn set_nodelay(&self, mode: bool) -> io::Result<()> {
- abi::tcpstream::set_nodelay(*self.0.as_inner(), mode)
- .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "set_nodelay failed"))
- }
-
- pub fn nodelay(&self) -> io::Result<bool> {
- abi::tcpstream::nodelay(*self.0.as_inner())
- .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "nodelay failed"))
- }
-
- pub fn set_ttl(&self, tll: u32) -> io::Result<()> {
- abi::tcpstream::set_tll(*self.0.as_inner(), tll)
- .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to set TTL"))
- }
-
- pub fn ttl(&self) -> io::Result<u32> {
- abi::tcpstream::get_tll(*self.0.as_inner())
- .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "unable to get TTL"))
- }
- pub fn take_error(&self) -> io::Result<Option<io::Error>> {
- unsupported()
- }
-
- pub fn set_nonblocking(&self, mode: bool) -> io::Result<()> {
- abi::tcpstream::set_nonblocking(*self.0.as_inner(), mode).map_err(|_| {
- io::const_io_error!(ErrorKind::Uncategorized, "unable to set blocking mode")
- })
- }
-}
-
-impl fmt::Debug for TcpStream {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Ok(())
- }
-}
-
-#[derive(Clone)]
-pub struct TcpListener(SocketAddr);
-
-impl TcpListener {
- pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> {
- let addr = addr?;
-
- Ok(TcpListener(*addr))
- }
-
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- Ok(self.0)
- }
-
- pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
- let (handle, ipaddr, port) = abi::tcplistener::accept(self.0.port())
- .map_err(|_| io::const_io_error!(ErrorKind::Uncategorized, "accept failed"))?;
- let saddr = match ipaddr {
- Ipv4(ref addr) => SocketAddr::new(IpAddr::V4(Ipv4Addr::from(addr.0)), port),
- Ipv6(ref addr) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from(addr.0)), port),
- _ => {
- return Err(io::const_io_error!(ErrorKind::Uncategorized, "accept failed"));
+ let timeout = timeout - elapsed;
+ let mut timeout = timeout
+ .as_secs()
+ .saturating_mul(1_000)
+ .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
+ if timeout == 0 {
+ timeout = 1;
}
- };
-
- Ok((TcpStream(Arc::new(Socket(handle))), saddr))
- }
- pub fn duplicate(&self) -> io::Result<TcpListener> {
- Ok(self.clone())
- }
-
- pub fn set_ttl(&self, _: u32) -> io::Result<()> {
- unsupported()
- }
-
- pub fn ttl(&self) -> io::Result<u32> {
- unsupported()
- }
-
- pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
- unsupported()
+ let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int;
+
+ match unsafe { netc::poll(&mut pollfd, 1, timeout) } {
+ -1 => {
+ let err = io::Error::last_os_error();
+ if err.kind() != io::ErrorKind::Interrupted {
+ return Err(err);
+ }
+ }
+ 0 => {}
+ _ => {
+ // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
+ // for POLLHUP rather than read readiness
+ if pollfd.revents & netc::POLLHUP != 0 {
+ let e = self.take_error()?.unwrap_or_else(|| {
+ io::const_io_error!(
+ io::ErrorKind::Uncategorized,
+ "no error set after POLLHUP",
+ )
+ });
+ return Err(e);
+ }
+
+ return Ok(());
+ }
+ }
+ }
}
- pub fn only_v6(&self) -> io::Result<bool> {
- unsupported()
+ pub fn accept(
+ &self,
+ storage: *mut netc::sockaddr,
+ len: *mut netc::socklen_t,
+ ) -> io::Result<Socket> {
+ let fd = cvt(unsafe { netc::accept(self.0.as_raw_fd(), storage, len) })?;
+ Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
}
- pub fn take_error(&self) -> io::Result<Option<io::Error>> {
- unsupported()
+ pub fn duplicate(&self) -> io::Result<Socket> {
+ let fd = cvt(unsafe { netc::dup(self.0.as_raw_fd()) })?;
+ Ok(Socket(unsafe { FileDesc::from_raw_fd(fd) }))
}
- pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
- unsupported()
+ fn recv_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<usize> {
+ let ret =
+ cvt(unsafe { netc::recv(self.0.as_raw_fd(), buf.as_mut_ptr(), buf.len(), flags) })?;
+ Ok(ret as usize)
}
-}
-impl fmt::Debug for TcpListener {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Ok(())
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, 0)
}
-}
-
-pub struct UdpSocket(abi::Handle);
-impl UdpSocket {
- pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> {
- unsupported()
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, netc::MSG_PEEK)
}
- pub fn peer_addr(&self) -> io::Result<SocketAddr> {
- unsupported()
- }
+ pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
+ let mut size: isize = 0;
- pub fn socket_addr(&self) -> io::Result<SocketAddr> {
- unsupported()
- }
+ for i in bufs.iter_mut() {
+ let ret: isize =
+ cvt(unsafe { netc::read(self.0.as_raw_fd(), i.as_mut_ptr(), i.len()) })?;
- pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
- unsupported()
- }
+ if ret != 0 {
+ size += ret;
+ }
+ }
- pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
- unsupported()
+ Ok(size.try_into().unwrap())
}
- pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
- unsupported()
+ #[inline]
+ pub fn is_read_vectored(&self) -> bool {
+ true
}
- pub fn duplicate(&self) -> io::Result<UdpSocket> {
- unsupported()
- }
+ fn recv_from_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<(usize, SocketAddr)> {
+ let mut storage: netc::sockaddr_storage = unsafe { mem::zeroed() };
+ let mut addrlen = mem::size_of_val(&storage) as netc::socklen_t;
- pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
- unsupported()
+ let n = cvt(unsafe {
+ netc::recvfrom(
+ self.as_raw_fd(),
+ buf.as_mut_ptr(),
+ buf.len(),
+ flags,
+ &mut storage as *mut _ as *mut _,
+ &mut addrlen,
+ )
+ })?;
+ Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
}
- pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
- unsupported()
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, 0)
}
- pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
- unsupported()
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, netc::MSG_PEEK)
}
- pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
- unsupported()
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ let sz = cvt(unsafe { netc::write(self.0.as_raw_fd(), buf.as_ptr(), buf.len()) })?;
+ Ok(sz.try_into().unwrap())
}
- pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
- unsupported()
- }
+ pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
+ let mut size: isize = 0;
- pub fn broadcast(&self) -> io::Result<bool> {
- unsupported()
- }
+ for i in bufs.iter() {
+ size += cvt(unsafe { netc::write(self.0.as_raw_fd(), i.as_ptr(), i.len()) })?;
+ }
- pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
- unsupported()
+ Ok(size.try_into().unwrap())
}
- pub fn multicast_loop_v4(&self) -> io::Result<bool> {
- unsupported()
+ pub fn is_write_vectored(&self) -> bool {
+ true
}
- pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
- unsupported()
- }
+ pub fn set_timeout(&self, dur: Option<Duration>, kind: i32) -> io::Result<()> {
+ let timeout = match dur {
+ Some(dur) => {
+ if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
+ return Err(io::const_io_error!(
+ io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout",
+ ));
+ }
+
+ let secs = if dur.as_secs() > netc::time_t::MAX as u64 {
+ netc::time_t::MAX
+ } else {
+ dur.as_secs() as netc::time_t
+ };
+ let mut timeout = netc::timeval {
+ tv_sec: secs,
+ tv_usec: dur.subsec_micros() as netc::suseconds_t,
+ };
+ if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+ timeout.tv_usec = 1;
+ }
+ timeout
+ }
+ None => netc::timeval { tv_sec: 0, tv_usec: 0 },
+ };
- pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
- unsupported()
+ setsockopt(self, netc::SOL_SOCKET, kind, timeout)
}
- pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
- unsupported()
+ pub fn timeout(&self, kind: i32) -> io::Result<Option<Duration>> {
+ let raw: netc::timeval = getsockopt(self, netc::SOL_SOCKET, kind)?;
+ if raw.tv_sec == 0 && raw.tv_usec == 0 {
+ Ok(None)
+ } else {
+ let sec = raw.tv_sec as u64;
+ let nsec = (raw.tv_usec as u32) * 1000;
+ Ok(Some(Duration::new(sec, nsec)))
+ }
}
- pub fn multicast_loop_v6(&self) -> io::Result<bool> {
- unsupported()
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ let how = match how {
+ Shutdown::Write => netc::SHUT_WR,
+ Shutdown::Read => netc::SHUT_RD,
+ Shutdown::Both => netc::SHUT_RDWR,
+ };
+ cvt(unsafe { netc::shutdown_socket(self.as_raw_fd(), how) })?;
+ Ok(())
}
- pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
- unsupported()
- }
+ pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
+ let linger = netc::linger {
+ l_onoff: linger.is_some() as i32,
+ l_linger: linger.unwrap_or_default().as_secs() as libc::c_int,
+ };
- pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
- unsupported()
+ setsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER, linger)
}
- pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
- unsupported()
- }
+ pub fn linger(&self) -> io::Result<Option<Duration>> {
+ let val: netc::linger = getsockopt(self, netc::SOL_SOCKET, netc::SO_LINGER)?;
- pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
- unsupported()
+ Ok((val.l_onoff != 0).then(|| Duration::from_secs(val.l_linger as u64)))
}
- pub fn set_ttl(&self, _: u32) -> io::Result<()> {
- unsupported()
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ let value: i32 = if nodelay { 1 } else { 0 };
+ setsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY, value)
}
- pub fn ttl(&self) -> io::Result<u32> {
- unsupported()
+ pub fn nodelay(&self) -> io::Result<bool> {
+ let raw: i32 = getsockopt(self, netc::IPPROTO_TCP, netc::TCP_NODELAY)?;
+ Ok(raw != 0)
+ }
+
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ let mut nonblocking: i32 = if nonblocking { 1 } else { 0 };
+ cvt(unsafe {
+ netc::ioctl(
+ self.as_raw_fd(),
+ netc::FIONBIO,
+ &mut nonblocking as *mut _ as *mut core::ffi::c_void,
+ )
+ })
+ .map(drop)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
- unsupported()
- }
-
- pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
- unsupported()
- }
-
- pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
- unsupported()
- }
-
- pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
- unsupported()
+ unimplemented!()
}
- pub fn send(&self, _: &[u8]) -> io::Result<usize> {
- unsupported()
- }
-
- pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> {
- unsupported()
+ // This is used by sys_common code to abstract over Windows and Unix.
+ pub fn as_raw(&self) -> RawFd {
+ self.0.as_raw_fd()
}
}
-impl fmt::Debug for UdpSocket {
- fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
- Ok(())
+impl AsInner<FileDesc> for Socket {
+ fn as_inner(&self) -> &FileDesc {
+ &self.0
}
}
-pub struct LookupHost(!);
-
-impl LookupHost {
- pub fn port(&self) -> u16 {
+impl IntoInner<FileDesc> for Socket {
+ fn into_inner(self) -> FileDesc {
self.0
}
}
-impl Iterator for LookupHost {
- type Item = SocketAddr;
- fn next(&mut self) -> Option<SocketAddr> {
- self.0
+impl FromInner<FileDesc> for Socket {
+ fn from_inner(file_desc: FileDesc) -> Self {
+ Self(file_desc)
}
}
-impl TryFrom<&str> for LookupHost {
- type Error = io::Error;
-
- fn try_from(_v: &str) -> io::Result<LookupHost> {
- unsupported()
+impl AsFd for Socket {
+ fn as_fd(&self) -> BorrowedFd<'_> {
+ self.0.as_fd()
}
}
-impl<'a> TryFrom<(&'a str, u16)> for LookupHost {
- type Error = io::Error;
-
- fn try_from(_v: (&'a str, u16)) -> io::Result<LookupHost> {
- unsupported()
+impl AsRawFd for Socket {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.as_raw_fd()
}
}
-
-#[allow(nonstandard_style)]
-pub mod netc {
- pub const AF_INET: u8 = 0;
- pub const AF_INET6: u8 = 1;
- pub type sa_family_t = u8;
-
- #[derive(Copy, Clone)]
- pub struct in_addr {
- pub s_addr: u32,
- }
-
- #[derive(Copy, Clone)]
- pub struct sockaddr_in {
- pub sin_family: sa_family_t,
- pub sin_port: u16,
- pub sin_addr: in_addr,
- }
-
- #[derive(Copy, Clone)]
- pub struct in6_addr {
- pub s6_addr: [u8; 16],
- }
-
- #[derive(Copy, Clone)]
- pub struct sockaddr_in6 {
- pub sin6_family: sa_family_t,
- pub sin6_port: u16,
- pub sin6_addr: in6_addr,
- pub sin6_flowinfo: u32,
- pub sin6_scope_id: u32,
- }
-
- #[derive(Copy, Clone)]
- pub struct sockaddr {}
-}
diff --git a/library/std/src/sys/hermit/os.rs b/library/std/src/sys/hermit/os.rs
index 8f927df85..e53dbae61 100644
--- a/library/std/src/sys/hermit/os.rs
+++ b/library/std/src/sys/hermit/os.rs
@@ -4,7 +4,7 @@ use crate::ffi::{CStr, OsStr, OsString};
use crate::fmt;
use crate::io;
use crate::marker::PhantomData;
-use crate::os::unix::ffi::OsStringExt;
+use crate::os::hermit::ffi::OsStringExt;
use crate::path::{self, PathBuf};
use crate::str;
use crate::sync::Mutex;
diff --git a/library/std/src/sys/hermit/thread.rs b/library/std/src/sys/hermit/thread.rs
index 8f65544a9..2507f7069 100644
--- a/library/std/src/sys/hermit/thread.rs
+++ b/library/std/src/sys/hermit/thread.rs
@@ -27,10 +27,10 @@ impl Thread {
p: Box<dyn FnOnce()>,
core_id: isize,
) -> io::Result<Thread> {
- let p = Box::into_raw(box p);
+ let p = Box::into_raw(Box::new(p));
let tid = abi::spawn2(
thread_start,
- p as usize,
+ p.expose_addr(),
abi::Priority::into(abi::NORMAL_PRIO),
stack,
core_id,
diff --git a/library/std/src/sys/hermit/thread_local_dtor.rs b/library/std/src/sys/hermit/thread_local_dtor.rs
index 9b683fce1..613266b95 100644
--- a/library/std/src/sys/hermit/thread_local_dtor.rs
+++ b/library/std/src/sys/hermit/thread_local_dtor.rs
@@ -5,32 +5,23 @@
// The this solution works like the implementation of macOS and
// doesn't additional OS support
-use crate::cell::Cell;
-use crate::ptr;
+use crate::mem;
#[thread_local]
-static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
-
-type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
+static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
- if DTORS.get().is_null() {
- let v: Box<List> = box Vec::new();
- DTORS.set(Box::into_raw(v));
- }
-
- let list: &mut List = &mut *DTORS.get();
+ let list = &mut DTORS;
list.push((t, dtor));
}
// every thread call this function to run through all possible destructors
pub unsafe fn run_dtors() {
- let mut ptr = DTORS.replace(ptr::null_mut());
- while !ptr.is_null() {
- let list = Box::from_raw(ptr);
- for (ptr, dtor) in list.into_iter() {
+ let mut list = mem::take(&mut DTORS);
+ while !list.is_empty() {
+ for (ptr, dtor) in list {
dtor(ptr);
}
- ptr = DTORS.replace(ptr::null_mut());
+ list = mem::take(&mut DTORS);
}
}
diff --git a/library/std/src/sys/hermit/time.rs b/library/std/src/sys/hermit/time.rs
index c17e6c8af..32ddc4346 100644
--- a/library/std/src/sys/hermit/time.rs
+++ b/library/std/src/sys/hermit/time.rs
@@ -1,6 +1,7 @@
#![allow(dead_code)]
use crate::cmp::Ordering;
+use crate::ops::{Add, AddAssign, Sub, SubAssign};
use crate::sys::hermit::abi;
use crate::sys::hermit::abi::timespec;
use crate::sys::hermit::abi::{CLOCK_MONOTONIC, CLOCK_REALTIME, NSEC_PER_SEC};
@@ -102,55 +103,122 @@ impl Hash for Timespec {
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
-pub struct Instant {
- t: Timespec,
-}
+pub struct Instant(Timespec);
impl Instant {
pub fn now() -> Instant {
let mut time: Timespec = Timespec::zero();
let _ = unsafe { abi::clock_gettime(CLOCK_MONOTONIC, &mut time.t as *mut timespec) };
- Instant { t: time }
+ Instant(time)
+ }
+
+ #[stable(feature = "time2", since = "1.8.0")]
+ pub fn elapsed(&self) -> Duration {
+ Instant::now() - *self
+ }
+
+ pub fn duration_since(&self, earlier: Instant) -> Duration {
+ self.checked_duration_since(earlier).unwrap_or_default()
+ }
+
+ pub fn checked_duration_since(&self, earlier: Instant) -> Option<Duration> {
+ self.checked_sub_instant(&earlier)
}
pub fn checked_sub_instant(&self, other: &Instant) -> Option<Duration> {
- self.t.sub_timespec(&other.t).ok()
+ self.0.sub_timespec(&other.0).ok()
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<Instant> {
- Some(Instant { t: self.t.checked_add_duration(other)? })
+ Some(Instant(self.0.checked_add_duration(other)?))
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<Instant> {
- Some(Instant { t: self.t.checked_sub_duration(other)? })
+ Some(Instant(self.0.checked_sub_duration(other)?))
+ }
+
+ pub fn checked_add(&self, duration: Duration) -> Option<Instant> {
+ self.0.checked_add_duration(&duration).map(Instant)
+ }
+
+ pub fn checked_sub(&self, duration: Duration) -> Option<Instant> {
+ self.0.checked_sub_duration(&duration).map(Instant)
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
-pub struct SystemTime {
- t: Timespec,
+impl Add<Duration> for Instant {
+ type Output = Instant;
+
+ /// # Panics
+ ///
+ /// This function may panic if the resulting point in time cannot be represented by the
+ /// underlying data structure. See [`Instant::checked_add`] for a version without panic.
+ fn add(self, other: Duration) -> Instant {
+ self.checked_add(other).expect("overflow when adding duration to instant")
+ }
}
-pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
+impl AddAssign<Duration> for Instant {
+ fn add_assign(&mut self, other: Duration) {
+ *self = *self + other;
+ }
+}
+
+impl Sub<Duration> for Instant {
+ type Output = Instant;
+
+ fn sub(self, other: Duration) -> Instant {
+ self.checked_sub(other).expect("overflow when subtracting duration from instant")
+ }
+}
+
+impl SubAssign<Duration> for Instant {
+ fn sub_assign(&mut self, other: Duration) {
+ *self = *self - other;
+ }
+}
+
+impl Sub<Instant> for Instant {
+ type Output = Duration;
+
+ /// Returns the amount of time elapsed from another instant to this one,
+ /// or zero duration if that instant is later than this one.
+ ///
+ /// # Panics
+ ///
+ /// Previous rust versions panicked when `other` was later than `self`. Currently this
+ /// method saturates. Future versions may reintroduce the panic in some circumstances.
+ /// See [Monotonicity].
+ ///
+ /// [Monotonicity]: Instant#monotonicity
+ fn sub(self, other: Instant) -> Duration {
+ self.duration_since(other)
+ }
+}
+
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+pub struct SystemTime(Timespec);
+
+pub const UNIX_EPOCH: SystemTime = SystemTime(Timespec::zero());
impl SystemTime {
pub fn now() -> SystemTime {
let mut time: Timespec = Timespec::zero();
let _ = unsafe { abi::clock_gettime(CLOCK_REALTIME, &mut time.t as *mut timespec) };
- SystemTime { t: time }
+ SystemTime(time)
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
- self.t.sub_timespec(&other.t)
+ self.0.sub_timespec(&other.0)
}
pub fn checked_add_duration(&self, other: &Duration) -> Option<SystemTime> {
- Some(SystemTime { t: self.t.checked_add_duration(other)? })
+ Some(SystemTime(self.0.checked_add_duration(other)?))
}
pub fn checked_sub_duration(&self, other: &Duration) -> Option<SystemTime> {
- Some(SystemTime { t: self.t.checked_sub_duration(other)? })
+ Some(SystemTime(self.0.checked_sub_duration(other)?))
}
}
diff --git a/library/std/src/sys/itron/thread.rs b/library/std/src/sys/itron/thread.rs
index 19350b83f..ae0f71853 100644
--- a/library/std/src/sys/itron/thread.rs
+++ b/library/std/src/sys/itron/thread.rs
@@ -247,7 +247,7 @@ impl Thread {
// [FINISHED → JOINED]
// To synchronize with the child task's memory accesses to
// `inner` up to the point of the assignment of `FINISHED`,
- // `Ordering::Acquire` must be used for the above `swap` call`.
+ // `Ordering::Acquire` must be used for the above `swap` call.
}
_ => unsafe { hint::unreachable_unchecked() },
}
diff --git a/library/std/src/sys/itron/thread_parking.rs b/library/std/src/sys/itron/thread_parking.rs
new file mode 100644
index 000000000..fe9934439
--- /dev/null
+++ b/library/std/src/sys/itron/thread_parking.rs
@@ -0,0 +1,37 @@
+use super::abi;
+use super::error::expect_success_aborting;
+use super::time::with_tmos;
+use crate::time::Duration;
+
+pub type ThreadId = abi::ID;
+
+pub use super::task::current_task_id_aborting as current;
+
+pub fn park(_hint: usize) {
+ match unsafe { abi::slp_tsk() } {
+ abi::E_OK | abi::E_RLWAI => {}
+ err => {
+ expect_success_aborting(err, &"slp_tsk");
+ }
+ }
+}
+
+pub fn park_timeout(dur: Duration, _hint: usize) {
+ match with_tmos(dur, |tmo| unsafe { abi::tslp_tsk(tmo) }) {
+ abi::E_OK | abi::E_RLWAI | abi::E_TMOUT => {}
+ err => {
+ expect_success_aborting(err, &"tslp_tsk");
+ }
+ }
+}
+
+pub fn unpark(id: ThreadId, _hint: usize) {
+ match unsafe { abi::wup_tsk(id) } {
+ // It is allowed to try to wake up a destroyed or unrelated task, so we ignore all
+ // errors that could result from that situation.
+ abi::E_OK | abi::E_NOEXS | abi::E_OBJ | abi::E_QOVR => {}
+ err => {
+ expect_success_aborting(err, &"wup_tsk");
+ }
+ }
+}
diff --git a/library/std/src/sys/itron/wait_flag.rs b/library/std/src/sys/itron/wait_flag.rs
deleted file mode 100644
index e432edd20..000000000
--- a/library/std/src/sys/itron/wait_flag.rs
+++ /dev/null
@@ -1,72 +0,0 @@
-use crate::mem::MaybeUninit;
-use crate::time::Duration;
-
-use super::{
- abi,
- error::{expect_success, fail},
- time::with_tmos,
-};
-
-const CLEAR: abi::FLGPTN = 0;
-const RAISED: abi::FLGPTN = 1;
-
-/// A thread parking primitive that is not susceptible to race conditions,
-/// but provides no atomic ordering guarantees and allows only one `raise` per wait.
-pub struct WaitFlag {
- flag: abi::ID,
-}
-
-impl WaitFlag {
- /// Creates a new wait flag.
- pub fn new() -> WaitFlag {
- let flag = expect_success(
- unsafe {
- abi::acre_flg(&abi::T_CFLG {
- flgatr: abi::TA_FIFO | abi::TA_WSGL | abi::TA_CLR,
- iflgptn: CLEAR,
- })
- },
- &"acre_flg",
- );
-
- WaitFlag { flag }
- }
-
- /// Wait for the wait flag to be raised.
- pub fn wait(&self) {
- let mut token = MaybeUninit::uninit();
- expect_success(
- unsafe { abi::wai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr()) },
- &"wai_flg",
- );
- }
-
- /// Wait for the wait flag to be raised or the timeout to occur.
- ///
- /// Returns whether the flag was raised (`true`) or the operation timed out (`false`).
- pub fn wait_timeout(&self, dur: Duration) -> bool {
- let mut token = MaybeUninit::uninit();
- let res = with_tmos(dur, |tmout| unsafe {
- abi::twai_flg(self.flag, RAISED, abi::TWF_ORW, token.as_mut_ptr(), tmout)
- });
-
- match res {
- abi::E_OK => true,
- abi::E_TMOUT => false,
- error => fail(error, &"twai_flg"),
- }
- }
-
- /// Raise the wait flag.
- ///
- /// Calls to this function should be balanced with the number of successful waits.
- pub fn raise(&self) {
- expect_success(unsafe { abi::set_flg(self.flag, RAISED) }, &"set_flg");
- }
-}
-
-impl Drop for WaitFlag {
- fn drop(&mut self) {
- expect_success(unsafe { abi::del_flg(self.flag) }, &"del_flg");
- }
-}
diff --git a/library/std/src/sys/solid/mod.rs b/library/std/src/sys/solid/mod.rs
index 5867979a2..923d27fd9 100644
--- a/library/std/src/sys/solid/mod.rs
+++ b/library/std/src/sys/solid/mod.rs
@@ -13,9 +13,9 @@ mod itron {
pub(super) mod spin;
pub(super) mod task;
pub mod thread;
+ pub mod thread_parking;
pub(super) mod time;
use super::unsupported;
- pub mod wait_flag;
}
pub mod alloc;
@@ -43,8 +43,8 @@ pub use self::itron::thread;
pub mod memchr;
pub mod thread_local_dtor;
pub mod thread_local_key;
+pub use self::itron::thread_parking;
pub mod time;
-pub use self::itron::wait_flag;
mod rwlock;
diff --git a/library/std/src/sys/solid/thread_local_dtor.rs b/library/std/src/sys/solid/thread_local_dtor.rs
index 973564570..bad14bb37 100644
--- a/library/std/src/sys/solid/thread_local_dtor.rs
+++ b/library/std/src/sys/solid/thread_local_dtor.rs
@@ -5,43 +5,35 @@
use super::{abi, itron::task};
use crate::cell::Cell;
-use crate::ptr;
+use crate::mem;
#[thread_local]
-static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
+static REGISTERED: Cell<bool> = Cell::new(false);
-type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
+#[thread_local]
+static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
- if DTORS.get().is_null() {
+ if !REGISTERED.get() {
let tid = task::current_task_id_aborting();
- let v: Box<List> = box Vec::new();
- DTORS.set(Box::into_raw(v));
-
// Register `tls_dtor` to make sure the TLS destructors are called
// for tasks created by other means than `std::thread`
unsafe { abi::SOLID_TLS_AddDestructor(tid as i32, tls_dtor) };
+ REGISTERED.set(true);
}
- let list: &mut List = unsafe { &mut *DTORS.get() };
+ let list = unsafe { &mut DTORS };
list.push((t, dtor));
}
pub unsafe fn run_dtors() {
- let ptr = DTORS.get();
- if !ptr.is_null() {
- // Swap the destructor list, call all registered destructors,
- // and repeat this until the list becomes permanently empty.
- while let Some(list) = Some(crate::mem::replace(unsafe { &mut *ptr }, Vec::new()))
- .filter(|list| !list.is_empty())
- {
- for (ptr, dtor) in list.into_iter() {
- unsafe { dtor(ptr) };
- }
+ let mut list = mem::take(unsafe { &mut DTORS });
+ while !list.is_empty() {
+ for (ptr, dtor) in list {
+ unsafe { dtor(ptr) };
}
- // Drop the destructor list
- unsafe { Box::from_raw(DTORS.replace(ptr::null_mut())) };
+ list = mem::take(unsafe { &mut DTORS });
}
}
diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs
index a342f0f5e..3d79058b3 100644
--- a/library/std/src/sys/unix/args.rs
+++ b/library/std/src/sys/unix/args.rs
@@ -69,7 +69,8 @@ impl DoubleEndedIterator for Args {
target_os = "fuchsia",
target_os = "redox",
target_os = "vxworks",
- target_os = "horizon"
+ target_os = "horizon",
+ target_os = "nto",
))]
mod imp {
use super::Args;
@@ -141,12 +142,28 @@ mod imp {
// list.
let argv = ARGV.load(Ordering::Relaxed);
let argc = if argv.is_null() { 0 } else { ARGC.load(Ordering::Relaxed) };
- (0..argc)
- .map(|i| {
- let cstr = CStr::from_ptr(*argv.offset(i) as *const libc::c_char);
- OsStringExt::from_vec(cstr.to_bytes().to_vec())
- })
- .collect()
+ let mut args = Vec::with_capacity(argc as usize);
+ for i in 0..argc {
+ let ptr = *argv.offset(i) as *const libc::c_char;
+
+ // Some C commandline parsers (e.g. GLib and Qt) are replacing already
+ // handled arguments in `argv` with `NULL` and move them to the end. That
+ // means that `argc` might be bigger than the actual number of non-`NULL`
+ // pointers in `argv` at this point.
+ //
+ // To handle this we simply stop iterating at the first `NULL` argument.
+ //
+ // `argv` is also guaranteed to be `NULL`-terminated so any non-`NULL` arguments
+ // after the first `NULL` can safely be ignored.
+ if ptr.is_null() {
+ break;
+ }
+
+ let cstr = CStr::from_ptr(ptr);
+ args.push(OsStringExt::from_vec(cstr.to_bytes().to_vec()));
+ }
+
+ args
}
}
}
diff --git a/library/std/src/sys/unix/env.rs b/library/std/src/sys/unix/env.rs
index c9ba661c8..1a9276f11 100644
--- a/library/std/src/sys/unix/env.rs
+++ b/library/std/src/sys/unix/env.rs
@@ -185,6 +185,17 @@ pub mod os {
pub const EXE_EXTENSION: &str = "";
}
+#[cfg(target_os = "nto")]
+pub mod os {
+ pub const FAMILY: &str = "unix";
+ pub const OS: &str = "nto";
+ pub const DLL_PREFIX: &str = "lib";
+ pub const DLL_SUFFIX: &str = ".so";
+ pub const DLL_EXTENSION: &str = "so";
+ pub const EXE_SUFFIX: &str = "";
+ pub const EXE_EXTENSION: &str = "";
+}
+
#[cfg(target_os = "redox")]
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 dbaa3c33e..9874af4d3 100644
--- a/library/std/src/sys/unix/fd.rs
+++ b/library/std/src/sys/unix/fd.rs
@@ -53,7 +53,12 @@ const fn max_iov() -> usize {
libc::IOV_MAX as usize
}
-#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))]
+#[cfg(any(
+ target_os = "android",
+ target_os = "emscripten",
+ target_os = "linux",
+ target_os = "nto",
+))]
const fn max_iov() -> usize {
libc::UIO_MAXIOV as usize
}
@@ -67,6 +72,7 @@ const fn max_iov() -> usize {
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
+ target_os = "nto",
target_os = "openbsd",
target_os = "horizon",
target_os = "watchos",
@@ -92,7 +98,7 @@ impl FileDesc {
let ret = cvt(unsafe {
libc::readv(
self.as_raw_fd(),
- bufs.as_ptr() as *const libc::iovec,
+ bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec,
cmp::min(bufs.len(), max_iov()) as libc::c_int,
)
})?;
@@ -101,7 +107,7 @@ impl FileDesc {
#[cfg(any(target_os = "espidf", target_os = "horizon"))]
pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
- return crate::io::default_read_vectored(|b| self.read(b), bufs);
+ io::default_read_vectored(|b| self.read(b), bufs)
}
#[inline]
@@ -147,6 +153,95 @@ impl FileDesc {
Ok(())
}
+ #[cfg(any(
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "netbsd",
+ ))]
+ pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ libc::preadv(
+ self.as_raw_fd(),
+ bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec,
+ cmp::min(bufs.len(), max_iov()) as libc::c_int,
+ offset as _,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+
+ #[cfg(not(any(
+ target_os = "android",
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ )))]
+ pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ io::default_read_vectored(|b| self.read_at(b, offset), bufs)
+ }
+
+ // We support some old Android versions that do not have `preadv` in libc,
+ // so we use weak linkage and fallback to a direct syscall if not available.
+ //
+ // On 32-bit targets, we don't want to deal with weird ABI issues around
+ // passing 64-bits parameters to syscalls, so we fallback to the default
+ // implementation if `preadv` is not available.
+ #[cfg(all(target_os = "android", target_pointer_width = "64"))]
+ pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ super::weak::syscall! {
+ fn preadv(
+ fd: libc::c_int,
+ iovec: *const libc::iovec,
+ n_iovec: libc::c_int,
+ offset: off64_t
+ ) -> isize
+ }
+
+ let ret = cvt(unsafe {
+ preadv(
+ self.as_raw_fd(),
+ bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec,
+ cmp::min(bufs.len(), max_iov()) as libc::c_int,
+ offset as _,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+
+ // We support old MacOS and iOS versions that do not have `preadv`. There is
+ // no `syscall` possible in these platform.
+ #[cfg(any(
+ all(target_os = "android", target_pointer_width = "32"),
+ target_os = "ios",
+ target_os = "macos",
+ ))]
+ pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ super::weak::weak!(fn preadv64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize);
+
+ match preadv64.get() {
+ Some(preadv) => {
+ let ret = cvt(unsafe {
+ preadv(
+ self.as_raw_fd(),
+ bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec,
+ cmp::min(bufs.len(), max_iov()) as libc::c_int,
+ offset as _,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+ None => io::default_read_vectored(|b| self.read_at(b, offset), bufs),
+ }
+ }
+
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::write(
@@ -172,7 +267,7 @@ impl FileDesc {
#[cfg(any(target_os = "espidf", target_os = "horizon"))]
pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
- return crate::io::default_write_vectored(|b| self.write(b), bufs);
+ io::default_write_vectored(|b| self.write(b), bufs)
}
#[inline]
@@ -197,9 +292,93 @@ impl FileDesc {
}
}
- #[cfg(target_os = "linux")]
- pub fn get_cloexec(&self) -> io::Result<bool> {
- unsafe { Ok((cvt(libc::fcntl(self.as_raw_fd(), libc::F_GETFD))? & libc::FD_CLOEXEC) != 0) }
+ #[cfg(any(
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "linux",
+ target_os = "netbsd",
+ ))]
+ pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ libc::pwritev(
+ self.as_raw_fd(),
+ bufs.as_ptr() as *const libc::iovec,
+ cmp::min(bufs.len(), max_iov()) as libc::c_int,
+ offset as _,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+
+ #[cfg(not(any(
+ target_os = "android",
+ target_os = "emscripten",
+ target_os = "freebsd",
+ target_os = "fuchsia",
+ target_os = "illumos",
+ target_os = "ios",
+ target_os = "linux",
+ target_os = "macos",
+ target_os = "netbsd",
+ )))]
+ pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ io::default_write_vectored(|b| self.write_at(b, offset), bufs)
+ }
+
+ // We support some old Android versions that do not have `pwritev` in libc,
+ // so we use weak linkage and fallback to a direct syscall if not available.
+ //
+ // On 32-bit targets, we don't want to deal with weird ABI issues around
+ // passing 64-bits parameters to syscalls, so we fallback to the default
+ // implementation if `pwritev` is not available.
+ #[cfg(all(target_os = "android", target_pointer_width = "64"))]
+ pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ super::weak::syscall! {
+ fn pwritev(
+ fd: libc::c_int,
+ iovec: *const libc::iovec,
+ n_iovec: libc::c_int,
+ offset: off64_t
+ ) -> isize
+ }
+
+ let ret = cvt(unsafe {
+ pwritev(
+ self.as_raw_fd(),
+ bufs.as_ptr() as *const libc::iovec,
+ cmp::min(bufs.len(), max_iov()) as libc::c_int,
+ offset as _,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+
+ // We support old MacOS and iOS versions that do not have `pwritev`. There is
+ // no `syscall` possible in these platform.
+ #[cfg(any(
+ all(target_os = "android", target_pointer_width = "32"),
+ target_os = "ios",
+ target_os = "macos",
+ ))]
+ pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ super::weak::weak!(fn pwritev64(libc::c_int, *const libc::iovec, libc::c_int, off64_t) -> isize);
+
+ match pwritev64.get() {
+ Some(pwritev) => {
+ let ret = cvt(unsafe {
+ pwritev(
+ self.as_raw_fd(),
+ bufs.as_ptr() as *const libc::iovec,
+ cmp::min(bufs.len(), max_iov()) as libc::c_int,
+ offset as _,
+ )
+ })?;
+ Ok(ret as usize)
+ }
+ None => io::default_write_vectored(|b| self.write_at(b, offset), bufs),
+ }
}
#[cfg(not(any(
@@ -212,7 +391,8 @@ impl FileDesc {
target_os = "linux",
target_os = "haiku",
target_os = "redox",
- target_os = "vxworks"
+ target_os = "vxworks",
+ target_os = "nto",
)))]
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
@@ -230,7 +410,8 @@ impl FileDesc {
target_os = "linux",
target_os = "haiku",
target_os = "redox",
- target_os = "vxworks"
+ target_os = "vxworks",
+ target_os = "nto",
))]
pub fn set_cloexec(&self) -> io::Result<()> {
unsafe {
@@ -284,6 +465,10 @@ impl<'a> Read for &'a FileDesc {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
+
+ fn read_buf(&mut self, cursor: BorrowedCursor<'_>) -> io::Result<()> {
+ (**self).read_buf(cursor)
+ }
}
impl AsInner<OwnedFd> for FileDesc {
diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs
index 8e1f35d6c..7566fafda 100644
--- a/library/std/src/sys/unix/fs.rs
+++ b/library/std/src/sys/unix/fs.rs
@@ -13,7 +13,8 @@ use crate::mem;
target_os = "solaris",
target_os = "fuchsia",
target_os = "redox",
- target_os = "illumos"
+ target_os = "illumos",
+ target_os = "nto",
))]
use crate::mem::MaybeUninit;
use crate::os::unix::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd};
@@ -54,7 +55,8 @@ use libc::fstatat64;
target_os = "solaris",
target_os = "fuchsia",
target_os = "redox",
- target_os = "illumos"
+ target_os = "illumos",
+ target_os = "nto",
))]
use libc::readdir as readdir64;
#[cfg(target_os = "linux")]
@@ -69,7 +71,8 @@ use libc::readdir64_r;
target_os = "illumos",
target_os = "l4re",
target_os = "fuchsia",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "nto",
)))]
use libc::readdir_r as readdir64_r;
#[cfg(target_os = "android")]
@@ -277,7 +280,8 @@ unsafe impl Sync for Dir {}
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "nto",
))]
pub struct DirEntry {
dir: Arc<InnerReadDir>,
@@ -297,11 +301,12 @@ pub struct DirEntry {
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "nto",
))]
struct dirent64_min {
d_ino: u64,
- #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+ #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "nto")))]
d_type: u8,
}
@@ -311,7 +316,8 @@ struct dirent64_min {
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "nto",
)))]
pub struct DirEntry {
dir: Arc<InnerReadDir>,
@@ -438,7 +444,7 @@ impl FileAttr {
}
}
-#[cfg(not(target_os = "netbsd"))]
+#[cfg(not(any(target_os = "netbsd", target_os = "nto")))]
impl FileAttr {
#[cfg(not(any(target_os = "vxworks", target_os = "espidf", target_os = "horizon")))]
pub fn modified(&self) -> io::Result<SystemTime> {
@@ -524,6 +530,21 @@ impl FileAttr {
}
}
+#[cfg(target_os = "nto")]
+impl FileAttr {
+ pub fn modified(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::new(self.stat.st_mtim.tv_sec, self.stat.st_mtim.tv_nsec))
+ }
+
+ pub fn accessed(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::new(self.stat.st_atim.tv_sec, self.stat.st_atim.tv_nsec))
+ }
+
+ pub fn created(&self) -> io::Result<SystemTime> {
+ Ok(SystemTime::new(self.stat.st_ctim.tv_sec, self.stat.st_ctim.tv_nsec))
+ }
+}
+
impl AsInner<stat64> for FileAttr {
fn as_inner(&self) -> &stat64 {
&self.stat
@@ -603,7 +624,8 @@ impl Iterator for ReadDir {
target_os = "solaris",
target_os = "fuchsia",
target_os = "redox",
- target_os = "illumos"
+ target_os = "illumos",
+ target_os = "nto",
))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
if self.end_of_stream {
@@ -686,7 +708,11 @@ impl Iterator for ReadDir {
let entry = dirent64_min {
d_ino: *offset_ptr!(entry_ptr, d_ino) as u64,
- #[cfg(not(any(target_os = "solaris", target_os = "illumos")))]
+ #[cfg(not(any(
+ target_os = "solaris",
+ target_os = "illumos",
+ target_os = "nto",
+ )))]
d_type: *offset_ptr!(entry_ptr, d_type) as u8,
};
@@ -705,7 +731,8 @@ impl Iterator for ReadDir {
target_os = "solaris",
target_os = "fuchsia",
target_os = "redox",
- target_os = "illumos"
+ target_os = "illumos",
+ target_os = "nto",
)))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
if self.end_of_stream {
@@ -794,7 +821,8 @@ impl DirEntry {
target_os = "solaris",
target_os = "illumos",
target_os = "haiku",
- target_os = "vxworks"
+ target_os = "vxworks",
+ target_os = "nto",
))]
pub fn file_type(&self) -> io::Result<FileType> {
self.metadata().map(|m| m.file_type())
@@ -804,7 +832,8 @@ impl DirEntry {
target_os = "solaris",
target_os = "illumos",
target_os = "haiku",
- target_os = "vxworks"
+ target_os = "vxworks",
+ target_os = "nto",
)))]
pub fn file_type(&self) -> io::Result<FileType> {
match self.entry.d_type {
@@ -834,7 +863,8 @@ impl DirEntry {
target_os = "redox",
target_os = "vxworks",
target_os = "espidf",
- target_os = "horizon"
+ target_os = "horizon",
+ target_os = "nto",
))]
pub fn ino(&self) -> u64 {
self.entry.d_ino as u64
@@ -887,7 +917,8 @@ impl DirEntry {
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "nto",
)))]
fn name_cstr(&self) -> &CStr {
unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) }
@@ -898,7 +929,8 @@ impl DirEntry {
target_os = "solaris",
target_os = "illumos",
target_os = "fuchsia",
- target_os = "redox"
+ target_os = "redox",
+ target_os = "nto",
))]
fn name_cstr(&self) -> &CStr {
&self.name
@@ -1051,7 +1083,8 @@ impl File {
target_os = "linux",
target_os = "android",
target_os = "netbsd",
- target_os = "openbsd"
+ target_os = "openbsd",
+ target_os = "nto",
))]
unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fdatasync(fd)
@@ -1065,6 +1098,7 @@ impl File {
target_os = "netbsd",
target_os = "openbsd",
target_os = "watchos",
+ target_os = "nto",
)))]
unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fsync(fd)
@@ -1098,6 +1132,10 @@ impl File {
self.0.read_buf(cursor)
}
+ pub fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result<usize> {
+ self.0.read_vectored_at(bufs, offset)
+ }
+
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
@@ -1115,6 +1153,10 @@ impl File {
self.0.write_at(buf, offset)
}
+ pub fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result<usize> {
+ self.0.write_vectored_at(bufs, offset)
+ }
+
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
@@ -1750,13 +1792,25 @@ pub fn chroot(dir: &Path) -> io::Result<()> {
pub use remove_dir_impl::remove_dir_all;
// Fallback for REDOX, ESP-ID, Horizon, and Miri
-#[cfg(any(target_os = "redox", target_os = "espidf", target_os = "horizon", miri))]
+#[cfg(any(
+ target_os = "redox",
+ target_os = "espidf",
+ target_os = "horizon",
+ target_os = "nto",
+ miri
+))]
mod remove_dir_impl {
pub use crate::sys_common::fs::remove_dir_all;
}
// Modern implementation using openat(), unlinkat() and fdopendir()
-#[cfg(not(any(target_os = "redox", target_os = "espidf", target_os = "horizon", miri)))]
+#[cfg(not(any(
+ target_os = "redox",
+ target_os = "espidf",
+ target_os = "horizon",
+ target_os = "nto",
+ miri
+)))]
mod remove_dir_impl {
use super::{lstat, Dir, DirEntry, InnerReadDir, ReadDir};
use crate::ffi::CStr;
diff --git a/library/std/src/sys/unix/locks/pthread_condvar.rs b/library/std/src/sys/unix/locks/pthread_condvar.rs
index 6be1abc2b..192fa216d 100644
--- a/library/std/src/sys/unix/locks/pthread_condvar.rs
+++ b/library/std/src/sys/unix/locks/pthread_condvar.rs
@@ -2,7 +2,10 @@ use crate::cell::UnsafeCell;
use crate::ptr;
use crate::sync::atomic::{AtomicPtr, Ordering::Relaxed};
use crate::sys::locks::{pthread_mutex, Mutex};
+#[cfg(not(target_os = "nto"))]
use crate::sys::time::TIMESPEC_MAX;
+#[cfg(target_os = "nto")]
+use crate::sys::time::TIMESPEC_MAX_CAPPED;
use crate::sys_common::lazy_box::{LazyBox, LazyInit};
use crate::time::Duration;
@@ -132,10 +135,18 @@ impl Condvar {
let mutex = pthread_mutex::raw(mutex);
self.verify(mutex);
+ #[cfg(not(target_os = "nto"))]
let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
.checked_add_duration(&dur)
.and_then(|t| t.to_timespec())
.unwrap_or(TIMESPEC_MAX);
+
+ #[cfg(target_os = "nto")]
+ let timeout = Timespec::now(libc::CLOCK_MONOTONIC)
+ .checked_add_duration(&dur)
+ .and_then(|t| t.to_timespec_capped())
+ .unwrap_or(TIMESPEC_MAX_CAPPED);
+
let r = libc::pthread_cond_timedwait(raw(self), mutex, &timeout);
assert!(r == libc::ETIMEDOUT || r == 0);
r == 0
diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs
index 30a96be14..68c9520cc 100644
--- a/library/std/src/sys/unix/mod.rs
+++ b/library/std/src/sys/unix/mod.rs
@@ -329,7 +329,7 @@ pub fn cvt_nz(error: libc::c_int) -> crate::io::Result<()> {
// do so. In 1003.1-2004 this was fixed.
//
// glibc's implementation did the flush, unsafely, before glibc commit
-// 91e7cf982d01 `abort: Do not flush stdio streams [BZ #15436]' by Florian
+// 91e7cf982d01 `abort: Do not flush stdio streams [BZ #15436]` by Florian
// Weimer. According to glibc's NEWS:
//
// The abort function terminates the process immediately, without flushing
diff --git a/library/std/src/sys/unix/net.rs b/library/std/src/sys/unix/net.rs
index c86f80972..8e05b618d 100644
--- a/library/std/src/sys/unix/net.rs
+++ b/library/std/src/sys/unix/net.rs
@@ -78,6 +78,7 @@ impl Socket {
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
+ target_os = "nto",
))] {
// On platforms that support it we pass the SOCK_CLOEXEC
// flag to atomically create the socket and set it as
@@ -115,6 +116,7 @@ impl Socket {
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
+ target_os = "nto",
))] {
// Like above, set cloexec atomically
cvt(libc::socketpair(fam, ty | libc::SOCK_CLOEXEC, 0, fds.as_mut_ptr()))?;
diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs
index 2f2663db6..21b035fb3 100644
--- a/library/std/src/sys/unix/os.rs
+++ b/library/std/src/sys/unix/os.rs
@@ -62,6 +62,7 @@ extern "C" {
link_name = "__errno"
)]
#[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")]
+ #[cfg_attr(target_os = "nto", link_name = "__get_errno_ptr")]
#[cfg_attr(
any(target_os = "macos", target_os = "ios", target_os = "freebsd", target_os = "watchos"),
link_name = "__error"
@@ -361,6 +362,17 @@ pub fn current_exe() -> io::Result<PathBuf> {
}
}
+#[cfg(target_os = "nto")]
+pub fn current_exe() -> io::Result<PathBuf> {
+ let mut e = crate::fs::read("/proc/self/exefile")?;
+ // Current versions of QNX Neutrino provide a null-terminated path.
+ // Ensure the trailing null byte is not returned here.
+ if let Some(0) = e.last() {
+ e.pop();
+ }
+ Ok(PathBuf::from(OsString::from_vec(e)))
+}
+
#[cfg(any(target_os = "macos", target_os = "ios", target_os = "watchos"))]
pub fn current_exe() -> io::Result<PathBuf> {
unsafe {
diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs
index 3bc17b775..ceaff5966 100644
--- a/library/std/src/sys/unix/process/process_unix.rs
+++ b/library/std/src/sys/unix/process/process_unix.rs
@@ -18,6 +18,7 @@ use crate::sys::weak::raw_syscall;
target_os = "freebsd",
all(target_os = "linux", target_env = "gnu"),
all(target_os = "linux", target_env = "musl"),
+ target_os = "nto",
))]
use crate::sys::weak::weak;
@@ -30,6 +31,15 @@ use libc::{c_int, pid_t};
#[cfg(not(any(target_os = "vxworks", target_os = "l4re")))]
use libc::{gid_t, uid_t};
+cfg_if::cfg_if! {
+ if #[cfg(all(target_os = "nto", target_env = "nto71"))] {
+ use crate::thread;
+ use libc::{c_char, posix_spawn_file_actions_t, posix_spawnattr_t};
+ // arbitrary number of tries:
+ const MAX_FORKSPAWN_TRIES: u32 = 4;
+ }
+}
+
////////////////////////////////////////////////////////////////////////////////
// Command
////////////////////////////////////////////////////////////////////////////////
@@ -140,11 +150,31 @@ impl Command {
// Attempts to fork the process. If successful, returns Ok((0, -1))
// in the child, and Ok((child_pid, -1)) in the parent.
- #[cfg(not(target_os = "linux"))]
+ #[cfg(not(any(target_os = "linux", all(target_os = "nto", target_env = "nto71"))))]
unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
cvt(libc::fork()).map(|res| (res, -1))
}
+ // On QNX Neutrino, fork can fail with EBADF in case "another thread might have opened
+ // or closed a file descriptor while the fork() was occurring".
+ // Documentation says "... or try calling fork() again". This is what we do here.
+ // See also https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html
+ #[cfg(all(target_os = "nto", target_env = "nto71"))]
+ unsafe fn do_fork(&mut self) -> Result<(pid_t, pid_t), io::Error> {
+ use crate::sys::os::errno;
+
+ let mut tries_left = MAX_FORKSPAWN_TRIES;
+ loop {
+ let r = libc::fork();
+ if r == -1 as libc::pid_t && tries_left > 0 && errno() as libc::c_int == libc::EBADF {
+ thread::yield_now();
+ tries_left -= 1;
+ } else {
+ return cvt(r).map(|res| (res, -1));
+ }
+ }
+ }
+
// Attempts to fork the process. If successful, returns Ok((0, -1))
// in the child, and Ok((child_pid, child_pidfd)) in the parent.
#[cfg(target_os = "linux")]
@@ -389,6 +419,7 @@ impl Command {
target_os = "freebsd",
all(target_os = "linux", target_env = "gnu"),
all(target_os = "linux", target_env = "musl"),
+ target_os = "nto",
)))]
fn posix_spawn(
&mut self,
@@ -405,6 +436,7 @@ impl Command {
target_os = "freebsd",
all(target_os = "linux", target_env = "gnu"),
all(target_os = "linux", target_env = "musl"),
+ target_os = "nto",
))]
fn posix_spawn(
&mut self,
@@ -436,6 +468,34 @@ impl Command {
}
}
+ // On QNX Neutrino, posix_spawnp can fail with EBADF in case "another thread might have opened
+ // or closed a file descriptor while the posix_spawn() was occurring".
+ // Documentation says "... or try calling posix_spawn() again". This is what we do here.
+ // See also http://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/p/posix_spawn.html
+ #[cfg(all(target_os = "nto", target_env = "nto71"))]
+ unsafe fn retrying_libc_posix_spawnp(
+ pid: *mut pid_t,
+ file: *const c_char,
+ file_actions: *const posix_spawn_file_actions_t,
+ attrp: *const posix_spawnattr_t,
+ argv: *const *mut c_char,
+ envp: *const *mut c_char,
+ ) -> i32 {
+ let mut tries_left = MAX_FORKSPAWN_TRIES;
+ loop {
+ match libc::posix_spawnp(pid, file, file_actions, attrp, argv, envp) {
+ libc::EBADF if tries_left > 0 => {
+ thread::yield_now();
+ tries_left -= 1;
+ continue;
+ }
+ r => {
+ return r;
+ }
+ }
+ }
+ }
+
// Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory,
// and maybe others will gain this non-POSIX function too. We'll check
// for this weak symbol as soon as it's needed, so we can return early
@@ -555,7 +615,12 @@ impl Command {
// Make sure we synchronize access to the global `environ` resource
let _env_lock = sys::os::env_read_lock();
let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _);
- cvt_nz(libc::posix_spawnp(
+
+ #[cfg(not(target_os = "nto"))]
+ let spawn_fn = libc::posix_spawnp;
+ #[cfg(target_os = "nto")]
+ let spawn_fn = retrying_libc_posix_spawnp;
+ cvt_nz(spawn_fn(
&mut p.pid,
self.get_program_cstr().as_ptr(),
file_actions.0.as_ptr(),
@@ -760,7 +825,7 @@ fn signal_string(signal: i32) -> &'static str {
)
))]
libc::SIGSTKFLT => " (SIGSTKFLT)",
- #[cfg(target_os = "linux")]
+ #[cfg(any(target_os = "linux", target_os = "nto"))]
libc::SIGPWR => " (SIGPWR)",
#[cfg(any(
target_os = "macos",
@@ -769,7 +834,8 @@ fn signal_string(signal: i32) -> &'static str {
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
- target_os = "dragonfly"
+ target_os = "dragonfly",
+ target_os = "nto",
))]
libc::SIGEMT => " (SIGEMT)",
#[cfg(any(
diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs
index 2a1830d06..15070b1f6 100644
--- a/library/std/src/sys/unix/thread.rs
+++ b/library/std/src/sys/unix/thread.rs
@@ -9,7 +9,7 @@ use crate::time::Duration;
#[cfg(all(target_os = "linux", target_env = "gnu"))]
use crate::sys::weak::dlsym;
-#[cfg(any(target_os = "solaris", target_os = "illumos"))]
+#[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
use crate::sys::weak::weak;
#[cfg(not(any(target_os = "l4re", target_os = "vxworks", target_os = "espidf")))]
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
@@ -49,7 +49,7 @@ unsafe impl Sync for Thread {}
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 p);
+ let p = Box::into_raw(Box::new(p));
let mut native: libc::pthread_t = mem::zeroed();
let mut attr: libc::pthread_attr_t = mem::zeroed();
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
@@ -173,7 +173,7 @@ impl Thread {
}
}
- #[cfg(any(target_os = "solaris", target_os = "illumos"))]
+ #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "nto"))]
pub fn set_name(name: &CStr) {
weak! {
fn pthread_setname_np(
@@ -381,6 +381,17 @@ pub fn available_parallelism() -> io::Result<NonZeroUsize> {
}
Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
+ } else if #[cfg(target_os = "nto")] {
+ unsafe {
+ use libc::_syspage_ptr;
+ if _syspage_ptr.is_null() {
+ Err(io::const_io_error!(io::ErrorKind::NotFound, "No syspage available"))
+ } else {
+ let cpus = (*_syspage_ptr).num_cpu;
+ NonZeroUsize::new(cpus as usize)
+ .ok_or(io::const_io_error!(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"))
+ }
+ }
} else if #[cfg(target_os = "haiku")] {
// system_info cpu_count field gets the static data set at boot time with `smp_set_num_cpus`
// `get_system_info` calls then `smp_get_num_cpus`
diff --git a/library/std/src/sys/unix/thread_local_dtor.rs b/library/std/src/sys/unix/thread_local_dtor.rs
index d7fd2130f..236d2f2ee 100644
--- a/library/std/src/sys/unix/thread_local_dtor.rs
+++ b/library/std/src/sys/unix/thread_local_dtor.rs
@@ -11,13 +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",
- target_os = "emscripten"
-))]
-#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
+#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))]
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;
@@ -57,44 +51,40 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
#[cfg(target_os = "macos")]
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
use crate::cell::Cell;
+ use crate::mem;
use crate::ptr;
#[thread_local]
static REGISTERED: Cell<bool> = Cell::new(false);
+
+ #[thread_local]
+ static mut DTORS: Vec<(*mut u8, unsafe extern "C" fn(*mut u8))> = Vec::new();
+
if !REGISTERED.get() {
_tlv_atexit(run_dtors, ptr::null_mut());
REGISTERED.set(true);
}
- type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
-
- #[thread_local]
- static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut());
- if DTORS.get().is_null() {
- let v: Box<List> = box Vec::new();
- DTORS.set(Box::into_raw(v));
- }
-
extern "C" {
fn _tlv_atexit(dtor: unsafe extern "C" fn(*mut u8), arg: *mut u8);
}
- let list: &mut List = &mut *DTORS.get();
+ let list = &mut DTORS;
list.push((t, dtor));
unsafe extern "C" fn run_dtors(_: *mut u8) {
- let mut ptr = DTORS.replace(ptr::null_mut());
- while !ptr.is_null() {
- let list = Box::from_raw(ptr);
- for (ptr, dtor) in list.into_iter() {
+ let mut list = mem::take(&mut DTORS);
+ while !list.is_empty() {
+ for (ptr, dtor) in list {
dtor(ptr);
}
- ptr = DTORS.replace(ptr::null_mut());
+ list = mem::take(&mut DTORS);
}
}
}
-#[cfg(any(target_os = "vxworks", target_os = "horizon"))]
+#[cfg(any(target_os = "vxworks", target_os = "horizon", target_os = "emscripten"))]
+#[cfg_attr(target_family = "wasm", allow(unused))] // might remain unused depending on target details (e.g. wasm32-unknown-emscripten)
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
use crate::sys_common::thread_local_dtor::register_dtor_fallback;
register_dtor_fallback(t, dtor);
diff --git a/library/std/src/sys/unix/thread_parking/pthread.rs b/library/std/src/sys/unix/thread_parking/pthread.rs
index 082d25e68..43046ed07 100644
--- a/library/std/src/sys/unix/thread_parking/pthread.rs
+++ b/library/std/src/sys/unix/thread_parking/pthread.rs
@@ -6,7 +6,10 @@ use crate::pin::Pin;
use crate::ptr::addr_of_mut;
use crate::sync::atomic::AtomicUsize;
use crate::sync::atomic::Ordering::SeqCst;
+#[cfg(not(target_os = "nto"))]
use crate::sys::time::TIMESPEC_MAX;
+#[cfg(target_os = "nto")]
+use crate::sys::time::TIMESPEC_MAX_CAPPED;
use crate::time::Duration;
const EMPTY: usize = 0;
@@ -80,8 +83,14 @@ unsafe fn wait_timeout(
(Timespec::now(libc::CLOCK_MONOTONIC), dur)
};
+ #[cfg(not(target_os = "nto"))]
let timeout =
now.checked_add_duration(&dur).and_then(|t| t.to_timespec()).unwrap_or(TIMESPEC_MAX);
+ #[cfg(target_os = "nto")]
+ let timeout = now
+ .checked_add_duration(&dur)
+ .and_then(|t| t.to_timespec_capped())
+ .unwrap_or(TIMESPEC_MAX_CAPPED);
let r = libc::pthread_cond_timedwait(cond, lock, &timeout);
debug_assert!(r == libc::ETIMEDOUT || r == 0);
}
diff --git a/library/std/src/sys/unix/time.rs b/library/std/src/sys/unix/time.rs
index 2daad981b..0f11de8f5 100644
--- a/library/std/src/sys/unix/time.rs
+++ b/library/std/src/sys/unix/time.rs
@@ -9,6 +9,14 @@ pub const UNIX_EPOCH: SystemTime = SystemTime { t: Timespec::zero() };
pub const TIMESPEC_MAX: libc::timespec =
libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 };
+// This additional constant is only used when calling
+// `libc::pthread_cond_timedwait`.
+#[cfg(target_os = "nto")]
+pub(super) const TIMESPEC_MAX_CAPPED: libc::timespec = libc::timespec {
+ tv_sec: (u64::MAX / NSEC_PER_SEC) as i64,
+ tv_nsec: (u64::MAX % NSEC_PER_SEC) as i64,
+};
+
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[repr(transparent)]
#[rustc_layout_scalar_valid_range_start(0)]
@@ -144,6 +152,20 @@ impl Timespec {
tv_nsec: self.tv_nsec.0.try_into().ok()?,
})
}
+
+ // On QNX Neutrino, the maximum timespec for e.g. pthread_cond_timedwait
+ // is 2^64 nanoseconds
+ #[cfg(target_os = "nto")]
+ pub(super) fn to_timespec_capped(&self) -> Option<libc::timespec> {
+ // Check if timeout in nanoseconds would fit into an u64
+ if (self.tv_nsec.0 as u64)
+ .checked_add((self.tv_sec as u64).checked_mul(NSEC_PER_SEC)?)
+ .is_none()
+ {
+ return None;
+ }
+ self.to_timespec()
+ }
}
impl From<libc::timespec> for Timespec {
diff --git a/library/std/src/sys/unsupported/once.rs b/library/std/src/sys/unsupported/once.rs
index b4bb4975f..11fde1888 100644
--- a/library/std/src/sys/unsupported/once.rs
+++ b/library/std/src/sys/unsupported/once.rs
@@ -1,5 +1,6 @@
use crate::cell::Cell;
use crate::sync as public;
+use crate::sync::once::ExclusiveState;
pub struct Once {
state: Cell<State>,
@@ -44,6 +45,16 @@ impl Once {
self.state.get() == State::Complete
}
+ #[inline]
+ pub(crate) fn state(&mut self) -> ExclusiveState {
+ match self.state.get() {
+ State::Incomplete => ExclusiveState::Incomplete,
+ State::Poisoned => ExclusiveState::Poisoned,
+ State::Complete => ExclusiveState::Complete,
+ _ => unreachable!("invalid Once state"),
+ }
+ }
+
#[cold]
#[track_caller]
pub fn call(&self, ignore_poisoning: bool, f: &mut impl FnMut(&public::OnceState)) {
diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs
index f5513e999..9919dc708 100644
--- a/library/std/src/sys/wasi/os.rs
+++ b/library/std/src/sys/wasi/os.rs
@@ -21,6 +21,7 @@ mod libc {
extern "C" {
pub fn getcwd(buf: *mut c_char, size: size_t) -> *mut c_char;
pub fn chdir(dir: *const c_char) -> c_int;
+ pub fn __wasilibc_get_environ() -> *mut *mut c_char;
}
}
@@ -161,7 +162,12 @@ impl Iterator for Env {
pub fn env() -> Env {
unsafe {
let _guard = env_read_lock();
- let mut environ = libc::environ;
+
+ // Use `__wasilibc_get_environ` instead of `environ` here so that we
+ // don't require wasi-libc to eagerly initialize the environment
+ // variables.
+ let mut environ = libc::__wasilibc_get_environ();
+
let mut result = Vec::new();
if !environ.is_null() {
while !(*environ).is_null() {
diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs
index 6741ae46d..30356fa85 100644
--- a/library/std/src/sys/windows/args.rs
+++ b/library/std/src/sys/windows/args.rs
@@ -270,7 +270,7 @@ pub(crate) fn make_bat_command_line(
// It is necessary to surround the command in an extra pair of quotes,
// hence the trailing quote here. It will be closed after all arguments
// have been added.
- let mut cmd: Vec<u16> = "cmd.exe /c \"".encode_utf16().collect();
+ let mut cmd: Vec<u16> = "cmd.exe /d /c \"".encode_utf16().collect();
// Push the script name surrounded by its quote pair.
cmd.push(b'"' as u16);
@@ -290,6 +290,15 @@ pub(crate) fn make_bat_command_line(
// reconstructed by the batch script by default.
for arg in args {
cmd.push(' ' as u16);
+ // Make sure to always quote special command prompt characters, including:
+ // * Characters `cmd /?` says require quotes.
+ // * `%` for environment variables, as in `%TMP%`.
+ // * `|<>` pipe/redirect characters.
+ const SPECIAL: &[u8] = b"\t &()[]{}^=;!'+,`~%|<>";
+ let force_quotes = match arg {
+ Arg::Regular(arg) if !force_quotes => arg.bytes().iter().any(|c| SPECIAL.contains(c)),
+ _ => force_quotes,
+ };
append_arg(&mut cmd, arg, force_quotes)?;
}
diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs
index f58dcf128..5d150eca0 100644
--- a/library/std/src/sys/windows/c.rs
+++ b/library/std/src/sys/windows/c.rs
@@ -6,13 +6,15 @@
use crate::ffi::CStr;
use crate::mem;
-use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort};
+use crate::os::raw::{c_char, c_long, c_longlong, c_uint, c_ulong, c_ushort};
use crate::os::windows::io::{BorrowedHandle, HandleOrInvalid, HandleOrNull};
use crate::ptr;
use core::ffi::NonZero_c_ulong;
use libc::{c_void, size_t, wchar_t};
+pub use crate::os::raw::c_int;
+
#[path = "c/errors.rs"] // c.rs is included from two places so we need to specify this
mod errors;
pub use errors::*;
@@ -47,16 +49,19 @@ pub type ACCESS_MASK = DWORD;
pub type LPBOOL = *mut BOOL;
pub type LPBYTE = *mut BYTE;
+pub type LPCCH = *const CHAR;
pub type LPCSTR = *const CHAR;
+pub type LPCWCH = *const WCHAR;
pub type LPCWSTR = *const WCHAR;
+pub type LPCVOID = *const c_void;
pub type LPDWORD = *mut DWORD;
pub type LPHANDLE = *mut HANDLE;
pub type LPOVERLAPPED = *mut OVERLAPPED;
pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION;
pub type LPSECURITY_ATTRIBUTES = *mut SECURITY_ATTRIBUTES;
pub type LPSTARTUPINFO = *mut STARTUPINFO;
+pub type LPSTR = *mut CHAR;
pub type LPVOID = *mut c_void;
-pub type LPCVOID = *const c_void;
pub type LPWCH = *mut WCHAR;
pub type LPWIN32_FIND_DATAW = *mut WIN32_FIND_DATAW;
pub type LPWSADATA = *mut WSADATA;
@@ -132,6 +137,10 @@ pub const MAX_PATH: usize = 260;
pub const FILE_TYPE_PIPE: u32 = 3;
+pub const CP_UTF8: DWORD = 65001;
+pub const MB_ERR_INVALID_CHARS: DWORD = 0x08;
+pub const WC_ERR_INVALID_CHARS: DWORD = 0x80;
+
#[repr(C)]
#[derive(Copy)]
pub struct WIN32_FIND_DATAW {
@@ -539,14 +548,6 @@ pub struct SYMBOLIC_LINK_REPARSE_BUFFER {
pub PathBuffer: WCHAR,
}
-/// NB: Use carefully! In general using this as a reference is likely to get the
-/// provenance wrong for the `PathBuffer` field!
-#[repr(C)]
-pub struct FILE_NAME_INFO {
- pub FileNameLength: DWORD,
- pub FileName: [WCHAR; 1],
-}
-
#[repr(C)]
pub struct MOUNT_POINT_REPARSE_BUFFER {
pub SubstituteNameOffset: c_ushort,
@@ -1155,6 +1156,25 @@ extern "system" {
lpFilePart: *mut LPWSTR,
) -> DWORD;
pub fn GetFileAttributesW(lpFileName: LPCWSTR) -> DWORD;
+
+ pub fn MultiByteToWideChar(
+ CodePage: UINT,
+ dwFlags: DWORD,
+ lpMultiByteStr: LPCCH,
+ cbMultiByte: c_int,
+ lpWideCharStr: LPWSTR,
+ cchWideChar: c_int,
+ ) -> c_int;
+ pub fn WideCharToMultiByte(
+ CodePage: UINT,
+ dwFlags: DWORD,
+ lpWideCharStr: LPCWCH,
+ cchWideChar: c_int,
+ lpMultiByteStr: LPSTR,
+ cbMultiByte: c_int,
+ lpDefaultChar: LPCCH,
+ lpUsedDefaultChar: LPBOOL,
+ ) -> c_int;
}
#[link(name = "ws2_32")]
diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs
index 378098038..d2c597664 100644
--- a/library/std/src/sys/windows/fs.rs
+++ b/library/std/src/sys/windows/fs.rs
@@ -1266,7 +1266,12 @@ fn metadata(path: &Path, reparse: ReparsePoint) -> io::Result<FileAttr> {
// If the fallback fails for any reason we return the original error.
match File::open(path, &opts) {
Ok(file) => file.file_attr(),
- Err(e) if e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _) => {
+ Err(e)
+ if [Some(c::ERROR_SHARING_VIOLATION as _), Some(c::ERROR_ACCESS_DENIED as _)]
+ .contains(&e.raw_os_error()) =>
+ {
+ // `ERROR_ACCESS_DENIED` is returned when the user doesn't have permission for the resource.
+ // One such example is `System Volume Information` as default but can be created as well
// `ERROR_SHARING_VIOLATION` will almost never be returned.
// Usually if a file is locked you can still read some metadata.
// However, there are special system files, such as
@@ -1393,6 +1398,8 @@ fn symlink_junction_inner(original: &Path, junction: &Path) -> io::Result<()> {
let mut data = Align8([MaybeUninit::<u8>::uninit(); c::MAXIMUM_REPARSE_DATA_BUFFER_SIZE]);
let data_ptr = data.0.as_mut_ptr();
let db = data_ptr.cast::<c::REPARSE_MOUNTPOINT_DATA_BUFFER>();
+ // Zero the header to ensure it's fully initialized, including reserved parameters.
+ *db = mem::zeroed();
let buf = ptr::addr_of_mut!((*db).ReparseTarget).cast::<c::WCHAR>();
let mut i = 0;
// FIXME: this conversion is very hacky
diff --git a/library/std/src/sys/windows/io.rs b/library/std/src/sys/windows/io.rs
index 2cc34c986..7fdd1f702 100644
--- a/library/std/src/sys/windows/io.rs
+++ b/library/std/src/sys/windows/io.rs
@@ -2,8 +2,7 @@ use crate::marker::PhantomData;
use crate::mem::size_of;
use crate::os::windows::io::{AsHandle, AsRawHandle, BorrowedHandle};
use crate::slice;
-use crate::sys::{c, Align8};
-use core;
+use crate::sys::c;
use libc;
#[derive(Copy, Clone)]
@@ -125,22 +124,33 @@ unsafe fn msys_tty_on(handle: c::HANDLE) -> bool {
return false;
}
- const SIZE: usize = size_of::<c::FILE_NAME_INFO>() + c::MAX_PATH * size_of::<c::WCHAR>();
- let mut name_info_bytes = Align8([0u8; SIZE]);
+ /// Mirrors [`FILE_NAME_INFO`], giving it a fixed length that we can stack
+ /// allocate
+ ///
+ /// [`FILE_NAME_INFO`]: https://learn.microsoft.com/en-us/windows/win32/api/winbase/ns-winbase-file_name_info
+ #[repr(C)]
+ #[allow(non_snake_case)]
+ struct FILE_NAME_INFO {
+ FileNameLength: u32,
+ FileName: [u16; c::MAX_PATH as usize],
+ }
+ let mut name_info = FILE_NAME_INFO { FileNameLength: 0, FileName: [0; c::MAX_PATH as usize] };
+ // Safety: buffer length is fixed.
let res = c::GetFileInformationByHandleEx(
handle,
c::FileNameInfo,
- name_info_bytes.0.as_mut_ptr() as *mut libc::c_void,
- SIZE as u32,
+ &mut name_info as *mut _ as *mut libc::c_void,
+ size_of::<FILE_NAME_INFO>() as u32,
);
if res == 0 {
return false;
}
- let name_info: &c::FILE_NAME_INFO = &*(name_info_bytes.0.as_ptr() as *const c::FILE_NAME_INFO);
- let name_len = name_info.FileNameLength as usize / 2;
- // Offset to get the `FileName` field.
- let name_ptr = name_info_bytes.0.as_ptr().offset(size_of::<c::DWORD>() as isize).cast::<u16>();
- let s = core::slice::from_raw_parts(name_ptr, name_len);
+
+ // Use `get` because `FileNameLength` can be out of range.
+ let s = match name_info.FileName.get(..name_info.FileNameLength as usize / 2) {
+ None => return false,
+ Some(s) => s,
+ };
let name = String::from_utf16_lossy(s);
// Get the file name only.
let name = name.rsplit('\\').next().unwrap_or(&name);
diff --git a/library/std/src/sys/windows/stdio.rs b/library/std/src/sys/windows/stdio.rs
index 70c9b14a0..32c6ccffb 100644
--- a/library/std/src/sys/windows/stdio.rs
+++ b/library/std/src/sys/windows/stdio.rs
@@ -1,6 +1,5 @@
#![unstable(issue = "none", feature = "windows_stdio")]
-use crate::char::decode_utf16;
use crate::cmp;
use crate::io;
use crate::mem::MaybeUninit;
@@ -170,14 +169,27 @@ fn write(
}
fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usize> {
+ debug_assert!(!utf8.is_empty());
+
let mut utf16 = [MaybeUninit::<u16>::uninit(); MAX_BUFFER_SIZE / 2];
- let mut len_utf16 = 0;
- for (chr, dest) in utf8.encode_utf16().zip(utf16.iter_mut()) {
- *dest = MaybeUninit::new(chr);
- len_utf16 += 1;
- }
- // Safety: We've initialized `len_utf16` values.
- let utf16: &[u16] = unsafe { MaybeUninit::slice_assume_init_ref(&utf16[..len_utf16]) };
+ let utf8 = &utf8[..utf8.floor_char_boundary(utf16.len())];
+
+ let utf16: &[u16] = unsafe {
+ // Note that this theoretically checks validity twice in the (most common) case
+ // where the underlying byte sequence is valid utf-8 (given the check in `write()`).
+ let result = c::MultiByteToWideChar(
+ c::CP_UTF8, // CodePage
+ c::MB_ERR_INVALID_CHARS, // dwFlags
+ utf8.as_ptr() as c::LPCCH, // lpMultiByteStr
+ utf8.len() as c::c_int, // cbMultiByte
+ utf16.as_mut_ptr() as c::LPWSTR, // lpWideCharStr
+ utf16.len() as c::c_int, // cchWideChar
+ );
+ assert!(result != 0, "Unexpected error in MultiByteToWideChar");
+
+ // Safety: MultiByteToWideChar initializes `result` values.
+ MaybeUninit::slice_assume_init_ref(&utf16[..result as usize])
+ };
let mut written = write_u16s(handle, &utf16)?;
@@ -190,8 +202,8 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usiz
// a missing surrogate can be produced (and also because of the UTF-8 validation above),
// write the missing surrogate out now.
// Buffering it would mean we have to lie about the number of bytes written.
- let first_char_remaining = utf16[written];
- if first_char_remaining >= 0xDCEE && first_char_remaining <= 0xDFFF {
+ let first_code_unit_remaining = utf16[written];
+ if first_code_unit_remaining >= 0xDCEE && first_code_unit_remaining <= 0xDFFF {
// low surrogate
// We just hope this works, and give up otherwise
let _ = write_u16s(handle, &utf16[written..written + 1]);
@@ -213,6 +225,7 @@ fn write_valid_utf8_to_console(handle: c::HANDLE, utf8: &str) -> io::Result<usiz
}
fn write_u16s(handle: c::HANDLE, data: &[u16]) -> io::Result<usize> {
+ debug_assert!(data.len() < u32::MAX as usize);
let mut written = 0;
cvt(unsafe {
c::WriteConsoleW(
@@ -366,26 +379,32 @@ fn read_u16s(handle: c::HANDLE, buf: &mut [MaybeUninit<u16>]) -> io::Result<usiz
Ok(amount as usize)
}
-#[allow(unused)]
fn utf16_to_utf8(utf16: &[u16], utf8: &mut [u8]) -> io::Result<usize> {
- let mut written = 0;
- for chr in decode_utf16(utf16.iter().cloned()) {
- match chr {
- Ok(chr) => {
- chr.encode_utf8(&mut utf8[written..]);
- written += chr.len_utf8();
- }
- Err(_) => {
- // We can't really do any better than forget all data and return an error.
- return Err(io::const_io_error!(
- io::ErrorKind::InvalidData,
- "Windows stdin in console mode does not support non-UTF-16 input; \
- encountered unpaired surrogate",
- ));
- }
- }
+ debug_assert!(utf16.len() <= c::c_int::MAX as usize);
+ debug_assert!(utf8.len() <= c::c_int::MAX as usize);
+
+ let result = unsafe {
+ c::WideCharToMultiByte(
+ c::CP_UTF8, // CodePage
+ c::WC_ERR_INVALID_CHARS, // dwFlags
+ utf16.as_ptr(), // lpWideCharStr
+ utf16.len() as c::c_int, // cchWideChar
+ utf8.as_mut_ptr() as c::LPSTR, // lpMultiByteStr
+ utf8.len() as c::c_int, // cbMultiByte
+ ptr::null(), // lpDefaultChar
+ ptr::null_mut(), // lpUsedDefaultChar
+ )
+ };
+ if result == 0 {
+ // We can't really do any better than forget all data and return an error.
+ Err(io::const_io_error!(
+ io::ErrorKind::InvalidData,
+ "Windows stdin in console mode does not support non-UTF-16 input; \
+ encountered unpaired surrogate",
+ ))
+ } else {
+ Ok(result as usize)
}
- Ok(written)
}
impl IncompleteUtf8 {
diff --git a/library/std/src/sys/windows/thread.rs b/library/std/src/sys/windows/thread.rs
index 1cb576c95..ed58c47e0 100644
--- a/library/std/src/sys/windows/thread.rs
+++ b/library/std/src/sys/windows/thread.rs
@@ -22,7 +22,7 @@ pub struct Thread {
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 p);
+ let p = Box::into_raw(Box::new(p));
// FIXME On UNIX, we guard against stack sizes that are too small but
// that's because pthreads enforces that stacks are at least
diff --git a/library/std/src/sys/windows/thread_parking.rs b/library/std/src/sys/windows/thread_parking.rs
index 5d43676ad..eb9167cd8 100644
--- a/library/std/src/sys/windows/thread_parking.rs
+++ b/library/std/src/sys/windows/thread_parking.rs
@@ -221,7 +221,7 @@ impl Parker {
fn keyed_event_handle() -> c::HANDLE {
const INVALID: c::HANDLE = ptr::invalid_mut(!0);
- static HANDLE: AtomicPtr<libc::c_void> = AtomicPtr::new(INVALID);
+ static HANDLE: AtomicPtr<crate::ffi::c_void> = AtomicPtr::new(INVALID);
match HANDLE.load(Relaxed) {
INVALID => {
let mut handle = c::INVALID_HANDLE_VALUE;