diff options
| author | bors <bors@rust-lang.org> | 2019-02-26 02:48:13 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2019-02-26 02:48:13 +0000 |
| commit | fb162e69449b423c5aed0d9c39f6c046fa300c30 (patch) | |
| tree | 5d4292df6a7db1b62137c4472f1e65317d3919e1 /src/libstd/sys | |
| parent | 55c173c8ae8bda689fd609f391ee5e2e5b1b6d44 (diff) | |
| parent | 4785c748f2190440fb3f90b5319f121f2d31e0e4 (diff) | |
| download | rust-fb162e69449b423c5aed0d9c39f6c046fa300c30.tar.gz rust-fb162e69449b423c5aed0d9c39f6c046fa300c30.zip | |
Auto merge of #58357 - sfackler:vectored-io, r=alexcrichton
Add vectored read and write support This functionality has lived for a while in the tokio ecosystem, where it can improve performance by minimizing copies. r? @alexcrichton
Diffstat (limited to 'src/libstd/sys')
| -rw-r--r-- | src/libstd/sys/cloudabi/io.rs | 32 | ||||
| -rw-r--r-- | src/libstd/sys/cloudabi/mod.rs | 36 | ||||
| -rw-r--r-- | src/libstd/sys/cloudabi/shims/net.rs | 10 | ||||
| -rw-r--r-- | src/libstd/sys/redox/io.rs | 32 | ||||
| -rw-r--r-- | src/libstd/sys/redox/mod.rs | 11 | ||||
| -rw-r--r-- | src/libstd/sys/redox/net/tcp.rs | 16 | ||||
| -rw-r--r-- | src/libstd/sys/sgx/io.rs | 32 | ||||
| -rw-r--r-- | src/libstd/sys/sgx/mod.rs | 52 | ||||
| -rw-r--r-- | src/libstd/sys/sgx/net.rs | 18 | ||||
| -rw-r--r-- | src/libstd/sys/unix/ext/net.rs | 37 | ||||
| -rw-r--r-- | src/libstd/sys/unix/fd.rs | 20 | ||||
| -rw-r--r-- | src/libstd/sys/unix/io.rs | 61 | ||||
| -rw-r--r-- | src/libstd/sys/unix/l4re.rs | 18 | ||||
| -rw-r--r-- | src/libstd/sys/unix/mod.rs | 9 | ||||
| -rw-r--r-- | src/libstd/sys/unix/net.rs | 10 | ||||
| -rw-r--r-- | src/libstd/sys/wasm/io.rs | 32 | ||||
| -rw-r--r-- | src/libstd/sys/wasm/mod.rs | 12 | ||||
| -rw-r--r-- | src/libstd/sys/wasm/net.rs | 10 | ||||
| -rw-r--r-- | src/libstd/sys/windows/c.rs | 25 | ||||
| -rw-r--r-- | src/libstd/sys/windows/io.rs | 63 | ||||
| -rw-r--r-- | src/libstd/sys/windows/mod.rs | 27 | ||||
| -rw-r--r-- | src/libstd/sys/windows/net.rs | 43 |
22 files changed, 525 insertions, 81 deletions
diff --git a/src/libstd/sys/cloudabi/io.rs b/src/libstd/sys/cloudabi/io.rs new file mode 100644 index 00000000000..8b02d3fd19d --- /dev/null +++ b/src/libstd/sys/cloudabi/io.rs @@ -0,0 +1,32 @@ +pub struct IoVec<'a>(&'a [u8]); + +impl<'a> IoVec<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoVec<'a> { + IoVec(buf) + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + self.0 + } +} + +pub struct IoVecMut<'a>(&'a mut [u8]); + +impl<'a> IoVecMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { + IoVecMut(buf) + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + self.0 + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + self.0 + } +} diff --git a/src/libstd/sys/cloudabi/mod.rs b/src/libstd/sys/cloudabi/mod.rs index cd621b76945..d9bc21861c9 100644 --- a/src/libstd/sys/cloudabi/mod.rs +++ b/src/libstd/sys/cloudabi/mod.rs @@ -1,4 +1,3 @@ -use io; use libc; use mem; @@ -10,6 +9,7 @@ pub mod backtrace; #[path = "../unix/cmath.rs"] pub mod cmath; pub mod condvar; +pub mod io; #[path = "../unix/memchr.rs"] pub mod memchr; pub mod mutex; @@ -32,24 +32,24 @@ pub use self::shims::*; #[allow(dead_code)] pub fn init() {} -pub fn decode_error_kind(errno: i32) -> io::ErrorKind { +pub fn decode_error_kind(errno: i32) -> ::io::ErrorKind { match errno { - x if x == abi::errno::ACCES as i32 => io::ErrorKind::PermissionDenied, - x if x == abi::errno::ADDRINUSE as i32 => io::ErrorKind::AddrInUse, - x if x == abi::errno::ADDRNOTAVAIL as i32 => io::ErrorKind::AddrNotAvailable, - x if x == abi::errno::AGAIN as i32 => io::ErrorKind::WouldBlock, - x if x == abi::errno::CONNABORTED as i32 => io::ErrorKind::ConnectionAborted, - x if x == abi::errno::CONNREFUSED as i32 => io::ErrorKind::ConnectionRefused, - x if x == abi::errno::CONNRESET as i32 => io::ErrorKind::ConnectionReset, - x if x == abi::errno::EXIST as i32 => io::ErrorKind::AlreadyExists, - x if x == abi::errno::INTR as i32 => io::ErrorKind::Interrupted, - x if x == abi::errno::INVAL as i32 => io::ErrorKind::InvalidInput, - x if x == abi::errno::NOENT as i32 => io::ErrorKind::NotFound, - x if x == abi::errno::NOTCONN as i32 => io::ErrorKind::NotConnected, - x if x == abi::errno::PERM as i32 => io::ErrorKind::PermissionDenied, - x if x == abi::errno::PIPE as i32 => io::ErrorKind::BrokenPipe, - x if x == abi::errno::TIMEDOUT as i32 => io::ErrorKind::TimedOut, - _ => io::ErrorKind::Other, + x if x == abi::errno::ACCES as i32 => ::io::ErrorKind::PermissionDenied, + x if x == abi::errno::ADDRINUSE as i32 => ::io::ErrorKind::AddrInUse, + x if x == abi::errno::ADDRNOTAVAIL as i32 => ::io::ErrorKind::AddrNotAvailable, + x if x == abi::errno::AGAIN as i32 => ::io::ErrorKind::WouldBlock, + x if x == abi::errno::CONNABORTED as i32 => ::io::ErrorKind::ConnectionAborted, + x if x == abi::errno::CONNREFUSED as i32 => ::io::ErrorKind::ConnectionRefused, + x if x == abi::errno::CONNRESET as i32 => ::io::ErrorKind::ConnectionReset, + x if x == abi::errno::EXIST as i32 => ::io::ErrorKind::AlreadyExists, + x if x == abi::errno::INTR as i32 => ::io::ErrorKind::Interrupted, + x if x == abi::errno::INVAL as i32 => ::io::ErrorKind::InvalidInput, + x if x == abi::errno::NOENT as i32 => ::io::ErrorKind::NotFound, + x if x == abi::errno::NOTCONN as i32 => ::io::ErrorKind::NotConnected, + x if x == abi::errno::PERM as i32 => ::io::ErrorKind::PermissionDenied, + x if x == abi::errno::PIPE as i32 => ::io::ErrorKind::BrokenPipe, + x if x == abi::errno::TIMEDOUT as i32 => ::io::ErrorKind::TimedOut, + _ => ::io::ErrorKind::Other, } } diff --git a/src/libstd/sys/cloudabi/shims/net.rs b/src/libstd/sys/cloudabi/shims/net.rs index b4caa899a75..869a0ef87a7 100644 --- a/src/libstd/sys/cloudabi/shims/net.rs +++ b/src/libstd/sys/cloudabi/shims/net.rs @@ -1,5 +1,5 @@ use fmt; -use io; +use io::{self, IoVec, IoVecMut}; use net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr}; use time::Duration; use sys::{unsupported, Void}; @@ -42,10 +42,18 @@ impl TcpStream { match self.0 {} } + pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn write(&self, _: &[u8]) -> io::Result<usize> { match self.0 {} } + pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn peer_addr(&self) -> io::Result<SocketAddr> { match self.0 {} } diff --git a/src/libstd/sys/redox/io.rs b/src/libstd/sys/redox/io.rs new file mode 100644 index 00000000000..8b02d3fd19d --- /dev/null +++ b/src/libstd/sys/redox/io.rs @@ -0,0 +1,32 @@ +pub struct IoVec<'a>(&'a [u8]); + +impl<'a> IoVec<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoVec<'a> { + IoVec(buf) + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + self.0 + } +} + +pub struct IoVecMut<'a>(&'a mut [u8]); + +impl<'a> IoVecMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { + IoVecMut(buf) + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + self.0 + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + self.0 + } +} diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs index c106db8ddfa..c3878349bb3 100644 --- a/src/libstd/sys/redox/mod.rs +++ b/src/libstd/sys/redox/mod.rs @@ -1,6 +1,6 @@ #![allow(dead_code, missing_docs, nonstandard_style)] -use io::{self, ErrorKind}; +use ::io::{ErrorKind}; pub use libc::strlen; pub use self::rand::hashmap_random_keys; @@ -17,6 +17,7 @@ pub mod ext; pub mod fast_thread_local; pub mod fd; pub mod fs; +pub mod io; pub mod memchr; pub mod mutex; pub mod net; @@ -63,8 +64,8 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { } } -pub fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> { - result.map_err(|err| io::Error::from_raw_os_error(err.errno)) +pub fn cvt(result: Result<usize, syscall::Error>) -> ::io::Result<usize> { + result.map_err(|err| ::io::Error::from_raw_os_error(err.errno)) } #[doc(hidden)] @@ -82,9 +83,9 @@ macro_rules! impl_is_minus_one { impl_is_minus_one! { i8 i16 i32 i64 isize } -pub fn cvt_libc<T: IsMinusOne>(t: T) -> io::Result<T> { +pub fn cvt_libc<T: IsMinusOne>(t: T) -> ::io::Result<T> { if t.is_minus_one() { - Err(io::Error::last_os_error()) + Err(::io::Error::last_os_error()) } else { Ok(t) } diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs index e0353b130bb..abb9f72c324 100644 --- a/src/libstd/sys/redox/net/tcp.rs +++ b/src/libstd/sys/redox/net/tcp.rs @@ -1,5 +1,5 @@ use cmp; -use io::{self, Error, ErrorKind, Result}; +use io::{self, Error, ErrorKind, Result, IoVec, IoVecMut}; use mem; use net::{SocketAddr, Shutdown}; use path::Path; @@ -34,10 +34,24 @@ impl TcpStream { self.0.read(buf) } + pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + match bufs.iter_mut().find(|b| !b.is_empty()) { + Some(buf) => self.read(buf), + None => Ok(0), + } + } + pub fn write(&self, buf: &[u8]) -> Result<usize> { self.0.write(buf) } + pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + match bufs.iter().find(|b| !b.is_empty()) { + Some(buf) => self.write(buf), + None => Ok(0), + } + } + pub fn take_error(&self) -> Result<Option<Error>> { Ok(None) } diff --git a/src/libstd/sys/sgx/io.rs b/src/libstd/sys/sgx/io.rs new file mode 100644 index 00000000000..8b02d3fd19d --- /dev/null +++ b/src/libstd/sys/sgx/io.rs @@ -0,0 +1,32 @@ +pub struct IoVec<'a>(&'a [u8]); + +impl<'a> IoVec<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoVec<'a> { + IoVec(buf) + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + self.0 + } +} + +pub struct IoVecMut<'a>(&'a mut [u8]); + +impl<'a> IoVecMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { + IoVecMut(buf) + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + self.0 + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + self.0 + } +} diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs index 4225ecbb206..403dd61187f 100644 --- a/src/libstd/sys/sgx/mod.rs +++ b/src/libstd/sys/sgx/mod.rs @@ -3,7 +3,6 @@ //! This module contains the facade (aka platform-specific) implementations of //! OS level functionality for Fortanix SGX. -use io; use os::raw::c_char; use sync::atomic::{AtomicBool, Ordering}; @@ -20,6 +19,7 @@ pub mod env; pub mod ext; pub mod fd; pub mod fs; +pub mod io; pub mod memchr; pub mod mutex; pub mod net; @@ -41,12 +41,12 @@ pub fn init() { /// This function is used to implement functionality that simply doesn't exist. /// Programs relying on this functionality will need to deal with the error. -pub fn unsupported<T>() -> io::Result<T> { +pub fn unsupported<T>() -> ::io::Result<T> { Err(unsupported_err()) } -pub fn unsupported_err() -> io::Error { - io::Error::new(io::ErrorKind::Other, +pub fn unsupported_err() -> ::io::Error { + ::io::Error::new(::io::ErrorKind::Other, "operation not supported on SGX yet") } @@ -55,58 +55,58 @@ pub fn unsupported_err() -> io::Error { /// returned, the program might very well be able to function normally. This is /// what happens when `SGX_INEFFECTIVE_ERROR` is set to `true`. If it is /// `false`, the behavior is the same as `unsupported`. -pub fn sgx_ineffective<T>(v: T) -> io::Result<T> { +pub fn sgx_ineffective<T>(v: T) -> ::io::Result<T> { static SGX_INEFFECTIVE_ERROR: AtomicBool = AtomicBool::new(false); if SGX_INEFFECTIVE_ERROR.load(Ordering::Relaxed) { - Err(io::Error::new(io::ErrorKind::Other, + Err(::io::Error::new(::io::ErrorKind::Other, "operation can't be trusted to have any effect on SGX")) } else { Ok(v) } } -pub fn decode_error_kind(code: i32) -> io::ErrorKind { +pub fn decode_error_kind(code: i32) -> ::io::ErrorKind { use fortanix_sgx_abi::Error; // FIXME: not sure how to make sure all variants of Error are covered if code == Error::NotFound as _ { - io::ErrorKind::NotFound + ::io::ErrorKind::NotFound } else if code == Error::PermissionDenied as _ { - io::ErrorKind::PermissionDenied + ::io::ErrorKind::PermissionDenied } else if code == Error::ConnectionRefused as _ { - io::ErrorKind::ConnectionRefused + ::io::ErrorKind::ConnectionRefused } else if code == Error::ConnectionReset as _ { - io::ErrorKind::ConnectionReset + ::io::ErrorKind::ConnectionReset } else if code == Error::ConnectionAborted as _ { - io::ErrorKind::ConnectionAborted + ::io::ErrorKind::ConnectionAborted } else if code == Error::NotConnected as _ { - io::ErrorKind::NotConnected + ::io::ErrorKind::NotConnected } else if code == Error::AddrInUse as _ { - io::ErrorKind::AddrInUse + ::io::ErrorKind::AddrInUse } else if code == Error::AddrNotAvailable as _ { - io::ErrorKind::AddrNotAvailable + ::io::ErrorKind::AddrNotAvailable } else if code == Error::BrokenPipe as _ { - io::ErrorKind::BrokenPipe + ::io::ErrorKind::BrokenPipe } else if code == Error::AlreadyExists as _ { - io::ErrorKind::AlreadyExists + ::io::ErrorKind::AlreadyExists } else if code == Error::WouldBlock as _ { - io::ErrorKind::WouldBlock + ::io::ErrorKind::WouldBlock } else if code == Error::InvalidInput as _ { - io::ErrorKind::InvalidInput + ::io::ErrorKind::InvalidInput } else if code == Error::InvalidData as _ { - io::ErrorKind::InvalidData + ::io::ErrorKind::InvalidData } else if code == Error::TimedOut as _ { - io::ErrorKind::TimedOut + ::io::ErrorKind::TimedOut } else if code == Error::WriteZero as _ { - io::ErrorKind::WriteZero + ::io::ErrorKind::WriteZero } else if code == Error::Interrupted as _ { - io::ErrorKind::Interrupted + ::io::ErrorKind::Interrupted } else if code == Error::Other as _ { - io::ErrorKind::Other + ::io::ErrorKind::Other } else if code == Error::UnexpectedEof as _ { - io::ErrorKind::UnexpectedEof + ::io::ErrorKind::UnexpectedEof } else { - io::ErrorKind::Other + ::io::ErrorKind::Other } } diff --git a/src/libstd/sys/sgx/net.rs b/src/libstd/sys/sgx/net.rs index 6e86b06b286..c4c2de43ff7 100644 --- a/src/libstd/sys/sgx/net.rs +++ b/src/libstd/sys/sgx/net.rs @@ -1,5 +1,5 @@ use fmt; -use io; +use io::{self, IoVec, IoVecMut}; use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr, ToSocketAddrs}; use time::Duration; use sys::{unsupported, Void, sgx_ineffective, AsInner, FromInner, IntoInner, TryIntoInner}; @@ -103,10 +103,26 @@ impl TcpStream { self.inner.inner.read(buf) } + pub fn read_vectored(&self, buf: &mut [IoVecMut<'_>]) -> io::Result<usize> { + let buf = match buf.get_mut(0) { + Some(buf) => buf, + None => return Ok(0), + }; + self.read(buf) + } + pub fn write(&self, buf: &[u8]) -> io::Result<usize> { self.inner.inner.write(buf) } + pub fn write_vectored(&self, buf: &[IoVec<'_>]) -> io::Result<usize> { + let buf = match buf.get(0) { + Some(buf) => buf, + None => return Ok(0), + }; + self.write(buf) + } + pub fn peer_addr(&self) -> io::Result<SocketAddr> { addr_to_sockaddr(&self.peer_addr) } diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index acc064acfcd..4b60ea654c1 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -18,7 +18,7 @@ mod libc { use ascii; use ffi::OsStr; use fmt; -use io::{self, Initializer}; +use io::{self, Initializer, IoVec, IoVecMut}; use mem; use net::{self, Shutdown}; use os::unix::ffi::OsStrExt; @@ -551,6 +551,10 @@ impl io::Read for UnixStream { io::Read::read(&mut &*self, buf) } + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + io::Read::read_vectored(&mut &*self, bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -563,6 +567,10 @@ impl<'a> io::Read for &'a UnixStream { self.0.read(buf) } + fn read_vectored(&mut self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.0.read_vectored(bufs) + } + #[inline] unsafe fn initializer(&self) -> Initializer { Initializer::nop() @@ -575,6 +583,10 @@ impl io::Write for UnixStream { io::Write::write(&mut &*self, buf) } + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + io::Write::write_vectored(&mut &*self, bufs) + } + fn flush(&mut self) -> io::Result<()> { io::Write::flush(&mut &*self) } @@ -586,6 +598,10 @@ impl<'a> io::Write for &'a UnixStream { self.0.write(buf) } + fn write_vectored(&mut self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.0.write_vectored(bufs) + } + fn flush(&mut self) -> io::Result<()> { Ok(()) } @@ -1511,6 +1527,25 @@ mod test { } #[test] + fn vectored() { + let (mut s1, mut s2) = or_panic!(UnixStream::pair()); + + let len = or_panic!(s1.write_vectored( + &[IoVec::new(b"hello"), IoVec::new(b" "), IoVec::new(b"world!")], + )); + assert_eq!(len, 12); + + let mut buf1 = [0; 6]; + let mut buf2 = [0; 7]; + let len = or_panic!(s2.read_vectored( + &mut [IoVecMut::new(&mut buf1), IoVecMut::new(&mut buf2)], + )); + assert_eq!(len, 12); + assert_eq!(&buf1, b"hello "); + assert_eq!(&buf2, b"world!\0"); + } + + #[test] fn pair() { let msg1 = b"hello"; let msg2 = b"world!"; diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index 2cbd9536f4d..6946b7b5dfa 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -1,7 +1,7 @@ #![unstable(reason = "not public", issue = "0", feature = "fd")] use cmp; -use io::{self, Read, Initializer}; +use io::{self, Read, Initializer, IoVec, IoVecMut}; use libc::{self, c_int, c_void, ssize_t}; use mem; use sync::atomic::{AtomicBool, Ordering}; @@ -52,6 +52,15 @@ impl FileDesc { Ok(ret as usize) } + pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + let ret = cvt(unsafe { + libc::readv(self.fd, + bufs.as_ptr() as *const libc::iovec, + cmp::min(bufs.len(), c_int::max_value() as usize) as c_int) + })?; + Ok(ret as usize) + } + pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> { let mut me = self; (&mut me).read_to_end(buf) @@ -105,6 +114,15 @@ impl FileDesc { Ok(ret as usize) } + pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + let ret = cvt(unsafe { + libc::writev(self.fd, + bufs.as_ptr() as *const libc::iovec, + cmp::min(bufs.len(), c_int::max_value() as usize) as c_int) + })?; + Ok(ret as usize) + } + pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> { #[cfg(target_os = "android")] use super::android::cvt_pwrite64; diff --git a/src/libstd/sys/unix/io.rs b/src/libstd/sys/unix/io.rs new file mode 100644 index 00000000000..65e4c6e0577 --- /dev/null +++ b/src/libstd/sys/unix/io.rs @@ -0,0 +1,61 @@ +use marker::PhantomData; +use libc::{iovec, c_void}; +use slice; + +#[repr(transparent)] +pub struct IoVec<'a> { + vec: iovec, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoVec<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoVec<'a> { + IoVec { + vec: iovec { + iov_base: buf.as_ptr() as *mut u8 as *mut c_void, + iov_len: buf.len() + }, + _p: PhantomData, + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) + } + } +} + +pub struct IoVecMut<'a> { + vec: iovec, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoVecMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { + IoVecMut { + vec: iovec { + iov_base: buf.as_mut_ptr() as *mut c_void, + iov_len: buf.len() + }, + _p: PhantomData, + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) + } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) + } + } +} diff --git a/src/libstd/sys/unix/l4re.rs b/src/libstd/sys/unix/l4re.rs index 48037310c8d..4775e29fb57 100644 --- a/src/libstd/sys/unix/l4re.rs +++ b/src/libstd/sys/unix/l4re.rs @@ -5,7 +5,7 @@ macro_rules! unimpl { pub mod net { #![allow(warnings)] use fmt; - use io; + use io::{self, IoVec, IoVecMut}; use libc; use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; use sys_common::{AsInner, FromInner, IntoInner}; @@ -46,6 +46,10 @@ pub mod net { unimpl!(); } + pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> { + unimpl!(); + } + pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> { unimpl!(); } @@ -62,6 +66,10 @@ pub mod net { unimpl!(); } + pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> { + unimpl!(); + } + pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> { unimpl!(); } @@ -144,10 +152,18 @@ pub mod net { unimpl!(); } + pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> { + unimpl!(); + } + pub fn write(&self, _: &[u8]) -> io::Result<usize> { unimpl!(); } + pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> { + 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 b36c117fd09..0de1a223fbd 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -1,6 +1,6 @@ #![allow(missing_docs, nonstandard_style)] -use io::{self, ErrorKind}; +use io::ErrorKind; use libc; #[cfg(any(rustdoc, target_os = "linux"))] pub use os::linux as platform; @@ -39,6 +39,7 @@ pub mod fast_thread_local; pub mod fd; pub mod fs; pub mod memchr; +pub mod io; pub mod mutex; #[cfg(not(target_os = "l4re"))] pub mod net; @@ -126,15 +127,15 @@ macro_rules! impl_is_minus_one { impl_is_minus_one! { i8 i16 i32 i64 isize } -pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> { +pub fn cvt<T: IsMinusOne>(t: T) -> ::io::Result<T> { if t.is_minus_one() { - Err(io::Error::last_os_error()) + Err(::io::Error::last_os_error()) } else { Ok(t) } } -pub fn cvt_r<T, F>(mut f: F) -> io::Result<T> +pub fn cvt_r<T, F>(mut f: F) -> ::io::Result<T> where T: IsMinusOne, F: FnMut() -> T { diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index d780d71c376..521d9b42517 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -1,5 +1,5 @@ use ffi::CStr; -use io; +use io::{self, IoVec, IoVecMut}; use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, EAI_SYSTEM, MSG_PEEK}; use mem; use net::{SocketAddr, Shutdown}; @@ -241,6 +241,10 @@ impl Socket { self.recv_with_flags(buf, MSG_PEEK) } + pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + self.0.read_vectored(bufs) + } + fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<(usize, SocketAddr)> { let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() }; @@ -269,6 +273,10 @@ impl Socket { self.0.write(buf) } + pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + self.0.write_vectored(bufs) + } + 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/wasm/io.rs b/src/libstd/sys/wasm/io.rs new file mode 100644 index 00000000000..8b02d3fd19d --- /dev/null +++ b/src/libstd/sys/wasm/io.rs @@ -0,0 +1,32 @@ +pub struct IoVec<'a>(&'a [u8]); + +impl<'a> IoVec<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoVec<'a> { + IoVec(buf) + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + self.0 + } +} + +pub struct IoVecMut<'a>(&'a mut [u8]); + +impl<'a> IoVecMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { + IoVecMut(buf) + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + self.0 + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + self.0 + } +} diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs index e21455ec6da..e71c6bcd7fe 100644 --- a/src/libstd/sys/wasm/mod.rs +++ b/src/libstd/sys/wasm/mod.rs @@ -14,7 +14,6 @@ //! compiling for wasm. That way it's a compile time error for something that's //! guaranteed to be a runtime error! -use io; use os::raw::c_char; use ptr; use sys::os_str::Buf; @@ -29,6 +28,7 @@ pub mod backtrace; pub mod cmath; pub mod env; pub mod fs; +pub mod io; pub mod memchr; pub mod net; pub mod os; @@ -63,17 +63,17 @@ cfg_if! { pub fn init() { } -pub fn unsupported<T>() -> io::Result<T> { +pub fn unsupported<T>() -> ::io::Result<T> { Err(unsupported_err()) } -pub fn unsupported_err() -> io::Error { - io::Error::new(io::ErrorKind::Other, +pub fn unsupported_err() -> ::io::Error { + ::io::Error::new(::io::ErrorKind::Other, "operation not supported on wasm yet") } -pub fn decode_error_kind(_code: i32) -> io::ErrorKind { - io::ErrorKind::Other +pub fn decode_error_kind(_code: i32) -> ::io::ErrorKind { + ::io::ErrorKind::Other } // This enum is used as the storage for a bunch of types which can't actually diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/wasm/net.rs index 81e4e8255bf..d9f5d538432 100644 --- a/src/libstd/sys/wasm/net.rs +++ b/src/libstd/sys/wasm/net.rs @@ -1,5 +1,5 @@ use fmt; -use io; +use io::{self, IoVec, IoVecMut}; use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; use time::Duration; use sys::{unsupported, Void}; @@ -40,10 +40,18 @@ impl TcpStream { match self.0 {} } + pub fn read_vectored(&self, _: &mut [IoVecMut<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn write(&self, _: &[u8]) -> io::Result<usize> { match self.0 {} } + pub fn write_vectored(&self, _: &[IoVec<'_>]) -> io::Result<usize> { + match self.0 {} + } + pub fn peer_addr(&self) -> io::Result<SocketAddr> { match self.0 {} } diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 28fd4df386e..a78b599204b 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -57,6 +57,9 @@ pub type LPWSAPROTOCOL_INFO = *mut WSAPROTOCOL_INFO; pub type LPSTR = *mut CHAR; pub type LPWSTR = *mut WCHAR; pub type LPFILETIME = *mut FILETIME; +pub type LPWSABUF = *mut WSABUF; +pub type LPWSAOVERLAPPED = *mut c_void; +pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void; pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; pub type PLARGE_INTEGER = *mut c_longlong; @@ -325,6 +328,12 @@ pub struct WSADATA { } #[repr(C)] +pub struct WSABUF { + pub len: ULONG, + pub buf: *mut CHAR, +} + +#[repr(C)] pub struct WSAPROTOCOL_INFO { pub dwServiceFlags1: DWORD, pub dwServiceFlags2: DWORD, @@ -988,6 +997,22 @@ extern "system" { dwProcessId: DWORD, lpProtocolInfo: LPWSAPROTOCOL_INFO) -> c_int; + pub fn WSASend(s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesSent: LPDWORD, + dwFlags: DWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE) + -> c_int; + pub fn WSARecv(s: SOCKET, + lpBuffers: LPWSABUF, + dwBufferCount: DWORD, + lpNumberOfBytesRecvd: LPDWORD, + lpFlags: LPDWORD, + lpOverlapped: LPWSAOVERLAPPED, + lpCompletionRoutine: LPWSAOVERLAPPED_COMPLETION_ROUTINE) + -> c_int; pub fn GetCurrentProcessId() -> DWORD; pub fn WSASocketW(af: c_int, kind: c_int, diff --git a/src/libstd/sys/windows/io.rs b/src/libstd/sys/windows/io.rs new file mode 100644 index 00000000000..662e3047923 --- /dev/null +++ b/src/libstd/sys/windows/io.rs @@ -0,0 +1,63 @@ +use marker::PhantomData; +use slice; +use sys::c; + +#[repr(transparent)] +pub struct IoVec<'a> { + vec: c::WSABUF, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoVec<'a> { + #[inline] + pub fn new(buf: &'a [u8]) -> IoVec<'a> { + assert!(buf.len() <= c::ULONG::max_value() as usize); + IoVec { + vec: c::WSABUF { + len: buf.len() as c::ULONG, + buf: buf.as_ptr() as *mut u8 as *mut c::CHAR, + }, + _p: PhantomData, + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize) + } + } +} + +pub struct IoVecMut<'a> { + vec: c::WSABUF, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoVecMut<'a> { + #[inline] + pub fn new(buf: &'a mut [u8]) -> IoVecMut<'a> { + assert!(buf.len() <= c::ULONG::max_value() as usize); + IoVecMut { + vec: c::WSABUF { + len: buf.len() as c::ULONG, + buf: buf.as_mut_ptr() as *mut c::CHAR, + }, + _p: PhantomData, + } + } + + #[inline] + pub fn as_slice(&self) -> &[u8] { + unsafe { + slice::from_raw_parts(self.vec.buf as *mut u8, self.vec.len as usize) + } + } + + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [u8] { + unsafe { + slice::from_raw_parts_mut(self.vec.buf as *mut u8, self.vec.len as usize) + } + } +} diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index e97e436efbf..56c76a169fe 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -2,7 +2,7 @@ use ptr; use ffi::{OsStr, OsString}; -use io::{self, ErrorKind}; +use io::ErrorKind; use os::windows::ffi::{OsStrExt, OsStringExt}; use path::PathBuf; use time::Duration; @@ -26,6 +26,7 @@ pub mod ext; pub mod fast_thread_local; pub mod fs; pub mod handle; +pub mod io; pub mod memchr; pub mod mutex; pub mod net; @@ -75,12 +76,12 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind { } } -pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> { - fn inner(s: &OsStr) -> io::Result<Vec<u16>> { +pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> ::io::Result<Vec<u16>> { + fn inner(s: &OsStr) -> ::io::Result<Vec<u16>> { let mut maybe_result: Vec<u16> = s.encode_wide().collect(); if maybe_result.iter().any(|&u| u == 0) { - return Err(io::Error::new(io::ErrorKind::InvalidInput, - "strings passed to WinAPI cannot contain NULs")); + return Err(::io::Error::new(::io::ErrorKind::InvalidInput, + "strings passed to WinAPI cannot contain NULs")); } maybe_result.push(0); Ok(maybe_result) @@ -102,7 +103,7 @@ pub fn to_u16s<S: AsRef<OsStr>>(s: S) -> io::Result<Vec<u16>> { // Once the syscall has completed (errors bail out early) the second closure is // yielded the data which has been read from the syscall. The return value // from this closure is then the return value of the function. -fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> io::Result<T> +fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> ::io::Result<T> where F1: FnMut(*mut u16, c::DWORD) -> c::DWORD, F2: FnOnce(&[u16]) -> T { @@ -134,7 +135,7 @@ fn fill_utf16_buf<F1, F2, T>(mut f1: F1, f2: F2) -> io::Result<T> c::SetLastError(0); let k = match f1(buf.as_mut_ptr(), n as c::DWORD) { 0 if c::GetLastError() == 0 => 0, - 0 => return Err(io::Error::last_os_error()), + 0 => return Err(::io::Error::last_os_error()), n => n, } as usize; if k == n && c::GetLastError() == c::ERROR_INSUFFICIENT_BUFFER { @@ -157,7 +158,7 @@ fn wide_char_to_multi_byte(code_page: u32, flags: u32, s: &[u16], no_default_char: bool) - -> io::Result<Vec<i8>> { + -> ::io::Result<Vec<i8>> { unsafe { let mut size = c::WideCharToMultiByte(code_page, flags, @@ -168,7 +169,7 @@ fn wide_char_to_multi_byte(code_page: u32, ptr::null(), ptr::null_mut()); if size == 0 { - return Err(io::Error::last_os_error()); + return Err(::io::Error::last_os_error()); } let mut buf = Vec::with_capacity(size as usize); @@ -185,10 +186,10 @@ fn wide_char_to_multi_byte(code_page: u32, if no_default_char { &mut used_default_char } else { ptr::null_mut() }); if size == 0 { - return Err(io::Error::last_os_error()); + return Err(::io::Error::last_os_error()); } if no_default_char && used_default_char == c::TRUE { - return Err(io::Error::new(io::ErrorKind::InvalidData, + return Err(::io::Error::new(::io::ErrorKind::InvalidData, "string cannot be converted to requested code page")); } @@ -220,9 +221,9 @@ macro_rules! impl_is_zero { impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } -pub fn cvt<I: IsZero>(i: I) -> io::Result<I> { +pub fn cvt<I: IsZero>(i: I) -> ::io::Result<I> { if i.is_zero() { - Err(io::Error::last_os_error()) + Err(::io::Error::last_os_error()) } else { Ok(i) } diff --git a/src/libstd/sys/windows/net.rs b/src/libstd/sys/windows/net.rs index acda81dcde5..76be26a9d1a 100644 --- a/src/libstd/sys/windows/net.rs +++ b/src/libstd/sys/windows/net.rs @@ -1,7 +1,7 @@ #![unstable(issue = "0", feature = "windows_net")] use cmp; -use io::{self, Read}; +use io::{self, Read, IoVec, IoVecMut}; use libc::{c_int, c_void, c_ulong, c_long}; use mem; use net::{SocketAddr, Shutdown}; @@ -207,6 +207,30 @@ impl Socket { self.recv_with_flags(buf, 0) } + pub fn read_vectored(&self, bufs: &mut [IoVecMut<'_>]) -> io::Result<usize> { + // On unix when a socket is shut down all further reads return 0, so we + // do the same on windows to map a shut down socket to returning EOF. + let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD; + let mut nread = 0; + let mut flags = 0; + unsafe { + let ret = c::WSARecv( + self.0, + bufs.as_mut_ptr() as *mut c::WSABUF, + len, + &mut nread, + &mut flags, + ptr::null_mut(), + ptr::null_mut(), + ); + match ret { + 0 => Ok(nread as usize), + _ if c::WSAGetLastError() == c::WSAESHUTDOWN => Ok(0), + _ => Err(last_error()), + } + } + } + pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> { self.recv_with_flags(buf, c::MSG_PEEK) } @@ -243,6 +267,23 @@ impl Socket { self.recv_from_with_flags(buf, c::MSG_PEEK) } + pub fn write_vectored(&self, bufs: &[IoVec<'_>]) -> io::Result<usize> { + let len = cmp::min(bufs.len(), c::DWORD::max_value() as usize) as c::DWORD; + let mut nwritten = 0; + unsafe { + cvt(c::WSASend( + self.0, + bufs.as_ptr() as *const c::WSABUF as *mut c::WSABUF, + len, + &mut nwritten, + 0, + ptr::null_mut(), + ptr::null_mut(), + ))?; + } + Ok(nwritten as usize) + } + pub fn set_timeout(&self, dur: Option<Duration>, kind: c_int) -> io::Result<()> { let timeout = match dur { |
