diff options
| author | Tyler Ruckinger <t.ruckinger@gmail.com> | 2020-06-26 00:37:12 -0400 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-06-26 00:37:12 -0400 |
| commit | 00ef46169e2b2631d41d6aa1b7c55b8abf006e50 (patch) | |
| tree | de82ec4b5eefbef6f58767a7ac5c823fbf8776be /src/libstd/sys | |
| parent | 8e6de3244cd62cbde367c206bc9972daded5281d (diff) | |
| parent | 1033351a51dd3ca342a83d4be13f7554f0b4fb1e (diff) | |
| download | rust-00ef46169e2b2631d41d6aa1b7c55b8abf006e50.tar.gz rust-00ef46169e2b2631d41d6aa1b7c55b8abf006e50.zip | |
Merge pull request #2 from rust-lang/master
update master
Diffstat (limited to 'src/libstd/sys')
100 files changed, 1164 insertions, 467 deletions
diff --git a/src/libstd/sys/cloudabi/condvar.rs b/src/libstd/sys/cloudabi/condvar.rs index 3ba51d77494..dabdc0c9b51 100644 --- a/src/libstd/sys/cloudabi/condvar.rs +++ b/src/libstd/sys/cloudabi/condvar.rs @@ -42,7 +42,7 @@ impl Condvar { let ret = abi::condvar_signal( condvar as *mut abi::condvar, abi::scope::PRIVATE, - abi::nthreads::max_value(), + abi::nthreads::MAX, ); assert_eq!(ret, abi::errno::SUCCESS, "Failed to broadcast on condition variable"); } diff --git a/src/libstd/sys/cloudabi/mod.rs b/src/libstd/sys/cloudabi/mod.rs index e5f1dd98435..8dbc31472d6 100644 --- a/src/libstd/sys/cloudabi/mod.rs +++ b/src/libstd/sys/cloudabi/mod.rs @@ -51,7 +51,7 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { } } -pub unsafe fn abort_internal() -> ! { +pub fn abort_internal() -> ! { core::intrinsics::abort(); } diff --git a/src/libstd/sys/cloudabi/mutex.rs b/src/libstd/sys/cloudabi/mutex.rs index 4aa25e25052..580ab0e8ad8 100644 --- a/src/libstd/sys/cloudabi/mutex.rs +++ b/src/libstd/sys/cloudabi/mutex.rs @@ -53,16 +53,16 @@ pub struct ReentrantMutex { } impl ReentrantMutex { - pub unsafe fn uninitialized() -> ReentrantMutex { + pub const unsafe fn uninitialized() -> ReentrantMutex { ReentrantMutex { lock: UnsafeCell::new(MaybeUninit::uninit()), recursion: UnsafeCell::new(MaybeUninit::uninit()), } } - pub unsafe fn init(&mut self) { - self.lock = UnsafeCell::new(MaybeUninit::new(AtomicU32::new(abi::LOCK_UNLOCKED.0))); - self.recursion = UnsafeCell::new(MaybeUninit::new(0)); + pub unsafe fn init(&self) { + *self.lock.get() = MaybeUninit::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)); + *self.recursion.get() = MaybeUninit::new(0); } pub unsafe fn try_lock(&self) -> bool { diff --git a/src/libstd/sys/cloudabi/shims/fs.rs b/src/libstd/sys/cloudabi/shims/fs.rs index e6160d1457d..ecb5b51cccd 100644 --- a/src/libstd/sys/cloudabi/shims/fs.rs +++ b/src/libstd/sys/cloudabi/shims/fs.rs @@ -202,6 +202,10 @@ impl File { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } @@ -210,6 +214,10 @@ impl File { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn flush(&self) -> io::Result<()> { match self.0 {} } diff --git a/src/libstd/sys/cloudabi/shims/net.rs b/src/libstd/sys/cloudabi/shims/net.rs index 67c436fa795..375aaab405d 100644 --- a/src/libstd/sys/cloudabi/shims/net.rs +++ b/src/libstd/sys/cloudabi/shims/net.rs @@ -47,6 +47,10 @@ impl TcpStream { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _: &[u8]) -> io::Result<usize> { match self.0 {} } @@ -55,6 +59,10 @@ impl TcpStream { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn peer_addr(&self) -> io::Result<SocketAddr> { match self.0 {} } diff --git a/src/libstd/sys/cloudabi/shims/pipe.rs b/src/libstd/sys/cloudabi/shims/pipe.rs index fb14dc59101..10d0925823e 100644 --- a/src/libstd/sys/cloudabi/shims/pipe.rs +++ b/src/libstd/sys/cloudabi/shims/pipe.rs @@ -12,6 +12,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } @@ -20,6 +24,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/cloudabi/stack_overflow.rs b/src/libstd/sys/cloudabi/stack_overflow.rs index e97831b2c28..9339b143731 100644 --- a/src/libstd/sys/cloudabi/stack_overflow.rs +++ b/src/libstd/sys/cloudabi/stack_overflow.rs @@ -1,13 +1,5 @@ #![cfg_attr(test, allow(dead_code))] -pub struct Handler; - -impl Handler { - pub unsafe fn new() -> Handler { - Handler - } -} - pub unsafe fn init() {} pub unsafe fn cleanup() {} diff --git a/src/libstd/sys/cloudabi/thread.rs b/src/libstd/sys/cloudabi/thread.rs index 3afcae7ae75..a15dc8653e8 100644 --- a/src/libstd/sys/cloudabi/thread.rs +++ b/src/libstd/sys/cloudabi/thread.rs @@ -5,7 +5,6 @@ use crate::mem; use crate::ptr; use crate::sys::cloudabi::abi; use crate::sys::time::checked_dur2intervals; -use crate::sys_common::thread::*; use crate::time::Duration; pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; @@ -22,7 +21,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 p; + let p = Box::into_raw(box 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); @@ -30,19 +29,25 @@ impl Thread { let stack_size = cmp::max(stack, min_stack_size(&attr)); assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0); - let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _); + let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); + // Note: if the thread creation fails and this assert fails, then p will + // be leaked. However, an alternative design could cause double-free + // which is clearly worse. assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); return if ret != 0 { + // The thread failed to start and as a result p was not consumed. Therefore, it is + // safe to reconstruct the box so that it gets deallocated. + drop(Box::from_raw(p)); Err(io::Error::from_raw_os_error(ret)) } else { - mem::forget(p); // ownership passed to pthread_create Ok(Thread { id: native }) }; extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { unsafe { - start_thread(main as *mut u8); + // Let's run some code. + Box::from_raw(main as *mut Box<dyn FnOnce()>)(); } ptr::null_mut() } diff --git a/src/libstd/sys/hermit/condvar.rs b/src/libstd/sys/hermit/condvar.rs index 5b7f16ce562..132e579b3a5 100644 --- a/src/libstd/sys/hermit/condvar.rs +++ b/src/libstd/sys/hermit/condvar.rs @@ -12,9 +12,8 @@ impl Condvar { Condvar { identifier: 0 } } - #[inline] pub unsafe fn init(&mut self) { - // nothing to do + let _ = abi::init_queue(self.id()); } pub unsafe fn notify_one(&self) { @@ -36,7 +35,7 @@ impl Condvar { pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { let nanos = dur.as_nanos(); - let nanos = cmp::min(i64::max_value() as u128, nanos); + let nanos = cmp::min(i64::MAX as u128, nanos); // add current task to the wait queue let _ = abi::add_queue(self.id(), nanos as i64); @@ -50,7 +49,6 @@ impl Condvar { ret } - #[inline] pub unsafe fn destroy(&self) { let _ = abi::destroy_queue(self.id()); } diff --git a/src/libstd/sys/hermit/ext/ffi.rs b/src/libstd/sys/hermit/ext/ffi.rs new file mode 100644 index 00000000000..07b59a02556 --- /dev/null +++ b/src/libstd/sys/hermit/ext/ffi.rs @@ -0,0 +1,38 @@ +//! HermitCore-specific extension to the primitives in the `std::ffi` module +//! +//! # Examples +//! +//! ``` +//! use std::ffi::OsString; +//! use std::os::hermit::ffi::OsStringExt; +//! +//! let bytes = b"foo".to_vec(); +//! +//! // OsStringExt::from_vec +//! let os_string = OsString::from_vec(bytes); +//! assert_eq!(os_string.to_str(), Some("foo")); +//! +//! // OsStringExt::into_vec +//! let bytes = os_string.into_vec(); +//! assert_eq!(bytes, b"foo"); +//! ``` +//! +//! ``` +//! use std::ffi::OsStr; +//! use std::os::hermit::ffi::OsStrExt; +//! +//! let bytes = b"foo"; +//! +//! // OsStrExt::from_bytes +//! let os_str = OsStr::from_bytes(bytes); +//! assert_eq!(os_str.to_str(), Some("foo")); +//! +//! // OsStrExt::as_bytes +//! let bytes = os_str.as_bytes(); +//! assert_eq!(bytes, b"foo"); +//! ``` + +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "rust1", since = "1.0.0")] +pub use crate::sys_common::os_str_bytes::*; diff --git a/src/libstd/sys/hermit/ext/mod.rs b/src/libstd/sys/hermit/ext/mod.rs new file mode 100644 index 00000000000..ea87d0ad2c9 --- /dev/null +++ b/src/libstd/sys/hermit/ext/mod.rs @@ -0,0 +1,14 @@ +#![stable(feature = "rust1", since = "1.0.0")] +#![allow(missing_docs)] + +pub mod ffi; + +/// 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/src/libstd/sys/hermit/fast_thread_local.rs b/src/libstd/sys/hermit/fast_thread_local.rs index 1108e2545bd..9b683fce157 100644 --- a/src/libstd/sys/hermit/fast_thread_local.rs +++ b/src/libstd/sys/hermit/fast_thread_local.rs @@ -1,4 +1,36 @@ #![cfg(target_thread_local)] #![unstable(feature = "thread_local_internals", issue = "none")] -pub use crate::sys_common::thread_local::register_dtor_fallback as register_dtor; +// Simplify dtor registration by using a list of destructors. +// The this solution works like the implementation of macOS and +// doesn't additional OS support + +use crate::cell::Cell; +use crate::ptr; + +#[thread_local] +static DTORS: Cell<*mut List> = Cell::new(ptr::null_mut()); + +type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>; + +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(); + 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() { + dtor(ptr); + } + ptr = DTORS.replace(ptr::null_mut()); + } +} diff --git a/src/libstd/sys/hermit/fs.rs b/src/libstd/sys/hermit/fs.rs index 37ac5984eee..82ccab1462b 100644 --- a/src/libstd/sys/hermit/fs.rs +++ b/src/libstd/sys/hermit/fs.rs @@ -6,6 +6,7 @@ use crate::io::{IoSlice, IoSliceMut, SeekFrom}; use crate::path::{Path, PathBuf}; 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::fd::FileDesc; use crate::sys::time::SystemTime; use crate::sys::{unsupported, Void}; @@ -17,14 +18,6 @@ pub use crate::sys_common::fs::copy; fn cstr(path: &Path) -> io::Result<CString> { Ok(CString::new(path.as_os_str().as_bytes())?) } -//const O_ACCMODE: i32 = 00000003; -const O_RDONLY: i32 = 00000000; -const O_WRONLY: i32 = 00000001; -const O_RDWR: i32 = 00000002; -const O_CREAT: i32 = 00000100; -const O_EXCL: i32 = 00000200; -const O_TRUNC: i32 = 00001000; -const O_APPEND: i32 = 00002000; #[derive(Debug)] pub struct File(FileDesc); @@ -308,6 +301,11 @@ impl File { crate::io::default_read_vectored(|buf| self.read(buf), bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + false + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } @@ -316,6 +314,11 @@ impl File { crate::io::default_write_vectored(|buf| self.write(buf), bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + false + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } diff --git a/src/libstd/sys/hermit/mod.rs b/src/libstd/sys/hermit/mod.rs index 1e4a53abdc7..7bdc1be3b17 100644 --- a/src/libstd/sys/hermit/mod.rs +++ b/src/libstd/sys/hermit/mod.rs @@ -21,6 +21,7 @@ pub mod args; pub mod cmath; pub mod condvar; pub mod env; +pub mod ext; pub mod fast_thread_local; pub mod fd; pub mod fs; @@ -73,8 +74,10 @@ pub extern "C" fn floor(x: f64) -> f64 { unsafe { intrinsics::floorf64(x) } } -pub unsafe fn abort_internal() -> ! { - abi::abort(); +pub fn abort_internal() -> ! { + unsafe { + abi::abort(); + } } // FIXME: just a workaround to test the system @@ -87,15 +90,13 @@ pub fn hashmap_random_keys() -> (u64, u64) { #[cfg(not(test))] #[no_mangle] // NB. used by both libunwind and libpanic_abort -pub unsafe extern "C" fn __rust_abort() { +pub extern "C" fn __rust_abort() { abort_internal(); } #[cfg(not(test))] pub fn init() { - unsafe { - let _ = net::init(); - } + let _ = net::init(); } #[cfg(not(test))] @@ -105,6 +106,7 @@ pub unsafe extern "C" fn runtime_entry( argv: *const *const c_char, env: *const *const c_char, ) -> ! { + use crate::sys::hermit::fast_thread_local::run_dtors; extern "C" { fn main(argc: isize, argv: *const *const c_char) -> i32; } @@ -114,6 +116,7 @@ pub unsafe extern "C" fn runtime_entry( let result = main(argc as isize, argv); + run_dtors(); abi::exit(result); } diff --git a/src/libstd/sys/hermit/mutex.rs b/src/libstd/sys/hermit/mutex.rs index b5c75f738d2..3d4813209cb 100644 --- a/src/libstd/sys/hermit/mutex.rs +++ b/src/libstd/sys/hermit/mutex.rs @@ -46,13 +46,13 @@ pub struct ReentrantMutex { } impl ReentrantMutex { - pub unsafe fn uninitialized() -> ReentrantMutex { + pub const unsafe fn uninitialized() -> ReentrantMutex { ReentrantMutex { inner: ptr::null() } } #[inline] - pub unsafe fn init(&mut self) { - let _ = abi::recmutex_init(&mut self.inner as *mut *const c_void); + pub unsafe fn init(&self) { + let _ = abi::recmutex_init(&self.inner as *const *const c_void as *mut _); } #[inline] diff --git a/src/libstd/sys/hermit/net.rs b/src/libstd/sys/hermit/net.rs index 82917e71be1..8a788a9265f 100644 --- a/src/libstd/sys/hermit/net.rs +++ b/src/libstd/sys/hermit/net.rs @@ -1,291 +1,405 @@ use crate::convert::TryFrom; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; +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, Void}; +use crate::sys_common::AsInner; use crate::time::Duration; -//// Iinitializes HermitCore's network stack -pub unsafe fn init() -> io::Result<()> { +/// 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::Error::new(ErrorKind::Other, "Unable to initialize network interface")); + } + Ok(()) } -pub struct TcpStream(Void); +#[derive(Debug, Clone)] +pub struct Socket(abi::Handle); + +impl AsInner<abi::Handle> for Socket { + fn as_inner(&self) -> &abi::Handle { + &self.0 + } +} + +impl Drop for Socket { + fn drop(&mut self) { + let _ = abi::tcpstream::close(self.0); + } +} + +// 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(_: io::Result<&SocketAddr>) -> io::Result<TcpStream> { - unsupported() + 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::Error::new(ErrorKind::Other, "Unable to initiate a connection on a socket")) + } + } } - pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> { - unsupported() + 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::Error::new(ErrorKind::Other, "Unable to initiate a connection on a socket")) + } + } } - pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> { - match self.0 {} + 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::Error::new(ErrorKind::Other, "Unable to set timeout value")) } - pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> { - match self.0 {} + 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::Error::new(ErrorKind::Other, "Unable to set timeout value")) } pub fn read_timeout(&self) -> io::Result<Option<Duration>> { - match self.0 {} + let duration = abi::tcpstream::get_read_timeout(*self.0.as_inner()) + .map_err(|_| io::Error::new(ErrorKind::Other, "Unable to determine timeout value"))?; + + Ok(duration.map(|d| Duration::from_millis(d))) } pub fn write_timeout(&self) -> io::Result<Option<Duration>> { - match self.0 {} + let duration = abi::tcpstream::get_write_timeout(*self.0.as_inner()) + .map_err(|_| io::Error::new(ErrorKind::Other, "Unable to determine timeout value"))?; + + Ok(duration.map(|d| Duration::from_millis(d))) } - pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { - match self.0 {} + pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { + abi::tcpstream::peek(*self.0.as_inner(), buf) + .map_err(|_| io::Error::new(ErrorKind::Other, "set_nodelay failed")) } - pub fn read(&self, _: &mut [u8]) -> io::Result<usize> { - match self.0 {} + pub fn read(&self, buffer: &mut [u8]) -> io::Result<usize> { + self.read_vectored(&mut [IoSliceMut::new(buffer)]) } - pub fn read_vectored(&self, _: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - match self.0 {} + 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::Error::new(ErrorKind::Other, "Unable to read on socket"))?; + + if ret != 0 { + size += ret; + } + } + + Ok(size) } - pub fn write(&self, _: &[u8]) -> io::Result<usize> { - match self.0 {} + #[inline] + pub fn is_read_vectored(&self) -> bool { + true } - pub fn write_vectored(&self, _: &[IoSlice<'_>]) -> io::Result<usize> { - match self.0 {} + pub fn write(&self, buffer: &[u8]) -> io::Result<usize> { + self.write_vectored(&[IoSlice::new(buffer)]) + } + + 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::Error::new(ErrorKind::Other, "Unable to write on socket"))?; + } + + Ok(size) + } + + #[inline] + pub fn is_write_vectored(&self) -> bool { + true } pub fn peer_addr(&self) -> io::Result<SocketAddr> { - match self.0 {} + let (ipaddr, port) = abi::tcpstream::peer_addr(*self.0.as_inner()) + .map_err(|_| io::Error::new(ErrorKind::Other, "peer_addr 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::Error::new(ErrorKind::Other, "peer_addr failed")); + } + }; + + Ok(saddr) } pub fn socket_addr(&self) -> io::Result<SocketAddr> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "socket_addr isn't supported")) } - pub fn shutdown(&self, _: Shutdown) -> io::Result<()> { - match self.0 {} + pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { + abi::tcpstream::shutdown(*self.0.as_inner(), how as i32) + .map_err(|_| io::Error::new(ErrorKind::Other, "unable to shutdown socket")) } pub fn duplicate(&self) -> io::Result<TcpStream> { - match self.0 {} + Ok(self.clone()) } - pub fn set_nodelay(&self, _: bool) -> io::Result<()> { - match self.0 {} + pub fn set_nodelay(&self, mode: bool) -> io::Result<()> { + abi::tcpstream::set_nodelay(*self.0.as_inner(), mode) + .map_err(|_| io::Error::new(ErrorKind::Other, "set_nodelay failed")) } pub fn nodelay(&self) -> io::Result<bool> { - match self.0 {} + abi::tcpstream::nodelay(*self.0.as_inner()) + .map_err(|_| io::Error::new(ErrorKind::Other, "nodelay failed")) } - pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} + pub fn set_ttl(&self, tll: u32) -> io::Result<()> { + abi::tcpstream::set_tll(*self.0.as_inner(), tll) + .map_err(|_| io::Error::new(ErrorKind::Other, "unable to set TTL")) } pub fn ttl(&self) -> io::Result<u32> { - match self.0 {} + abi::tcpstream::get_tll(*self.0.as_inner()) + .map_err(|_| io::Error::new(ErrorKind::Other, "unable to get TTL")) } pub fn take_error(&self) -> io::Result<Option<io::Error>> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "take_error isn't supported")) } - pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} + pub fn set_nonblocking(&self, mode: bool) -> io::Result<()> { + abi::tcpstream::set_nonblocking(*self.0.as_inner(), mode) + .map_err(|_| io::Error::new(ErrorKind::Other, "unable to set blocking mode")) } } impl fmt::Debug for TcpStream { fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} + Ok(()) } } -pub struct TcpListener(Void); +#[derive(Clone)] +pub struct TcpListener(SocketAddr); impl TcpListener { - pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> { - unsupported() + pub fn bind(addr: io::Result<&SocketAddr>) -> io::Result<TcpListener> { + let addr = addr?; + + Ok(TcpListener(*addr)) } pub fn socket_addr(&self) -> io::Result<SocketAddr> { - match self.0 {} + Ok(self.0) } pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - match self.0 {} + let (handle, ipaddr, port) = abi::tcplistener::accept(self.0.port()) + .map_err(|_| io::Error::new(ErrorKind::Other, "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::Error::new(ErrorKind::Other, "accept failed")); + } + }; + + Ok((TcpStream(Arc::new(Socket(handle))), saddr)) } pub fn duplicate(&self) -> io::Result<TcpListener> { - match self.0 {} + Ok(self.clone()) } pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn ttl(&self) -> io::Result<u32> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn set_only_v6(&self, _: bool) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn only_v6(&self) -> io::Result<bool> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn take_error(&self) -> io::Result<Option<io::Error>> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } } impl fmt::Debug for TcpListener { fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} + Ok(()) } } -pub struct UdpSocket(Void); +pub struct UdpSocket(abi::Handle); impl UdpSocket { pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<UdpSocket> { - unsupported() + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn peer_addr(&self) -> io::Result<SocketAddr> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn socket_addr(&self) -> io::Result<SocketAddr> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn duplicate(&self) -> io::Result<UdpSocket> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn read_timeout(&self) -> io::Result<Option<Duration>> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn write_timeout(&self) -> io::Result<Option<Duration>> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn set_broadcast(&self, _: bool) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn broadcast(&self) -> io::Result<bool> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn multicast_loop_v4(&self) -> io::Result<bool> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn multicast_ttl_v4(&self) -> io::Result<u32> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn multicast_loop_v6(&self) -> io::Result<bool> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn set_ttl(&self, _: u32) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn ttl(&self) -> io::Result<u32> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn take_error(&self) -> io::Result<Option<io::Error>> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn set_nonblocking(&self, _: bool) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn send(&self, _: &[u8]) -> io::Result<usize> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn connect(&self, _: io::Result<&SocketAddr>) -> io::Result<()> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } } impl fmt::Debug for UdpSocket { fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} + Ok(()) } } diff --git a/src/libstd/sys/hermit/pipe.rs b/src/libstd/sys/hermit/pipe.rs index fb14dc59101..10d0925823e 100644 --- a/src/libstd/sys/hermit/pipe.rs +++ b/src/libstd/sys/hermit/pipe.rs @@ -12,6 +12,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } @@ -20,6 +24,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/hermit/stack_overflow.rs b/src/libstd/sys/hermit/stack_overflow.rs index 65a1b17acce..121fe42011d 100644 --- a/src/libstd/sys/hermit/stack_overflow.rs +++ b/src/libstd/sys/hermit/stack_overflow.rs @@ -1,11 +1,3 @@ -pub struct Handler; - -impl Handler { - pub unsafe fn new() -> Handler { - Handler - } -} - #[inline] pub unsafe fn init() {} diff --git a/src/libstd/sys/hermit/stdio.rs b/src/libstd/sys/hermit/stdio.rs index 2eb011ccb39..f3654ee3871 100644 --- a/src/libstd/sys/hermit/stdio.rs +++ b/src/libstd/sys/hermit/stdio.rs @@ -10,24 +10,31 @@ impl Stdin { pub fn new() -> io::Result<Stdin> { Ok(Stdin) } +} - pub fn read(&self, data: &mut [u8]) -> io::Result<usize> { +impl io::Read for Stdin { + fn read(&mut self, data: &mut [u8]) -> io::Result<usize> { self.read_vectored(&mut [IoSliceMut::new(data)]) } - pub fn read_vectored(&self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> { - //ManuallyDrop::new(unsafe { WasiFd::from_raw(libc::STDIN_FILENO as u32) }) - // .read(data) + fn read_vectored(&mut self, _data: &mut [IoSliceMut<'_>]) -> io::Result<usize> { Ok(0) } + + #[inline] + fn is_read_vectored(&self) -> bool { + true + } } impl Stdout { pub fn new() -> io::Result<Stdout> { Ok(Stdout) } +} - pub fn write(&self, data: &[u8]) -> io::Result<usize> { +impl io::Write for Stdout { + fn write(&mut self, data: &[u8]) -> io::Result<usize> { let len; unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) } @@ -39,7 +46,7 @@ impl Stdout { } } - pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> { + fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> { let len; unsafe { len = abi::write(1, data.as_ptr() as *const u8, data.len()) } @@ -51,7 +58,12 @@ impl Stdout { } } - pub fn flush(&self) -> io::Result<()> { + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + fn flush(&mut self) -> io::Result<()> { Ok(()) } } @@ -60,8 +72,10 @@ impl Stderr { pub fn new() -> io::Result<Stderr> { Ok(Stderr) } +} - pub fn write(&self, data: &[u8]) -> io::Result<usize> { +impl io::Write for Stderr { + fn write(&mut self, data: &[u8]) -> io::Result<usize> { let len; unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) } @@ -73,7 +87,7 @@ impl Stderr { } } - pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> { + fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> { let len; unsafe { len = abi::write(2, data.as_ptr() as *const u8, data.len()) } @@ -85,17 +99,13 @@ impl Stderr { } } - pub fn flush(&self) -> io::Result<()> { - Ok(()) + #[inline] + fn is_write_vectored(&self) -> bool { + true } -} -impl io::Write for Stderr { - fn write(&mut self, data: &[u8]) -> io::Result<usize> { - (&*self).write(data) - } fn flush(&mut self) -> io::Result<()> { - (&*self).flush() + Ok(()) } } diff --git a/src/libstd/sys/hermit/thread.rs b/src/libstd/sys/hermit/thread.rs index c3c29c93826..e11afed6687 100644 --- a/src/libstd/sys/hermit/thread.rs +++ b/src/libstd/sys/hermit/thread.rs @@ -1,39 +1,14 @@ #![allow(dead_code)] use crate::ffi::CStr; -use crate::fmt; use crate::io; use crate::mem; use crate::sys::hermit::abi; +use crate::sys::hermit::fast_thread_local::run_dtors; use crate::time::Duration; -use core::u32; - -use crate::sys_common::thread::*; pub type Tid = abi::Tid; -/// Priority of a task -#[derive(PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] -pub struct Priority(u8); - -impl Priority { - pub const fn into(self) -> u8 { - self.0 - } - - pub const fn from(x: u8) -> Self { - Priority(x) - } -} - -impl fmt::Display for Priority { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) - } -} - -pub const NORMAL_PRIO: Priority = Priority::from(2); - pub struct Thread { tid: Tid, } @@ -41,34 +16,39 @@ pub struct Thread { unsafe impl Send for Thread {} unsafe impl Sync for Thread {} -pub const DEFAULT_MIN_STACK_SIZE: usize = 262144; +pub const DEFAULT_MIN_STACK_SIZE: usize = 1 << 20; impl Thread { pub unsafe fn new_with_coreid( - _stack: usize, + stack: usize, p: Box<dyn FnOnce()>, core_id: isize, ) -> io::Result<Thread> { - let p = box p; - let mut tid: Tid = u32::MAX; - let ret = abi::spawn( - &mut tid as *mut Tid, + let p = Box::into_raw(box p); + let tid = abi::spawn2( thread_start, - &*p as *const _ as *const u8 as usize, - Priority::into(NORMAL_PRIO), + p as usize, + abi::Priority::into(abi::NORMAL_PRIO), + stack, core_id, ); - return if ret == 0 { - mem::forget(p); // ownership passed to pthread_create - Ok(Thread { tid: tid }) - } else { + return if tid == 0 { + // The thread failed to start and as a result p was not consumed. Therefore, it is + // safe to reconstruct the box so that it gets deallocated. + drop(Box::from_raw(p)); Err(io::Error::new(io::ErrorKind::Other, "Unable to create thread!")) + } else { + Ok(Thread { tid: tid }) }; extern "C" fn thread_start(main: usize) { unsafe { - start_thread(main as *mut u8); + // Finally, let's run some code. + Box::from_raw(main as *mut Box<dyn FnOnce()>)(); + + // run all destructors + run_dtors(); } } } diff --git a/src/libstd/sys/hermit/thread_local.rs b/src/libstd/sys/hermit/thread_local.rs index c6f8adb2162..f8be9863ed5 100644 --- a/src/libstd/sys/hermit/thread_local.rs +++ b/src/libstd/sys/hermit/thread_local.rs @@ -1,60 +1,26 @@ -#![allow(dead_code)] // not used on all platforms - -use crate::collections::BTreeMap; -use crate::ptr; -use crate::sync::atomic::{AtomicUsize, Ordering}; -use crate::sys_common::mutex::Mutex; - pub type Key = usize; -type Dtor = unsafe extern "C" fn(*mut u8); - -static NEXT_KEY: AtomicUsize = AtomicUsize::new(0); - -static mut KEYS: *mut BTreeMap<Key, Option<Dtor>> = ptr::null_mut(); -static KEYS_LOCK: Mutex = Mutex::new(); - -#[thread_local] -static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut(); - -unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> { - if KEYS.is_null() { - KEYS = Box::into_raw(Box::new(BTreeMap::new())); - } - &mut *KEYS -} - -unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> { - if LOCALS.is_null() { - LOCALS = Box::into_raw(Box::new(BTreeMap::new())); - } - &mut *LOCALS -} - #[inline] -pub unsafe fn create(dtor: Option<Dtor>) -> Key { - let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst); - let _guard = KEYS_LOCK.lock(); - keys().insert(key, dtor); - key +pub unsafe fn create(_dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key { + panic!("should not be used on the wasm target"); } #[inline] -pub unsafe fn get(key: Key) -> *mut u8 { - if let Some(&entry) = locals().get(&key) { entry } else { ptr::null_mut() } +pub unsafe fn set(_key: Key, _value: *mut u8) { + panic!("should not be used on the wasm target"); } #[inline] -pub unsafe fn set(key: Key, value: *mut u8) { - locals().insert(key, value); +pub unsafe fn get(_key: Key) -> *mut u8 { + panic!("should not be used on the wasm target"); } #[inline] -pub unsafe fn destroy(key: Key) { - keys().remove(&key); +pub unsafe fn destroy(_key: Key) { + panic!("should not be used on the wasm target"); } #[inline] pub fn requires_synchronized_create() -> bool { - false + panic!("should not be used on the wasm target"); } diff --git a/src/libstd/sys/sgx/abi/entry.S b/src/libstd/sys/sgx/abi/entry.S index 1f06c9da3a9..fc6ce577033 100644 --- a/src/libstd/sys/sgx/abi/entry.S +++ b/src/libstd/sys/sgx/abi/entry.S @@ -26,18 +26,10 @@ IMAGE_BASE: .Lxsave_clear: .org .+24 .Lxsave_mxcsr: - .int 0 + .short 0x1f80 /* We can store a bunch of data in the gap between MXCSR and the XSAVE header */ -/* MXCSR initialization value for ABI */ -.Lmxcsr_init: - .int 0x1f80 - -/* x87 FPU control word initialization value for ABI */ -.Lfpucw_init: - .int 0x037f - /* The following symbols point at read-only data that will be filled in by the */ /* post-linker. */ @@ -177,13 +169,17 @@ sgx_entry: jz .Lskip_debug_init mov %r10,%gs:tcsls_debug_panic_buf_ptr .Lskip_debug_init: +/* reset cpu state */ + mov %rdx, %r10 + mov $-1, %rax + mov $-1, %rdx + xrstor .Lxsave_clear(%rip) + mov %r10, %rdx + /* check if returning from usercall */ mov %gs:tcsls_last_rsp,%r11 test %r11,%r11 jnz .Lusercall_ret -/* reset user state */ - ldmxcsr .Lmxcsr_init(%rip) - fldcw .Lfpucw_init(%rip) /* setup stack */ mov %gs:tcsls_tos,%rsp /* initially, RSP is not set to the correct value */ /* here. This is fixed below under "adjust stack". */ @@ -324,7 +320,9 @@ usercall: /* return */ mov %rsi,%rax /* RAX = return value */ /* NOP: mov %rdx,%rdx */ /* RDX = return value */ - ret + pop %r11 + lfence + jmp *%r11 /* The following functions need to be defined externally: @@ -343,20 +341,28 @@ extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64 .global get_tcs_addr get_tcs_addr: mov %gs:tcsls_tcs_addr,%rax - ret + pop %r11 + lfence + jmp *%r11 .global get_tls_ptr get_tls_ptr: mov %gs:tcsls_tls_ptr,%rax - ret + pop %r11 + lfence + jmp *%r11 .global set_tls_ptr set_tls_ptr: mov %rdi,%gs:tcsls_tls_ptr - ret + pop %r11 + lfence + jmp *%r11 .global take_debug_panic_buf_ptr take_debug_panic_buf_ptr: xor %rax,%rax xchg %gs:tcsls_debug_panic_buf_ptr,%rax - ret + pop %r11 + lfence + jmp *%r11 diff --git a/src/libstd/sys/sgx/abi/mem.rs b/src/libstd/sys/sgx/abi/mem.rs index 500e62b1cb5..57fd7efdd49 100644 --- a/src/libstd/sys/sgx/abi/mem.rs +++ b/src/libstd/sys/sgx/abi/mem.rs @@ -22,7 +22,7 @@ extern "C" { #[unstable(feature = "sgx_platform", issue = "56975")] pub fn image_base() -> u64 { let base; - unsafe { asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) }; + unsafe { llvm_asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) }; base } diff --git a/src/libstd/sys/sgx/abi/mod.rs b/src/libstd/sys/sgx/abi/mod.rs index 87e7a5da2b7..5ef26d4cc4d 100644 --- a/src/libstd/sys/sgx/abi/mod.rs +++ b/src/libstd/sys/sgx/abi/mod.rs @@ -56,6 +56,7 @@ unsafe extern "C" fn tcs_init(secondary: bool) { // able to specify this #[cfg(not(test))] #[no_mangle] +#[allow(improper_ctypes_definitions)] extern "C" fn entry(p1: u64, p2: u64, p3: u64, secondary: bool, p4: u64, p5: u64) -> (u64, u64) { // FIXME: how to support TLS in library mode? let tls = Box::new(tls::Tls::new()); diff --git a/src/libstd/sys/sgx/ext/arch.rs b/src/libstd/sys/sgx/ext/arch.rs index 5056e388112..0c97a87e2e4 100644 --- a/src/libstd/sys/sgx/ext/arch.rs +++ b/src/libstd/sys/sgx/ext/arch.rs @@ -31,7 +31,7 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result<Align16<[u8; 16]>, u32> let mut out = MaybeUninit::uninit(); let error; - asm!( + llvm_asm!( "enclu" : "={eax}"(error) : "{eax}"(ENCLU_EGETKEY), @@ -60,7 +60,7 @@ pub fn ereport( unsafe { let mut report = MaybeUninit::uninit(); - asm!( + llvm_asm!( "enclu" : /* no output registers */ : "{eax}"(ENCLU_EREPORT), diff --git a/src/libstd/sys/sgx/fd.rs b/src/libstd/sys/sgx/fd.rs index 7da2424a642..90158030c7f 100644 --- a/src/libstd/sys/sgx/fd.rs +++ b/src/libstd/sys/sgx/fd.rs @@ -34,6 +34,11 @@ impl FileDesc { usercalls::read(self.fd, bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { usercalls::write(self.fd, &[IoSlice::new(buf)]) } @@ -42,6 +47,11 @@ impl FileDesc { usercalls::write(self.fd, bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn flush(&self) -> io::Result<()> { usercalls::flush(self.fd) } diff --git a/src/libstd/sys/sgx/fs.rs b/src/libstd/sys/sgx/fs.rs index e6160d1457d..ecb5b51cccd 100644 --- a/src/libstd/sys/sgx/fs.rs +++ b/src/libstd/sys/sgx/fs.rs @@ -202,6 +202,10 @@ impl File { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } @@ -210,6 +214,10 @@ impl File { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn flush(&self) -> io::Result<()> { match self.0 {} } diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index 83cee0cf35a..397dd496ae8 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -124,7 +124,7 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize { return n; } -pub unsafe fn abort_internal() -> ! { +pub fn abort_internal() -> ! { abi::usercalls::exit(true) } @@ -133,7 +133,7 @@ pub unsafe fn abort_internal() -> ! { #[cfg(not(test))] #[no_mangle] // NB. used by both libunwind and libpanic_abort -pub unsafe extern "C" fn __rust_abort() { +pub extern "C" fn __rust_abort() { abort_internal(); } diff --git a/src/libstd/sys/sgx/mutex.rs b/src/libstd/sys/sgx/mutex.rs index eebbea1b285..4911c2f5387 100644 --- a/src/libstd/sys/sgx/mutex.rs +++ b/src/libstd/sys/sgx/mutex.rs @@ -75,7 +75,7 @@ impl ReentrantMutex { } #[inline] - pub unsafe fn init(&mut self) {} + pub unsafe fn init(&self) {} #[inline] pub unsafe fn lock(&self) { diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs index bd0652ab464..666a157b09c 100644 --- a/src/libstd/sys/sgx/net.rs +++ b/src/libstd/sys/sgx/net.rs @@ -149,6 +149,11 @@ impl TcpStream { self.inner.inner.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.inner.inner.is_read_vectored() + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.inner.inner.write(buf) } @@ -157,6 +162,11 @@ impl TcpStream { self.inner.inner.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.inner.inner.is_write_vectored() + } + pub fn peer_addr(&self) -> io::Result<SocketAddr> { addr_to_sockaddr(&self.peer_addr) } diff --git a/src/libstd/sys/sgx/pipe.rs b/src/libstd/sys/sgx/pipe.rs index fb14dc59101..10d0925823e 100644 --- a/src/libstd/sys/sgx/pipe.rs +++ b/src/libstd/sys/sgx/pipe.rs @@ -12,6 +12,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } @@ -20,6 +24,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/sgx/stack_overflow.rs b/src/libstd/sys/sgx/stack_overflow.rs index a2d13d11849..b96652a8330 100644 --- a/src/libstd/sys/sgx/stack_overflow.rs +++ b/src/libstd/sys/sgx/stack_overflow.rs @@ -1,11 +1,3 @@ -pub struct Handler; - -impl Handler { - pub unsafe fn new() -> Handler { - Handler - } -} - #[cfg_attr(test, allow(dead_code))] pub unsafe fn init() {} diff --git a/src/libstd/sys/unix/alloc.rs b/src/libstd/sys/unix/alloc.rs index 77417e41331..8e193935460 100644 --- a/src/libstd/sys/unix/alloc.rs +++ b/src/libstd/sys/unix/alloc.rs @@ -52,7 +52,12 @@ unsafe impl GlobalAlloc for System { } } -#[cfg(any(target_os = "android", target_os = "redox", target_os = "solaris"))] +#[cfg(any( + target_os = "android", + target_os = "illumos", + target_os = "redox", + target_os = "solaris" +))] #[inline] unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { // On android we currently target API level 9 which unfortunately @@ -75,7 +80,12 @@ unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { libc::memalign(layout.align(), layout.size()) as *mut u8 } -#[cfg(not(any(target_os = "android", target_os = "redox", target_os = "solaris")))] +#[cfg(not(any( + target_os = "android", + target_os = "illumos", + target_os = "redox", + target_os = "solaris" +)))] #[inline] unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { let mut out = ptr::null_mut(); diff --git a/src/libstd/sys/unix/android.rs b/src/libstd/sys/unix/android.rs index 8fc2599f0d7..ea05ee3d7ce 100644 --- a/src/libstd/sys/unix/android.rs +++ b/src/libstd/sys/unix/android.rs @@ -95,7 +95,7 @@ pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> { match ftruncate64.get() { Some(f) => cvt_r(|| f(fd, size as i64)).map(drop), None => { - if size > i32::max_value() as u64 { + if size > i32::MAX as u64 { Err(io::Error::new(io::ErrorKind::InvalidInput, "cannot truncate >2GB")) } else { cvt_r(|| ftruncate(fd, size as i32)).map(drop) diff --git a/src/libstd/sys/unix/args.rs b/src/libstd/sys/unix/args.rs index 09acc3f6e3e..1d1cdda1257 100644 --- a/src/libstd/sys/unix/args.rs +++ b/src/libstd/sys/unix/args.rs @@ -65,6 +65,7 @@ impl DoubleEndedIterator for Args { target_os = "netbsd", target_os = "openbsd", target_os = "solaris", + target_os = "illumos", target_os = "emscripten", target_os = "haiku", target_os = "l4re", @@ -204,6 +205,7 @@ mod imp { #[cfg(target_arch = "aarch64")] extern "C" { fn objc_msgSend(obj: NsId, sel: Sel) -> NsId; + #[cfg_attr(not(bootstrap), allow(clashing_extern_decl))] #[link_name = "objc_msgSend"] fn objc_msgSend_ul(obj: NsId, sel: Sel, i: libc::c_ulong) -> NsId; } @@ -211,6 +213,7 @@ mod imp { #[cfg(not(target_arch = "aarch64"))] extern "C" { fn objc_msgSend(obj: NsId, sel: Sel, ...) -> NsId; + #[cfg_attr(not(bootstrap), allow(clashing_extern_decl))] #[link_name = "objc_msgSend"] fn objc_msgSend_ul(obj: NsId, sel: Sel, ...) -> NsId; } diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs index b4896b7ad74..9f1847943f3 100644 --- a/src/libstd/sys/unix/condvar.rs +++ b/src/libstd/sys/unix/condvar.rs @@ -10,14 +10,10 @@ unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} const TIMESPEC_MAX: libc::timespec = - libc::timespec { tv_sec: <libc::time_t>::max_value(), tv_nsec: 1_000_000_000 - 1 }; + libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 }; fn saturating_cast_to_time_t(value: u64) -> libc::time_t { - if value > <libc::time_t>::max_value() as u64 { - <libc::time_t>::max_value() - } else { - value as libc::time_t - } + if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t } } impl Condvar { diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs index 984bcfa4509..7f5e9b04dba 100644 --- a/src/libstd/sys/unix/env.rs +++ b/src/libstd/sys/unix/env.rs @@ -97,6 +97,17 @@ pub mod os { pub const EXE_EXTENSION: &str = ""; } +#[cfg(target_os = "illumos")] +pub mod os { + pub const FAMILY: &str = "unix"; + pub const OS: &str = "illumos"; + pub const DLL_PREFIX: &str = "lib"; + pub const DLL_SUFFIX: &str = ".so"; + pub const DLL_EXTENSION: &str = "so"; + pub const EXE_SUFFIX: &str = ""; + pub const EXE_EXTENSION: &str = ""; +} + #[cfg(target_os = "haiku")] pub mod os { pub const FAMILY: &str = "unix"; diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 732cd677a18..e4d71493604 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -242,7 +242,8 @@ pub trait PermissionsExt { /// let permissions = metadata.permissions(); /// /// println!("permissions: {:o}", permissions.mode()); - /// Ok(()) } + /// Ok(()) + /// } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn mode(&self) -> u32; @@ -262,7 +263,8 @@ pub trait PermissionsExt { /// /// permissions.set_mode(0o644); // Read/write for owner and read for others. /// assert_eq!(permissions.mode(), 0o644); - /// Ok(()) } + /// Ok(()) + /// } /// ``` #[stable(feature = "fs_ext", since = "1.1.0")] fn set_mode(&mut self, mode: u32); diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 4c3cb67c9ee..ada8eaa1c97 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -2,11 +2,9 @@ //! Unix-specific networking functionality -#[cfg(unix)] -use libc; - // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? #[cfg(not(unix))] +#[allow(non_camel_case_types)] mod libc { pub use libc::c_int; pub type socklen_t = u32; @@ -614,6 +612,11 @@ impl io::Read for UnixStream { } #[inline] + fn is_read_vectored(&self) -> bool { + io::Read::is_read_vectored(&&*self) + } + + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() } @@ -630,6 +633,11 @@ impl<'a> io::Read for &'a UnixStream { } #[inline] + fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() } @@ -645,6 +653,11 @@ impl io::Write for UnixStream { io::Write::write_vectored(&mut &*self, bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + fn flush(&mut self) -> io::Result<()> { io::Write::flush(&mut &*self) } @@ -660,6 +673,11 @@ impl<'a> io::Write for &'a UnixStream { self.0.write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } @@ -1069,7 +1087,7 @@ impl<'a> Iterator for Incoming<'a> { } fn size_hint(&self) -> (usize, Option<usize>) { - (usize::max_value(), None) + (usize::MAX, None) } } diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index fa8670b4aec..048ce24d6ba 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -111,7 +111,7 @@ pub trait CommandExt { /// /// Set the first process argument, `argv[0]`, to something other than the /// default executable path. - #[unstable(feature = "process_set_argv0", issue = "66510")] + #[stable(feature = "process_set_argv0", since = "1.45.0")] fn arg0<S>(&mut self, arg: S) -> &mut process::Command where S: AsRef<OsStr>; diff --git a/src/libstd/sys/unix/ext/raw.rs b/src/libstd/sys/unix/ext/raw.rs index d81368a18b4..40fa53d484f 100644 --- a/src/libstd/sys/unix/ext/raw.rs +++ b/src/libstd/sys/unix/ext/raw.rs @@ -11,10 +11,15 @@ #![allow(deprecated)] #[stable(feature = "raw_ext", since = "1.1.0")] +#[allow(non_camel_case_types)] pub type uid_t = u32; + #[stable(feature = "raw_ext", since = "1.1.0")] +#[allow(non_camel_case_types)] pub type gid_t = u32; + #[stable(feature = "raw_ext", since = "1.1.0")] +#[allow(non_camel_case_types)] pub type pid_t = i32; #[doc(inline)] diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 8a99836912a..c481ca8961f 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -23,11 +23,7 @@ fn max_len() -> usize { // intentionally showing odd behavior by rejecting any read with a size // larger than or equal to INT_MAX. To handle both of these the read // size is capped on both platforms. - if cfg!(target_os = "macos") { - <c_int>::max_value() as usize - 1 - } else { - <ssize_t>::max_value() as usize - } + if cfg!(target_os = "macos") { <c_int>::MAX as usize - 1 } else { <ssize_t>::MAX as usize } } impl FileDesc { @@ -58,12 +54,17 @@ impl FileDesc { libc::readv( self.fd, bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::max_value() as usize) as c_int, + cmp::min(bufs.len(), c_int::MAX as usize) as c_int, ) })?; Ok(ret as usize) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { let mut me = self; (&mut me).read_to_end(buf) @@ -110,12 +111,17 @@ impl FileDesc { libc::writev( self.fd, bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::max_value() as usize) as c_int, + cmp::min(bufs.len(), c_int::MAX as usize) as c_int, ) })?; Ok(ret as usize) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { #[cfg(target_os = "android")] use super::android::cvt_pwrite64; @@ -153,6 +159,7 @@ impl FileDesc { #[cfg(not(any( target_env = "newlib", target_os = "solaris", + target_os = "illumos", target_os = "emscripten", target_os = "fuchsia", target_os = "l4re", @@ -169,6 +176,7 @@ impl FileDesc { #[cfg(any( target_env = "newlib", target_os = "solaris", + target_os = "illumos", target_os = "emscripten", target_os = "fuchsia", target_os = "l4re", diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index ab2a871b92d..29cdbf05354 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -22,6 +22,7 @@ use libc::fstatat64; target_os = "linux", target_os = "emscripten", target_os = "solaris", + target_os = "illumos", target_os = "l4re", target_os = "fuchsia", target_os = "redox" @@ -200,7 +201,12 @@ pub struct DirEntry { // on Solaris and Fuchsia because a) it uses a zero-length // array to store the name, b) its lifetime between readdir // calls is not guaranteed. - #[cfg(any(target_os = "solaris", target_os = "fuchsia", target_os = "redox"))] + #[cfg(any( + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "redox" + ))] name: Box<[u8]>, } @@ -403,7 +409,12 @@ impl fmt::Debug for ReadDir { impl Iterator for ReadDir { type Item = io::Result<DirEntry>; - #[cfg(any(target_os = "solaris", target_os = "fuchsia", target_os = "redox"))] + #[cfg(any( + target_os = "solaris", + target_os = "fuchsia", + target_os = "redox", + target_os = "illumos" + ))] fn next(&mut self) -> Option<io::Result<DirEntry>> { use crate::slice; @@ -441,7 +452,12 @@ impl Iterator for ReadDir { } } - #[cfg(not(any(target_os = "solaris", target_os = "fuchsia", target_os = "redox")))] + #[cfg(not(any( + target_os = "solaris", + target_os = "fuchsia", + target_os = "redox", + target_os = "illumos" + )))] fn next(&mut self) -> Option<io::Result<DirEntry>> { if self.end_of_stream { return None; @@ -514,12 +530,12 @@ impl DirEntry { lstat(&self.path()) } - #[cfg(any(target_os = "solaris", target_os = "haiku"))] + #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "haiku"))] pub fn file_type(&self) -> io::Result<FileType> { lstat(&self.path()).map(|m| m.file_type()) } - #[cfg(not(any(target_os = "solaris", target_os = "haiku")))] + #[cfg(not(any(target_os = "solaris", target_os = "illumos", target_os = "haiku")))] pub fn file_type(&self) -> io::Result<FileType> { match self.entry.d_type { libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }), @@ -540,6 +556,7 @@ impl DirEntry { target_os = "emscripten", target_os = "android", target_os = "solaris", + target_os = "illumos", target_os = "haiku", target_os = "l4re", target_os = "fuchsia", @@ -586,7 +603,12 @@ impl DirEntry { fn name_bytes(&self) -> &[u8] { unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes() } } - #[cfg(any(target_os = "solaris", target_os = "fuchsia", target_os = "redox"))] + #[cfg(any( + target_os = "solaris", + target_os = "illumos", + target_os = "fuchsia", + target_os = "redox" + ))] fn name_bytes(&self) -> &[u8] { &*self.name } @@ -681,6 +703,10 @@ impl File { | opts.get_access_mode()? | opts.get_creation_mode()? | (opts.custom_flags as c_int & !libc::O_ACCMODE); + // The third argument of `open64` is documented to have type `mode_t`. On + // some platforms (like macOS, where `open64` is actually `open`), `mode_t` is `u16`. + // However, since this is a variadic function, C integer promotion rules mean that on + // the ABI level, this still gets passed as `c_int` (aka `u32` on Unix platforms). let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; let fd = FileDesc::new(fd); @@ -806,6 +832,11 @@ impl File { self.0.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { self.0.read_at(buf, offset) } @@ -818,6 +849,11 @@ impl File { self.0.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { self.0.write_at(buf, offset) } @@ -1160,7 +1196,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { let mut written = 0u64; while written < len { let copy_result = if has_copy_file_range { - let bytes_to_copy = cmp::min(len - written, usize::max_value() as u64) as usize; + let bytes_to_copy = cmp::min(len - written, usize::MAX as u64) as usize; let copy_result = unsafe { // We actually don't have to adjust the offsets, // because copy_file_range adjusts the file offset automatically diff --git a/src/libstd/sys/unix/l4re.rs b/src/libstd/sys/unix/l4re.rs index c6e4f5693ed..a2912387108 100644 --- a/src/libstd/sys/unix/l4re.rs +++ b/src/libstd/sys/unix/l4re.rs @@ -55,6 +55,10 @@ pub mod net { unimpl!(); } + pub fn is_read_vectored(&self) -> bool { + unimpl!(); + } + pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { unimpl!(); } @@ -75,6 +79,10 @@ pub mod net { unimpl!(); } + pub fn is_write_vectored(&self) -> bool { + unimpl!(); + } + pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> { unimpl!(); } @@ -171,6 +179,10 @@ pub mod net { unimpl!(); } + pub fn is_read_vectored(&self) -> bool { + unimpl!(); + } + pub fn write(&self, _: &[u8]) -> io::Result<usize> { unimpl!(); } @@ -179,6 +191,10 @@ pub mod net { unimpl!(); } + pub fn is_write_vectored(&self) -> bool { + unimpl!(); + } + pub fn peer_addr(&self) -> io::Result<SocketAddr> { unimpl!(); } diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index fbcb006ecdf..b1688e74173 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -17,6 +17,8 @@ pub use crate::os::freebsd as platform; pub use crate::os::fuchsia as platform; #[cfg(all(not(doc), target_os = "haiku"))] pub use crate::os::haiku as platform; +#[cfg(all(not(doc), target_os = "illumos"))] +pub use crate::os::illumos as platform; #[cfg(all(not(doc), target_os = "ios"))] pub use crate::os::ios as platform; #[cfg(all(not(doc), target_os = "l4re"))] @@ -161,6 +163,6 @@ where // understandable error message like "Abort trap" rather than "Illegal // instruction" that intrinsics::abort would cause, as intrinsics::abort is // implemented as an illegal instruction. -pub unsafe fn abort_internal() -> ! { - libc::abort() +pub fn abort_internal() -> ! { + unsafe { libc::abort() } } diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs index b38375a2e03..45c600f75f5 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -28,14 +28,20 @@ impl Mutex { // // A pthread mutex initialized with PTHREAD_MUTEX_INITIALIZER will have // a type of PTHREAD_MUTEX_DEFAULT, which has undefined behavior if you - // try to re-lock it from the same thread when you already hold a lock. + // try to re-lock it from the same thread when you already hold a lock + // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_init.html). + // This is the case even if PTHREAD_MUTEX_DEFAULT == PTHREAD_MUTEX_NORMAL + // (https://github.com/rust-lang/rust/issues/33770#issuecomment-220847521) -- in that + // case, `pthread_mutexattr_settype(PTHREAD_MUTEX_DEFAULT)` will of course be the same + // as setting it to `PTHREAD_MUTEX_NORMAL`, but not setting any mode will result in + // a Mutex where re-locking is UB. // // In practice, glibc takes advantage of this undefined behavior to // implement hardware lock elision, which uses hardware transactional // memory to avoid acquiring the lock. While a transaction is in // progress, the lock appears to be unlocked. This isn't a problem for // other threads since the transactional memory will abort if a conflict - // is detected, however no abort is generated if re-locking from the + // is detected, however no abort is generated when re-locking from the // same thread. // // Since locking the same mutex twice will result in two aliasing &mut @@ -92,11 +98,11 @@ unsafe impl Send for ReentrantMutex {} unsafe impl Sync for ReentrantMutex {} impl ReentrantMutex { - pub unsafe fn uninitialized() -> ReentrantMutex { + pub const unsafe fn uninitialized() -> ReentrantMutex { ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } } - pub unsafe fn init(&mut self) { + pub unsafe fn init(&self) { let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit(); let result = libc::pthread_mutexattr_init(attr.as_mut_ptr()); debug_assert_eq!(result, 0); diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index b37675e0a0a..3717c660b57 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -148,7 +148,7 @@ impl Socket { timeout = 1; } - let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int; + let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int; match unsafe { libc::poll(&mut pollfd, 1, timeout) } { -1 => { @@ -226,6 +226,11 @@ impl Socket { self.0.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + fn recv_from_with_flags( &self, buf: &mut [u8], @@ -263,6 +268,11 @@ impl Socket { self.0.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> { let timeout = match dur { Some(dur) => { @@ -273,8 +283,8 @@ impl Socket { )); } - let secs = if dur.as_secs() > libc::time_t::max_value() as u64 { - libc::time_t::max_value() + let secs = if dur.as_secs() > libc::time_t::MAX as u64 { + libc::time_t::MAX } else { dur.as_secs() as libc::time_t }; @@ -322,11 +332,19 @@ impl Socket { Ok(raw != 0) } + #[cfg(not(any(target_os = "solaris", target_os = "illumos")))] pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { let mut nonblocking = nonblocking as libc::c_int; cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO, &mut nonblocking) }).map(drop) } + #[cfg(any(target_os = "solaris", target_os = "illumos"))] + pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + // FIONBIO is inadequate for sockets on illumos/Solaris, so use the + // fcntl(F_[GS]ETFL)-based method provided by FileDesc instead. + self.0.set_nonblocking(nonblocking) + } + pub fn take_error(&self) -> io::Result<Option<io::Error>> { let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?; if raw == 0 { Ok(None) } else { Ok(Some(io::Error::from_raw_os_error(raw as i32))) } diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 91f7d1524cc..a9cd5094997 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -54,7 +54,7 @@ extern "C" { ), link_name = "__errno" )] - #[cfg_attr(target_os = "solaris", link_name = "___errno")] + #[cfg_attr(any(target_os = "solaris", target_os = "illumos"), link_name = "___errno")] #[cfg_attr( any(target_os = "macos", target_os = "ios", target_os = "freebsd"), link_name = "__error" @@ -357,7 +357,7 @@ pub fn current_exe() -> io::Result<PathBuf> { } } -#[cfg(any(target_os = "solaris"))] +#[cfg(any(target_os = "solaris", target_os = "illumos"))] pub fn current_exe() -> io::Result<PathBuf> { extern "C" { fn getexecname() -> *const c_char; diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 2a861c87801..f2a2eabef91 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -64,6 +64,11 @@ impl AnonPipe { self.0.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } @@ -72,6 +77,11 @@ impl AnonPipe { self.0.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + pub fn fd(&self) -> &FileDesc { &self.0 } diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 859da691ad2..6e33cdd3c48 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -86,11 +86,13 @@ pub struct Command { stderr: Option<Stdio>, } -// Create a new type for argv, so that we can make it `Send` +// Create a new type for argv, so that we can make it `Send` and `Sync` struct Argv(Vec<*const c_char>); -// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args` +// It is safe to make `Argv` `Send` and `Sync`, because it contains +// pointers to memory owned by `Command.args` unsafe impl Send for Argv {} +unsafe impl Sync for Argv {} // passed back to std::process with the pipes connected to the child, if any // were requested @@ -426,6 +428,7 @@ mod tests { // ignored there. #[cfg_attr(target_arch = "arm", ignore)] #[cfg_attr(target_arch = "aarch64", ignore)] + #[cfg_attr(target_arch = "riscv64", ignore)] fn test_process_mask() { unsafe { // Test to make sure that a signal mask does not get inherited. diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 07d0fbf61fe..f389c60615f 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -72,7 +72,7 @@ impl Command { } }; - let mut p = Process { pid: pid, status: None }; + let mut p = Process { pid, status: None }; drop(output); let mut bytes = [0; 8]; diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index 9ce5f3d014c..eed6fbf13b7 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -12,6 +12,7 @@ pub fn hashmap_random_keys() -> (u64, u64) { #[cfg(all( unix, + not(target_os = "macos"), not(target_os = "ios"), not(target_os = "openbsd"), not(target_os = "freebsd"), @@ -92,6 +93,42 @@ mod imp { } } +#[cfg(target_os = "macos")] +mod imp { + use crate::fs::File; + use crate::io::Read; + use crate::sys::os::errno; + use libc::{c_int, c_void, size_t}; + + fn getentropy_fill_bytes(v: &mut [u8]) -> bool { + weak!(fn getentropy(*mut c_void, size_t) -> c_int); + + getentropy + .get() + .map(|f| { + // getentropy(2) permits a maximum buffer size of 256 bytes + for s in v.chunks_mut(256) { + let ret = unsafe { f(s.as_mut_ptr() as *mut c_void, s.len()) }; + if ret == -1 { + panic!("unexpected getentropy error: {}", errno()); + } + } + true + }) + .unwrap_or(false) + } + + pub fn fill_bytes(v: &mut [u8]) { + if getentropy_fill_bytes(v) { + return; + } + + // for older macos which doesn't support getentropy + let mut file = File::open("/dev/urandom").expect("failed to open /dev/urandom"); + file.read_exact(v).expect("failed to read /dev/urandom") + } +} + #[cfg(target_os = "openbsd")] mod imp { use crate::sys::os::errno; diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs index 079dea671ef..2b5067a34f6 100644 --- a/src/libstd/sys/unix/rwlock.rs +++ b/src/libstd/sys/unix/rwlock.rs @@ -22,32 +22,33 @@ impl RWLock { pub unsafe fn read(&self) { let r = libc::pthread_rwlock_rdlock(self.inner.get()); - // According to the pthread_rwlock_rdlock spec, this function **may** - // fail with EDEADLK if a deadlock is detected. On the other hand - // pthread mutexes will *never* return EDEADLK if they are initialized - // as the "fast" kind (which ours always are). As a result, a deadlock - // situation may actually return from the call to pthread_rwlock_rdlock - // instead of blocking forever (as mutexes and Windows rwlocks do). Note - // that not all unix implementations, however, will return EDEADLK for - // their rwlocks. + // According to POSIX, when a thread tries to acquire this read lock + // while it already holds the write lock + // (or vice versa, or tries to acquire the write lock twice), + // "the call shall either deadlock or return [EDEADLK]" + // (https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html, + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_rdlock.html). + // So, in principle, all we have to do here is check `r == 0` to be sure we properly + // got the lock. // - // We roughly maintain the deadlocking behavior by panicking to ensure - // that this lock acquisition does not succeed. - // - // We also check whether this lock is already write locked. This - // is only possible if it was write locked by the current thread and - // the implementation allows recursive locking. The POSIX standard - // doesn't require recursively locking a rwlock to deadlock, but we can't - // allow that because it could lead to aliasing issues. + // However, (at least) glibc before version 2.25 does not conform to this spec, + // and can return `r == 0` even when this thread already holds the write lock. + // We thus check for this situation ourselves and panic when detecting that a thread + // got the write lock more than once, or got a read and a write lock. if r == libc::EAGAIN { panic!("rwlock maximum reader count exceeded"); } else if r == libc::EDEADLK || (r == 0 && *self.write_locked.get()) { + // Above, we make sure to only access `write_locked` when `r == 0` to avoid + // data races. if r == 0 { + // `pthread_rwlock_rdlock` succeeded when it should not have. self.raw_unlock(); } panic!("rwlock read lock would result in deadlock"); } else { - assert_eq!(r, 0); + // According to POSIX, for a properly initialized rwlock this can only + // return EAGAIN or EDEADLK or 0. We rely on that. + debug_assert_eq!(r, 0); self.num_readers.fetch_add(1, Ordering::Relaxed); } } @@ -56,6 +57,7 @@ impl RWLock { let r = libc::pthread_rwlock_tryrdlock(self.inner.get()); if r == 0 { if *self.write_locked.get() { + // `pthread_rwlock_tryrdlock` succeeded when it should not have. self.raw_unlock(); false } else { @@ -69,17 +71,22 @@ impl RWLock { #[inline] pub unsafe fn write(&self) { let r = libc::pthread_rwlock_wrlock(self.inner.get()); - // See comments above for why we check for EDEADLK and write_locked. We - // also need to check that num_readers is 0. + // See comments above for why we check for EDEADLK and write_locked. For the same reason, + // we also need to check that there are no readers (tracked in `num_readers`). if r == libc::EDEADLK - || *self.write_locked.get() + || (r == 0 && *self.write_locked.get()) || self.num_readers.load(Ordering::Relaxed) != 0 { + // Above, we make sure to only access `write_locked` when `r == 0` to avoid + // data races. if r == 0 { + // `pthread_rwlock_wrlock` succeeded when it should not have. self.raw_unlock(); } panic!("rwlock write lock would result in deadlock"); } else { + // According to POSIX, for a properly initialized rwlock this can only + // return EDEADLK or 0. We rely on that. debug_assert_eq!(r, 0); } *self.write_locked.get() = true; @@ -89,6 +96,7 @@ impl RWLock { let r = libc::pthread_rwlock_trywrlock(self.inner.get()); if r == 0 { if *self.write_locked.get() || self.num_readers.load(Ordering::Relaxed) != 0 { + // `pthread_rwlock_trywrlock` succeeded when it should not have. self.raw_unlock(); false } else { diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 9e8be550755..5e103578350 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -33,6 +33,7 @@ impl Drop for Handler { target_os = "dragonfly", target_os = "freebsd", target_os = "solaris", + target_os = "illumos", all(target_os = "netbsd", not(target_vendor = "rumprun")), target_os = "openbsd" ))] @@ -45,8 +46,9 @@ mod imp { use libc::{mmap, munmap}; use libc::{sigaction, sighandler_t, SA_ONSTACK, SA_SIGINFO, SIGBUS, SIG_DFL}; use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE}; - use libc::{MAP_ANON, MAP_PRIVATE, PROT_READ, PROT_WRITE, SIGSEGV}; + use libc::{MAP_ANON, MAP_PRIVATE, PROT_NONE, PROT_READ, PROT_WRITE, SIGSEGV}; + use crate::sys::unix::os::page_size; use crate::sys_common::thread_info; #[cfg(any(target_os = "linux", target_os = "android"))] @@ -137,12 +139,22 @@ mod imp { } unsafe fn get_stackp() -> *mut libc::c_void { - let stackp = - mmap(ptr::null_mut(), SIGSTKSZ, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + let stackp = mmap( + ptr::null_mut(), + SIGSTKSZ + page_size(), + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, + -1, + 0, + ); if stackp == MAP_FAILED { panic!("failed to allocate an alternative stack"); } - stackp + let guard_result = libc::mprotect(stackp, page_size(), PROT_NONE); + if guard_result != 0 { + panic!("failed to set up alternative stack guard page"); + } + stackp.add(page_size()) } #[cfg(any( @@ -151,7 +163,8 @@ mod imp { target_os = "freebsd", target_os = "netbsd", target_os = "openbsd", - target_os = "solaris" + target_os = "solaris", + target_os = "illumos" ))] unsafe fn get_stack() -> libc::stack_t { libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ } @@ -190,7 +203,9 @@ mod imp { ss_size: SIGSTKSZ, }; sigaltstack(&stack, ptr::null_mut()); - munmap(handler._data, SIGSTKSZ); + // We know from `get_stackp` that the alternate stack we installed is part of a mapping + // that started one page earlier, so walk back a page and unmap from there. + munmap(handler._data.sub(page_size()), SIGSTKSZ + page_size()); } } } @@ -201,6 +216,7 @@ mod imp { target_os = "dragonfly", target_os = "freebsd", target_os = "solaris", + target_os = "illumos", all(target_os = "netbsd", not(target_vendor = "rumprun")), target_os = "openbsd" )))] diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index b9c56963885..f8353214cbc 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -20,6 +20,11 @@ impl io::Read for Stdin { fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { ManuallyDrop::new(FileDesc::new(libc::STDIN_FILENO)).read_vectored(bufs) } + + #[inline] + fn is_read_vectored(&self) -> bool { + true + } } impl Stdout { @@ -37,6 +42,11 @@ impl io::Write for Stdout { ManuallyDrop::new(FileDesc::new(libc::STDOUT_FILENO)).write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } @@ -57,6 +67,11 @@ impl io::Write for Stderr { ManuallyDrop::new(FileDesc::new(libc::STDERR_FILENO)).write_vectored(bufs) } + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 674d4c71138..7b3d69dcaa0 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -3,11 +3,9 @@ use crate::ffi::CStr; use crate::io; use crate::mem; use crate::ptr; -use crate::sys::os; +use crate::sys::{os, stack_overflow}; use crate::time::Duration; -use crate::sys_common::thread::*; - #[cfg(not(target_os = "l4re"))] pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024; #[cfg(target_os = "l4re")] @@ -43,7 +41,7 @@ unsafe fn pthread_attr_setstacksize( 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 p; + let p = Box::into_raw(box 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); @@ -65,19 +63,28 @@ impl Thread { } }; - let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _); + let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); + // Note: if the thread creation fails and this assert fails, then p will + // be leaked. However, an alternative design could cause double-free + // which is clearly worse. assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); return if ret != 0 { + // The thread failed to start and as a result p was not consumed. Therefore, it is + // safe to reconstruct the box so that it gets deallocated. + drop(Box::from_raw(p)); Err(io::Error::from_raw_os_error(ret)) } else { - mem::forget(p); // ownership passed to pthread_create Ok(Thread { id: native }) }; extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { unsafe { - start_thread(main as *mut u8); + // Next, set up our stack overflow handler which may get triggered if we run + // out of stack. + let _handler = stack_overflow::Handler::new(); + // Finally, let's run some code. + Box::from_raw(main as *mut Box<dyn FnOnce()>)(); } ptr::null_mut() } @@ -125,7 +132,7 @@ impl Thread { } } - #[cfg(target_os = "solaris")] + #[cfg(any(target_os = "solaris", target_os = "illumos"))] pub fn set_name(name: &CStr) { weak! { fn pthread_setname_np( @@ -148,7 +155,7 @@ impl Thread { target_os = "redox" ))] pub fn set_name(_name: &CStr) { - // Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name. + // Newlib, Haiku, and Emscripten have no way to set a thread name. } #[cfg(target_os = "fuchsia")] pub fn set_name(_name: &CStr) { @@ -164,7 +171,7 @@ impl Thread { unsafe { while secs > 0 || nsecs > 0 { let mut ts = libc::timespec { - tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t, + tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t, tv_nsec: nsecs, }; secs -= ts.tv_sec as u64; diff --git a/src/libstd/sys/vxworks/args.rs b/src/libstd/sys/vxworks/args.rs index efd615f404d..adff6c489bb 100644 --- a/src/libstd/sys/vxworks/args.rs +++ b/src/libstd/sys/vxworks/args.rs @@ -56,7 +56,6 @@ mod imp { use crate::ffi::{CStr, OsString}; use crate::marker::PhantomData; use crate::ptr; - use libc; use crate::sys_common::mutex::Mutex; diff --git a/src/libstd/sys/vxworks/condvar.rs b/src/libstd/sys/vxworks/condvar.rs index f2a1d681529..5a77966d974 100644 --- a/src/libstd/sys/vxworks/condvar.rs +++ b/src/libstd/sys/vxworks/condvar.rs @@ -10,14 +10,10 @@ unsafe impl Send for Condvar {} unsafe impl Sync for Condvar {} const TIMESPEC_MAX: libc::timespec = - libc::timespec { tv_sec: <libc::time_t>::max_value(), tv_nsec: 1_000_000_000 - 1 }; + libc::timespec { tv_sec: <libc::time_t>::MAX, tv_nsec: 1_000_000_000 - 1 }; fn saturating_cast_to_time_t(value: u64) -> libc::time_t { - if value > <libc::time_t>::max_value() as u64 { - <libc::time_t>::max_value() - } else { - value as libc::time_t - } + if value > <libc::time_t>::MAX as u64 { <libc::time_t>::MAX } else { value as libc::time_t } } impl Condvar { diff --git a/src/libstd/sys/vxworks/ext/fs.rs b/src/libstd/sys/vxworks/ext/fs.rs index 9864a855df7..7cc64658ee1 100644 --- a/src/libstd/sys/vxworks/ext/fs.rs +++ b/src/libstd/sys/vxworks/ext/fs.rs @@ -6,7 +6,6 @@ use crate::path::Path; use crate::sys; use crate::sys::platform::fs::MetadataExt as UnixMetadataExt; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; -use libc; /// Unix-specific extensions to [`File`]. /// diff --git a/src/libstd/sys/vxworks/ext/process.rs b/src/libstd/sys/vxworks/ext/process.rs index 31e691dd136..c3710f4b912 100644 --- a/src/libstd/sys/vxworks/ext/process.rs +++ b/src/libstd/sys/vxworks/ext/process.rs @@ -111,7 +111,7 @@ pub trait CommandExt { /// /// Set the first process argument, `argv[0]`, to something other than the /// default executable path. - #[unstable(feature = "process_set_argv0", issue = "66510")] + #[stable(feature = "process_set_argv0", since = "1.45.0")] fn arg0<S>(&mut self, arg: S) -> &mut process::Command where S: AsRef<OsStr>; diff --git a/src/libstd/sys/vxworks/fd.rs b/src/libstd/sys/vxworks/fd.rs index 65c67dabc1a..7fa86f0db04 100644 --- a/src/libstd/sys/vxworks/fd.rs +++ b/src/libstd/sys/vxworks/fd.rs @@ -17,7 +17,7 @@ fn max_len() -> usize { // The maximum read limit on most posix-like systems is `SSIZE_MAX`, // with the man page quoting that if the count of bytes to read is // greater than `SSIZE_MAX` the result is "unspecified". - <ssize_t>::max_value() as usize + <ssize_t>::MAX as usize } impl FileDesc { @@ -48,12 +48,17 @@ impl FileDesc { libc::readv( self.fd, bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::max_value() as usize) as c_int, + cmp::min(bufs.len(), c_int::MAX as usize) as c_int, ) })?; Ok(ret as usize) } + #[inline] + fn is_read_vectored(&self) -> bool { + true + } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { let mut me = self; (&mut me).read_to_end(buf) @@ -93,12 +98,17 @@ impl FileDesc { libc::writev( self.fd, bufs.as_ptr() as *const libc::iovec, - cmp::min(bufs.len(), c_int::max_value() as usize) as c_int, + cmp::min(bufs.len(), c_int::MAX as usize) as c_int, ) })?; Ok(ret as usize) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { unsafe fn cvt_pwrite( fd: c_int, diff --git a/src/libstd/sys/vxworks/fs.rs b/src/libstd/sys/vxworks/fs.rs index 68f2c133170..557e65ca01b 100644 --- a/src/libstd/sys/vxworks/fs.rs +++ b/src/libstd/sys/vxworks/fs.rs @@ -351,6 +351,11 @@ impl File { self.0.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { self.0.read_at(buf, offset) } @@ -363,6 +368,11 @@ impl File { self.0.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { self.0.write_at(buf, offset) } diff --git a/src/libstd/sys/vxworks/mod.rs b/src/libstd/sys/vxworks/mod.rs index e23191c9431..0787e709898 100644 --- a/src/libstd/sys/vxworks/mod.rs +++ b/src/libstd/sys/vxworks/mod.rs @@ -108,6 +108,6 @@ where // understandable error message like "Abort trap" rather than "Illegal // instruction" that intrinsics::abort would cause, as intrinsics::abort is // implemented as an illegal instruction. -pub unsafe fn abort_internal() -> ! { - libc::abort() +pub fn abort_internal() -> ! { + unsafe { libc::abort() } } diff --git a/src/libstd/sys/vxworks/mutex.rs b/src/libstd/sys/vxworks/mutex.rs index b38375a2e03..103d87e3d2f 100644 --- a/src/libstd/sys/vxworks/mutex.rs +++ b/src/libstd/sys/vxworks/mutex.rs @@ -92,11 +92,11 @@ unsafe impl Send for ReentrantMutex {} unsafe impl Sync for ReentrantMutex {} impl ReentrantMutex { - pub unsafe fn uninitialized() -> ReentrantMutex { + pub const unsafe fn uninitialized() -> ReentrantMutex { ReentrantMutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) } } - pub unsafe fn init(&mut self) { + pub unsafe fn init(&self) { let mut attr = MaybeUninit::<libc::pthread_mutexattr_t>::uninit(); let result = libc::pthread_mutexattr_init(attr.as_mut_ptr()); debug_assert_eq!(result, 0); diff --git a/src/libstd/sys/vxworks/net.rs b/src/libstd/sys/vxworks/net.rs index 7d4e5624f7e..32c27ab6e9e 100644 --- a/src/libstd/sys/vxworks/net.rs +++ b/src/libstd/sys/vxworks/net.rs @@ -107,7 +107,7 @@ impl Socket { timeout = 1; } - let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int; + let timeout = cmp::min(timeout, c_int::MAX as u64) as c_int; match unsafe { libc::poll(&mut pollfd, 1, timeout) } { -1 => { @@ -163,6 +163,11 @@ impl Socket { self.0.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + fn recv_from_with_flags( &self, buf: &mut [u8], @@ -200,6 +205,11 @@ impl Socket { self.0.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> { let timeout = match dur { Some(dur) => { @@ -210,8 +220,8 @@ impl Socket { )); } - let secs = if dur.as_secs() > libc::time_t::max_value() as u64 { - libc::time_t::max_value() + let secs = if dur.as_secs() > libc::time_t::MAX as u64 { + libc::time_t::MAX } else { dur.as_secs() as libc::time_t }; diff --git a/src/libstd/sys/vxworks/pipe.rs b/src/libstd/sys/vxworks/pipe.rs index 0990cb8e83c..a18376212af 100644 --- a/src/libstd/sys/vxworks/pipe.rs +++ b/src/libstd/sys/vxworks/pipe.rs @@ -24,10 +24,16 @@ impl AnonPipe { pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { self.0.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.0.is_read_vectored() + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.0.write(buf) } @@ -36,6 +42,11 @@ impl AnonPipe { self.0.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.0.is_write_vectored() + } + pub fn fd(&self) -> &FileDesc { &self.0 } diff --git a/src/libstd/sys/vxworks/process/process_common.rs b/src/libstd/sys/vxworks/process/process_common.rs index 6d5506bec5f..78b6e9a4db7 100644 --- a/src/libstd/sys/vxworks/process/process_common.rs +++ b/src/libstd/sys/vxworks/process/process_common.rs @@ -49,11 +49,13 @@ pub struct Command { stderr: Option<Stdio>, } -// Create a new type for argv, so that we can make it `Send` +// Create a new type for `Argv`, so that we can make it `Send` and `Sync` struct Argv(Vec<*const c_char>); -// It is safe to make Argv Send, because it contains pointers to memory owned by `Command.args` +// It is safe to make `Argv` `Send` and `Sync`, because it contains +// pointers to memory owned by `Command.args` unsafe impl Send for Argv {} +unsafe impl Sync for Argv {} // passed back to std::process with the pipes connected to the child, if any // were requested diff --git a/src/libstd/sys/vxworks/rand.rs b/src/libstd/sys/vxworks/rand.rs index 87ebd2c9593..3a1ff5fd3b9 100644 --- a/src/libstd/sys/vxworks/rand.rs +++ b/src/libstd/sys/vxworks/rand.rs @@ -13,7 +13,6 @@ pub fn hashmap_random_keys() -> (u64, u64) { mod imp { use crate::io; use core::sync::atomic::{AtomicBool, Ordering::Relaxed}; - use libc; pub fn fill_bytes(v: &mut [u8]) { static RNG_INIT: AtomicBool = AtomicBool::new(false); diff --git a/src/libstd/sys/vxworks/rwlock.rs b/src/libstd/sys/vxworks/rwlock.rs index fd2e1a6e7bc..c90304c2b4a 100644 --- a/src/libstd/sys/vxworks/rwlock.rs +++ b/src/libstd/sys/vxworks/rwlock.rs @@ -1,6 +1,5 @@ use crate::cell::UnsafeCell; use crate::sync::atomic::{AtomicUsize, Ordering}; -use libc; pub struct RWLock { inner: UnsafeCell<libc::pthread_rwlock_t>, diff --git a/src/libstd/sys/vxworks/thread.rs b/src/libstd/sys/vxworks/thread.rs index e0d104b5f3e..24a2e0f965d 100644 --- a/src/libstd/sys/vxworks/thread.rs +++ b/src/libstd/sys/vxworks/thread.rs @@ -3,11 +3,9 @@ use crate::ffi::CStr; use crate::io; use crate::mem; use crate::ptr; -use crate::sys::os; +use crate::sys::{os, stack_overflow}; use crate::time::Duration; -use crate::sys_common::thread::*; - pub const DEFAULT_MIN_STACK_SIZE: usize = 0x40000; // 256K pub struct Thread { @@ -31,7 +29,7 @@ unsafe fn pthread_attr_setstacksize( 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 p; + let p = Box::into_raw(box 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); @@ -53,19 +51,28 @@ impl Thread { } }; - let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _); + let ret = libc::pthread_create(&mut native, &attr, thread_start, p as *mut _); + // Note: if the thread creation fails and this assert fails, then p will + // be leaked. However, an alternative design could cause double-free + // which is clearly worse. assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); return if ret != 0 { + // The thread failed to start and as a result p was not consumed. Therefore, it is + // safe to reconstruct the box so that it gets deallocated. + drop(Box::from_raw(p)); Err(io::Error::from_raw_os_error(ret)) } else { - mem::forget(p); // ownership passed to pthread_create Ok(Thread { id: native }) }; extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { unsafe { - start_thread(main as *mut u8); + // Next, set up our stack overflow handler which may get triggered if we run + // out of stack. + let _handler = stack_overflow::Handler::new(); + // Finally, let's run some code. + Box::from_raw(main as *mut Box<dyn FnOnce()>)(); } ptr::null_mut() } @@ -89,7 +96,7 @@ impl Thread { unsafe { while secs > 0 || nsecs > 0 { let mut ts = libc::timespec { - tv_sec: cmp::min(libc::time_t::max_value() as u64, secs) as libc::time_t, + tv_sec: cmp::min(libc::time_t::MAX as u64, secs) as libc::time_t, tv_nsec: nsecs, }; secs -= ts.tv_sec as u64; diff --git a/src/libstd/sys/vxworks/time.rs b/src/libstd/sys/vxworks/time.rs index 8ebbf89213f..8365c9ee9c9 100644 --- a/src/libstd/sys/vxworks/time.rs +++ b/src/libstd/sys/vxworks/time.rs @@ -1,7 +1,6 @@ use crate::cmp::Ordering; use crate::time::Duration; use ::core::hash::{Hash, Hasher}; -use libc; pub use self::inner::{Instant, SystemTime, UNIX_EPOCH}; use crate::convert::TryInto; @@ -104,7 +103,6 @@ mod inner { use crate::fmt; use crate::sys::cvt; use crate::time::Duration; - use libc; use super::Timespec; diff --git a/src/libstd/sys/wasi/alloc.rs b/src/libstd/sys/wasi/alloc.rs index e9760d050e1..57187851a14 100644 --- a/src/libstd/sys/wasi/alloc.rs +++ b/src/libstd/sys/wasi/alloc.rs @@ -1,7 +1,6 @@ use crate::alloc::{GlobalAlloc, Layout, System}; use crate::ptr; use crate::sys_common::alloc::{realloc_fallback, MIN_ALIGN}; -use libc; #[stable(feature = "alloc_system_type", since = "1.28.0")] unsafe impl GlobalAlloc for System { @@ -10,7 +9,7 @@ unsafe impl GlobalAlloc for System { if layout.align() <= MIN_ALIGN && layout.align() <= layout.size() { libc::malloc(layout.size()) as *mut u8 } else { - libc::aligned_alloc(layout.size(), layout.align()) as *mut u8 + libc::aligned_alloc(layout.align(), layout.size()) as *mut u8 } } diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs index a11f61fdd69..793daea43c2 100644 --- a/src/libstd/sys/wasi/fs.rs +++ b/src/libstd/sys/wasi/fs.rs @@ -399,6 +399,11 @@ impl File { self.fd.read(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.write_vectored(&[IoSlice::new(buf)]) } @@ -407,6 +412,11 @@ impl File { self.fd.write(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } diff --git a/src/libstd/sys/wasi/mod.rs b/src/libstd/sys/wasi/mod.rs index 241d499ca3b..4fe9661421b 100644 --- a/src/libstd/sys/wasi/mod.rs +++ b/src/libstd/sys/wasi/mod.rs @@ -64,7 +64,7 @@ pub fn unsupported_err() -> std_io::Error { pub fn decode_error_kind(errno: i32) -> std_io::ErrorKind { use std_io::ErrorKind::*; - if errno > u16::max_value() as i32 || errno < 0 { + if errno > u16::MAX as i32 || errno < 0 { return Other; } match errno as u16 { @@ -100,8 +100,8 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize { return n; } -pub unsafe fn abort_internal() -> ! { - libc::abort() +pub fn abort_internal() -> ! { + unsafe { libc::abort() } } pub fn hashmap_random_keys() -> (u64, u64) { diff --git a/src/libstd/sys/wasi/net.rs b/src/libstd/sys/wasi/net.rs index 8a69028ff1d..e186453588d 100644 --- a/src/libstd/sys/wasi/net.rs +++ b/src/libstd/sys/wasi/net.rs @@ -48,6 +48,10 @@ impl TcpStream { unsupported() } + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn write(&self, _: &[u8]) -> io::Result<usize> { unsupported() } @@ -56,6 +60,10 @@ impl TcpStream { unsupported() } + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn peer_addr(&self) -> io::Result<SocketAddr> { unsupported() } diff --git a/src/libstd/sys/wasi/pipe.rs b/src/libstd/sys/wasi/pipe.rs index fb14dc59101..10d0925823e 100644 --- a/src/libstd/sys/wasi/pipe.rs +++ b/src/libstd/sys/wasi/pipe.rs @@ -12,6 +12,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } @@ -20,6 +24,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/wasi/stdio.rs b/src/libstd/sys/wasi/stdio.rs index 1d53884f2d6..78e3911dc4e 100644 --- a/src/libstd/sys/wasi/stdio.rs +++ b/src/libstd/sys/wasi/stdio.rs @@ -11,16 +11,24 @@ impl Stdin { Ok(Stdin) } - pub fn read(&self, data: &mut [u8]) -> io::Result<usize> { + #[inline] + pub fn as_raw_fd(&self) -> u32 { + 0 + } +} + +impl io::Read for Stdin { + fn read(&mut self, data: &mut [u8]) -> io::Result<usize> { self.read_vectored(&mut [IoSliceMut::new(data)]) } - pub fn read_vectored(&self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> { + fn read_vectored(&mut self, data: &mut [IoSliceMut<'_>]) -> io::Result<usize> { ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).read(data) } - pub fn as_raw_fd(&self) -> u32 { - 0 + #[inline] + fn is_read_vectored(&self) -> bool { + true } } @@ -29,20 +37,27 @@ impl Stdout { Ok(Stdout) } - pub fn write(&self, data: &[u8]) -> io::Result<usize> { + #[inline] + pub fn as_raw_fd(&self) -> u32 { + 1 + } +} + +impl io::Write for Stdout { + fn write(&mut self, data: &[u8]) -> io::Result<usize> { self.write_vectored(&[IoSlice::new(data)]) } - pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> { + fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> { ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data) } - pub fn flush(&self) -> io::Result<()> { - Ok(()) + #[inline] + fn is_write_vectored(&self) -> bool { + true } - - pub fn as_raw_fd(&self) -> u32 { - 1 + fn flush(&mut self) -> io::Result<()> { + Ok(()) } } @@ -51,18 +66,7 @@ impl Stderr { Ok(Stderr) } - pub fn write(&self, data: &[u8]) -> io::Result<usize> { - self.write_vectored(&[IoSlice::new(data)]) - } - - pub fn write_vectored(&self, data: &[IoSlice<'_>]) -> io::Result<usize> { - ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data) - } - - pub fn flush(&self) -> io::Result<()> { - Ok(()) - } - + #[inline] pub fn as_raw_fd(&self) -> u32 { 2 } @@ -70,11 +74,20 @@ impl Stderr { impl io::Write for Stderr { fn write(&mut self, data: &[u8]) -> io::Result<usize> { - (&*self).write(data) + self.write_vectored(&[IoSlice::new(data)]) + } + + fn write_vectored(&mut self, data: &[IoSlice<'_>]) -> io::Result<usize> { + ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true } fn flush(&mut self) -> io::Result<()> { - (&*self).flush() + Ok(()) } } diff --git a/src/libstd/sys/wasi/thread.rs b/src/libstd/sys/wasi/thread.rs index 0986759b89b..0d39b1cec32 100644 --- a/src/libstd/sys/wasi/thread.rs +++ b/src/libstd/sys/wasi/thread.rs @@ -25,7 +25,7 @@ impl Thread { pub fn sleep(dur: Duration) { let nanos = dur.as_nanos(); - assert!(nanos <= u64::max_value() as u128); + assert!(nanos <= u64::MAX as u128); const USERDATA: wasi::Userdata = 0x0123_45678; diff --git a/src/libstd/sys/wasm/condvar_atomics.rs b/src/libstd/sys/wasm/condvar_atomics.rs index a4021c0ee83..1859cdd5a0e 100644 --- a/src/libstd/sys/wasm/condvar_atomics.rs +++ b/src/libstd/sys/wasm/condvar_atomics.rs @@ -48,7 +48,7 @@ impl Condvar { #[inline] pub unsafe fn notify_all(&self) { self.cnt.fetch_add(1, SeqCst); - wasm32::atomic_notify(self.ptr(), u32::max_value()); // -1 == "wake everyone" + wasm32::atomic_notify(self.ptr(), u32::MAX); // -1 == "wake everyone" } pub unsafe fn wait(&self, mutex: &Mutex) { @@ -72,7 +72,7 @@ impl Condvar { let ticket = self.cnt.load(SeqCst) as i32; mutex.unlock(); let nanos = dur.as_nanos(); - let nanos = cmp::min(i64::max_value() as u128, nanos); + let nanos = cmp::min(i64::MAX as u128, nanos); // If the return value is 2 then a timeout happened, so we return // `false` as we weren't actually notified. diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/wasm/fs.rs index e6160d1457d..ecb5b51cccd 100644 --- a/src/libstd/sys/wasm/fs.rs +++ b/src/libstd/sys/wasm/fs.rs @@ -202,6 +202,10 @@ impl File { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } @@ -210,6 +214,10 @@ impl File { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn flush(&self) -> io::Result<()> { match self.0 {} } diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs index c115f756450..050e8099af4 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -81,8 +81,8 @@ pub unsafe fn strlen(mut s: *const c_char) -> usize { return n; } -pub unsafe fn abort_internal() -> ! { - crate::arch::wasm32::unreachable() +pub fn abort_internal() -> ! { + unsafe { crate::arch::wasm32::unreachable() } } // We don't have randomness yet, but I totally used a random number generator to diff --git a/src/libstd/sys/wasm/mutex.rs b/src/libstd/sys/wasm/mutex.rs index 07238d08730..7aaf1b3a343 100644 --- a/src/libstd/sys/wasm/mutex.rs +++ b/src/libstd/sys/wasm/mutex.rs @@ -47,11 +47,11 @@ impl Mutex { pub struct ReentrantMutex {} impl ReentrantMutex { - pub unsafe fn uninitialized() -> ReentrantMutex { + pub const unsafe fn uninitialized() -> ReentrantMutex { ReentrantMutex {} } - pub unsafe fn init(&mut self) {} + pub unsafe fn init(&self) {} pub unsafe fn lock(&self) {} diff --git a/src/libstd/sys/wasm/mutex_atomics.rs b/src/libstd/sys/wasm/mutex_atomics.rs index 90c628a19c2..268a53bb564 100644 --- a/src/libstd/sys/wasm/mutex_atomics.rs +++ b/src/libstd/sys/wasm/mutex_atomics.rs @@ -80,11 +80,11 @@ unsafe impl Sync for ReentrantMutex {} // released when this recursion counter reaches 0. impl ReentrantMutex { - pub unsafe fn uninitialized() -> ReentrantMutex { + pub const unsafe fn uninitialized() -> ReentrantMutex { ReentrantMutex { owner: AtomicU32::new(0), recursions: UnsafeCell::new(0) } } - pub unsafe fn init(&mut self) { + pub unsafe fn init(&self) { // nothing to do... } diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/wasm/net.rs index b7c3108f172..5c9f1098f9b 100644 --- a/src/libstd/sys/wasm/net.rs +++ b/src/libstd/sys/wasm/net.rs @@ -44,6 +44,10 @@ impl TcpStream { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _: &[u8]) -> io::Result<usize> { match self.0 {} } @@ -52,6 +56,10 @@ impl TcpStream { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn peer_addr(&self) -> io::Result<SocketAddr> { match self.0 {} } diff --git a/src/libstd/sys/wasm/pipe.rs b/src/libstd/sys/wasm/pipe.rs index fb14dc59101..10d0925823e 100644 --- a/src/libstd/sys/wasm/pipe.rs +++ b/src/libstd/sys/wasm/pipe.rs @@ -12,6 +12,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_read_vectored(&self) -> bool { + match self.0 {} + } + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { match self.0 {} } @@ -20,6 +24,10 @@ impl AnonPipe { match self.0 {} } + pub fn is_write_vectored(&self) -> bool { + match self.0 {} + } + pub fn diverge(&self) -> ! { match self.0 {} } diff --git a/src/libstd/sys/wasm/stack_overflow.rs b/src/libstd/sys/wasm/stack_overflow.rs index cbf62b6e5b7..32555394cd5 100644 --- a/src/libstd/sys/wasm/stack_overflow.rs +++ b/src/libstd/sys/wasm/stack_overflow.rs @@ -1,11 +1,3 @@ -pub struct Handler; - -impl Handler { - pub unsafe fn new() -> Handler { - Handler - } -} - pub unsafe fn init() {} pub unsafe fn cleanup() {} diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs index 0e0e78a8276..0a11896a004 100644 --- a/src/libstd/sys/wasm/thread.rs +++ b/src/libstd/sys/wasm/thread.rs @@ -38,7 +38,7 @@ impl Thread { // 2). let mut nanos = dur.as_nanos(); while nanos > 0 { - let amt = cmp::min(i64::max_value() as u128, nanos); + let amt = cmp::min(i64::MAX as u128, nanos); let mut x = 0; let val = unsafe { wasm32::i32_atomic_wait(&mut x, 0, amt as i64) }; debug_assert_eq!(val, 2); diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 7f93ef87953..f440442ca30 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -161,6 +161,8 @@ pub const STD_ERROR_HANDLE: DWORD = -12i32 as DWORD; pub const PROGRESS_CONTINUE: DWORD = 0; +// List of Windows system error codes with descriptions: +// https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes#system-error-codes pub const ERROR_FILE_NOT_FOUND: DWORD = 2; pub const ERROR_PATH_NOT_FOUND: DWORD = 3; pub const ERROR_ACCESS_DENIED: DWORD = 5; @@ -171,13 +173,26 @@ pub const ERROR_FILE_EXISTS: DWORD = 80; pub const ERROR_INVALID_PARAMETER: DWORD = 87; pub const ERROR_BROKEN_PIPE: DWORD = 109; pub const ERROR_CALL_NOT_IMPLEMENTED: DWORD = 120; +pub const ERROR_SEM_TIMEOUT: DWORD = 121; pub const ERROR_INSUFFICIENT_BUFFER: DWORD = 122; pub const ERROR_ALREADY_EXISTS: DWORD = 183; -pub const ERROR_NO_DATA: DWORD = 232; pub const ERROR_ENVVAR_NOT_FOUND: DWORD = 203; +pub const ERROR_NO_DATA: DWORD = 232; +pub const ERROR_DRIVER_CANCEL_TIMEOUT: DWORD = 594; pub const ERROR_OPERATION_ABORTED: DWORD = 995; pub const ERROR_IO_PENDING: DWORD = 997; -pub const ERROR_TIMEOUT: DWORD = 0x5B4; +pub const ERROR_SERVICE_REQUEST_TIMEOUT: DWORD = 1053; +pub const ERROR_COUNTER_TIMEOUT: DWORD = 1121; +pub const ERROR_TIMEOUT: DWORD = 1460; +pub const ERROR_RESOURCE_CALL_TIMED_OUT: DWORD = 5910; +pub const ERROR_CTX_MODEM_RESPONSE_TIMEOUT: DWORD = 7012; +pub const ERROR_CTX_CLIENT_QUERY_TIMEOUT: DWORD = 7040; +pub const FRS_ERR_SYSVOL_POPULATE_TIMEOUT: DWORD = 8014; +pub const ERROR_DS_TIMELIMIT_EXCEEDED: DWORD = 8226; +pub const DNS_ERROR_RECORD_TIMED_OUT: DWORD = 9705; +pub const ERROR_IPSEC_IKE_TIMED_OUT: DWORD = 13805; +pub const ERROR_RUNLEVEL_SWITCH_TIMEOUT: DWORD = 15402; +pub const ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT: DWORD = 15403; pub const E_NOTIMPL: HRESULT = 0x80004001u32 as HRESULT; @@ -216,7 +231,6 @@ pub const SOCK_STREAM: c_int = 1; pub const SOL_SOCKET: c_int = 0xffff; pub const SO_RCVTIMEO: c_int = 0x1006; pub const SO_SNDTIMEO: c_int = 0x1005; -pub const SO_REUSEADDR: c_int = 0x0004; pub const IPPROTO_IP: c_int = 0; pub const IPPROTO_TCP: c_int = 6; pub const IPPROTO_IPV6: c_int = 41; @@ -778,7 +792,7 @@ extern "system" { pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int; pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); - pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOLEAN; + pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL; pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION); pub fn DeleteCriticalSection(CriticalSection: *mut CRITICAL_SECTION); diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index d508a333484..f85120d170f 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -224,7 +224,7 @@ pub trait OpenOptionsExt { /// opening a named pipe, to control to which degree a server process can /// act on behalf of a client process (security impersonation level). /// - /// When `security_qos_flags` is not set a malicious program can gain the + /// When `security_qos_flags` is not set, a malicious program can gain the /// elevated privileges of a privileged Rust process when it allows opening /// user-specified paths, by tricking it into opening a named pipe. So /// arguably `security_qos_flags` should also be set when opening arbitrary diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index 427f4b684e1..cdbfac267b9 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -409,6 +409,11 @@ impl File { self.handle.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.handle.is_read_vectored() + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { self.handle.read_at(buf, offset) } @@ -421,6 +426,11 @@ impl File { self.handle.write_vectored(bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.handle.is_write_vectored() + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { self.handle.write_at(buf, offset) } diff --git a/src/libstd/sys/windows/handle.rs b/src/libstd/sys/windows/handle.rs index f2ad057b6b6..0d4baa3b340 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -70,7 +70,7 @@ impl RawHandle { pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { let mut read = 0; - let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; let res = cvt(unsafe { c::ReadFile(self.0, buf.as_mut_ptr() as c::LPVOID, len, &mut read, ptr::null_mut()) }); @@ -92,9 +92,14 @@ impl RawHandle { crate::io::default_read_vectored(|buf| self.read(buf), bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + false + } + pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> { let mut read = 0; - let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; let res = unsafe { let mut overlapped: c::OVERLAPPED = mem::zeroed(); overlapped.Offset = offset as u32; @@ -113,10 +118,9 @@ impl RawHandle { buf: &mut [u8], overlapped: *mut c::OVERLAPPED, ) -> io::Result<Option<usize>> { - let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; let mut amt = 0; - let res = - cvt({ c::ReadFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, overlapped) }); + let res = cvt(c::ReadFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, overlapped)); match res { Ok(_) => Ok(Some(amt as usize)), Err(e) => { @@ -139,7 +143,7 @@ impl RawHandle { unsafe { let mut bytes = 0; let wait = if wait { c::TRUE } else { c::FALSE }; - let res = cvt({ c::GetOverlappedResult(self.raw(), overlapped, &mut bytes, wait) }); + let res = cvt(c::GetOverlappedResult(self.raw(), overlapped, &mut bytes, wait)); match res { Ok(_) => Ok(bytes as usize), Err(e) => { @@ -161,7 +165,7 @@ impl RawHandle { pub fn write(&self, buf: &[u8]) -> io::Result<usize> { let mut amt = 0; - let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; cvt(unsafe { c::WriteFile(self.0, buf.as_ptr() as c::LPVOID, len, &mut amt, ptr::null_mut()) })?; @@ -172,9 +176,14 @@ impl RawHandle { crate::io::default_write_vectored(|buf| self.write(buf), bufs) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + false + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { let mut written = 0; - let len = cmp::min(buf.len(), <c::DWORD>::max_value() as usize) as c::DWORD; + let len = cmp::min(buf.len(), <c::DWORD>::MAX as usize) as c::DWORD; unsafe { let mut overlapped: c::OVERLAPPED = mem::zeroed(); overlapped.Offset = offset as u32; diff --git a/src/libstd/sys/windows/io.rs b/src/libstd/sys/windows/io.rs index 5525d283252..fb06df1f80c 100644 --- a/src/libstd/sys/windows/io.rs +++ b/src/libstd/sys/windows/io.rs @@ -12,7 +12,7 @@ pub struct IoSlice<'a> { impl<'a> IoSlice<'a> { #[inline] pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - assert!(buf.len() <= c::ULONG::max_value() as usize); + assert!(buf.len() <= c::ULONG::MAX as usize); IoSlice { vec: c::WSABUF { len: buf.len() as c::ULONG, @@ -49,7 +49,7 @@ pub struct IoSliceMut<'a> { impl<'a> IoSliceMut<'a> { #[inline] pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - assert!(buf.len() <= c::ULONG::max_value() as usize); + assert!(buf.len() <= c::ULONG::MAX as usize); IoSliceMut { vec: c::WSABUF { len: buf.len() as c::ULONG, buf: buf.as_mut_ptr() as *mut c::CHAR }, _p: PhantomData, diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index b004cd19020..640c9f3636d 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -61,7 +61,22 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { c::ERROR_FILE_NOT_FOUND => return ErrorKind::NotFound, c::ERROR_PATH_NOT_FOUND => return ErrorKind::NotFound, c::ERROR_NO_DATA => return ErrorKind::BrokenPipe, - c::ERROR_OPERATION_ABORTED => return ErrorKind::TimedOut, + c::ERROR_SEM_TIMEOUT + | c::WAIT_TIMEOUT + | c::ERROR_DRIVER_CANCEL_TIMEOUT + | c::ERROR_OPERATION_ABORTED + | c::ERROR_SERVICE_REQUEST_TIMEOUT + | c::ERROR_COUNTER_TIMEOUT + | c::ERROR_TIMEOUT + | c::ERROR_RESOURCE_CALL_TIMED_OUT + | c::ERROR_CTX_MODEM_RESPONSE_TIMEOUT + | c::ERROR_CTX_CLIENT_QUERY_TIMEOUT + | c::FRS_ERR_SYSVOL_POPULATE_TIMEOUT + | c::ERROR_DS_TIMELIMIT_EXCEEDED + | c::DNS_ERROR_RECORD_TIMED_OUT + | c::ERROR_IPSEC_IKE_TIMED_OUT + | c::ERROR_RUNLEVEL_SWITCH_TIMEOUT + | c::ERROR_RUNLEVEL_SWITCH_AGENT_TIMEOUT => return ErrorKind::TimedOut, _ => {} } @@ -81,10 +96,54 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { } } +pub fn unrolled_find_u16s(needle: u16, haystack: &[u16]) -> Option<usize> { + let ptr = haystack.as_ptr(); + let mut len = haystack.len(); + let mut start = &haystack[..]; + + // For performance reasons unfold the loop eight times. + while len >= 8 { + if start[0] == needle { + return Some((start.as_ptr() as usize - ptr as usize) / 2); + } + if start[1] == needle { + return Some((start[1..].as_ptr() as usize - ptr as usize) / 2); + } + if start[2] == needle { + return Some((start[2..].as_ptr() as usize - ptr as usize) / 2); + } + if start[3] == needle { + return Some((start[3..].as_ptr() as usize - ptr as usize) / 2); + } + if start[4] == needle { + return Some((start[4..].as_ptr() as usize - ptr as usize) / 2); + } + if start[5] == needle { + return Some((start[5..].as_ptr() as usize - ptr as usize) / 2); + } + if start[6] == needle { + return Some((start[6..].as_ptr() as usize - ptr as usize) / 2); + } + if start[7] == needle { + return Some((start[7..].as_ptr() as usize - ptr as usize) / 2); + } + + start = &start[8..]; + len -= 8; + } + + for (i, c) in start.iter().enumerate() { + if *c == needle { + return Some((start.as_ptr() as usize - ptr as usize) / 2 + i); + } + } + None +} + pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> crate::io::Result<Vec<u16>> { fn inner(s: &OsStr) -> crate::io::Result<Vec<u16>> { let mut maybe_result: Vec<u16> = s.encode_wide().collect(); - if maybe_result.iter().any(|&u| u == 0) { + if unrolled_find_u16s(0, &maybe_result).is_some() { return Err(crate::io::Error::new( ErrorKind::InvalidInput, "strings passed to WinAPI cannot contain NULs", @@ -214,7 +273,7 @@ fn wide_char_to_multi_byte( } pub fn truncate_utf16_at_nul(v: &[u16]) -> &[u16] { - match v.iter().position(|c| *c == 0) { + match unrolled_find_u16s(0, v) { // don't include the 0 Some(i) => &v[..i], None => v, @@ -251,7 +310,7 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { .checked_mul(1000) .and_then(|ms| ms.checked_add((dur.subsec_nanos() as u64) / 1_000_000)) .and_then(|ms| ms.checked_add(if dur.subsec_nanos() % 1_000_000 > 0 { 1 } else { 0 })) - .map(|ms| if ms > <c::DWORD>::max_value() as u64 { c::INFINITE } else { ms as c::DWORD }) + .map(|ms| if ms > <c::DWORD>::MAX as u64 { c::INFINITE } else { ms as c::DWORD }) .unwrap_or(c::INFINITE) } @@ -264,10 +323,10 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { // // https://docs.microsoft.com/en-us/cpp/intrinsics/fastfail #[allow(unreachable_code)] -pub unsafe fn abort_internal() -> ! { +pub fn abort_internal() -> ! { #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] - { - asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT + unsafe { + llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT crate::intrinsics::unreachable(); } crate::intrinsics::abort(); diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 281eb294c65..63dfc640908 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -109,7 +109,7 @@ impl Mutex { 0 => {} n => return n as *mut _, } - let mut re = box ReentrantMutex::uninitialized(); + let re = box ReentrantMutex::uninitialized(); re.init(); let re = Box::into_raw(re); match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) { @@ -157,11 +157,11 @@ unsafe impl Send for ReentrantMutex {} unsafe impl Sync for ReentrantMutex {} impl ReentrantMutex { - pub fn uninitialized() -> ReentrantMutex { + pub const fn uninitialized() -> ReentrantMutex { ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninit()) } } - pub unsafe fn init(&mut self) { + pub unsafe fn init(&self) { c::InitializeCriticalSection((&mut *self.inner.get()).as_mut_ptr()); } diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index d8d4fdfce2f..9e74454bc23 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -228,7 +228,7 @@ impl Socket { fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> { // 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 len = cmp::min(buf.len(), i32::max_value() as usize) as i32; + let len = cmp::min(buf.len(), i32::MAX as usize) as i32; unsafe { match c::recv(self.0, buf.as_mut_ptr() as *mut c_void, len, flags) { -1 if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0), @@ -245,7 +245,7 @@ impl Socket { pub fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> { // 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 len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD; + let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; let mut nread = 0; let mut flags = 0; unsafe { @@ -266,6 +266,11 @@ impl Socket { } } + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { self.recv_with_flags(buf, c::MSG_PEEK) } @@ -277,7 +282,7 @@ impl Socket { ) -> io::Result<(usize, SocketAddr)> { let mut storage: c::SOCKADDR_STORAGE_LH = unsafe { mem::zeroed() }; let mut addrlen = mem::size_of_val(&storage) as c::socklen_t; - let len = cmp::min(buf.len(), <wrlen_t>::max_value() as usize) as wrlen_t; + let len = cmp::min(buf.len(), <wrlen_t>::MAX as usize) as wrlen_t; // 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. @@ -308,7 +313,7 @@ impl Socket { } pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { - let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD; + let len = cmp::min(bufs.len(), c::DWORD::MAX as usize) as c::DWORD; let mut nwritten = 0; unsafe { cvt(c::WSASend( @@ -324,6 +329,11 @@ impl Socket { Ok(nwritten as usize) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> { let timeout = match dur { Some(dur) => { diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index cc4ae405906..a0da2498bb7 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -94,7 +94,7 @@ impl Iterator for Env { if *self.cur == 0 { return None; } - let p = &*self.cur as *const u16; + let p = self.cur as *const u16; let mut len = 0; while *p.offset(len) != 0 { len += 1; diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index ef260f9c5d2..2f5fc72ab44 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -77,9 +77,21 @@ impl Buf { } pub fn as_slice(&self) -> &Slice { + // Safety: Slice is just a wrapper for Wtf8, + // and self.inner.as_slice() returns &Wtf8. + // Therefore, transmuting &Wtf8 to &Slice is safe. unsafe { mem::transmute(self.inner.as_slice()) } } + pub fn as_mut_slice(&mut self) -> &mut Slice { + // Safety: Slice is just a wrapper for Wtf8, + // and self.inner.as_mut_slice() returns &mut Wtf8. + // Therefore, transmuting &mut Wtf8 to &mut Slice is safe. + // Additionally, care should be taken to ensure the slice + // is always valid Wtf8. + unsafe { mem::transmute(self.inner.as_mut_slice()) } + } + pub fn into_string(self) -> Result<String, Buf> { self.inner.into_string().map_err(|buf| Buf { inner: buf }) } @@ -147,6 +159,10 @@ impl Slice { Buf { inner: buf } } + pub fn clone_into(&self, buf: &mut Buf) { + self.inner.clone_into(&mut buf.inner) + } + #[inline] pub fn into_box(&self) -> Box<Slice> { unsafe { mem::transmute(self.inner.into_box()) } @@ -167,4 +183,34 @@ impl Slice { let rc = self.inner.into_rc(); unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } } + + #[inline] + pub fn make_ascii_lowercase(&mut self) { + self.inner.make_ascii_lowercase() + } + + #[inline] + pub fn make_ascii_uppercase(&mut self) { + self.inner.make_ascii_uppercase() + } + + #[inline] + pub fn to_ascii_lowercase(&self) -> Buf { + Buf { inner: self.inner.to_ascii_lowercase() } + } + + #[inline] + pub fn to_ascii_uppercase(&self) -> Buf { + Buf { inner: self.inner.to_ascii_uppercase() } + } + + #[inline] + pub fn is_ascii(&self) -> bool { + self.inner.is_ascii() + } + + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &Self) -> bool { + self.inner.eq_ignore_ascii_case(&other.inner) + } } diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index 992e634dea5..104a8db4659 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -182,6 +182,11 @@ impl AnonPipe { self.inner.read_vectored(bufs) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + self.inner.is_read_vectored() + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.inner.write(buf) } @@ -189,6 +194,11 @@ impl AnonPipe { pub fn write_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> { self.inner.write_vectored(bufs) } + + #[inline] + pub fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } } pub fn read2(p1: AnonPipe, v1: &mut Vec<u8>, p2: AnonPipe, v2: &mut Vec<u8>) -> io::Result<()> { diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index a62a637393e..77f9a5c9dc7 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -20,7 +20,7 @@ use crate::sys::mutex::Mutex; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::stdio; use crate::sys_common::process::CommandEnv; -use crate::sys_common::{AsInner, FromInner, IntoInner}; +use crate::sys_common::AsInner; use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS}; @@ -33,10 +33,9 @@ use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS}; pub struct EnvKey(OsString); impl From<OsString> for EnvKey { - fn from(k: OsString) -> Self { - let mut buf = k.into_inner().into_inner(); - buf.make_ascii_uppercase(); - EnvKey(FromInner::from_inner(FromInner::from_inner(buf))) + fn from(mut k: OsString) -> Self { + k.make_ascii_uppercase(); + EnvKey(k) } } diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index c828243a59b..38839ea5e90 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -1,10 +1,9 @@ use crate::ffi::CStr; use crate::io; -use crate::mem; use crate::ptr; use crate::sys::c; use crate::sys::handle::Handle; -use crate::sys_common::thread::*; +use crate::sys::stack_overflow; use crate::time::Duration; use libc::c_void; @@ -20,7 +19,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 p; + let p = Box::into_raw(box p); // FIXME On UNIX, we guard against stack sizes that are too small but // that's because pthreads enforces that stacks are at least @@ -34,21 +33,27 @@ impl Thread { ptr::null_mut(), stack_size, thread_start, - &*p as *const _ as *mut _, + p as *mut _, c::STACK_SIZE_PARAM_IS_A_RESERVATION, ptr::null_mut(), ); return if ret as usize == 0 { + // The thread failed to start and as a result p was not consumed. Therefore, it is + // safe to reconstruct the box so that it gets deallocated. + drop(Box::from_raw(p)); Err(io::Error::last_os_error()) } else { - mem::forget(p); // ownership passed to CreateThread Ok(Thread { handle: Handle::new(ret) }) }; extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { unsafe { - start_thread(main as *mut u8); + // Next, set up our stack overflow handler which may get triggered if we run + // out of stack. + let _handler = stack_overflow::Handler::new(); + // Finally, let's run some code. + Box::from_raw(main as *mut Box<dyn FnOnce()>)(); } 0 } |
