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 | |
| 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')
| -rw-r--r-- | src/libstd/collections/hash/map.rs | 4 | ||||
| -rw-r--r-- | src/libstd/collections/hash/table.rs | 3 | ||||
| -rw-r--r-- | src/libstd/ffi/os_str.rs | 23 | ||||
| -rw-r--r-- | src/libstd/io/error.rs | 4 | ||||
| -rw-r--r-- | src/libstd/lib.rs | 5 | ||||
| -rw-r--r-- | src/libstd/macros.rs | 2 | ||||
| -rw-r--r-- | src/libstd/net/addr.rs | 14 | ||||
| -rw-r--r-- | src/libstd/net/ip.rs | 14 | ||||
| -rw-r--r-- | src/libstd/net/tcp.rs | 41 | ||||
| -rw-r--r-- | src/libstd/net/udp.rs | 20 | ||||
| -rw-r--r-- | src/libstd/path.rs | 133 | ||||
| -rw-r--r-- | src/libstd/primitive_docs.rs | 2 | ||||
| -rw-r--r-- | src/libstd/process.rs | 127 | ||||
| -rw-r--r-- | src/libstd/sync/mutex.rs | 83 | ||||
| -rw-r--r-- | src/libstd/sync/rwlock.rs | 3 | ||||
| -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 | ||||
| -rw-r--r-- | src/libstd/time/mod.rs | 129 |
24 files changed, 720 insertions, 166 deletions
diff --git a/src/libstd/collections/hash/map.rs b/src/libstd/collections/hash/map.rs index 2fa3a9c4844..a314717a877 100644 --- a/src/libstd/collections/hash/map.rs +++ b/src/libstd/collections/hash/map.rs @@ -1779,11 +1779,11 @@ impl<'a, K, V> Entry<'a, K, V> { /// use std::collections::HashMap; /// /// let mut map: HashMap<&str, String> = HashMap::new(); - /// let s = "hoho".to_owned(); + /// let s = "hoho".to_string(); /// /// map.entry("poneyland").or_insert_with(|| s); /// - /// assert_eq!(map["poneyland"], "hoho".to_owned()); + /// assert_eq!(map["poneyland"], "hoho".to_string()); /// ``` pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V { match self { diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index 2cd9362a657..1ab62130cd3 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -1061,8 +1061,7 @@ impl<K: Clone, V: Clone> Clone for RawTable<K, V> { } } -impl<K, V> Drop for RawTable<K, V> { - #[unsafe_destructor_blind_to_params] +unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> { fn drop(&mut self) { if self.capacity == 0 { return; diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs index 84b50f04463..175fe30db66 100644 --- a/src/libstd/ffi/os_str.rs +++ b/src/libstd/ffi/os_str.rs @@ -259,6 +259,15 @@ impl OsStr { /// Yields a `&str` slice if the `OsStr` is valid Unicode. /// /// This conversion may entail doing a check for UTF-8 validity. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("foo"); + /// assert_eq!(os_str.to_str(), Some("foo")); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_str(&self) -> Option<&str> { self.inner.to_str() @@ -267,6 +276,20 @@ impl OsStr { /// Converts an `OsStr` to a `Cow<str>`. /// /// Any non-Unicode sequences are replaced with U+FFFD REPLACEMENT CHARACTER. + /// + /// # Examples + /// + /// Calling `to_string_lossy` on an `OsStr` with valid unicode: + /// + /// ``` + /// use std::ffi::OsStr; + /// + /// let os_str = OsStr::new("foo"); + /// assert_eq!(os_str.to_string_lossy(), "foo"); + /// ``` + /// + /// Had `os_str` contained invalid unicode, the `to_string_lossy` call might + /// have returned `"fo�"`. #[stable(feature = "rust1", since = "1.0.0")] pub fn to_string_lossy(&self) -> Cow<str> { self.inner.to_string_lossy() diff --git a/src/libstd/io/error.rs b/src/libstd/io/error.rs index 795c89c0007..434f522cc1e 100644 --- a/src/libstd/io/error.rs +++ b/src/libstd/io/error.rs @@ -388,12 +388,12 @@ impl Error { /// impl MyError { /// fn new() -> MyError { /// MyError { - /// v: "oh no!".to_owned() + /// v: "oh no!".to_string() /// } /// } /// /// fn change_message(&mut self, new_message: &str) { - /// self.v = new_message.to_owned(); + /// self.v = new_message.to_string(); /// } /// } /// diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index f1e3996e825..521b938acfb 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -225,7 +225,7 @@ // Turn warnings into errors, but only after stage0, where it can be useful for // code to emit warnings during language transitions -#![cfg_attr(not(stage0), deny(warnings))] +#![deny(warnings)] // std may use features in a platform-specific way #![allow(unused_features)] @@ -250,13 +250,14 @@ #![feature(const_fn)] #![feature(core_float)] #![feature(core_intrinsics)] -#![feature(dropck_parametricity)] +#![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(float_extras)] #![feature(float_from_str_radix)] #![feature(fn_traits)] #![feature(fnbox)] #![feature(fused)] +#![feature(generic_param_attrs)] #![feature(hashmap_hasher)] #![feature(heap_api)] #![feature(inclusive_range)] diff --git a/src/libstd/macros.rs b/src/libstd/macros.rs index 0ce6b0a9431..52c6da58151 100644 --- a/src/libstd/macros.rs +++ b/src/libstd/macros.rs @@ -112,7 +112,7 @@ macro_rules! print { /// # Examples /// /// ``` -/// println!(); +/// println!(); // prints just a newline /// println!("hello there!"); /// println!("format {} arguments", "some"); /// ``` diff --git a/src/libstd/net/addr.rs b/src/libstd/net/addr.rs index 1ce37f6cc0a..f5348934310 100644 --- a/src/libstd/net/addr.rs +++ b/src/libstd/net/addr.rs @@ -446,6 +446,20 @@ impl FromInner<c::sockaddr_in6> for SocketAddrV6 { } } +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From<SocketAddrV4> for SocketAddr { + fn from(sock4: SocketAddrV4) -> SocketAddr { + SocketAddr::V4(sock4) + } +} + +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From<SocketAddrV6> for SocketAddr { + fn from(sock6: SocketAddrV6) -> SocketAddr { + SocketAddr::V6(sock6) + } +} + impl<'a> IntoInner<(*const c::sockaddr, c::socklen_t)> for &'a SocketAddr { fn into_inner(self) -> (*const c::sockaddr, c::socklen_t) { match *self { diff --git a/src/libstd/net/ip.rs b/src/libstd/net/ip.rs index 6aab7486004..249f1c76680 100644 --- a/src/libstd/net/ip.rs +++ b/src/libstd/net/ip.rs @@ -524,6 +524,20 @@ impl fmt::Display for IpAddr { } } +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From<Ipv4Addr> for IpAddr { + fn from(ipv4: Ipv4Addr) -> IpAddr { + IpAddr::V4(ipv4) + } +} + +#[stable(feature = "ip_from_ip", since = "1.16.0")] +impl From<Ipv6Addr> for IpAddr { + fn from(ipv6: Ipv6Addr) -> IpAddr { + IpAddr::V6(ipv6) + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl fmt::Display for Ipv4Addr { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs index 63817c9f10f..cbc672c28bc 100644 --- a/src/libstd/net/tcp.rs +++ b/src/libstd/net/tcp.rs @@ -52,7 +52,7 @@ pub struct TcpStream(net_imp::TcpStream); /// // ... /// } /// -/// // accept connections and process them, spawning a new thread for each one +/// // accept connections and process them serially /// for stream in listener.incoming() { /// match stream { /// Ok(stream) => { @@ -613,44 +613,18 @@ impl TcpListener { self.0.ttl() } - /// Sets the value for the `IPV6_V6ONLY` option on this socket. - /// - /// If this is set to `true` then the socket is restricted to sending and - /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications - /// can bind the same port at the same time. - /// - /// If this is set to `false` then the socket can be used to send and - /// receive packets from an IPv4-mapped IPv6 address. - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpListener; - /// - /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); - /// listener.set_only_v6(true).expect("Cannot set to IPv6"); - /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] + #[rustc_deprecated(since = "1.16.0", + reason = "this option can only be set before the socket is bound")] + #[allow(missing_docs)] pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { self.0.set_only_v6(only_v6) } - /// Gets the value of the `IPV6_V6ONLY` option for this socket. - /// - /// For more information about this option, see [`set_only_v6`][link]. - /// - /// [link]: #method.set_only_v6 - /// - /// # Examples - /// - /// ```no_run - /// use std::net::TcpListener; - /// - /// let listener = TcpListener::bind("127.0.0.1:80").unwrap(); - /// listener.set_only_v6(true).expect("Cannot set to IPv6"); - /// assert_eq!(listener.only_v6().unwrap_or(false), true); - /// ``` #[stable(feature = "net2_mutators", since = "1.9.0")] + #[rustc_deprecated(since = "1.16.0", + reason = "this option can only be set before the socket is bound")] + #[allow(missing_docs)] pub fn only_v6(&self) -> io::Result<bool> { self.0.only_v6() } @@ -1179,6 +1153,7 @@ mod tests { } #[test] + #[cfg(unix)] // test doesn't work on Windows, see #31657 fn close_read_wakes_up() { each_ip(&mut |addr| { let a = t!(TcpListener::bind(&addr)); diff --git a/src/libstd/net/udp.rs b/src/libstd/net/udp.rs index f8a5ec0b379..a9a19aee5d1 100644 --- a/src/libstd/net/udp.rs +++ b/src/libstd/net/udp.rs @@ -883,11 +883,23 @@ mod tests { #[test] fn set_nonblocking() { - let addr = next_test_ip4(); + each_ip(&mut |addr, _| { + let socket = t!(UdpSocket::bind(&addr)); - let stream = t!(UdpSocket::bind(&addr)); + t!(socket.set_nonblocking(true)); + t!(socket.set_nonblocking(false)); + + t!(socket.connect(addr)); - t!(stream.set_nonblocking(true)); - t!(stream.set_nonblocking(false)); + t!(socket.set_nonblocking(false)); + t!(socket.set_nonblocking(true)); + + let mut buf = [0]; + match socket.recv(&mut buf) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error {}", e), + } + }) } } diff --git a/src/libstd/path.rs b/src/libstd/path.rs index d13baea40a9..eb0a6cd74d7 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -10,9 +10,9 @@ //! Cross-platform path manipulation. //! -//! This module provides two types, `PathBuf` and `Path` (akin to `String` and -//! `str`), for working with paths abstractly. These types are thin wrappers -//! around `OsString` and `OsStr` respectively, meaning that they work directly +//! This module provides two types, [`PathBuf`] and [`Path`][`Path`] (akin to [`String`] +//! and [`str`]), for working with paths abstractly. These types are thin wrappers +//! around [`OsString`] and [`OsStr`] respectively, meaning that they work directly //! on strings according to the local platform's path syntax. //! //! ## Simple usage @@ -20,10 +20,10 @@ //! Path manipulation includes both parsing components from slices and building //! new owned paths. //! -//! To parse a path, you can create a `Path` slice from a `str` +//! To parse a path, you can create a [`Path`] slice from a [`str`] //! slice and start asking questions: //! -//! ```rust +//! ``` //! use std::path::Path; //! use std::ffi::OsStr; //! @@ -39,9 +39,9 @@ //! assert_eq!(extension, Some(OsStr::new("txt"))); //! ``` //! -//! To build or modify paths, use `PathBuf`: +//! To build or modify paths, use [`PathBuf`]: //! -//! ```rust +//! ``` //! use std::path::PathBuf; //! //! let mut path = PathBuf::from("c:\\"); @@ -103,6 +103,13 @@ //! that `b` is a symbolic link (so its parent isn't `a`). Further //! normalization is possible to build on top of the components APIs, //! and will be included in this library in the near future. +//! +//! [`PathBuf`]: ../../std/path/struct.PathBuf.html +//! [`Path`]: ../../std/path/struct.Path.html +//! [`String`]: ../../std/string/struct.String.html +//! [`str`]: ../../std/primitive.str.html +//! [`OsString`]: ../../std/ffi/struct.OsString.html +//! [`OsStr`]: ../../std/ffi/struct.OsStr.html #![stable(feature = "rust1", since = "1.0.0")] @@ -527,7 +534,9 @@ pub struct Components<'a> { back: State, } -/// An iterator over the components of a path, as `OsStr` slices. +/// An iterator over the components of a path, as [`OsStr`] slices. +/// +/// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a> { @@ -1089,10 +1098,11 @@ impl PathBuf { /// Updates [`self.file_name()`] to `file_name`. /// - /// If [`self.file_name()`] was `None`, this is equivalent to pushing + /// If [`self.file_name()`] was [`None`], this is equivalent to pushing /// `file_name`. /// /// [`self.file_name()`]: struct.PathBuf.html#method.file_name + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -1124,11 +1134,12 @@ impl PathBuf { /// /// If [`self.file_name()`] is `None`, does nothing and returns `false`. /// - /// Otherwise, returns `true`; if [`self.extension()`] is `None`, the + /// Otherwise, returns `true`; if [`self.extension()`] is [`None`], the /// extension is added; otherwise it is replaced. /// /// [`self.file_name()`]: struct.PathBuf.html#method.file_name /// [`self.extension()`]: struct.PathBuf.html#method.extension + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -1356,8 +1367,10 @@ pub struct Path { inner: OsStr, } -/// An error returned from the `Path::strip_prefix` method indicating that the +/// An error returned from the [`Path::strip_prefix`] method indicating that the /// prefix was not found in `self`. +/// +/// [`Path::strip_prefix`]: struct.Path.html#method.strip_prefix #[derive(Debug, Clone, PartialEq, Eq)] #[stable(since = "1.7.0", feature = "strip_prefix")] pub struct StripPrefixError(()); @@ -1428,8 +1441,8 @@ impl Path { /// ``` /// use std::path::Path; /// - /// let path_str = Path::new("foo.txt").to_str(); - /// assert_eq!(path_str, Some("foo.txt")); + /// let path = Path::new("foo.txt"); + /// assert_eq!(path.to_str(), Some("foo.txt")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn to_str(&self) -> Option<&str> { @@ -1444,12 +1457,17 @@ impl Path { /// /// # Examples /// + /// Calling `to_string_lossy` on a `Path` with valid unicode: + /// /// ``` /// use std::path::Path; /// - /// let path_str = Path::new("foo.txt").to_string_lossy(); - /// assert_eq!(path_str, "foo.txt"); + /// let path = Path::new("foo.txt"); + /// assert_eq!(path.to_string_lossy(), "foo.txt"); /// ``` + /// + /// Had `os_str` contained invalid unicode, the `to_string_lossy` call might + /// have returned `"fo�.txt"`. #[stable(feature = "rust1", since = "1.0.0")] pub fn to_string_lossy(&self) -> Cow<str> { self.inner.to_string_lossy() @@ -1490,7 +1508,8 @@ impl Path { #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] pub fn is_absolute(&self) -> bool { - self.has_root() && (cfg!(unix) || self.prefix().is_some()) + // FIXME: Remove target_os = "redox" and allow Redox prefixes + self.has_root() && (cfg!(unix) || cfg!(target_os = "redox") || self.prefix().is_some()) } /// A path is *relative* if it is not absolute. @@ -1534,7 +1553,9 @@ impl Path { /// The path without its final component, if any. /// - /// Returns `None` if the path terminates in a root or prefix. + /// Returns [`None`] if the path terminates in a root or prefix. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -1565,7 +1586,9 @@ impl Path { /// The final component of the path, if it is a normal file. /// - /// If the path terminates in `..`, `file_name` will return `None`. + /// If the path terminates in `..`, `file_name` will return [`None`]. + /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None /// /// # Examples /// @@ -1603,8 +1626,11 @@ impl Path { /// /// # Errors /// - /// If `base` is not a prefix of `self` (i.e. `starts_with` - /// returns `false`), returns `Err`. + /// If `base` is not a prefix of `self` (i.e. [`starts_with`] + /// returns `false`), returns [`Err`]. + /// + /// [`starts_with`]: #method.starts_with + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err /// /// # Examples /// @@ -1684,11 +1710,13 @@ impl Path { /// /// The stem is: /// - /// * None, if there is no file name; + /// * [`None`], if there is no file name; /// * The entire file name if there is no embedded `.`; /// * The entire file name if the file name begins with `.` and has no other `.`s within; /// * Otherwise, the portion of the file name before the final `.` /// + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// /// # Examples /// /// ``` @@ -1705,15 +1733,16 @@ impl Path { /// Extracts the extension of [`self.file_name()`], if possible. /// - /// [`self.file_name()`]: struct.Path.html#method.file_name - /// /// The extension is: /// - /// * None, if there is no file name; - /// * None, if there is no embedded `.`; - /// * None, if the file name begins with `.` and has no other `.`s within; + /// * [`None`], if there is no file name; + /// * [`None`], if there is no embedded `.`; + /// * [`None`], if the file name begins with `.` and has no other `.`s within; /// * Otherwise, the portion of the file name after the final `.` /// + /// [`self.file_name()`]: struct.Path.html#method.file_name + /// [`None`]: ../../std/option/enum.Option.html#variant.None + /// /// # Examples /// /// ``` @@ -1872,7 +1901,6 @@ impl Path { Display { path: self } } - /// Query the file system to get information about a file, directory, etc. /// /// This function will traverse symbolic links to query information about the @@ -1881,6 +1909,16 @@ impl Path { /// This is an alias to [`fs::metadata`]. /// /// [`fs::metadata`]: ../fs/fn.metadata.html + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// + /// let path = Path::new("/Minas/tirith"); + /// let metadata = path.metadata().expect("metadata call failed"); + /// println!("{:?}", metadata.file_type()); + /// ``` #[stable(feature = "path_ext", since = "1.5.0")] pub fn metadata(&self) -> io::Result<fs::Metadata> { fs::metadata(self) @@ -1891,6 +1929,16 @@ impl Path { /// This is an alias to [`fs::symlink_metadata`]. /// /// [`fs::symlink_metadata`]: ../fs/fn.symlink_metadata.html + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// + /// let path = Path::new("/Minas/tirith"); + /// let metadata = path.symlink_metadata().expect("symlink_metadata call failed"); + /// println!("{:?}", metadata.file_type()); + /// ``` #[stable(feature = "path_ext", since = "1.5.0")] pub fn symlink_metadata(&self) -> io::Result<fs::Metadata> { fs::symlink_metadata(self) @@ -1902,6 +1950,15 @@ impl Path { /// This is an alias to [`fs::canonicalize`]. /// /// [`fs::canonicalize`]: ../fs/fn.canonicalize.html + /// + /// # Examples + /// + /// ```no_run + /// use std::path::{Path, PathBuf}; + /// + /// let path = Path::new("/foo/test/../test/bar.rs"); + /// assert_eq!(path.canonicalize().unwrap(), PathBuf::from("/foo/test/bar.rs")); + /// ``` #[stable(feature = "path_ext", since = "1.5.0")] pub fn canonicalize(&self) -> io::Result<PathBuf> { fs::canonicalize(self) @@ -1912,6 +1969,15 @@ impl Path { /// This is an alias to [`fs::read_link`]. /// /// [`fs::read_link`]: ../fs/fn.read_link.html + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// + /// let path = Path::new("/laputa/sky_castle.rs"); + /// let path_link = path.read_link().expect("read_link call failed"); + /// ``` #[stable(feature = "path_ext", since = "1.5.0")] pub fn read_link(&self) -> io::Result<PathBuf> { fs::read_link(self) @@ -1927,6 +1993,19 @@ impl Path { /// [`io::Result`]: ../io/type.Result.html /// [`DirEntry`]: ../fs/struct.DirEntry.html /// [`fs::read_dir`]: ../fs/fn.read_dir.html + /// + /// # Examples + /// + /// ```no_run + /// use std::path::Path; + /// + /// let path = Path::new("/laputa"); + /// for entry in path.read_dir().expect("read_dir call failed") { + /// if let Ok(entry) = entry { + /// println!("{:?}", entry.path()); + /// } + /// } + /// ``` #[stable(feature = "path_ext", since = "1.5.0")] pub fn read_dir(&self) -> io::Result<fs::ReadDir> { fs::read_dir(self) diff --git a/src/libstd/primitive_docs.rs b/src/libstd/primitive_docs.rs index 5981b482a97..ced0288766b 100644 --- a/src/libstd/primitive_docs.rs +++ b/src/libstd/primitive_docs.rs @@ -502,7 +502,7 @@ mod prim_str { } /// [`Hash`]: hash/trait.Hash.html /// /// Due to a temporary restriction in Rust's type system, these traits are only -/// implemented on tuples of arity 32 or less. In the future, this may change. +/// implemented on tuples of arity 12 or less. In the future, this may change. /// /// # Examples /// diff --git a/src/libstd/process.rs b/src/libstd/process.rs index e15c37aaf24..aa76b792535 100644 --- a/src/libstd/process.rs +++ b/src/libstd/process.rs @@ -260,11 +260,18 @@ impl fmt::Debug for ChildStderr { /// ``` /// use std::process::Command; /// -/// let output = Command::new("sh") -/// .arg("-c") -/// .arg("echo hello") -/// .output() -/// .expect("failed to execute process"); +/// let output = if cfg!(target_os = "windows") { +/// Command::new("cmd") +/// .args(&["/C", "echo hello"]) +/// .output() +/// .expect("failed to execute process") +/// } else { +/// Command::new("sh") +/// .arg("-c") +/// .arg("echo hello") +/// .output() +/// .expect("failed to execute process") +/// }; /// /// let hello = output.stdout; /// ``` @@ -793,6 +800,48 @@ impl Child { self.handle.wait().map(ExitStatus) } + /// Attempts to collect the exit status of the child if it has already + /// exited. + /// + /// This function will not block the calling thread and will only advisorily + /// check to see if the child process has exited or not. If the child has + /// exited then on Unix the process id is reaped. This function is + /// guaranteed to repeatedly return a successful exit status so long as the + /// child has already exited. + /// + /// If the child has exited, then `Ok(status)` is returned. If the exit + /// status is not available at this time then an error is returned with the + /// error kind `WouldBlock`. If an error occurs, then that error is returned. + /// + /// Note that unlike `wait`, this function will not attempt to drop stdin. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ```no_run + /// #![feature(process_try_wait)] + /// + /// use std::io; + /// use std::process::Command; + /// + /// let mut child = Command::new("ls").spawn().unwrap(); + /// + /// match child.try_wait() { + /// Ok(status) => println!("exited with: {}", status), + /// Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => { + /// println!("status not ready yet, let's really wait"); + /// let res = child.wait(); + /// println!("result: {:?}", res); + /// } + /// Err(e) => println!("error attempting to wait: {}", e), + /// } + /// ``` + #[unstable(feature = "process_try_wait", issue = "38903")] + pub fn try_wait(&mut self) -> io::Result<ExitStatus> { + self.handle.try_wait().map(ExitStatus) + } + /// Simultaneously waits for the child to exit and collect all remaining /// output on the stdout/stderr handles, returning an `Output` /// instance. @@ -925,7 +974,11 @@ mod tests { #[test] #[cfg_attr(target_os = "android", ignore)] fn smoke() { - let p = Command::new("true").spawn(); + let p = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 0"]).spawn() + } else { + Command::new("true").spawn() + }; assert!(p.is_ok()); let mut p = p.unwrap(); assert!(p.wait().unwrap().success()); @@ -943,7 +996,11 @@ mod tests { #[test] #[cfg_attr(target_os = "android", ignore)] fn exit_reported_right() { - let p = Command::new("false").spawn(); + let p = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 1"]).spawn() + } else { + Command::new("false").spawn() + }; assert!(p.is_ok()); let mut p = p.unwrap(); assert!(p.wait().unwrap().code() == Some(1)); @@ -982,9 +1039,15 @@ mod tests { #[test] #[cfg_attr(target_os = "android", ignore)] fn stdout_works() { - let mut cmd = Command::new("echo"); - cmd.arg("foobar").stdout(Stdio::piped()); - assert_eq!(run_output(cmd), "foobar\n"); + if cfg!(target_os = "windows") { + let mut cmd = Command::new("cmd"); + cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped()); + assert_eq!(run_output(cmd), "foobar\r\n"); + } else { + let mut cmd = Command::new("echo"); + cmd.arg("foobar").stdout(Stdio::piped()); + assert_eq!(run_output(cmd), "foobar\n"); + } } #[test] @@ -1044,10 +1107,18 @@ mod tests { #[test] #[cfg_attr(target_os = "android", ignore)] fn test_process_status() { - let mut status = Command::new("false").status().unwrap(); + let mut status = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap() + } else { + Command::new("false").status().unwrap() + }; assert!(status.code() == Some(1)); - status = Command::new("true").status().unwrap(); + status = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap() + } else { + Command::new("true").status().unwrap() + }; assert!(status.success()); } @@ -1063,7 +1134,11 @@ mod tests { #[cfg_attr(target_os = "android", ignore)] fn test_process_output_output() { let Output {status, stdout, stderr} - = Command::new("echo").arg("hello").output().unwrap(); + = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap() + } else { + Command::new("echo").arg("hello").output().unwrap() + }; let output_str = str::from_utf8(&stdout).unwrap(); assert!(status.success()); @@ -1075,7 +1150,11 @@ mod tests { #[cfg_attr(target_os = "android", ignore)] fn test_process_output_error() { let Output {status, stdout, stderr} - = Command::new("mkdir").arg(".").output().unwrap(); + = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap() + } else { + Command::new("mkdir").arg(".").output().unwrap() + }; assert!(status.code() == Some(1)); assert_eq!(stdout, Vec::new()); @@ -1085,14 +1164,22 @@ mod tests { #[test] #[cfg_attr(target_os = "android", ignore)] fn test_finish_once() { - let mut prog = Command::new("false").spawn().unwrap(); + let mut prog = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() + } else { + Command::new("false").spawn().unwrap() + }; assert!(prog.wait().unwrap().code() == Some(1)); } #[test] #[cfg_attr(target_os = "android", ignore)] fn test_finish_twice() { - let mut prog = Command::new("false").spawn().unwrap(); + let mut prog = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() + } else { + Command::new("false").spawn().unwrap() + }; assert!(prog.wait().unwrap().code() == Some(1)); assert!(prog.wait().unwrap().code() == Some(1)); } @@ -1100,8 +1187,12 @@ mod tests { #[test] #[cfg_attr(target_os = "android", ignore)] fn test_wait_with_output_once() { - let prog = Command::new("echo").arg("hello").stdout(Stdio::piped()) - .spawn().unwrap(); + let prog = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap() + } else { + Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap() + }; + let Output {status, stdout, stderr} = prog.wait_with_output().unwrap(); let output_str = str::from_utf8(&stdout).unwrap(); diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs index f6dbe01d7bd..2efddeb4610 100644 --- a/src/libstd/sync/mutex.rs +++ b/src/libstd/sync/mutex.rs @@ -155,6 +155,14 @@ impl<'a, T: ?Sized> !marker::Send for MutexGuard<'a, T> {} impl<T> Mutex<T> { /// Creates a new mutex in an unlocked state ready for use. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Mutex; + /// + /// let mutex = Mutex::new(0); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> Mutex<T> { let mut m = Mutex { @@ -190,6 +198,21 @@ impl<T: ?Sized> Mutex<T> { /// /// This function might panic when called if the lock is already held by /// the current thread. + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Mutex}; + /// use std::thread; + /// + /// let mutex = Arc::new(Mutex::new(0)); + /// let c_mutex = mutex.clone(); + /// + /// thread::spawn(move || { + /// *c_mutex.lock().unwrap() = 10; + /// }).join().expect("thread::spawn failed"); + /// assert_eq!(*mutex.lock().unwrap(), 10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn lock(&self) -> LockResult<MutexGuard<T>> { unsafe { @@ -211,6 +234,26 @@ impl<T: ?Sized> Mutex<T> { /// If another user of this mutex panicked while holding the mutex, then /// this call will return failure if the mutex would otherwise be /// acquired. + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Mutex}; + /// use std::thread; + /// + /// let mutex = Arc::new(Mutex::new(0)); + /// let c_mutex = mutex.clone(); + /// + /// thread::spawn(move || { + /// let mut lock = c_mutex.try_lock(); + /// if let Ok(ref mut mutex) = lock { + /// **mutex = 10; + /// } else { + /// println!("try_lock failed"); + /// } + /// }).join().expect("thread::spawn failed"); + /// assert_eq!(*mutex.lock().unwrap(), 10); + /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn try_lock(&self) -> TryLockResult<MutexGuard<T>> { unsafe { @@ -225,8 +268,24 @@ impl<T: ?Sized> Mutex<T> { /// Determines whether the lock is poisoned. /// /// If another thread is active, the lock can still become poisoned at any - /// time. You should not trust a `false` value for program correctness + /// time. You should not trust a `false` value for program correctness /// without additional synchronization. + /// + /// # Examples + /// + /// ``` + /// use std::sync::{Arc, Mutex}; + /// use std::thread; + /// + /// let mutex = Arc::new(Mutex::new(0)); + /// let c_mutex = mutex.clone(); + /// + /// let _ = thread::spawn(move || { + /// let _lock = c_mutex.lock().unwrap(); + /// panic!(); // the mutex gets poisoned + /// }).join(); + /// assert_eq!(mutex.is_poisoned(), true); + /// ``` #[inline] #[stable(feature = "sync_poison", since = "1.2.0")] pub fn is_poisoned(&self) -> bool { @@ -239,6 +298,15 @@ impl<T: ?Sized> Mutex<T> { /// /// If another user of this mutex panicked while holding the mutex, then /// this call will return an error instead. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Mutex; + /// + /// let mutex = Mutex::new(0); + /// assert_eq!(mutex.into_inner().unwrap(), 0); + /// ``` #[stable(feature = "mutex_into_inner", since = "1.6.0")] pub fn into_inner(self) -> LockResult<T> where T: Sized { // We know statically that there are no outstanding references to @@ -270,6 +338,16 @@ impl<T: ?Sized> Mutex<T> { /// /// If another user of this mutex panicked while holding the mutex, then /// this call will return an error instead. + /// + /// # Examples + /// + /// ``` + /// use std::sync::Mutex; + /// + /// let mut mutex = Mutex::new(0); + /// *mutex.get_mut().unwrap() = 10; + /// assert_eq!(*mutex.lock().unwrap(), 10); + /// ``` #[stable(feature = "mutex_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { // We know statically that there are no other references to `self`, so @@ -280,8 +358,7 @@ impl<T: ?Sized> Mutex<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Drop for Mutex<T> { - #[unsafe_destructor_blind_to_params] +unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex<T> { fn drop(&mut self) { // This is actually safe b/c we know that there is no further usage of // this mutex (it's up to the user to arrange for a mutex to get diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs index 0a11c71706b..adbb98e4b1f 100644 --- a/src/libstd/sync/rwlock.rs +++ b/src/libstd/sync/rwlock.rs @@ -310,8 +310,7 @@ impl<T: ?Sized> RwLock<T> { } #[stable(feature = "rust1", since = "1.0.0")] -impl<T: ?Sized> Drop for RwLock<T> { - #[unsafe_destructor_blind_to_params] +unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock<T> { fn drop(&mut self) { // IMPORTANT: This code needs to be kept in sync with `RwLock::into_inner`. unsafe { self.inner.destroy() } 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 } diff --git a/src/libstd/time/mod.rs b/src/libstd/time/mod.rs index 6854f1e14fa..e4b8d457e2d 100644 --- a/src/libstd/time/mod.rs +++ b/src/libstd/time/mod.rs @@ -34,7 +34,7 @@ pub use self::duration::Duration; mod duration; /// A measurement of a monotonically increasing clock. -/// Opaque and useful only with `Duration`. +/// Opaque and useful only with `Duration`. /// /// Instants are always guaranteed to be greater than any previously measured /// instant when created, and are often useful for tasks such as measuring @@ -73,7 +73,7 @@ pub struct Instant(time::Instant); /// A measurement of the system clock, useful for talking to /// external entities like the file system or other processes. /// -/// Distinct from the `Instant` type, this time measurement **is not +/// Distinct from the [`Instant`] type, this time measurement **is not /// monotonic**. This means that you can save a file to the file system, then /// save another file to the file system, **and the second file has a /// `SystemTime` measurement earlier than the first**. In other words, an @@ -81,15 +81,20 @@ pub struct Instant(time::Instant); /// earlier `SystemTime`! /// /// Consequently, comparing two `SystemTime` instances to learn about the -/// duration between them returns a `Result` instead of an infallible `Duration` +/// duration between them returns a [`Result`] instead of an infallible [`Duration`] /// to indicate that this sort of time drift may happen and needs to be handled. /// -/// Although a `SystemTime` cannot be directly inspected, the `UNIX_EPOCH` +/// Although a `SystemTime` cannot be directly inspected, the [`UNIX_EPOCH`] /// constant is provided in this module as an anchor in time to learn /// information about a `SystemTime`. By calculating the duration from this /// fixed point in time, a `SystemTime` can be converted to a human-readable time, /// or perhaps some other string representation. /// +/// [`Instant`]: ../../std/time/struct.Instant.html +/// [`Result`]: ../../std/result/enum.Result.html +/// [`Duration`]: ../../std/time/struct.Duration.html +/// [`UNIX_EPOCH`]: ../../std/time/constant.UNIX_EPOCH.html +/// /// Example: /// /// ```no_run @@ -117,14 +122,38 @@ pub struct Instant(time::Instant); #[stable(feature = "time2", since = "1.8.0")] pub struct SystemTime(time::SystemTime); -/// An error returned from the `duration_since` method on `SystemTime`, -/// used to learn how far in the opposite direction a system time lies. +/// An error returned from the `duration_since` and `elapsed` methods on +/// `SystemTime`, used to learn how far in the opposite direction a system time +/// lies. +/// +/// # Examples +/// +/// ```no_run +/// use std::thread::sleep; +/// use std::time::{Duration, SystemTime}; +/// +/// let sys_time = SystemTime::now(); +/// sleep(Duration::from_secs(1)); +/// let new_sys_time = SystemTime::now(); +/// match sys_time.duration_since(new_sys_time) { +/// Ok(_) => {} +/// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), +/// } +/// ``` #[derive(Clone, Debug)] #[stable(feature = "time2", since = "1.8.0")] pub struct SystemTimeError(Duration); impl Instant { /// Returns an instant corresponding to "now". + /// + /// # Examples + /// + /// ``` + /// use std::time::Instant; + /// + /// let now = Instant::now(); + /// ``` #[stable(feature = "time2", since = "1.8.0")] pub fn now() -> Instant { Instant(time::Instant::now()) @@ -138,6 +167,18 @@ impl Instant { /// only be possible if `earlier` was created after `self`. Because /// `Instant` is monotonic, the only time that this should happen should be /// a bug. + /// + /// # Examples + /// + /// ```no_run + /// use std::time::{Duration, Instant}; + /// use std::thread::sleep; + /// + /// let now = Instant::now(); + /// sleep(Duration::new(1, 0)); + /// let new_now = Instant::now(); + /// println!("{:?}", new_now.duration_since(now)); + /// ``` #[stable(feature = "time2", since = "1.8.0")] pub fn duration_since(&self, earlier: Instant) -> Duration { self.0.sub_instant(&earlier.0) @@ -218,6 +259,14 @@ impl fmt::Debug for Instant { impl SystemTime { /// Returns the system time corresponding to "now". + /// + /// # Examples + /// + /// ``` + /// use std::time::SystemTime; + /// + /// let sys_time = SystemTime::now(); + /// ``` #[stable(feature = "time2", since = "1.8.0")] pub fn now() -> SystemTime { SystemTime(time::SystemTime::now()) @@ -229,11 +278,26 @@ impl SystemTime { /// guaranteed to always be before later measurements (due to anomalies such /// as the system clock being adjusted either forwards or backwards). /// - /// If successful, `Ok(Duration)` is returned where the duration represents + /// If successful, [`Ok`]`(`[`Duration`]`)` is returned where the duration represents /// the amount of time elapsed from the specified measurement to this one. /// - /// Returns an `Err` if `earlier` is later than `self`, and the error + /// Returns an [`Err`] if `earlier` is later than `self`, and the error /// contains how far from `self` the time is. + /// + /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok + /// [`Duration`]: ../../std/time/struct.Duration.html + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err + /// + /// # Examples + /// + /// ``` + /// use std::time::SystemTime; + /// + /// let sys_time = SystemTime::now(); + /// let difference = sys_time.duration_since(sys_time) + /// .expect("SystemTime::duration_since failed"); + /// println!("{:?}", difference); + /// ``` #[stable(feature = "time2", since = "1.8.0")] pub fn duration_since(&self, earlier: SystemTime) -> Result<Duration, SystemTimeError> { @@ -244,12 +308,28 @@ impl SystemTime { /// /// This function may fail as the underlying system clock is susceptible to /// drift and updates (e.g. the system clock could go backwards), so this - /// function may not always succeed. If successful, `Ok(duration)` is + /// function may not always succeed. If successful, [`Ok`]`(`[`Duration`]`)` is /// returned where the duration represents the amount of time elapsed from /// this time measurement to the current time. /// - /// Returns an `Err` if `self` is later than the current system time, and + /// Returns an [`Err`] if `self` is later than the current system time, and /// the error contains how far from the current system time `self` is. + /// + /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok + /// [`Duration`]: ../../std/time/struct.Duration.html + /// [`Err`]: ../../std/result/enum.Result.html#variant.Err + /// + /// # Examples + /// + /// ```no_run + /// use std::thread::sleep; + /// use std::time::{Duration, SystemTime}; + /// + /// let sys_time = SystemTime::now(); + /// let one_sec = Duration::from_secs(1); + /// sleep(one_sec); + /// assert!(sys_time.elapsed().unwrap() >= one_sec); + /// ``` #[stable(feature = "time2", since = "1.8.0")] pub fn elapsed(&self) -> Result<Duration, SystemTimeError> { SystemTime::now().duration_since(*self) @@ -300,9 +380,11 @@ impl fmt::Debug for SystemTime { /// /// This constant is defined to be "1970-01-01 00:00:00 UTC" on all systems with /// respect to the system clock. Using `duration_since` on an existing -/// `SystemTime` instance can tell how far away from this point in time a +/// [`SystemTime`] instance can tell how far away from this point in time a /// measurement lies, and using `UNIX_EPOCH + duration` can be used to create a -/// `SystemTime` instance to represent another fixed point in time. +/// [`SystemTime`] instance to represent another fixed point in time. +/// +/// [`SystemTime`]: ../../std/time/struct.SystemTime.html #[stable(feature = "time2", since = "1.8.0")] pub const UNIX_EPOCH: SystemTime = SystemTime(time::UNIX_EPOCH); @@ -310,9 +392,28 @@ impl SystemTimeError { /// Returns the positive duration which represents how far forward the /// second system time was from the first. /// - /// A `SystemTimeError` is returned from the `duration_since` - /// operation whenever the second system time represents a point later + /// A `SystemTimeError` is returned from the [`duration_since`] and [`elapsed`] + /// methods of [`SystemTime`] whenever the second system time represents a point later /// in time than the `self` of the method call. + /// + /// [`duration_since`]: ../../std/time/struct.SystemTime.html#method.duration_since + /// [`elapsed`]: ../../std/time/struct.SystemTime.html#method.elapsed + /// [`SystemTime`]: ../../std/time/struct.SystemTime.html + /// + /// # Examples + /// + /// ```no_run + /// use std::thread::sleep; + /// use std::time::{Duration, SystemTime}; + /// + /// let sys_time = SystemTime::now(); + /// sleep(Duration::from_secs(1)); + /// let new_sys_time = SystemTime::now(); + /// match sys_time.duration_since(new_sys_time) { + /// Ok(_) => {} + /// Err(e) => println!("SystemTimeError difference: {:?}", e.duration()), + /// } + /// ``` #[stable(feature = "time2", since = "1.8.0")] pub fn duration(&self) -> Duration { self.0 |
