diff options
| author | comex <comexk@gmail.com> | 2017-01-14 18:04:27 -0500 |
|---|---|---|
| committer | comex <comexk@gmail.com> | 2017-01-14 18:44:35 -0500 |
| commit | 9cfb8b730a473814c2ae090c342abb95e53502db (patch) | |
| tree | ac757a3acf31331c3ef7c9a0f3f063b1d85c9fd6 /src/libstd/sys | |
| parent | 743535a643ff9c7f5791a71f6b62c27617cdbb3e (diff) | |
| parent | 93e70ecb7fbe05caa74dfb2bf3c29315edc2b3e6 (diff) | |
| download | rust-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.rs | 4 | ||||
| -rw-r--r-- | src/libstd/sys/redox/net/tcp.rs | 75 | ||||
| -rw-r--r-- | src/libstd/sys/redox/net/udp.rs | 56 | ||||
| -rw-r--r-- | src/libstd/sys/redox/syscall/data.rs | 19 | ||||
| -rw-r--r-- | src/libstd/sys/unix/process/process_unix.rs | 17 | ||||
| -rw-r--r-- | src/libstd/sys/windows/c.rs | 2 | ||||
| -rw-r--r-- | src/libstd/sys/windows/pipe.rs | 77 | ||||
| -rw-r--r-- | src/libstd/sys/windows/process.rs | 29 |
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 } |
