about summary refs log tree commit diff
path: root/src/libstd/sys
diff options
context:
space:
mode:
authorcomex <comexk@gmail.com>2017-01-14 18:04:27 -0500
committercomex <comexk@gmail.com>2017-01-14 18:44:35 -0500
commit9cfb8b730a473814c2ae090c342abb95e53502db (patch)
treeac757a3acf31331c3ef7c9a0f3f063b1d85c9fd6 /src/libstd/sys
parent743535a643ff9c7f5791a71f6b62c27617cdbb3e (diff)
parent93e70ecb7fbe05caa74dfb2bf3c29315edc2b3e6 (diff)
downloadrust-9cfb8b730a473814c2ae090c342abb95e53502db.tar.gz
rust-9cfb8b730a473814c2ae090c342abb95e53502db.zip
Merge branch 'master' into lint-attr-fix
Diffstat (limited to 'src/libstd/sys')
-rw-r--r--src/libstd/sys/redox/net/mod.rs4
-rw-r--r--src/libstd/sys/redox/net/tcp.rs75
-rw-r--r--src/libstd/sys/redox/net/udp.rs56
-rw-r--r--src/libstd/sys/redox/syscall/data.rs19
-rw-r--r--src/libstd/sys/unix/process/process_unix.rs17
-rw-r--r--src/libstd/sys/windows/c.rs2
-rw-r--r--src/libstd/sys/windows/pipe.rs77
-rw-r--r--src/libstd/sys/windows/process.rs29
8 files changed, 224 insertions, 55 deletions
diff --git a/src/libstd/sys/redox/net/mod.rs b/src/libstd/sys/redox/net/mod.rs
index 3fdf61cfed8..0291d7f0e92 100644
--- a/src/libstd/sys/redox/net/mod.rs
+++ b/src/libstd/sys/redox/net/mod.rs
@@ -15,7 +15,7 @@ use net::{Ipv4Addr, SocketAddr, SocketAddrV4};
 use str::FromStr;
 use string::{String, ToString};
 use sys::syscall::EINVAL;
-use time;
+use time::{self, Duration};
 use vec::{IntoIter, Vec};
 
 use self::dns::{Dns, DnsQuery};
@@ -69,6 +69,8 @@ pub fn lookup_host(host: &str) -> Result<LookupHost> {
         let my_ip = Ipv4Addr::new(ip[0], ip[1], ip[2], ip[3]);
         let dns_ip = Ipv4Addr::new(dns[0], dns[1], dns[2], dns[3]);
         let socket = UdpSocket::bind(&SocketAddr::V4(SocketAddrV4::new(my_ip, 0)))?;
+        socket.set_read_timeout(Some(Duration::new(5, 0)))?;
+        socket.set_write_timeout(Some(Duration::new(5, 0)))?;
         socket.connect(&SocketAddr::V4(SocketAddrV4::new(dns_ip, 53)))?;
         socket.send(&packet_data)?;
 
diff --git a/src/libstd/sys/redox/net/tcp.rs b/src/libstd/sys/redox/net/tcp.rs
index d5362c9f131..a3f202ccd97 100644
--- a/src/libstd/sys/redox/net/tcp.rs
+++ b/src/libstd/sys/redox/net/tcp.rs
@@ -8,10 +8,13 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use cmp;
 use io::{Error, ErrorKind, Result};
+use mem;
 use net::{SocketAddr, Shutdown};
 use path::Path;
 use sys::fs::{File, OpenOptions};
+use sys::syscall::TimeSpec;
 use sys_common::{AsInner, FromInner, IntoInner};
 use time::Duration;
 use vec::Vec;
@@ -77,15 +80,30 @@ impl TcpStream {
     }
 
     pub fn ttl(&self) -> Result<u32> {
-        Err(Error::new(ErrorKind::Other, "TcpStream::ttl not implemented"))
+        let mut ttl = [0];
+        let file = self.0.dup(b"ttl")?;
+        file.read(&mut ttl)?;
+        Ok(ttl[0] as u32)
     }
 
     pub fn read_timeout(&self) -> Result<Option<Duration>> {
-        Err(Error::new(ErrorKind::Other, "TcpStream::read_timeout not implemented"))
+        let mut time = TimeSpec::default();
+        let file = self.0.dup(b"read_timeout")?;
+        if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+            Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+        } else {
+            Ok(None)
+        }
     }
 
     pub fn write_timeout(&self) -> Result<Option<Duration>> {
-        Err(Error::new(ErrorKind::Other, "TcpStream::write_timeout not implemented"))
+        let mut time = TimeSpec::default();
+        let file = self.0.dup(b"write_timeout")?;
+        if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+            Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+        } else {
+            Ok(None)
+        }
     }
 
     pub fn set_nodelay(&self, _nodelay: bool) -> Result<()> {
@@ -100,16 +118,36 @@ impl TcpStream {
         Err(Error::new(ErrorKind::Other, "TcpStream::set_only_v6 not implemented"))
     }
 
-    pub fn set_ttl(&self, _ttl: u32) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "TcpStream::set_ttl not implemented"))
-    }
-
-    pub fn set_read_timeout(&self, _dur: Option<Duration>) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "TcpStream::set_read_timeout not implemented"))
-    }
-
-    pub fn set_write_timeout(&self, _dur: Option<Duration>) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "TcpStream::set_write_timeout not implemented"))
+    pub fn set_ttl(&self, ttl: u32) -> Result<()> {
+        let file = self.0.dup(b"ttl")?;
+        file.write(&[cmp::min(ttl, 255) as u8])?;
+        Ok(())
+    }
+
+    pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+        let file = self.0.dup(b"read_timeout")?;
+        if let Some(duration) = duration_option {
+            file.write(&TimeSpec {
+                tv_sec: duration.as_secs() as i64,
+                tv_nsec: duration.subsec_nanos() as i32
+            })?;
+        } else {
+            file.write(&[])?;
+        }
+        Ok(())
+    }
+
+    pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+        let file = self.0.dup(b"write_timeout")?;
+        if let Some(duration) = duration_option {
+            file.write(&TimeSpec {
+                tv_sec: duration.as_secs() as i64,
+                tv_nsec: duration.subsec_nanos() as i32
+            })?;
+        } else {
+            file.write(&[])?;
+        }
+        Ok(())
     }
 }
 
@@ -168,7 +206,10 @@ impl TcpListener {
     }
 
     pub fn ttl(&self) -> Result<u32> {
-        Err(Error::new(ErrorKind::Other, "TcpListener::ttl not implemented"))
+        let mut ttl = [0];
+        let file = self.0.dup(b"ttl")?;
+        file.read(&mut ttl)?;
+        Ok(ttl[0] as u32)
     }
 
     pub fn set_nonblocking(&self, _nonblocking: bool) -> Result<()> {
@@ -179,8 +220,10 @@ impl TcpListener {
         Err(Error::new(ErrorKind::Other, "TcpListener::set_only_v6 not implemented"))
     }
 
-    pub fn set_ttl(&self, _ttl: u32) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "TcpListener::set_ttl not implemented"))
+    pub fn set_ttl(&self, ttl: u32) -> Result<()> {
+        let file = self.0.dup(b"ttl")?;
+        file.write(&[cmp::min(ttl, 255) as u8])?;
+        Ok(())
     }
 }
 
diff --git a/src/libstd/sys/redox/net/udp.rs b/src/libstd/sys/redox/net/udp.rs
index 607c66c2ba7..36f0819d308 100644
--- a/src/libstd/sys/redox/net/udp.rs
+++ b/src/libstd/sys/redox/net/udp.rs
@@ -9,10 +9,13 @@
 // except according to those terms.
 
 use cell::UnsafeCell;
+use cmp;
 use io::{Error, ErrorKind, Result};
+use mem;
 use net::{SocketAddr, Ipv4Addr, Ipv6Addr};
 use path::Path;
 use sys::fs::{File, OpenOptions};
+use sys::syscall::TimeSpec;
 use sys_common::{AsInner, FromInner, IntoInner};
 use time::Duration;
 
@@ -109,15 +112,30 @@ impl UdpSocket {
     }
 
     pub fn ttl(&self) -> Result<u32> {
-        Err(Error::new(ErrorKind::Other, "UdpSocket::ttl not implemented"))
+        let mut ttl = [0];
+        let file = self.0.dup(b"ttl")?;
+        file.read(&mut ttl)?;
+        Ok(ttl[0] as u32)
     }
 
     pub fn read_timeout(&self) -> Result<Option<Duration>> {
-        Err(Error::new(ErrorKind::Other, "UdpSocket::read_timeout not implemented"))
+        let mut time = TimeSpec::default();
+        let file = self.0.dup(b"read_timeout")?;
+        if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+            Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+        } else {
+            Ok(None)
+        }
     }
 
     pub fn write_timeout(&self) -> Result<Option<Duration>> {
-        Err(Error::new(ErrorKind::Other, "UdpSocket::write_timeout not implemented"))
+        let mut time = TimeSpec::default();
+        let file = self.0.dup(b"write_timeout")?;
+        if file.read(&mut time)? >= mem::size_of::<TimeSpec>() {
+            Ok(Some(Duration::new(time.tv_sec as u64, time.tv_nsec as u32)))
+        } else {
+            Ok(None)
+        }
     }
 
     pub fn set_broadcast(&self, _broadcast: bool) -> Result<()> {
@@ -144,16 +162,36 @@ impl UdpSocket {
         Err(Error::new(ErrorKind::Other, "UdpSocket::set_only_v6 not implemented"))
     }
 
-    pub fn set_ttl(&self, _ttl: u32) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "UdpSocket::set_ttl not implemented"))
+    pub fn set_ttl(&self, ttl: u32) -> Result<()> {
+        let file = self.0.dup(b"ttl")?;
+        file.write(&[cmp::min(ttl, 255) as u8])?;
+        Ok(())
     }
 
-    pub fn set_read_timeout(&self, _dur: Option<Duration>) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "UdpSocket::set_read_timeout not implemented"))
+    pub fn set_read_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+        let file = self.0.dup(b"read_timeout")?;
+        if let Some(duration) = duration_option {
+            file.write(&TimeSpec {
+                tv_sec: duration.as_secs() as i64,
+                tv_nsec: duration.subsec_nanos() as i32
+            })?;
+        } else {
+            file.write(&[])?;
+        }
+        Ok(())
     }
 
-    pub fn set_write_timeout(&self, _dur: Option<Duration>) -> Result<()> {
-        Err(Error::new(ErrorKind::Other, "UdpSocket::set_write_timeout not implemented"))
+    pub fn set_write_timeout(&self, duration_option: Option<Duration>) -> Result<()> {
+        let file = self.0.dup(b"write_timeout")?;
+        if let Some(duration) = duration_option {
+            file.write(&TimeSpec {
+                tv_sec: duration.as_secs() as i64,
+                tv_nsec: duration.subsec_nanos() as i32
+            })?;
+        } else {
+            file.write(&[])?;
+        }
+        Ok(())
     }
 
     pub fn join_multicast_v4(&self, _multiaddr: &Ipv4Addr, _interface: &Ipv4Addr) -> Result<()> {
diff --git a/src/libstd/sys/redox/syscall/data.rs b/src/libstd/sys/redox/syscall/data.rs
index ac3946672a3..a6b0ada72b8 100644
--- a/src/libstd/sys/redox/syscall/data.rs
+++ b/src/libstd/sys/redox/syscall/data.rs
@@ -84,3 +84,22 @@ pub struct TimeSpec {
     pub tv_sec: i64,
     pub tv_nsec: i32,
 }
+
+impl Deref for TimeSpec {
+    type Target = [u8];
+    fn deref(&self) -> &[u8] {
+        unsafe {
+            slice::from_raw_parts(self as *const TimeSpec as *const u8,
+                                  mem::size_of::<TimeSpec>()) as &[u8]
+        }
+    }
+}
+
+impl DerefMut for TimeSpec {
+    fn deref_mut(&mut self) -> &mut [u8] {
+        unsafe {
+            slice::from_raw_parts_mut(self as *mut TimeSpec as *mut u8,
+                                      mem::size_of::<TimeSpec>()) as &mut [u8]
+        }
+    }
+}
diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs
index aa426722025..0dc1739c1a1 100644
--- a/src/libstd/sys/unix/process/process_unix.rs
+++ b/src/libstd/sys/unix/process/process_unix.rs
@@ -237,6 +237,7 @@ impl Process {
             cvt(unsafe { libc::kill(self.pid, libc::SIGKILL) }).map(|_| ())
         }
     }
+
     pub fn wait(&mut self) -> io::Result<ExitStatus> {
         use sys::cvt_r;
         if let Some(status) = self.status {
@@ -247,4 +248,20 @@ impl Process {
         self.status = Some(ExitStatus::new(status));
         Ok(ExitStatus::new(status))
     }
+
+    pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+        if let Some(status) = self.status {
+            return Ok(status)
+        }
+        let mut status = 0 as c_int;
+        let pid = cvt(unsafe {
+            libc::waitpid(self.pid, &mut status, libc::WNOHANG)
+        })?;
+        if pid == 0 {
+            Err(io::Error::from_raw_os_error(libc::EWOULDBLOCK))
+        } else {
+            self.status = Some(ExitStatus::new(status));
+            Ok(ExitStatus::new(status))
+        }
+    }
 }
diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs
index d1c404195bc..dc7b2fc9a6b 100644
--- a/src/libstd/sys/windows/c.rs
+++ b/src/libstd/sys/windows/c.rs
@@ -265,6 +265,7 @@ pub const FILE_CURRENT: DWORD = 1;
 pub const FILE_END: DWORD = 2;
 
 pub const WAIT_OBJECT_0: DWORD = 0x00000000;
+pub const WAIT_TIMEOUT: DWORD = 258;
 
 #[cfg(target_env = "msvc")]
 pub const MAX_SYM_NAME: usize = 2000;
@@ -282,6 +283,7 @@ pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
 pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15;
 
 pub const PIPE_ACCESS_INBOUND: DWORD = 0x00000001;
+pub const PIPE_ACCESS_OUTBOUND: DWORD = 0x00000002;
 pub const FILE_FLAG_FIRST_PIPE_INSTANCE: DWORD = 0x00080000;
 pub const FILE_FLAG_OVERLAPPED: DWORD = 0x40000000;
 pub const PIPE_WAIT: DWORD = 0x00000000;
diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs
index 1eb17305476..8073473f7ff 100644
--- a/src/libstd/sys/windows/pipe.rs
+++ b/src/libstd/sys/windows/pipe.rs
@@ -29,18 +29,43 @@ pub struct AnonPipe {
     inner: Handle,
 }
 
-pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
+pub struct Pipes {
+    pub ours: AnonPipe,
+    pub theirs: AnonPipe,
+}
+
+/// Although this looks similar to `anon_pipe` in the Unix module it's actually
+/// subtly different. Here we'll return two pipes in the `Pipes` return value,
+/// but one is intended for "us" where as the other is intended for "someone
+/// else".
+///
+/// Currently the only use case for this function is pipes for stdio on
+/// processes in the standard library, so "ours" is the one that'll stay in our
+/// process whereas "theirs" will be inherited to a child.
+///
+/// The ours/theirs pipes are *not* specifically readable or writable. Each
+/// one only supports a read or a write, but which is which depends on the
+/// boolean flag given. If `ours_readable` is true then `ours` is readable where
+/// `theirs` is writable. Conversely if `ours_readable` is false then `ours` is
+/// writable where `theirs` is readable.
+///
+/// Also note that the `ours` pipe is always a handle opened up in overlapped
+/// mode. This means that technically speaking it should only ever be used
+/// with `OVERLAPPED` instances, but also works out ok if it's only ever used
+/// once at a time (which we do indeed guarantee).
+pub fn anon_pipe(ours_readable: bool) -> io::Result<Pipes> {
     // Note that we specifically do *not* use `CreatePipe` here because
     // unfortunately the anonymous pipes returned do not support overlapped
-    // operations.
-    //
-    // Instead, we create a "hopefully unique" name and create a named pipe
-    // which has overlapped operations enabled.
+    // operations. Instead, we create a "hopefully unique" name and create a
+    // named pipe which has overlapped operations enabled.
     //
-    // Once we do this, we connect do it as usual via `CreateFileW`, and then we
-    // return those reader/writer halves.
+    // Once we do this, we connect do it as usual via `CreateFileW`, and then
+    // we return those reader/writer halves. Note that the `ours` pipe return
+    // value is always the named pipe, whereas `theirs` is just the normal file.
+    // This should hopefully shield us from child processes which assume their
+    // stdout is a named pipe, which would indeed be odd!
     unsafe {
-        let reader;
+        let ours;
         let mut name;
         let mut tries = 0;
         let mut reject_remote_clients_flag = c::PIPE_REJECT_REMOTE_CLIENTS;
@@ -54,11 +79,16 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
                                   .encode_wide()
                                   .chain(Some(0))
                                   .collect::<Vec<_>>();
+            let mut flags = c::FILE_FLAG_FIRST_PIPE_INSTANCE |
+                c::FILE_FLAG_OVERLAPPED;
+            if ours_readable {
+                flags |= c::PIPE_ACCESS_INBOUND;
+            } else {
+                flags |= c::PIPE_ACCESS_OUTBOUND;
+            }
 
             let handle = c::CreateNamedPipeW(wide_name.as_ptr(),
-                                             c::PIPE_ACCESS_INBOUND |
-                                             c::FILE_FLAG_FIRST_PIPE_INSTANCE |
-                                             c::FILE_FLAG_OVERLAPPED,
+                                             flags,
                                              c::PIPE_TYPE_BYTE |
                                              c::PIPE_READMODE_BYTE |
                                              c::PIPE_WAIT |
@@ -101,21 +131,28 @@ pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
                 }
                 return Err(err)
             }
-            reader = Handle::new(handle);
+            ours = Handle::new(handle);
             break
         }
 
-        // Connect to the named pipe we just created in write-only mode (also
-        // overlapped for async I/O below).
+        // Connect to the named pipe we just created. This handle is going to be
+        // returned in `theirs`, so if `ours` is readable we want this to be
+        // writable, otherwise if `ours` is writable we want this to be
+        // readable.
+        //
+        // Additionally we don't enable overlapped mode on this because most
+        // client processes aren't enabled to work with that.
         let mut opts = OpenOptions::new();
-        opts.write(true);
-        opts.read(false);
+        opts.write(ours_readable);
+        opts.read(!ours_readable);
         opts.share_mode(0);
-        opts.attributes(c::FILE_FLAG_OVERLAPPED);
-        let writer = File::open(Path::new(&name), &opts)?;
-        let writer = AnonPipe { inner: writer.into_handle() };
+        let theirs = File::open(Path::new(&name), &opts)?;
+        let theirs = AnonPipe { inner: theirs.into_handle() };
 
-        Ok((AnonPipe { inner: reader }, AnonPipe { inner: writer.into_handle() }))
+        Ok(Pipes {
+            ours: AnonPipe { inner: ours },
+            theirs: AnonPipe { inner: theirs.into_handle() },
+        })
     }
 }
 
diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs
index 969de6b85a6..d2ad81023e7 100644
--- a/src/libstd/sys/windows/process.rs
+++ b/src/libstd/sys/windows/process.rs
@@ -264,19 +264,15 @@ impl Stdio {
             }
 
             Stdio::MakePipe => {
-                let (reader, writer) = pipe::anon_pipe()?;
-                let (ours, theirs) = if stdio_id == c::STD_INPUT_HANDLE {
-                    (writer, reader)
-                } else {
-                    (reader, writer)
-                };
-                *pipe = Some(ours);
+                let ours_readable = stdio_id != c::STD_INPUT_HANDLE;
+                let pipes = pipe::anon_pipe(ours_readable)?;
+                *pipe = Some(pipes.ours);
                 cvt(unsafe {
-                    c::SetHandleInformation(theirs.handle().raw(),
+                    c::SetHandleInformation(pipes.theirs.handle().raw(),
                                             c::HANDLE_FLAG_INHERIT,
                                             c::HANDLE_FLAG_INHERIT)
                 })?;
-                Ok(theirs.into_handle())
+                Ok(pipes.theirs.into_handle())
             }
 
             Stdio::Handle(ref handle) => {
@@ -344,6 +340,21 @@ impl Process {
         }
     }
 
+    pub fn try_wait(&mut self) -> io::Result<ExitStatus> {
+        unsafe {
+            match c::WaitForSingleObject(self.handle.raw(), 0) {
+                c::WAIT_OBJECT_0 => {}
+                c::WAIT_TIMEOUT => {
+                    return Err(io::Error::from_raw_os_error(c::WSAEWOULDBLOCK))
+                }
+                _ => return Err(io::Error::last_os_error()),
+            }
+            let mut status = 0;
+            cvt(c::GetExitCodeProcess(self.handle.raw(), &mut status))?;
+            Ok(ExitStatus(status))
+        }
+    }
+
     pub fn handle(&self) -> &Handle { &self.handle }
 
     pub fn into_handle(self) -> Handle { self.handle }