about summary refs log tree commit diff
path: root/src/libstd/sys/windows
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2019-02-26 02:48:13 +0000
committerbors <bors@rust-lang.org>2019-02-26 02:48:13 +0000
commitfb162e69449b423c5aed0d9c39f6c046fa300c30 (patch)
tree5d4292df6a7db1b62137c4472f1e65317d3919e1 /src/libstd/sys/windows
parent55c173c8ae8bda689fd609f391ee5e2e5b1b6d44 (diff)
parent4785c748f2190440fb3f90b5319f121f2d31e0e4 (diff)
downloadrust-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/windows')
-rw-r--r--src/libstd/sys/windows/c.rs25
-rw-r--r--src/libstd/sys/windows/io.rs63
-rw-r--r--src/libstd/sys/windows/mod.rs27
-rw-r--r--src/libstd/sys/windows/net.rs43
4 files changed, 144 insertions, 14 deletions
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 {