diff options
Diffstat (limited to 'src/libstd/sys')
86 files changed, 1002 insertions, 332 deletions
diff --git a/src/libstd/sys/cloudabi/io.rs b/src/libstd/sys/cloudabi/io.rs index 976e122463d..d5f475b4310 100644 --- a/src/libstd/sys/cloudabi/io.rs +++ b/src/libstd/sys/cloudabi/io.rs @@ -1,5 +1,6 @@ use crate::mem; +#[derive(Copy, Clone)] pub struct IoSlice<'a>(&'a [u8]); impl<'a> IoSlice<'a> { 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/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/io.rs b/src/libstd/sys/hermit/io.rs index 976e122463d..d5f475b4310 100644 --- a/src/libstd/sys/hermit/io.rs +++ b/src/libstd/sys/hermit/io.rs @@ -1,5 +1,6 @@ use crate::mem; +#[derive(Copy, Clone)] pub struct IoSlice<'a>(&'a [u8]); impl<'a> IoSlice<'a> { diff --git a/src/libstd/sys/hermit/mod.rs b/src/libstd/sys/hermit/mod.rs index 1e4a53abdc7..f739df88ea6 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; @@ -93,9 +94,7 @@ pub unsafe extern "C" fn __rust_abort() { #[cfg(not(test))] pub fn init() { - unsafe { - let _ = net::init(); - } + let _ = net::init(); } #[cfg(not(test))] @@ -105,6 +104,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 +114,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..5b5379c8b05 100644 --- a/src/libstd/sys/hermit/net.rs +++ b/src/libstd/sys/hermit/net.rs @@ -1,291 +1,372 @@ use crate::convert::TryFrom; use crate::fmt; -use crate::io::{self, IoSlice, IoSliceMut}; +use crate::io::{self, ErrorKind, IoSlice, IoSliceMut}; use crate::net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use crate::str; +use crate::sys::hermit::abi; use crate::sys::{unsupported, Void}; 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); +pub struct TcpStream(abi::Handle); 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(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(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, 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, 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) + .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) + .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, 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 mut pos: usize = 0; + + while pos < i.len() { + let ret = abi::tcpstream::read(self.0, &mut i[pos..]) + .map_err(|_| io::Error::new(ErrorKind::Other, "Unable to read on socket"))?; + + if ret == 0 { + return Ok(size); + } else { + size += ret; + pos += 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, 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 {} + Err(io::Error::new(ErrorKind::Other, "peer_addr isn't supported")) } 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, how as i32) + .map_err(|_| io::Error::new(ErrorKind::Other, "unable to shutdown socket")) } pub fn duplicate(&self) -> io::Result<TcpStream> { - match self.0 {} + let handle = abi::tcpstream::duplicate(self.0) + .map_err(|_| io::Error::new(ErrorKind::Other, "unable to duplicate stream"))?; + + Ok(TcpStream(handle)) } - 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, 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) + .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, 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) + .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, mode) + .map_err(|_| io::Error::new(ErrorKind::Other, "unable to set blocking mode")) + } +} + +impl Drop for TcpStream { + fn drop(&mut self) { + let _ = abi::tcpstream::close(self.0); } } impl fmt::Debug for TcpStream { fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} + Ok(()) } } -pub struct TcpListener(Void); +pub struct TcpListener(abi::Handle); impl TcpListener { pub fn bind(_: io::Result<&SocketAddr>) -> io::Result<TcpListener> { - unsupported() + 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 accept(&self) -> io::Result<(TcpStream, SocketAddr)> { - match self.0 {} + Err(io::Error::new(ErrorKind::Other, "not supported")) } pub fn duplicate(&self) -> io::Result<TcpListener> { - 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 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..208265de465 100644 --- a/src/libstd/sys/hermit/stdio.rs +++ b/src/libstd/sys/hermit/stdio.rs @@ -20,6 +20,11 @@ impl Stdin { // .read(data) Ok(0) } + + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } } impl Stdout { @@ -51,6 +56,11 @@ impl Stdout { } } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } @@ -85,6 +95,11 @@ impl Stderr { } } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn flush(&self) -> io::Result<()> { 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/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/usercalls/alloc.rs b/src/libstd/sys/sgx/abi/usercalls/alloc.rs index b54c115a2b6..76a9b427b39 100644 --- a/src/libstd/sys/sgx/abi/usercalls/alloc.rs +++ b/src/libstd/sys/sgx/abi/usercalls/alloc.rs @@ -151,7 +151,7 @@ unsafe impl<T: UserSafeSized> UserSafe for [T] { /// It is also possible to obtain a mutable reference `&mut UserRef<T>`. Unlike /// regular mutable references, these are not exclusive. Userspace may always /// write to the backing memory at any time, so it can't be assumed that there -/// the pointed-to memory is uniquely borrowed. The two different refence types +/// the pointed-to memory is uniquely borrowed. The two different reference types /// are used solely to indicate intent: a mutable reference is for writing to /// user memory, an immutable reference for reading from user memory. #[unstable(feature = "sgx_platform", issue = "56975")] 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/io.rs b/src/libstd/sys/sgx/io.rs index 976e122463d..d5f475b4310 100644 --- a/src/libstd/sys/sgx/io.rs +++ b/src/libstd/sys/sgx/io.rs @@ -1,5 +1,6 @@ use crate::mem; +#[derive(Copy, Clone)] pub struct IoSlice<'a>(&'a [u8]); impl<'a> IoSlice<'a> { 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/args.rs b/src/libstd/sys/unix/args.rs index 09acc3f6e3e..4c3e8542d57 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", 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/net.rs b/src/libstd/sys/unix/ext/net.rs index 4c3cb67c9ee..32c2ac43129 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -7,6 +7,7 @@ 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 +615,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 +636,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 +656,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 +676,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(()) } 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..1ef7ffacfcf 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -64,6 +64,11 @@ impl FileDesc { 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) @@ -116,6 +121,11 @@ impl FileDesc { 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 +163,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 +180,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..80cf6a5dbc2 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) } diff --git a/src/libstd/sys/unix/io.rs b/src/libstd/sys/unix/io.rs index b4a64e93c84..deb5ee76bd0 100644 --- a/src/libstd/sys/unix/io.rs +++ b/src/libstd/sys/unix/io.rs @@ -3,6 +3,7 @@ use crate::slice; use libc::{c_void, iovec}; +#[derive(Copy, Clone)] #[repr(transparent)] pub struct IoSlice<'a> { vec: iovec, 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 06876cb0614..0154609d939 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"))] @@ -156,7 +158,7 @@ where // On Unix-like platforms, libc::abort will unregister signal handlers // including the SIGABRT handler, preventing the abort from being blocked, and -// fclose streams, with the side effect of flushing them so libc bufferred +// fclose streams, with the side effect of flushing them so libc buffered // output will be printed. Additionally the shell will generally print a more // understandable error message like "Abort trap" rather than "Illegal // instruction" that intrinsics::abort would cause, as intrinsics::abort is 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 79b0dc02978..f062bc012f7 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -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) => { @@ -280,7 +290,7 @@ impl Socket { }; let mut timeout = libc::timeval { tv_sec: secs, - tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t, + tv_usec: dur.subsec_micros() as libc::suseconds_t, }; if timeout.tv_sec == 0 && timeout.tv_usec == 0 { timeout.tv_usec = 1; @@ -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 e66d6fdc56a..859da691ad2 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -19,9 +19,9 @@ cfg_if::cfg_if! { if #[cfg(target_os = "fuchsia")] { // fuchsia doesn't have /dev/null } else if #[cfg(target_os = "redox")] { - const DEV_NULL: &'static str = "null:\0"; + const DEV_NULL: &str = "null:\0"; } else { - const DEV_NULL: &'static str = "/dev/null\0"; + const DEV_NULL: &str = "/dev/null\0"; } } @@ -287,9 +287,7 @@ impl CStringArray { fn construct_envp(env: BTreeMap<OsString, OsString>, saw_nul: &mut bool) -> CStringArray { let mut result = CStringArray::with_capacity(env.len()); - for (k, v) in env { - let mut k: OsString = k.into(); - + for (mut k, v) in env { // Reserve additional space for '=' and null terminator k.reserve_exact(v.len() + 2); k.push("="); 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 528fe321efb..5e103578350 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -13,6 +13,10 @@ impl Handler { pub unsafe fn new() -> Handler { make_handler() } + + fn null() -> Handler { + Handler { _data: crate::ptr::null_mut() } + } } impl Drop for Handler { @@ -29,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" ))] @@ -41,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"))] @@ -108,13 +114,20 @@ mod imp { } static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut(); + static mut NEED_ALTSTACK: bool = false; pub unsafe fn init() { let mut action: sigaction = mem::zeroed(); - action.sa_flags = SA_SIGINFO | SA_ONSTACK; - action.sa_sigaction = signal_handler as sighandler_t; - sigaction(SIGSEGV, &action, ptr::null_mut()); - sigaction(SIGBUS, &action, ptr::null_mut()); + for &signal in &[SIGSEGV, SIGBUS] { + sigaction(signal, ptr::null_mut(), &mut action); + // Configure our signal handler if one is not already set. + if action.sa_sigaction == SIG_DFL { + action.sa_flags = SA_SIGINFO | SA_ONSTACK; + action.sa_sigaction = signal_handler as sighandler_t; + sigaction(signal, &action, ptr::null_mut()); + NEED_ALTSTACK = true; + } + } let handler = make_handler(); MAIN_ALTSTACK = handler._data; @@ -126,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( @@ -140,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 } @@ -152,6 +176,9 @@ mod imp { } pub unsafe fn make_handler() -> Handler { + if !NEED_ALTSTACK { + return Handler::null(); + } let mut stack = mem::zeroed(); sigaltstack(ptr::null(), &mut stack); // Configure alternate signal stack, if one is not already set. @@ -160,7 +187,7 @@ mod imp { sigaltstack(&stack, ptr::null_mut()); Handler { _data: stack.ss_sp as *mut libc::c_void } } else { - Handler { _data: ptr::null_mut() } + Handler::null() } } @@ -176,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()); } } } @@ -187,18 +216,17 @@ 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" )))] mod imp { - use crate::ptr; - pub unsafe fn init() {} pub unsafe fn cleanup() {} pub unsafe fn make_handler() -> super::Handler { - super::Handler { _data: ptr::null_mut() } + super::Handler::null() } pub unsafe fn drop_handler(_handler: &mut super::Handler) {} 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..895ea48e2b4 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) { diff --git a/src/libstd/sys/vxworks/fd.rs b/src/libstd/sys/vxworks/fd.rs index 65c67dabc1a..23e9dc428ce 100644 --- a/src/libstd/sys/vxworks/fd.rs +++ b/src/libstd/sys/vxworks/fd.rs @@ -54,6 +54,11 @@ impl FileDesc { 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) @@ -99,6 +104,11 @@ impl FileDesc { 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/io.rs b/src/libstd/sys/vxworks/io.rs index f1a2c8446ff..0f68ebf8da9 100644 --- a/src/libstd/sys/vxworks/io.rs +++ b/src/libstd/sys/vxworks/io.rs @@ -3,6 +3,7 @@ use crate::slice; use libc::{c_void, iovec}; +#[derive(Copy, Clone)] #[repr(transparent)] pub struct IoSlice<'a> { vec: iovec, diff --git a/src/libstd/sys/vxworks/mod.rs b/src/libstd/sys/vxworks/mod.rs index 12bbfa1d4e1..e23191c9431 100644 --- a/src/libstd/sys/vxworks/mod.rs +++ b/src/libstd/sys/vxworks/mod.rs @@ -103,7 +103,7 @@ where // On Unix-like platforms, libc::abort will unregister signal handlers // including the SIGABRT handler, preventing the abort from being blocked, and -// fclose streams, with the side effect of flushing them so libc bufferred +// fclose streams, with the side effect of flushing them so libc buffered // output will be printed. Additionally the shell will generally print a more // understandable error message like "Abort trap" rather than "Illegal // instruction" that intrinsics::abort would cause, as intrinsics::abort is 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..de0b15b43a2 100644 --- a/src/libstd/sys/vxworks/net.rs +++ b/src/libstd/sys/vxworks/net.rs @@ -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) => { 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/thread.rs b/src/libstd/sys/vxworks/thread.rs index e0d104b5f3e..4d0196e4b4d 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() } diff --git a/src/libstd/sys/wasi/alloc.rs b/src/libstd/sys/wasi/alloc.rs index e9760d050e1..bc614162784 100644 --- a/src/libstd/sys/wasi/alloc.rs +++ b/src/libstd/sys/wasi/alloc.rs @@ -10,7 +10,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/io.rs b/src/libstd/sys/wasi/io.rs index ee20ea6dab8..0ad2e152855 100644 --- a/src/libstd/sys/wasi/io.rs +++ b/src/libstd/sys/wasi/io.rs @@ -1,6 +1,7 @@ use crate::marker::PhantomData; use crate::slice; +#[derive(Copy, Clone)] #[repr(transparent)] pub struct IoSlice<'a> { vec: wasi::Ciovec, 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..9f9e35566ec 100644 --- a/src/libstd/sys/wasi/stdio.rs +++ b/src/libstd/sys/wasi/stdio.rs @@ -19,6 +19,11 @@ impl Stdin { ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).read(data) } + #[inline] + pub fn is_read_vectored(&self) -> bool { + true + } + pub fn as_raw_fd(&self) -> u32 { 0 } @@ -37,6 +42,11 @@ impl Stdout { ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } @@ -59,6 +69,11 @@ impl Stderr { ManuallyDrop::new(unsafe { WasiFd::from_raw(self.as_raw_fd()) }).write(data) } + #[inline] + pub fn is_write_vectored(&self) -> bool { + true + } + pub fn flush(&self) -> io::Result<()> { Ok(()) } 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/io.rs b/src/libstd/sys/wasm/io.rs index 976e122463d..d5f475b4310 100644 --- a/src/libstd/sys/wasm/io.rs +++ b/src/libstd/sys/wasm/io.rs @@ -1,5 +1,6 @@ use crate::mem; +#[derive(Copy, Clone)] pub struct IoSlice<'a>(&'a [u8]); impl<'a> IoSlice<'a> { 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/windows/c.rs b/src/libstd/sys/windows/c.rs index 4d377341be3..6115d652b0c 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -216,7 +216,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; @@ -295,6 +294,7 @@ pub struct WSADATA { pub szSystemStatus: [u8; WSASYS_STATUS_LEN + 1], } +#[derive(Copy, Clone)] #[repr(C)] pub struct WSABUF { pub len: ULONG, @@ -777,7 +777,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); @@ -1044,6 +1044,10 @@ compat_fn! { _dwBufferSize: DWORD) -> BOOL { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } + pub fn GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime: LPFILETIME) + -> () { + GetSystemTimeAsFileTime(lpSystemTimeAsFileTime) + } pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE, SRWLock: PSRWLOCK, dwMilliseconds: DWORD, 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..2131cfc2c94 100644 --- a/src/libstd/sys/windows/handle.rs +++ b/src/libstd/sys/windows/handle.rs @@ -92,6 +92,11 @@ 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; @@ -115,8 +120,7 @@ impl RawHandle { ) -> io::Result<Option<usize>> { let len = cmp::min(buf.len(), <c::DWORD>::max_value() 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) => { @@ -172,6 +176,11 @@ 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; diff --git a/src/libstd/sys/windows/io.rs b/src/libstd/sys/windows/io.rs index 9d8018fd5e8..5525d283252 100644 --- a/src/libstd/sys/windows/io.rs +++ b/src/libstd/sys/windows/io.rs @@ -2,6 +2,7 @@ use crate::marker::PhantomData; use crate::slice; use crate::sys::c; +#[derive(Copy, Clone)] #[repr(transparent)] pub struct IoSlice<'a> { vec: c::WSABUF, diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index b004cd19020..d745e87a072 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -81,10 +81,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 +258,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, @@ -267,7 +311,7 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { pub unsafe 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 + 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..a15ded92f08 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -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) } @@ -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 } diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs index 86667ca7ab2..900260169c7 100644 --- a/src/libstd/sys/windows/time.rs +++ b/src/libstd/sys/windows/time.rs @@ -74,7 +74,7 @@ impl SystemTime { pub fn now() -> SystemTime { unsafe { let mut t: SystemTime = mem::zeroed(); - c::GetSystemTimeAsFileTime(&mut t.t); + c::GetSystemTimePreciseAsFileTime(&mut t.t); t } } |
