about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorjohnthagen <johnthagen@users.noreply.github.com>2017-10-16 17:56:12 -0400
committerGitHub <noreply@github.com>2017-10-16 17:56:12 -0400
commitbd8497884c2863a10b6d67855bd90d40783ce2da (patch)
tree5fe9ffe7f65dbea1130217b5136264d4dbc7b513 /src/libstd
parent49a73d0901a60b1b77452b92372fd8629f636c2a (diff)
parent4e9527cf6f2d3749554d07a96fe14967f5470ef6 (diff)
downloadrust-bd8497884c2863a10b6d67855bd90d40783ce2da.tar.gz
rust-bd8497884c2863a10b6d67855bd90d40783ce2da.zip
Merge branch 'master' into future_imports
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/Cargo.toml1
-rw-r--r--src/libstd/build.rs12
-rw-r--r--src/libstd/collections/hash/table.rs32
-rw-r--r--src/libstd/ffi/c_str.rs251
-rw-r--r--src/libstd/ffi/mod.rs151
-rw-r--r--src/libstd/ffi/os_str.rs51
-rw-r--r--src/libstd/lib.rs2
-rw-r--r--src/libstd/net/tcp.rs15
-rw-r--r--src/libstd/process.rs122
-rw-r--r--src/libstd/sync/mpsc/cache_aligned.rs37
-rw-r--r--src/libstd/sync/mpsc/mod.rs26
-rw-r--r--src/libstd/sync/mpsc/select.rs18
-rw-r--r--src/libstd/sync/mpsc/spsc_queue.rs153
-rw-r--r--src/libstd/sync/mpsc/stream.rs105
-rw-r--r--src/libstd/sync/mutex.rs13
-rw-r--r--src/libstd/sync/rwlock.rs13
-rw-r--r--src/libstd/sys/unix/net.rs13
-rw-r--r--src/libstd/sys/windows/ext/ffi.rs56
-rw-r--r--src/libstd/sys_common/remutex.rs13
-rw-r--r--src/libstd/thread/mod.rs12
20 files changed, 835 insertions, 261 deletions
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index fb276448ffa..866c0038a7f 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -36,7 +36,6 @@ rustc_tsan = { path = "../librustc_tsan" }
 
 [build-dependencies]
 build_helper = { path = "../build_helper" }
-cc = "1.0"
 
 [features]
 backtrace = []
diff --git a/src/libstd/build.rs b/src/libstd/build.rs
index 7ca762c801a..0e6214ea04f 100644
--- a/src/libstd/build.rs
+++ b/src/libstd/build.rs
@@ -11,7 +11,6 @@
 #![deny(warnings)]
 
 extern crate build_helper;
-extern crate cc;
 
 use std::env;
 use std::process::Command;
@@ -77,12 +76,6 @@ fn main() {
 fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> {
     let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", ".libs")?;
 
-    let compiler = cc::Build::new().get_compiler();
-    // only msvc returns None for ar so unwrap is okay
-    let ar = build_helper::cc2ar(compiler.path(), target).unwrap();
-    let mut cflags = compiler.args().iter().map(|s| s.to_str().unwrap())
-                             .collect::<Vec<_>>().join(" ");
-    cflags.push_str(" -fvisibility=hidden");
     run(Command::new("sh")
                 .current_dir(&native.out_dir)
                 .arg(native.src_dir.join("configure").to_str().unwrap()
@@ -94,10 +87,7 @@ fn build_libbacktrace(host: &str, target: &str) -> Result<(), ()> {
                 .arg("--disable-host-shared")
                 .arg(format!("--host={}", build_helper::gnu_target(target)))
                 .arg(format!("--build={}", build_helper::gnu_target(host)))
-                .env("CC", compiler.path())
-                .env("AR", &ar)
-                .env("RANLIB", format!("{} s", ar.display()))
-                .env("CFLAGS", cflags),
+                .env("CFLAGS", env::var("CFLAGS").unwrap_or_default() + " -fvisibility=hidden"),
         BuildExpectation::None);
 
     run(Command::new(build_helper::make(host))
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs
index 93929637e2f..7e623a0af17 100644
--- a/src/libstd/collections/hash/table.rs
+++ b/src/libstd/collections/hash/table.rs
@@ -717,26 +717,25 @@ fn calculate_offsets(hashes_size: usize,
     (pairs_offset, end_of_pairs, oflo)
 }
 
-// Returns a tuple of (minimum required malloc alignment, hash_offset,
+// Returns a tuple of (minimum required malloc alignment,
 // array_size), from the start of a mallocated array.
 fn calculate_allocation(hash_size: usize,
                         hash_align: usize,
                         pairs_size: usize,
                         pairs_align: usize)
-                        -> (usize, usize, usize, bool) {
-    let hash_offset = 0;
+                        -> (usize, usize, bool) {
     let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align);
 
     let align = cmp::max(hash_align, pairs_align);
 
-    (align, hash_offset, end_of_pairs, oflo)
+    (align, end_of_pairs, oflo)
 }
 
 #[test]
 fn test_offset_calculation() {
-    assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 0, 144, false));
-    assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 0, 5, false));
-    assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 0, 20, false));
+    assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 144, false));
+    assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 5, false));
+    assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 20, false));
     assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false));
     assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false));
     assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false));
@@ -768,10 +767,10 @@ impl<K, V> RawTable<K, V> {
         // This is great in theory, but in practice getting the alignment
         // right is a little subtle. Therefore, calculating offsets has been
         // factored out into a different function.
-        let (alignment, hash_offset, size, oflo) = calculate_allocation(hashes_size,
-                                                                        align_of::<HashUint>(),
-                                                                        pairs_size,
-                                                                        align_of::<(K, V)>());
+        let (alignment, size, oflo) = calculate_allocation(hashes_size,
+                                                           align_of::<HashUint>(),
+                                                           pairs_size,
+                                                           align_of::<(K, V)>());
         assert!(!oflo, "capacity overflow");
 
         // One check for overflow that covers calculation and rounding of size.
@@ -784,7 +783,7 @@ impl<K, V> RawTable<K, V> {
         let buffer = Heap.alloc(Layout::from_size_align(size, alignment).unwrap())
             .unwrap_or_else(|e| Heap.oom(e));
 
-        let hashes = buffer.offset(hash_offset as isize) as *mut HashUint;
+        let hashes = buffer as *mut HashUint;
 
         RawTable {
             capacity_mask: capacity.wrapping_sub(1),
@@ -1157,6 +1156,7 @@ impl<K: Clone, V: Clone> Clone for RawTable<K, V> {
             }
 
             new_ht.size = self.size();
+            new_ht.set_tag(self.tag());
 
             new_ht
         }
@@ -1183,10 +1183,10 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
 
         let hashes_size = self.capacity() * size_of::<HashUint>();
         let pairs_size = self.capacity() * size_of::<(K, V)>();
-        let (align, _, size, oflo) = calculate_allocation(hashes_size,
-                                                          align_of::<HashUint>(),
-                                                          pairs_size,
-                                                          align_of::<(K, V)>());
+        let (align, size, oflo) = calculate_allocation(hashes_size,
+                                                       align_of::<HashUint>(),
+                                                       pairs_size,
+                                                       align_of::<(K, V)>());
 
         debug_assert!(!oflo, "should be impossible");
 
diff --git a/src/libstd/ffi/c_str.rs b/src/libstd/ffi/c_str.rs
index f9d80336477..b5460391942 100644
--- a/src/libstd/ffi/c_str.rs
+++ b/src/libstd/ffi/c_str.rs
@@ -23,19 +23,69 @@ use ptr;
 use slice;
 use str::{self, Utf8Error};
 
-/// A type representing an owned C-compatible string.
+/// A type representing an owned, C-compatible, nul-terminated string with no nul bytes in the
+/// middle.
 ///
-/// This type serves the primary purpose of being able to safely generate a
+/// This type serves the purpose of being able to safely generate a
 /// C-compatible string from a Rust byte slice or vector. An instance of this
 /// type is a static guarantee that the underlying bytes contain no interior 0
-/// bytes and the final byte is 0.
+/// bytes ("nul characters") and that the final byte is 0 ("nul terminator").
 ///
-/// A `CString` is created from either a byte slice or a byte vector. A [`u8`]
-/// slice can be obtained with the `as_bytes` method. Slices produced from a
-/// `CString` do *not* contain the trailing nul terminator unless otherwise
-/// specified.
+/// `CString` is to [`CStr`] as [`String`] is to [`&str`]: the former
+/// in each pair are owned strings; the latter are borrowed
+/// references.
 ///
+/// # Creating a `CString`
+///
+/// A `CString` is created from either a byte slice or a byte vector,
+/// or anything that implements [`Into`]`<`[`Vec`]`<`[`u8`]`>>` (for
+/// example, you can build a `CString` straight out of a [`String`] or
+/// a [`&str`], since both implement that trait).
+///
+/// The [`new`] method will actually check that the provided `&[u8]`
+/// does not have 0 bytes in the middle, and return an error if it
+/// finds one.
+///
+/// # Extracting a raw pointer to the whole C string
+///
+/// `CString` implements a [`as_ptr`] method through the [`Deref`]
+/// trait. This method will give you a `*const c_char` which you can
+/// feed directly to extern functions that expect a nul-terminated
+/// string, like C's `strdup()`.
+///
+/// # Extracting a slice of the whole C string
+///
+/// Alternatively, you can obtain a `&[`[`u8`]`]` slice from a
+/// `CString` with the [`as_bytes`] method. Slices produced in this
+/// way do *not* contain the trailing nul terminator. This is useful
+/// when you will be calling an extern function that takes a `*const
+/// u8` argument which is not necessarily nul-terminated, plus another
+/// argument with the length of the string — like C's `strndup()`.
+/// You can of course get the slice's length with its
+/// [`len`][slice.len] method.
+///
+/// If you need a `&[`[`u8`]`]` slice *with* the nul terminator, you
+/// can use [`as_bytes_with_nul`] instead.
+///
+/// Once you have the kind of slice you need (with or without a nul
+/// terminator), you can call the slice's own
+/// [`as_ptr`][slice.as_ptr] method to get a raw pointer to pass to
+/// extern functions. See the documentation for that function for a
+/// discussion on ensuring the lifetime of the raw pointer.
+///
+/// [`Into`]: ../convert/trait.Into.html
+/// [`Vec`]: ../vec/struct.Vec.html
+/// [`String`]: ../string/struct.String.html
+/// [`&str`]: ../primitive.str.html
 /// [`u8`]: ../primitive.u8.html
+/// [`new`]: #method.new
+/// [`as_bytes`]: #method.as_bytes
+/// [`as_bytes_with_nul`]: #method.as_bytes_with_nul
+/// [`as_ptr`]: #method.as_ptr
+/// [slice.as_ptr]: ../primitive.slice.html#method.as_ptr
+/// [slice.len]: ../primitive.slice.html#method.len
+/// [`Deref`]: ../ops/trait.Deref.html
+/// [`CStr`]: struct.CStr.html
 ///
 /// # Examples
 ///
@@ -48,6 +98,8 @@ use str::{self, Utf8Error};
 ///     fn my_printer(s: *const c_char);
 /// }
 ///
+/// // We are certain that our string doesn't have 0 bytes in the middle,
+/// // so we can .unwrap()
 /// let c_to_print = CString::new("Hello, world!").unwrap();
 /// unsafe {
 ///     my_printer(c_to_print.as_ptr());
@@ -58,7 +110,7 @@ use str::{self, Utf8Error};
 /// # Safety
 ///
 /// `CString` is intended for working with traditional C-style strings
-/// (a sequence of non-null bytes terminated by a single null byte); the
+/// (a sequence of non-nul bytes terminated by a single nul byte); the
 /// primary use case for these kinds of strings is interoperating with C-like
 /// code. Often you will need to transfer ownership to/from that external
 /// code. It is strongly recommended that you thoroughly read through the
@@ -77,17 +129,21 @@ pub struct CString {
 
 /// Representation of a borrowed C string.
 ///
-/// This dynamically sized type is only safely constructed via a borrowed
-/// version of an instance of `CString`. This type can be constructed from a raw
-/// C string as well and represents a C string borrowed from another location.
+/// This type represents a borrowed reference to a nul-terminated
+/// array of bytes. It can be constructed safely from a `&[`[`u8`]`]`
+/// slice, or unsafely from a raw `*const c_char`. It can then be
+/// converted to a Rust [`&str`] by performing UTF-8 validation, or
+/// into an owned [`CString`].
+///
+/// `CStr` is to [`CString`] as [`&str`] is to [`String`]: the former
+/// in each pair are borrowed references; the latter are owned
+/// strings.
 ///
 /// Note that this structure is **not** `repr(C)` and is not recommended to be
-/// placed in the signatures of FFI functions. Instead safe wrappers of FFI
+/// placed in the signatures of FFI functions. Instead, safe wrappers of FFI
 /// functions may leverage the unsafe [`from_ptr`] constructor to provide a safe
 /// interface to other consumers.
 ///
-/// [`from_ptr`]: #method.from_ptr
-///
 /// # Examples
 ///
 /// Inspecting a foreign C string:
@@ -100,7 +156,7 @@ pub struct CString {
 ///
 /// unsafe {
 ///     let slice = CStr::from_ptr(my_string());
-///     println!("string length: {}", slice.to_bytes().len());
+///     println!("string buffer size without nul terminator: {}", slice.to_bytes().len());
 /// }
 /// ```
 ///
@@ -122,8 +178,6 @@ pub struct CString {
 ///
 /// Converting a foreign C string into a Rust [`String`]:
 ///
-/// [`String`]: ../string/struct.String.html
-///
 /// ```no_run
 /// use std::ffi::CStr;
 /// use std::os::raw::c_char;
@@ -138,6 +192,12 @@ pub struct CString {
 ///
 /// println!("string: {}", my_string_safe());
 /// ```
+///
+/// [`u8`]: ../primitive.u8.html
+/// [`&str`]: ../primitive.str.html
+/// [`String`]: ../string/struct.String.html
+/// [`CString`]: struct.CString.html
+/// [`from_ptr`]: #method.from_ptr
 #[derive(Hash)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct CStr {
@@ -148,9 +208,15 @@ pub struct CStr {
     inner: [c_char]
 }
 
-/// An error returned from [`CString::new`] to indicate that a nul byte was found
-/// in the vector provided.
+/// An error indicating that an interior nul byte was found.
+///
+/// While Rust strings may contain nul bytes in the middle, C strings
+/// can't, as that byte would effectively truncate the string.
 ///
+/// This error is created by the [`new`][`CString::new`] method on
+/// [`CString`]. See its documentation for more.
+///
+/// [`CString`]: struct.CString.html
 /// [`CString::new`]: struct.CString.html#method.new
 ///
 /// # Examples
@@ -164,9 +230,16 @@ pub struct CStr {
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct NulError(usize, Vec<u8>);
 
-/// An error returned from [`CStr::from_bytes_with_nul`] to indicate that a nul
-/// byte was found too early in the slice provided or one wasn't found at all.
+/// An error indicating that a nul byte was not in the expected position.
+///
+/// The slice used to create a [`CStr`] must have one and only one nul
+/// byte at the end of the slice.
 ///
+/// This error is created by the
+/// [`from_bytes_with_nul`][`CStr::from_bytes_with_nul`] method on
+/// [`CStr`]. See its documentation for more.
+///
+/// [`CStr`]: struct.CStr.html
 /// [`CStr::from_bytes_with_nul`]: struct.CStr.html#method.from_bytes_with_nul
 ///
 /// # Examples
@@ -201,9 +274,18 @@ impl FromBytesWithNulError {
     }
 }
 
-/// An error returned from [`CString::into_string`] to indicate that a UTF-8 error
-/// was encountered during the conversion.
+/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
+///
+/// `CString` is just a wrapper over a buffer of bytes with a nul
+/// terminator; [`into_string`][`CString::into_string`] performs UTF-8
+/// validation on those bytes and may return this error.
+///
+/// This `struct` is created by the
+/// [`into_string`][`CString::into_string`] method on [`CString`]. See
+/// its documentation for more.
 ///
+/// [`String`]: ../string/struct.String.html
+/// [`CString`]: struct.CString.html
 /// [`CString::into_string`]: struct.CString.html#method.into_string
 #[derive(Clone, PartialEq, Eq, Debug)]
 #[stable(feature = "cstring_into", since = "1.7.0")]
@@ -215,8 +297,11 @@ pub struct IntoStringError {
 impl CString {
     /// Creates a new C-compatible string from a container of bytes.
     ///
-    /// This method will consume the provided data and use the underlying bytes
-    /// to construct a new string, ensuring that there is a trailing 0 byte.
+    /// This function will consume the provided data and use the
+    /// underlying bytes to construct a new string, ensuring that
+    /// there is a trailing 0 byte. This trailing 0 byte will be
+    /// appended by this function; the provided data should *not*
+    /// contain any 0 bytes in it.
     ///
     /// # Examples
     ///
@@ -234,9 +319,11 @@ impl CString {
     ///
     /// # Errors
     ///
-    /// This function will return an error if the bytes yielded contain an
-    /// internal 0 byte. The error returned will contain the bytes as well as
+    /// This function will return an error if the supplied bytes contain an
+    /// internal 0 byte. The [`NulError`] returned will contain the bytes as well as
     /// the position of the nul byte.
+    ///
+    /// [`NulError`]: struct.NulError.html
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> {
         Self::_new(t.into())
@@ -249,8 +336,8 @@ impl CString {
         }
     }
 
-    /// Creates a C-compatible string from a byte vector without checking for
-    /// interior 0 bytes.
+    /// Creates a C-compatible string by consuming a byte vector,
+    /// without checking for interior 0 bytes.
     ///
     /// This method is equivalent to [`new`] except that no runtime assertion
     /// is made that `v` contains no 0 bytes, and it requires an actual
@@ -275,7 +362,7 @@ impl CString {
         CString { inner: v.into_boxed_slice() }
     }
 
-    /// Retakes ownership of a `CString` that was transferred to C.
+    /// Retakes ownership of a `CString` that was transferred to C via [`into_raw`].
     ///
     /// Additionally, the length of the string will be recalculated from the pointer.
     ///
@@ -286,7 +373,14 @@ impl CString {
     /// ownership of a string that was allocated by foreign code) is likely to lead
     /// to undefined behavior or allocator corruption.
     ///
+    /// > **Note:** If you need to borrow a string that was allocated by
+    /// > foreign code, use [`CStr`]. If you need to take ownership of
+    /// > a string that was allocated by foreign code, you will need to
+    /// > make your own provisions for freeing it appropriately, likely
+    /// > with the foreign code's API to do that.
+    ///
     /// [`into_raw`]: #method.into_raw
+    /// [`CStr`]: struct.CStr.html
     ///
     /// # Examples
     ///
@@ -315,11 +409,11 @@ impl CString {
         CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) }
     }
 
-    /// Transfers ownership of the string to a C caller.
+    /// Consumes the `CString` and transfers ownership of the string to a C caller.
     ///
-    /// The pointer must be returned to Rust and reconstituted using
+    /// The pointer which this function returns must be returned to Rust and reconstituted using
     /// [`from_raw`] to be properly deallocated. Specifically, one
-    /// should *not* use the standard C `free` function to deallocate
+    /// should *not* use the standard C `free()` function to deallocate
     /// this string.
     ///
     /// Failure to call [`from_raw`] will lead to a memory leak.
@@ -351,11 +445,27 @@ impl CString {
         Box::into_raw(self.into_inner()) as *mut c_char
     }
 
-    /// Converts the `CString` into a [`String`] if it contains valid Unicode data.
+    /// Converts the `CString` into a [`String`] if it contains valid UTF-8 data.
     ///
     /// On failure, ownership of the original `CString` is returned.
     ///
     /// [`String`]: ../string/struct.String.html
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// use std::ffi::CString;
+    ///
+    /// let valid_utf8 = vec![b'f', b'o', b'o'];
+    /// let cstring = CString::new(valid_utf8).unwrap();
+    /// assert_eq!(cstring.into_string().unwrap(), "foo");
+    ///
+    /// let invalid_utf8 = vec![b'f', 0xff, b'o', b'o'];
+    /// let cstring = CString::new(invalid_utf8).unwrap();
+    /// let err = cstring.into_string().err().unwrap();
+    /// assert_eq!(err.utf8_error().valid_up_to(), 1);
+    /// ```
+
     #[stable(feature = "cstring_into", since = "1.7.0")]
     pub fn into_string(self) -> Result<String, IntoStringError> {
         String::from_utf8(self.into_bytes())
@@ -365,10 +475,11 @@ impl CString {
             })
     }
 
-    /// Returns the underlying byte buffer.
+    /// Consumes the `CString` and returns the underlying byte buffer.
     ///
-    /// The returned buffer does **not** contain the trailing nul separator and
-    /// it is guaranteed to not have any interior nul bytes.
+    /// The returned buffer does **not** contain the trailing nul
+    /// terminator, and it is guaranteed to not have any interior nul
+    /// bytes.
     ///
     /// # Examples
     ///
@@ -388,7 +499,7 @@ impl CString {
     }
 
     /// Equivalent to the [`into_bytes`] function except that the returned vector
-    /// includes the trailing nul byte.
+    /// includes the trailing nul terminator.
     ///
     /// [`into_bytes`]: #method.into_bytes
     ///
@@ -408,8 +519,12 @@ impl CString {
 
     /// Returns the contents of this `CString` as a slice of bytes.
     ///
-    /// The returned slice does **not** contain the trailing nul separator and
-    /// it is guaranteed to not have any interior nul bytes.
+    /// The returned slice does **not** contain the trailing nul
+    /// terminator, and it is guaranteed to not have any interior nul
+    /// bytes. If you need the nul terminator, use
+    /// [`as_bytes_with_nul`] instead.
+    ///
+    /// [`as_bytes_with_nul`]: #method.as_bytes_with_nul
     ///
     /// # Examples
     ///
@@ -427,7 +542,7 @@ impl CString {
     }
 
     /// Equivalent to the [`as_bytes`] function except that the returned slice
-    /// includes the trailing nul byte.
+    /// includes the trailing nul terminator.
     ///
     /// [`as_bytes`]: #method.as_bytes
     ///
@@ -598,8 +713,8 @@ impl Default for Box<CStr> {
 }
 
 impl NulError {
-    /// Returns the position of the nul byte in the slice that was provided to
-    /// [`CString::new`].
+    /// Returns the position of the nul byte in the slice that caused
+    /// [`CString::new`] to fail.
     ///
     /// [`CString::new`]: struct.CString.html#method.new
     ///
@@ -711,9 +826,9 @@ impl fmt::Display for IntoStringError {
 }
 
 impl CStr {
-    /// Casts a raw C string to a safe C string wrapper.
+    /// Wraps a raw C string with a safe C string wrapper.
     ///
-    /// This function will cast the provided `ptr` to the `CStr` wrapper which
+    /// This function will wrap the provided `ptr` with a `CStr` wrapper, which
     /// allows inspection and interoperation of non-owned C strings. This method
     /// is unsafe for a number of reasons:
     ///
@@ -753,9 +868,9 @@ impl CStr {
 
     /// Creates a C string wrapper from a byte slice.
     ///
-    /// This function will cast the provided `bytes` to a `CStr` wrapper after
-    /// ensuring that it is null terminated and does not contain any interior
-    /// nul bytes.
+    /// This function will cast the provided `bytes` to a `CStr`
+    /// wrapper after ensuring that the byte slice is nul-terminated
+    /// and does not contain any interior nul bytes.
     ///
     /// # Examples
     ///
@@ -766,7 +881,7 @@ impl CStr {
     /// assert!(cstr.is_ok());
     /// ```
     ///
-    /// Creating a `CStr` without a trailing nul byte is an error:
+    /// Creating a `CStr` without a trailing nul terminator is an error:
     ///
     /// ```
     /// use std::ffi::CStr;
@@ -800,7 +915,7 @@ impl CStr {
     /// Unsafely creates a C string wrapper from a byte slice.
     ///
     /// This function will cast the provided `bytes` to a `CStr` wrapper without
-    /// performing any sanity checks. The provided slice must be null terminated
+    /// performing any sanity checks. The provided slice **must** be nul-terminated
     /// and not contain any interior nul bytes.
     ///
     /// # Examples
@@ -822,7 +937,7 @@ impl CStr {
 
     /// Returns the inner pointer to this C string.
     ///
-    /// The returned pointer will be valid for as long as `self` is and points
+    /// The returned pointer will be valid for as long as `self` is, and points
     /// to a contiguous region of memory terminated with a 0 byte to represent
     /// the end of the string.
     ///
@@ -843,9 +958,9 @@ impl CStr {
     /// ```
     ///
     /// This happens because the pointer returned by `as_ptr` does not carry any
-    /// lifetime information and the string is deallocated immediately after
+    /// lifetime information and the [`CString`] is deallocated immediately after
     /// the `CString::new("Hello").unwrap().as_ptr()` expression is evaluated.
-    /// To fix the problem, bind the string to a local variable:
+    /// To fix the problem, bind the `CString` to a local variable:
     ///
     /// ```no_run
     /// use std::ffi::{CString};
@@ -857,6 +972,11 @@ impl CStr {
     ///     *ptr;
     /// }
     /// ```
+    ///
+    /// This way, the lifetime of the `CString` in `hello` encompasses
+    /// the lifetime of `ptr` and the `unsafe` block.
+    ///
+    /// [`CString`]: struct.CString.html
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn as_ptr(&self) -> *const c_char {
@@ -865,11 +985,7 @@ impl CStr {
 
     /// Converts this C string to a byte slice.
     ///
-    /// This function will calculate the length of this string (which normally
-    /// requires a linear amount of work to be done) and then return the
-    /// resulting slice of `u8` elements.
-    ///
-    /// The returned slice will **not** contain the trailing nul that this C
+    /// The returned slice will **not** contain the trailing nul terminator that this C
     /// string has.
     ///
     /// > **Note**: This method is currently implemented as a 0-cost cast, but
@@ -894,7 +1010,7 @@ impl CStr {
     /// Converts this C string to a byte slice containing the trailing 0 byte.
     ///
     /// This function is the equivalent of [`to_bytes`] except that it will retain
-    /// the trailing nul instead of chopping it off.
+    /// the trailing nul terminator instead of chopping it off.
     ///
     /// > **Note**: This method is currently implemented as a 0-cost cast, but
     /// > it is planned to alter its definition in the future to perform the
@@ -918,8 +1034,9 @@ impl CStr {
 
     /// Yields a [`&str`] slice if the `CStr` contains valid UTF-8.
     ///
-    /// This function will calculate the length of this string and check for
-    /// UTF-8 validity, and then return the [`&str`] if it's valid.
+    /// If the contents of the `CStr` are valid UTF-8 data, this
+    /// function will return the corresponding [`&str`] slice. Otherwise,
+    /// it will return an error with details of where UTF-8 validation failed.
     ///
     /// > **Note**: This method is currently implemented to check for validity
     /// > after a 0-cost cast, but it is planned to alter its definition in the
@@ -947,10 +1064,12 @@ impl CStr {
 
     /// Converts a `CStr` into a [`Cow`]`<`[`str`]`>`.
     ///
-    /// This function will calculate the length of this string (which normally
-    /// requires a linear amount of work to be done) and then return the
-    /// resulting slice as a [`Cow`]`<`[`str`]`>`, replacing any invalid UTF-8 sequences
-    /// with `U+FFFD REPLACEMENT CHARACTER`.
+    /// If the contents of the `CStr` are valid UTF-8 data, this
+    /// function will return a [`Cow`]`::`[`Borrowed`]`(`[`&str`]`)`
+    /// with the the corresponding [`&str`] slice. Otherwise, it will
+    /// replace any invalid UTF-8 sequences with `U+FFFD REPLACEMENT
+    /// CHARACTER` and return a [`Cow`]`::`[`Owned`]`(`[`String`]`)`
+    /// with the result.
     ///
     /// > **Note**: This method is currently implemented to check for validity
     /// > after a 0-cost cast, but it is planned to alter its definition in the
@@ -958,7 +1077,9 @@ impl CStr {
     /// > check whenever this method is called.
     ///
     /// [`Cow`]: ../borrow/enum.Cow.html
+    /// [`Borrowed`]: ../borrow/enum.Cow.html#variant.Borrowed
     /// [`str`]: ../primitive.str.html
+    /// [`String`]: ../string/struct.String.html
     ///
     /// # Examples
     ///
diff --git a/src/libstd/ffi/mod.rs b/src/libstd/ffi/mod.rs
index ca1ff18f1ca..a75596351e4 100644
--- a/src/libstd/ffi/mod.rs
+++ b/src/libstd/ffi/mod.rs
@@ -9,6 +9,157 @@
 // except according to those terms.
 
 //! Utilities related to FFI bindings.
+//!
+//! This module provides utilities to handle data across non-Rust
+//! interfaces, like other programming languages and the underlying
+//! operating system. It is mainly of use for FFI (Foreign Function
+//! Interface) bindings and code that needs to exchange C-like strings
+//! with other languages.
+//!
+//! # Overview
+//!
+//! Rust represents owned strings with the [`String`] type, and
+//! borrowed slices of strings with the [`str`] primitive. Both are
+//! always in UTF-8 encoding, and may contain nul bytes in the middle,
+//! i.e. if you look at the bytes that make up the string, there may
+//! be a `\0` among them. Both `String` and `str` store their length
+//! explicitly; there are no nul terminators at the end of strings
+//! like in C.
+//!
+//! C strings are different from Rust strings:
+//!
+//! * **Encodings** - Rust strings are UTF-8, but C strings may use
+//! other encodings. If you are using a string from C, you should
+//! check its encoding explicitly, rather than just assuming that it
+//! is UTF-8 like you can do in Rust.
+//!
+//! * **Character size** - C strings may use `char` or `wchar_t`-sized
+//! characters; please **note** that C's `char` is different from Rust's.
+//! The C standard leaves the actual sizes of those types open to
+//! interpretation, but defines different APIs for strings made up of
+//! each character type. Rust strings are always UTF-8, so different
+//! Unicode characters will be encoded in a variable number of bytes
+//! each. The Rust type [`char`] represents a '[Unicode scalar
+//! value]', which is similar to, but not the same as, a '[Unicode
+//! code point]'.
+//!
+//! * **Nul terminators and implicit string lengths** - Often, C
+//! strings are nul-terminated, i.e. they have a `\0` character at the
+//! end. The length of a string buffer is not stored, but has to be
+//! calculated; to compute the length of a string, C code must
+//! manually call a function like `strlen()` for `char`-based strings,
+//! or `wcslen()` for `wchar_t`-based ones. Those functions return
+//! the number of characters in the string excluding the nul
+//! terminator, so the buffer length is really `len+1` characters.
+//! Rust strings don't have a nul terminator; their length is always
+//! stored and does not need to be calculated. While in Rust
+//! accessing a string's length is a O(1) operation (becasue the
+//! length is stored); in C it is an O(length) operation because the
+//! length needs to be computed by scanning the string for the nul
+//! terminator.
+//!
+//! * **Internal nul characters** - When C strings have a nul
+//! terminator character, this usually means that they cannot have nul
+//! characters in the middle — a nul character would essentially
+//! truncate the string. Rust strings *can* have nul characters in
+//! the middle, because nul does not have to mark the end of the
+//! string in Rust.
+//!
+//! # Representations of non-Rust strings
+//!
+//! [`CString`] and [`CStr`] are useful when you need to transfer
+//! UTF-8 strings to and from languages with a C ABI, like Python.
+//!
+//! * **From Rust to C:** [`CString`] represents an owned, C-friendly
+//! string: it is nul-terminated, and has no internal nul characters.
+//! Rust code can create a `CString` out of a normal string (provided
+//! that the string doesn't have nul characters in the middle), and
+//! then use a variety of methods to obtain a raw `*mut u8` that can
+//! then be passed as an argument to functions which use the C
+//! conventions for strings.
+//!
+//! * **From C to Rust:** [`CStr`] represents a borrowed C string; it
+//! is what you would use to wrap a raw `*const u8` that you got from
+//! a C function. A `CStr` is guaranteed to be a nul-terminated array
+//! of bytes. Once you have a `CStr`, you can convert it to a Rust
+//! `&str` if it's valid UTF-8, or lossily convert it by adding
+//! replacement characters.
+//!
+//! [`OsString`] and [`OsStr`] are useful when you need to transfer
+//! strings to and from the operating system itself, or when capturing
+//! the output of external commands. Conversions between `OsString`,
+//! `OsStr` and Rust strings work similarly to those for [`CString`]
+//! and [`CStr`].
+//!
+//! * [`OsString`] represents an owned string in whatever
+//! representation the operating system prefers. In the Rust standard
+//! library, various APIs that transfer strings to/from the operating
+//! system use `OsString` instead of plain strings. For example,
+//! [`env::var_os()`] is used to query environment variables; it
+//! returns an `Option<OsString>`. If the environment variable exists
+//! you will get a `Some(os_string)`, which you can *then* try to
+//! convert to a Rust string. This yields a [`Result<>`], so that
+//! your code can detect errors in case the environment variable did
+//! not in fact contain valid Unicode data.
+//!
+//! * [`OsStr`] represents a borrowed reference to a string in a
+//! format that can be passed to the operating system. It can be
+//! converted into an UTF-8 Rust string slice in a similar way to
+//! `OsString`.
+//!
+//! # Conversions
+//!
+//! ## On Unix
+//!
+//! On Unix, [`OsStr`] implements the
+//! `std::os::unix:ffi::`[`OsStrExt`][unix.OsStrExt] trait, which
+//! augments it with two methods, [`from_bytes`] and [`as_bytes`].
+//! These do inexpensive conversions from and to UTF-8 byte slices.
+//!
+//! Additionally, on Unix [`OsString`] implements the
+//! `std::os::unix:ffi::`[`OsStringExt`][unix.OsStringExt] trait,
+//! which provides [`from_vec`] and [`into_vec`] methods that consume
+//! their arguments, and take or produce vectors of [`u8`].
+//!
+//! ## On Windows
+//!
+//! On Windows, [`OsStr`] implements the
+//! `std::os::windows::ffi::`[`OsStrExt`][windows.OsStrExt] trait,
+//! which provides an [`encode_wide`] method. This provides an
+//! iterator that can be [`collect`]ed into a vector of [`u16`].
+//!
+//! Additionally, on Windows [`OsString`] implements the
+//! `std::os::windows:ffi::`[`OsStringExt`][windows.OsStringExt]
+//! trait, which provides a [`from_wide`] method. The result of this
+//! method is an `OsString` which can be round-tripped to a Windows
+//! string losslessly.
+//!
+//! [`String`]: ../string/struct.String.html
+//! [`str`]: ../primitive.str.html
+//! [`char`]: ../primitive.char.html
+//! [`u8`]: ../primitive.u8.html
+//! [`u16`]: ../primitive.u16.html
+//! [Unicode scalar value]: http://www.unicode.org/glossary/#unicode_scalar_value
+//! [Unicode code point]: http://www.unicode.org/glossary/#code_point
+//! [`CString`]: struct.CString.html
+//! [`CStr`]: struct.CStr.html
+//! [`OsString`]: struct.OsString.html
+//! [`OsStr`]: struct.OsStr.html
+//! [`env::set_var()`]: ../env/fn.set_var.html
+//! [`env::var_os()`]: ../env/fn.var_os.html
+//! [`Result<>`]: ../result/enum.Result.html
+//! [unix.OsStringExt]: ../os/unix/ffi/trait.OsStringExt.html
+//! [`from_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.from_vec
+//! [`into_vec`]: ../os/unix/ffi/trait.OsStringExt.html#tymethod.into_vec
+//! [unix.OsStrExt]: ../os/unix/ffi/trait.OsStrExt.html
+//! [`from_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.from_bytes
+//! [`as_bytes`]: ../os/unix/ffi/trait.OsStrExt.html#tymethod.as_bytes
+//! [`OsStrExt`]: ../os/unix/ffi/trait.OsStrExt.html
+//! [windows.OsStrExt]: ../os/windows/ffi/trait.OsStrExt.html
+//! [`encode_wide`]: ../os/windows/ffi/trait.OsStrExt.html#tymethod.encode_wide
+//! [`collect`]: ../iter/trait.Iterator.html#method.collect
+//! [windows.OsStringExt]: ../os/windows/ffi/trait.OsStringExt.html
+//! [`from_wide`]: ../os/windows/ffi/trait.OsStringExt.html#tymethod.from_wide
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index 88ee5c9a734..a97075ff8d8 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -32,18 +32,65 @@ use sys_common::{AsInner, IntoInner, FromInner};
 ///
 /// `OsString` and [`OsStr`] bridge this gap by simultaneously representing Rust
 /// and platform-native string values, and in particular allowing a Rust string
-/// to be converted into an "OS" string with no cost.
+/// to be converted into an "OS" string with no cost if possible.
+///
+/// `OsString` is to [`OsStr`] as [`String`] is to [`&str`]: the former
+/// in each pair are owned strings; the latter are borrowed
+/// references.
+///
+/// # Creating an `OsString`
+///
+/// **From a Rust string**: `OsString` implements
+/// [`From`]`<`[`String`]`>`, so you can use `my_string.`[`from`] to
+/// create an `OsString` from a normal Rust string.
+///
+/// **From slices:** Just like you can start with an empty Rust
+/// [`String`] and then [`push_str`][String.push_str] `&str`
+/// sub-string slices into it, you can create an empty `OsString` with
+/// the [`new`] method and then push string slices into it with the
+/// [`push`] method.
+///
+/// # Extracting a borrowed reference to the whole OS string
+///
+/// You can use the [`as_os_str`] method to get an `&`[`OsStr`] from
+/// an `OsString`; this is effectively a borrowed reference to the
+/// whole string.
+///
+/// # Conversions
+///
+/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
+/// the traits which `OsString` implements for conversions from/to native representations.
 ///
 /// [`OsStr`]: struct.OsStr.html
+/// [`From`]: ../convert/trait.From.html
+/// [`from`]: ../convert/trait.From.html#tymethod.from
+/// [`String`]: ../string/struct.String.html
+/// [`&str`]: ../primitive.str.html
+/// [`u8`]: ../primitive.u8.html
+/// [`u16`]: ../primitive.u16.html
+/// [String.push_str]: ../string/struct.String.html#method.push_str
+/// [`new`]: #method.new
+/// [`push`]: #method.push
+/// [`as_os_str`]: #method.as_os_str
 #[derive(Clone)]
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OsString {
     inner: Buf
 }
 
-/// Slices into OS strings (see [`OsString`]).
+/// Borrowed reference to an OS string (see [`OsString`]).
+///
+/// This type represents a borrowed reference to a string in the operating system's preferred
+/// representation.
+///
+/// `OsStr` is to [`OsString`] as [`String`] is to [`&str`]: the former in each pair are borrowed
+/// references; the latter are owned strings.
+///
+/// See the [module's toplevel documentation about conversions][conversions] for a discussion on
+/// the traits which `OsStr` implements for conversions from/to native representations.
 ///
 /// [`OsString`]: struct.OsString.html
+/// [conversions]: index.html#conversions
 #[stable(feature = "rust1", since = "1.0.0")]
 pub struct OsStr {
     inner: Slice
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 9fc7e2c01aa..83cc9ce582e 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -244,6 +244,7 @@
 #![feature(allow_internal_unstable)]
 #![feature(align_offset)]
 #![feature(asm)]
+#![feature(attr_literals)]
 #![feature(box_syntax)]
 #![feature(cfg_target_has_atomic)]
 #![feature(cfg_target_thread_local)]
@@ -290,6 +291,7 @@
 #![feature(prelude_import)]
 #![feature(rand)]
 #![feature(raw)]
+#![feature(repr_align)]
 #![feature(repr_simd)]
 #![feature(rustc_attrs)]
 #![cfg_attr(not(stage0), feature(rustc_const_unstable))]
diff --git a/src/libstd/net/tcp.rs b/src/libstd/net/tcp.rs
index b904641a336..4656cc5a7a7 100644
--- a/src/libstd/net/tcp.rs
+++ b/src/libstd/net/tcp.rs
@@ -1580,6 +1580,21 @@ mod tests {
     }
 
     #[test]
+    fn connect_timeout_unbound() {
+        // bind and drop a socket to track down a "probably unassigned" port
+        let socket = TcpListener::bind("127.0.0.1:0").unwrap();
+        let addr = socket.local_addr().unwrap();
+        drop(socket);
+
+        let timeout = Duration::from_secs(1);
+        let e = TcpStream::connect_timeout(&addr, timeout).unwrap_err();
+        assert!(e.kind() == io::ErrorKind::ConnectionRefused ||
+                e.kind() == io::ErrorKind::TimedOut ||
+                e.kind() == io::ErrorKind::Other,
+                "bad error: {} {:?}", e, e.kind());
+    }
+
+    #[test]
     fn connect_timeout_valid() {
         let listener = TcpListener::bind("127.0.0.1:0").unwrap();
         let addr = listener.local_addr().unwrap();
diff --git a/src/libstd/process.rs b/src/libstd/process.rs
index dbb58991215..f448cffd372 100644
--- a/src/libstd/process.rs
+++ b/src/libstd/process.rs
@@ -702,6 +702,15 @@ impl AsInnerMut<imp::Command> for Command {
 }
 
 /// The output of a finished process.
+///
+/// This is returned in a Result by either the [`output`] method of a
+/// [`Command`], or the [`wait_with_output`] method of a [`Child`]
+/// process.
+///
+/// [`Command`]: struct.Command.html
+/// [`Child`]: struct.Child.html
+/// [`output`]: struct.Command.html#method.output
+/// [`wait_with_output`]: struct.Child.html#method.wait_with_output
 #[derive(PartialEq, Eq, Clone)]
 #[stable(feature = "process", since = "1.0.0")]
 pub struct Output {
@@ -742,21 +751,128 @@ impl fmt::Debug for Output {
     }
 }
 
-/// Describes what to do with a standard I/O stream for a child process.
+/// Describes what to do with a standard I/O stream for a child process when
+/// passed to the [`stdin`], [`stdout`], and [`stderr`] methods of [`Command`].
+///
+/// [`stdin`]: struct.Command.html#method.stdin
+/// [`stdout`]: struct.Command.html#method.stdout
+/// [`stderr`]: struct.Command.html#method.stderr
+/// [`Command`]: struct.Command.html
 #[stable(feature = "process", since = "1.0.0")]
 pub struct Stdio(imp::Stdio);
 
 impl Stdio {
     /// A new pipe should be arranged to connect the parent and child processes.
+    ///
+    /// # Examples
+    ///
+    /// With stdout:
+    ///
+    /// ```no_run
+    /// use std::process::{Command, Stdio};
+    ///
+    /// let output = Command::new("echo")
+    ///     .arg("Hello, world!")
+    ///     .stdout(Stdio::piped())
+    ///     .output()
+    ///     .expect("Failed to execute command");
+    ///
+    /// assert_eq!(String::from_utf8_lossy(&output.stdout), "Hello, world!\n");
+    /// // Nothing echoed to console
+    /// ```
+    ///
+    /// With stdin:
+    ///
+    /// ```no_run
+    /// use std::io::Write;
+    /// use std::process::{Command, Stdio};
+    ///
+    /// let mut child = Command::new("rev")
+    ///     .stdin(Stdio::piped())
+    ///     .stdout(Stdio::piped())
+    ///     .spawn()
+    ///     .expect("Failed to spawn child process");
+    ///
+    /// {
+    ///     let mut stdin = child.stdin.as_mut().expect("Failed to open stdin");
+    ///     stdin.write_all("Hello, world!".as_bytes()).expect("Failed to write to stdin");
+    /// }
+    ///
+    /// let output = child.wait_with_output().expect("Failed to read stdout");
+    /// assert_eq!(String::from_utf8_lossy(&output.stdout), "!dlrow ,olleH\n");
+    /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn piped() -> Stdio { Stdio(imp::Stdio::MakePipe) }
 
     /// The child inherits from the corresponding parent descriptor.
+    ///
+    /// # Examples
+    ///
+    /// With stdout:
+    ///
+    /// ```no_run
+    /// use std::process::{Command, Stdio};
+    ///
+    /// let output = Command::new("echo")
+    ///     .arg("Hello, world!")
+    ///     .stdout(Stdio::inherit())
+    ///     .output()
+    ///     .expect("Failed to execute command");
+    ///
+    /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
+    /// // "Hello, world!" echoed to console
+    /// ```
+    ///
+    /// With stdin:
+    ///
+    /// ```no_run
+    /// use std::process::{Command, Stdio};
+    ///
+    /// let output = Command::new("rev")
+    ///     .stdin(Stdio::inherit())
+    ///     .stdout(Stdio::piped())
+    ///     .output()
+    ///     .expect("Failed to execute command");
+    ///
+    /// println!("You piped in the reverse of: {}", String::from_utf8_lossy(&output.stdout));
+    /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn inherit() -> Stdio { Stdio(imp::Stdio::Inherit) }
 
     /// This stream will be ignored. This is the equivalent of attaching the
     /// stream to `/dev/null`
+    ///
+    /// # Examples
+    ///
+    /// With stdout:
+    ///
+    /// ```no_run
+    /// use std::process::{Command, Stdio};
+    ///
+    /// let output = Command::new("echo")
+    ///     .arg("Hello, world!")
+    ///     .stdout(Stdio::null())
+    ///     .output()
+    ///     .expect("Failed to execute command");
+    ///
+    /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
+    /// // Nothing echoed to console
+    /// ```
+    ///
+    /// With stdin:
+    ///
+    /// ```no_run
+    /// use std::process::{Command, Stdio};
+    ///
+    /// let output = Command::new("rev")
+    ///     .stdin(Stdio::null())
+    ///     .stdout(Stdio::piped())
+    ///     .output()
+    ///     .expect("Failed to execute command");
+    ///
+    /// assert_eq!(String::from_utf8_lossy(&output.stdout), "");
+    /// // Ignores any piped-in input
+    /// ```
     #[stable(feature = "process", since = "1.0.0")]
     pub fn null() -> Stdio { Stdio(imp::Stdio::Null) }
 }
@@ -1083,8 +1199,6 @@ impl Child {
 /// function and compute the exit code from its return value:
 ///
 /// ```
-/// use std::io::{self, Write};
-///
 /// fn run_app() -> Result<(), ()> {
 ///     // Application logic here
 ///     Ok(())
@@ -1094,7 +1208,7 @@ impl Child {
 ///     ::std::process::exit(match run_app() {
 ///        Ok(_) => 0,
 ///        Err(err) => {
-///            writeln!(io::stderr(), "error: {:?}", err).unwrap();
+///            eprintln!("error: {:?}", err);
 ///            1
 ///        }
 ///     });
diff --git a/src/libstd/sync/mpsc/cache_aligned.rs b/src/libstd/sync/mpsc/cache_aligned.rs
new file mode 100644
index 00000000000..5af01262573
--- /dev/null
+++ b/src/libstd/sync/mpsc/cache_aligned.rs
@@ -0,0 +1,37 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use ops::{Deref, DerefMut};
+
+#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+#[repr(align(64))]
+pub(super) struct Aligner;
+
+#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd, Ord, Hash)]
+pub(super) struct CacheAligned<T>(pub T, pub Aligner);
+
+impl<T> Deref for CacheAligned<T> {
+     type Target = T;
+     fn deref(&self) -> &Self::Target {
+         &self.0
+     }
+}
+
+impl<T> DerefMut for CacheAligned<T> {
+     fn deref_mut(&mut self) -> &mut Self::Target {
+         &mut self.0
+     }
+}
+
+impl<T> CacheAligned<T> {
+    pub(super) fn new(t: T) -> Self {
+        CacheAligned(t, Aligner)
+    }
+}
diff --git a/src/libstd/sync/mpsc/mod.rs b/src/libstd/sync/mpsc/mod.rs
index dcd4c8dfdf5..45a26e594b0 100644
--- a/src/libstd/sync/mpsc/mod.rs
+++ b/src/libstd/sync/mpsc/mod.rs
@@ -297,6 +297,8 @@ mod sync;
 mod mpsc_queue;
 mod spsc_queue;
 
+mod cache_aligned;
+
 /// The receiving half of Rust's [`channel`][] (or [`sync_channel`]) type.
 /// This half can only be owned by one thread.
 ///
@@ -919,7 +921,7 @@ impl<T> Drop for Sender<T> {
 #[stable(feature = "mpsc_debug", since = "1.8.0")]
 impl<T> fmt::Debug for Sender<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Sender {{ .. }}")
+        f.debug_struct("Sender").finish()
     }
 }
 
@@ -1049,7 +1051,7 @@ impl<T> Drop for SyncSender<T> {
 #[stable(feature = "mpsc_debug", since = "1.8.0")]
 impl<T> fmt::Debug for SyncSender<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "SyncSender {{ .. }}")
+        f.debug_struct("SyncSender").finish()
     }
 }
 
@@ -1551,7 +1553,7 @@ impl<T> Drop for Receiver<T> {
 #[stable(feature = "mpsc_debug", since = "1.8.0")]
 impl<T> fmt::Debug for Receiver<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Receiver {{ .. }}")
+        f.debug_struct("Receiver").finish()
     }
 }
 
@@ -3009,22 +3011,4 @@ mod sync_tests {
             repro()
         }
     }
-
-    #[test]
-    fn fmt_debug_sender() {
-        let (tx, _) = channel::<i32>();
-        assert_eq!(format!("{:?}", tx), "Sender { .. }");
-    }
-
-    #[test]
-    fn fmt_debug_recv() {
-        let (_, rx) = channel::<i32>();
-        assert_eq!(format!("{:?}", rx), "Receiver { .. }");
-    }
-
-    #[test]
-    fn fmt_debug_sync_sender() {
-        let (tx, _) = sync_channel::<i32>(1);
-        assert_eq!(format!("{:?}", tx), "SyncSender { .. }");
-    }
 }
diff --git a/src/libstd/sync/mpsc/select.rs b/src/libstd/sync/mpsc/select.rs
index e49f4cff024..a9f3cea243f 100644
--- a/src/libstd/sync/mpsc/select.rs
+++ b/src/libstd/sync/mpsc/select.rs
@@ -354,13 +354,13 @@ impl Iterator for Packets {
 
 impl fmt::Debug for Select {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Select {{ .. }}")
+        f.debug_struct("Select").finish()
     }
 }
 
 impl<'rx, T:Send+'rx> fmt::Debug for Handle<'rx, T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        write!(f, "Handle {{ .. }}")
+        f.debug_struct("Handle").finish()
     }
 }
 
@@ -774,18 +774,4 @@ mod tests {
             }
         }
     }
-
-    #[test]
-    fn fmt_debug_select() {
-        let sel = Select::new();
-        assert_eq!(format!("{:?}", sel), "Select { .. }");
-    }
-
-    #[test]
-    fn fmt_debug_handle() {
-        let (_, rx) = channel::<i32>();
-        let sel = Select::new();
-        let handle = sel.handle(&rx);
-        assert_eq!(format!("{:?}", handle), "Handle { .. }");
-    }
 }
diff --git a/src/libstd/sync/mpsc/spsc_queue.rs b/src/libstd/sync/mpsc/spsc_queue.rs
index 1148bc66fba..cc4be92276a 100644
--- a/src/libstd/sync/mpsc/spsc_queue.rs
+++ b/src/libstd/sync/mpsc/spsc_queue.rs
@@ -22,12 +22,15 @@ use core::cell::UnsafeCell;
 
 use sync::atomic::{AtomicPtr, AtomicUsize, Ordering};
 
+use super::cache_aligned::CacheAligned;
+
 // Node within the linked list queue of messages to send
 struct Node<T> {
     // FIXME: this could be an uninitialized T if we're careful enough, and
     //      that would reduce memory usage (and be a bit faster).
     //      is it worth it?
     value: Option<T>,           // nullable for re-use of nodes
+    cached: bool,               // This node goes into the node cache
     next: AtomicPtr<Node<T>>,   // next node in the queue
 }
 
@@ -35,38 +38,55 @@ struct Node<T> {
 /// but it can be safely shared in an Arc if it is guaranteed that there
 /// is only one popper and one pusher touching the queue at any one point in
 /// time.
-pub struct Queue<T> {
+pub struct Queue<T, ProducerAddition=(), ConsumerAddition=()> {
     // consumer fields
+    consumer: CacheAligned<Consumer<T, ConsumerAddition>>,
+
+    // producer fields
+    producer: CacheAligned<Producer<T, ProducerAddition>>,
+}
+
+struct Consumer<T, Addition> {
     tail: UnsafeCell<*mut Node<T>>, // where to pop from
     tail_prev: AtomicPtr<Node<T>>, // where to pop from
+    cache_bound: usize, // maximum cache size
+    cached_nodes: AtomicUsize, // number of nodes marked as cachable
+    addition: Addition,
+}
 
-    // producer fields
+struct Producer<T, Addition> {
     head: UnsafeCell<*mut Node<T>>,      // where to push to
     first: UnsafeCell<*mut Node<T>>,     // where to get new nodes from
     tail_copy: UnsafeCell<*mut Node<T>>, // between first/tail
-
-    // Cache maintenance fields. Additions and subtractions are stored
-    // separately in order to allow them to use nonatomic addition/subtraction.
-    cache_bound: usize,
-    cache_additions: AtomicUsize,
-    cache_subtractions: AtomicUsize,
+    addition: Addition,
 }
 
-unsafe impl<T: Send> Send for Queue<T> { }
+unsafe impl<T: Send, P: Send + Sync, C: Send + Sync> Send for Queue<T, P, C> { }
 
-unsafe impl<T: Send> Sync for Queue<T> { }
+unsafe impl<T: Send, P: Send + Sync, C: Send + Sync> Sync for Queue<T, P, C> { }
 
 impl<T> Node<T> {
     fn new() -> *mut Node<T> {
         Box::into_raw(box Node {
             value: None,
+            cached: false,
             next: AtomicPtr::new(ptr::null_mut::<Node<T>>()),
         })
     }
 }
 
-impl<T> Queue<T> {
-    /// Creates a new queue.
+impl<T, ProducerAddition, ConsumerAddition> Queue<T, ProducerAddition, ConsumerAddition> {
+
+    /// Creates a new queue. With given additional elements in the producer and
+    /// consumer portions of the queue.
+    ///
+    /// Due to the performance implications of cache-contention,
+    /// we wish to keep fields used mainly by the producer on a separate cache
+    /// line than those used by the consumer.
+    /// Since cache lines are usually 64 bytes, it is unreasonably expensive to
+    /// allocate one for small fields, so we allow users to insert additional
+    /// fields into the cache lines already allocated by this for the producer
+    /// and consumer.
     ///
     /// This is unsafe as the type system doesn't enforce a single
     /// consumer-producer relationship. It also allows the consumer to `pop`
@@ -83,19 +103,28 @@ impl<T> Queue<T> {
     ///               cache (if desired). If the value is 0, then the cache has
     ///               no bound. Otherwise, the cache will never grow larger than
     ///               `bound` (although the queue itself could be much larger.
-    pub unsafe fn new(bound: usize) -> Queue<T> {
+    pub unsafe fn with_additions(
+        bound: usize,
+        producer_addition: ProducerAddition,
+        consumer_addition: ConsumerAddition,
+    ) -> Self {
         let n1 = Node::new();
         let n2 = Node::new();
         (*n1).next.store(n2, Ordering::Relaxed);
         Queue {
-            tail: UnsafeCell::new(n2),
-            tail_prev: AtomicPtr::new(n1),
-            head: UnsafeCell::new(n2),
-            first: UnsafeCell::new(n1),
-            tail_copy: UnsafeCell::new(n1),
-            cache_bound: bound,
-            cache_additions: AtomicUsize::new(0),
-            cache_subtractions: AtomicUsize::new(0),
+            consumer: CacheAligned::new(Consumer {
+                tail: UnsafeCell::new(n2),
+                tail_prev: AtomicPtr::new(n1),
+                cache_bound: bound,
+                cached_nodes: AtomicUsize::new(0),
+                addition: consumer_addition
+            }),
+            producer: CacheAligned::new(Producer {
+                head: UnsafeCell::new(n2),
+                first: UnsafeCell::new(n1),
+                tail_copy: UnsafeCell::new(n1),
+                addition: producer_addition
+            }),
         }
     }
 
@@ -109,35 +138,25 @@ impl<T> Queue<T> {
             assert!((*n).value.is_none());
             (*n).value = Some(t);
             (*n).next.store(ptr::null_mut(), Ordering::Relaxed);
-            (**self.head.get()).next.store(n, Ordering::Release);
-            *self.head.get() = n;
+            (**self.producer.head.get()).next.store(n, Ordering::Release);
+            *(&self.producer.head).get() = n;
         }
     }
 
     unsafe fn alloc(&self) -> *mut Node<T> {
         // First try to see if we can consume the 'first' node for our uses.
-        // We try to avoid as many atomic instructions as possible here, so
-        // the addition to cache_subtractions is not atomic (plus we're the
-        // only one subtracting from the cache).
-        if *self.first.get() != *self.tail_copy.get() {
-            if self.cache_bound > 0 {
-                let b = self.cache_subtractions.load(Ordering::Relaxed);
-                self.cache_subtractions.store(b + 1, Ordering::Relaxed);
-            }
-            let ret = *self.first.get();
-            *self.first.get() = (*ret).next.load(Ordering::Relaxed);
+        if *self.producer.first.get() != *self.producer.tail_copy.get() {
+            let ret = *self.producer.first.get();
+            *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed);
             return ret;
         }
         // If the above fails, then update our copy of the tail and try
         // again.
-        *self.tail_copy.get() = self.tail_prev.load(Ordering::Acquire);
-        if *self.first.get() != *self.tail_copy.get() {
-            if self.cache_bound > 0 {
-                let b = self.cache_subtractions.load(Ordering::Relaxed);
-                self.cache_subtractions.store(b + 1, Ordering::Relaxed);
-            }
-            let ret = *self.first.get();
-            *self.first.get() = (*ret).next.load(Ordering::Relaxed);
+        *self.producer.0.tail_copy.get() =
+            self.consumer.tail_prev.load(Ordering::Acquire);
+        if *self.producer.first.get() != *self.producer.tail_copy.get() {
+            let ret = *self.producer.first.get();
+            *self.producer.0.first.get() = (*ret).next.load(Ordering::Relaxed);
             return ret;
         }
         // If all of that fails, then we have to allocate a new node
@@ -153,27 +172,27 @@ impl<T> Queue<T> {
             // sentinel from where we should start popping from. Hence, look at
             // tail's next field and see if we can use it. If we do a pop, then
             // the current tail node is a candidate for going into the cache.
-            let tail = *self.tail.get();
+            let tail = *self.consumer.tail.get();
             let next = (*tail).next.load(Ordering::Acquire);
             if next.is_null() { return None }
             assert!((*next).value.is_some());
             let ret = (*next).value.take();
 
-            *self.tail.get() = next;
-            if self.cache_bound == 0 {
-                self.tail_prev.store(tail, Ordering::Release);
+            *self.consumer.0.tail.get() = next;
+            if self.consumer.cache_bound == 0 {
+                self.consumer.tail_prev.store(tail, Ordering::Release);
             } else {
-                // FIXME: this is dubious with overflow.
-                let additions = self.cache_additions.load(Ordering::Relaxed);
-                let subtractions = self.cache_subtractions.load(Ordering::Relaxed);
-                let size = additions - subtractions;
-
-                if size < self.cache_bound {
-                    self.tail_prev.store(tail, Ordering::Release);
-                    self.cache_additions.store(additions + 1, Ordering::Relaxed);
+                let cached_nodes = self.consumer.cached_nodes.load(Ordering::Relaxed);
+                if cached_nodes < self.consumer.cache_bound && !(*tail).cached {
+                    self.consumer.cached_nodes.store(cached_nodes, Ordering::Relaxed);
+                    (*tail).cached = true;
+                }
+
+                if (*tail).cached {
+                    self.consumer.tail_prev.store(tail, Ordering::Release);
                 } else {
-                    (*self.tail_prev.load(Ordering::Relaxed))
-                          .next.store(next, Ordering::Relaxed);
+                    (*self.consumer.tail_prev.load(Ordering::Relaxed))
+                        .next.store(next, Ordering::Relaxed);
                     // We have successfully erased all references to 'tail', so
                     // now we can safely drop it.
                     let _: Box<Node<T>> = Box::from_raw(tail);
@@ -194,17 +213,25 @@ impl<T> Queue<T> {
         // This is essentially the same as above with all the popping bits
         // stripped out.
         unsafe {
-            let tail = *self.tail.get();
+            let tail = *self.consumer.tail.get();
             let next = (*tail).next.load(Ordering::Acquire);
             if next.is_null() { None } else { (*next).value.as_mut() }
         }
     }
+
+    pub fn producer_addition(&self) -> &ProducerAddition {
+        &self.producer.addition
+    }
+
+    pub fn consumer_addition(&self) -> &ConsumerAddition {
+        &self.consumer.addition
+    }
 }
 
-impl<T> Drop for Queue<T> {
+impl<T, ProducerAddition, ConsumerAddition> Drop for Queue<T, ProducerAddition, ConsumerAddition> {
     fn drop(&mut self) {
         unsafe {
-            let mut cur = *self.first.get();
+            let mut cur = *self.producer.first.get();
             while !cur.is_null() {
                 let next = (*cur).next.load(Ordering::Relaxed);
                 let _n: Box<Node<T>> = Box::from_raw(cur);
@@ -224,7 +251,7 @@ mod tests {
     #[test]
     fn smoke() {
         unsafe {
-            let queue = Queue::new(0);
+            let queue = Queue::with_additions(0, (), ());
             queue.push(1);
             queue.push(2);
             assert_eq!(queue.pop(), Some(1));
@@ -241,7 +268,7 @@ mod tests {
     #[test]
     fn peek() {
         unsafe {
-            let queue = Queue::new(0);
+            let queue = Queue::with_additions(0, (), ());
             queue.push(vec![1]);
 
             // Ensure the borrowchecker works
@@ -264,7 +291,7 @@ mod tests {
     #[test]
     fn drop_full() {
         unsafe {
-            let q: Queue<Box<_>> = Queue::new(0);
+            let q: Queue<Box<_>> = Queue::with_additions(0, (), ());
             q.push(box 1);
             q.push(box 2);
         }
@@ -273,7 +300,7 @@ mod tests {
     #[test]
     fn smoke_bound() {
         unsafe {
-            let q = Queue::new(0);
+            let q = Queue::with_additions(0, (), ());
             q.push(1);
             q.push(2);
             assert_eq!(q.pop(), Some(1));
@@ -295,7 +322,7 @@ mod tests {
         }
 
         unsafe fn stress_bound(bound: usize) {
-            let q = Arc::new(Queue::new(bound));
+            let q = Arc::new(Queue::with_additions(bound, (), ()));
 
             let (tx, rx) = channel();
             let q2 = q.clone();
diff --git a/src/libstd/sync/mpsc/stream.rs b/src/libstd/sync/mpsc/stream.rs
index 47cd8977fda..d1515eba68c 100644
--- a/src/libstd/sync/mpsc/stream.rs
+++ b/src/libstd/sync/mpsc/stream.rs
@@ -41,15 +41,22 @@ const MAX_STEALS: isize = 5;
 const MAX_STEALS: isize = 1 << 20;
 
 pub struct Packet<T> {
-    queue: spsc::Queue<Message<T>>, // internal queue for all message
+    // internal queue for all messages
+    queue: spsc::Queue<Message<T>, ProducerAddition, ConsumerAddition>,
+}
 
+struct ProducerAddition {
     cnt: AtomicIsize, // How many items are on this channel
-    steals: UnsafeCell<isize>, // How many times has a port received without blocking?
     to_wake: AtomicUsize, // SignalToken for the blocked thread to wake up
 
     port_dropped: AtomicBool, // flag if the channel has been destroyed.
 }
 
+struct ConsumerAddition {
+    steals: UnsafeCell<isize>,  // How many times has a port received without blocking?
+}
+
+
 pub enum Failure<T> {
     Empty,
     Disconnected,
@@ -78,13 +85,18 @@ enum Message<T> {
 impl<T> Packet<T> {
     pub fn new() -> Packet<T> {
         Packet {
-            queue: unsafe { spsc::Queue::new(128) },
-
-            cnt: AtomicIsize::new(0),
-            steals: UnsafeCell::new(0),
-            to_wake: AtomicUsize::new(0),
-
-            port_dropped: AtomicBool::new(false),
+            queue: unsafe { spsc::Queue::with_additions(
+                128,
+                ProducerAddition {
+                    cnt: AtomicIsize::new(0),
+                    to_wake: AtomicUsize::new(0),
+
+                    port_dropped: AtomicBool::new(false),
+                },
+                ConsumerAddition {
+                    steals: UnsafeCell::new(0),
+                }
+            )},
         }
     }
 
@@ -92,7 +104,7 @@ impl<T> Packet<T> {
         // If the other port has deterministically gone away, then definitely
         // must return the data back up the stack. Otherwise, the data is
         // considered as being sent.
-        if self.port_dropped.load(Ordering::SeqCst) { return Err(t) }
+        if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) { return Err(t) }
 
         match self.do_send(Data(t)) {
             UpSuccess | UpDisconnected => {},
@@ -104,14 +116,16 @@ impl<T> Packet<T> {
     pub fn upgrade(&self, up: Receiver<T>) -> UpgradeResult {
         // If the port has gone away, then there's no need to proceed any
         // further.
-        if self.port_dropped.load(Ordering::SeqCst) { return UpDisconnected }
+        if self.queue.producer_addition().port_dropped.load(Ordering::SeqCst) {
+            return UpDisconnected
+        }
 
         self.do_send(GoUp(up))
     }
 
     fn do_send(&self, t: Message<T>) -> UpgradeResult {
         self.queue.push(t);
-        match self.cnt.fetch_add(1, Ordering::SeqCst) {
+        match self.queue.producer_addition().cnt.fetch_add(1, Ordering::SeqCst) {
             // As described in the mod's doc comment, -1 == wakeup
             -1 => UpWoke(self.take_to_wake()),
             // As as described before, SPSC queues must be >= -2
@@ -125,7 +139,7 @@ impl<T> Packet<T> {
             // will never remove this data. We can only have at most one item to
             // drain (the port drains the rest).
             DISCONNECTED => {
-                self.cnt.store(DISCONNECTED, Ordering::SeqCst);
+                self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
                 let first = self.queue.pop();
                 let second = self.queue.pop();
                 assert!(second.is_none());
@@ -144,8 +158,8 @@ impl<T> Packet<T> {
 
     // Consumes ownership of the 'to_wake' field.
     fn take_to_wake(&self) -> SignalToken {
-        let ptr = self.to_wake.load(Ordering::SeqCst);
-        self.to_wake.store(0, Ordering::SeqCst);
+        let ptr = self.queue.producer_addition().to_wake.load(Ordering::SeqCst);
+        self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst);
         assert!(ptr != 0);
         unsafe { SignalToken::cast_from_usize(ptr) }
     }
@@ -154,14 +168,16 @@ impl<T> Packet<T> {
     // back if it shouldn't sleep. Note that this is the location where we take
     // steals into account.
     fn decrement(&self, token: SignalToken) -> Result<(), SignalToken> {
-        assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+        assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
         let ptr = unsafe { token.cast_to_usize() };
-        self.to_wake.store(ptr, Ordering::SeqCst);
+        self.queue.producer_addition().to_wake.store(ptr, Ordering::SeqCst);
 
-        let steals = unsafe { ptr::replace(self.steals.get(), 0) };
+        let steals = unsafe { ptr::replace(self.queue.consumer_addition().steals.get(), 0) };
 
-        match self.cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
-            DISCONNECTED => { self.cnt.store(DISCONNECTED, Ordering::SeqCst); }
+        match self.queue.producer_addition().cnt.fetch_sub(1 + steals, Ordering::SeqCst) {
+            DISCONNECTED => {
+                self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
+            }
             // If we factor in our steals and notice that the channel has no
             // data, we successfully sleep
             n => {
@@ -170,7 +186,7 @@ impl<T> Packet<T> {
             }
         }
 
-        self.to_wake.store(0, Ordering::SeqCst);
+        self.queue.producer_addition().to_wake.store(0, Ordering::SeqCst);
         Err(unsafe { SignalToken::cast_from_usize(ptr) })
     }
 
@@ -201,7 +217,7 @@ impl<T> Packet<T> {
             // "steal" factored into the channel count above).
             data @ Ok(..) |
             data @ Err(Upgraded(..)) => unsafe {
-                *self.steals.get() -= 1;
+                *self.queue.consumer_addition().steals.get() -= 1;
                 data
             },
 
@@ -223,20 +239,21 @@ impl<T> Packet<T> {
             // down as much as possible (without going negative), and then
             // adding back in whatever we couldn't factor into steals.
             Some(data) => unsafe {
-                if *self.steals.get() > MAX_STEALS {
-                    match self.cnt.swap(0, Ordering::SeqCst) {
+                if *self.queue.consumer_addition().steals.get() > MAX_STEALS {
+                    match self.queue.producer_addition().cnt.swap(0, Ordering::SeqCst) {
                         DISCONNECTED => {
-                            self.cnt.store(DISCONNECTED, Ordering::SeqCst);
+                            self.queue.producer_addition().cnt.store(
+                                DISCONNECTED, Ordering::SeqCst);
                         }
                         n => {
-                            let m = cmp::min(n, *self.steals.get());
-                            *self.steals.get() -= m;
+                            let m = cmp::min(n, *self.queue.consumer_addition().steals.get());
+                            *self.queue.consumer_addition().steals.get() -= m;
                             self.bump(n - m);
                         }
                     }
-                    assert!(*self.steals.get() >= 0);
+                    assert!(*self.queue.consumer_addition().steals.get() >= 0);
                 }
-                *self.steals.get() += 1;
+                *self.queue.consumer_addition().steals.get() += 1;
                 match data {
                     Data(t) => Ok(t),
                     GoUp(up) => Err(Upgraded(up)),
@@ -244,7 +261,7 @@ impl<T> Packet<T> {
             },
 
             None => {
-                match self.cnt.load(Ordering::SeqCst) {
+                match self.queue.producer_addition().cnt.load(Ordering::SeqCst) {
                     n if n != DISCONNECTED => Err(Empty),
 
                     // This is a little bit of a tricky case. We failed to pop
@@ -273,7 +290,7 @@ impl<T> Packet<T> {
     pub fn drop_chan(&self) {
         // Dropping a channel is pretty simple, we just flag it as disconnected
         // and then wakeup a blocker if there is one.
-        match self.cnt.swap(DISCONNECTED, Ordering::SeqCst) {
+        match self.queue.producer_addition().cnt.swap(DISCONNECTED, Ordering::SeqCst) {
             -1 => { self.take_to_wake().signal(); }
             DISCONNECTED => {}
             n => { assert!(n >= 0); }
@@ -300,7 +317,7 @@ impl<T> Packet<T> {
         // sends are gated on this flag, so we're immediately guaranteed that
         // there are a bounded number of active sends that we'll have to deal
         // with.
-        self.port_dropped.store(true, Ordering::SeqCst);
+        self.queue.producer_addition().port_dropped.store(true, Ordering::SeqCst);
 
         // Now that we're guaranteed to deal with a bounded number of senders,
         // we need to drain the queue. This draining process happens atomically
@@ -310,9 +327,9 @@ impl<T> Packet<T> {
         // continue to fail while active senders send data while we're dropping
         // data, but eventually we're guaranteed to break out of this loop
         // (because there is a bounded number of senders).
-        let mut steals = unsafe { *self.steals.get() };
+        let mut steals = unsafe { *self.queue.consumer_addition().steals.get() };
         while {
-            let cnt = self.cnt.compare_and_swap(
+            let cnt = self.queue.producer_addition().cnt.compare_and_swap(
                             steals, DISCONNECTED, Ordering::SeqCst);
             cnt != DISCONNECTED && cnt != steals
         } {
@@ -353,9 +370,9 @@ impl<T> Packet<T> {
 
     // increment the count on the channel (used for selection)
     fn bump(&self, amt: isize) -> isize {
-        match self.cnt.fetch_add(amt, Ordering::SeqCst) {
+        match self.queue.producer_addition().cnt.fetch_add(amt, Ordering::SeqCst) {
             DISCONNECTED => {
-                self.cnt.store(DISCONNECTED, Ordering::SeqCst);
+                self.queue.producer_addition().cnt.store(DISCONNECTED, Ordering::SeqCst);
                 DISCONNECTED
             }
             n => n
@@ -404,8 +421,8 @@ impl<T> Packet<T> {
         // this end. This is fine because we know it's a small bounded windows
         // of time until the data is actually sent.
         if was_upgrade {
-            assert_eq!(unsafe { *self.steals.get() }, 0);
-            assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+            assert_eq!(unsafe { *self.queue.consumer_addition().steals.get() }, 0);
+            assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
             return Ok(true)
         }
 
@@ -418,7 +435,7 @@ impl<T> Packet<T> {
         // If we were previously disconnected, then we know for sure that there
         // is no thread in to_wake, so just keep going
         let has_data = if prev == DISCONNECTED {
-            assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+            assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
             true // there is data, that data is that we're disconnected
         } else {
             let cur = prev + steals + 1;
@@ -441,13 +458,13 @@ impl<T> Packet<T> {
             if prev < 0 {
                 drop(self.take_to_wake());
             } else {
-                while self.to_wake.load(Ordering::SeqCst) != 0 {
+                while self.queue.producer_addition().to_wake.load(Ordering::SeqCst) != 0 {
                     thread::yield_now();
                 }
             }
             unsafe {
-                assert_eq!(*self.steals.get(), 0);
-                *self.steals.get() = steals;
+                assert_eq!(*self.queue.consumer_addition().steals.get(), 0);
+                *self.queue.consumer_addition().steals.get() = steals;
             }
 
             // if we were previously positive, then there's surely data to
@@ -481,7 +498,7 @@ impl<T> Drop for Packet<T> {
         // disconnection, but also a proper fence before the read of
         // `to_wake`, so this assert cannot be removed with also removing
         // the `to_wake` assert.
-        assert_eq!(self.cnt.load(Ordering::SeqCst), DISCONNECTED);
-        assert_eq!(self.to_wake.load(Ordering::SeqCst), 0);
+        assert_eq!(self.queue.producer_addition().cnt.load(Ordering::SeqCst), DISCONNECTED);
+        assert_eq!(self.queue.producer_addition().to_wake.load(Ordering::SeqCst), 0);
     }
 }
diff --git a/src/libstd/sync/mutex.rs b/src/libstd/sync/mutex.rs
index 1d62853e906..eb507858b92 100644
--- a/src/libstd/sync/mutex.rs
+++ b/src/libstd/sync/mutex.rs
@@ -394,11 +394,18 @@ impl<T: ?Sized + Default> Default for Mutex<T> {
 impl<T: ?Sized + fmt::Debug> fmt::Debug for Mutex<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.try_lock() {
-            Ok(guard) => write!(f, "Mutex {{ data: {:?} }}", &*guard),
+            Ok(guard) => f.debug_struct("Mutex").field("data", &&*guard).finish(),
             Err(TryLockError::Poisoned(err)) => {
-                write!(f, "Mutex {{ data: Poisoned({:?}) }}", &**err.get_ref())
+                f.debug_struct("Mutex").field("data", &&**err.get_ref()).finish()
             },
-            Err(TryLockError::WouldBlock) => write!(f, "Mutex {{ <locked> }}")
+            Err(TryLockError::WouldBlock) => {
+                struct LockedPlaceholder;
+                impl fmt::Debug for LockedPlaceholder {
+                    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("<locked>") }
+                }
+
+                f.debug_struct("Mutex").field("data", &LockedPlaceholder).finish()
+            }
         }
     }
 }
diff --git a/src/libstd/sync/rwlock.rs b/src/libstd/sync/rwlock.rs
index 4757faabfb8..5c49d6b5845 100644
--- a/src/libstd/sync/rwlock.rs
+++ b/src/libstd/sync/rwlock.rs
@@ -428,11 +428,18 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for RwLock<T> {
 impl<T: ?Sized + fmt::Debug> fmt::Debug for RwLock<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.try_read() {
-            Ok(guard) => write!(f, "RwLock {{ data: {:?} }}", &*guard),
+            Ok(guard) => f.debug_struct("RwLock").field("data", &&*guard).finish(),
             Err(TryLockError::Poisoned(err)) => {
-                write!(f, "RwLock {{ data: Poisoned({:?}) }}", &**err.get_ref())
+                f.debug_struct("RwLock").field("data", &&**err.get_ref()).finish()
             },
-            Err(TryLockError::WouldBlock) => write!(f, "RwLock {{ <locked> }}")
+            Err(TryLockError::WouldBlock) => {
+                struct LockedPlaceholder;
+                impl fmt::Debug for LockedPlaceholder {
+                    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("<locked>") }
+                }
+
+                f.debug_struct("RwLock").field("data", &LockedPlaceholder).finish()
+            }
         }
     }
 }
diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs
index c8019d1c768..e775f857f2b 100644
--- a/src/libstd/sys/unix/net.rs
+++ b/src/libstd/sys/unix/net.rs
@@ -176,11 +176,16 @@ impl Socket {
                 }
                 0 => {}
                 _ => {
-                    if pollfd.revents & libc::POLLOUT == 0 {
-                        if let Some(e) = self.take_error()? {
-                            return Err(e);
-                        }
+                    // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
+                    // for POLLHUP rather than read readiness
+                    if pollfd.revents & libc::POLLHUP != 0 {
+                        let e = self.take_error()?
+                            .unwrap_or_else(|| {
+                                io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
+                            });
+                        return Err(e);
                     }
+
                     return Ok(());
                 }
             }
diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs
index 3f6c2827a3f..d6b8896ac09 100644
--- a/src/libstd/sys/windows/ext/ffi.rs
+++ b/src/libstd/sys/windows/ext/ffi.rs
@@ -9,6 +9,62 @@
 // except according to those terms.
 
 //! Windows-specific extensions to the primitives in the `std::ffi` module.
+//!
+//! # Overview
+//!
+//! For historical reasons, the Windows API uses a form of potentially
+//! ill-formed UTF-16 encoding for strings.  Specifically, the 16-bit
+//! code units in Windows strings may contain [isolated surrogate code
+//! points which are not paired together][ill-formed-utf-16].  The
+//! Unicode standard requires that surrogate code points (those in the
+//! range U+D800 to U+DFFF) always be *paired*, because in the UTF-16
+//! encoding a *surrogate code unit pair* is used to encode a single
+//! character.  For compatibility with code that does not enforce
+//! these pairings, Windows does not enforce them, either.
+//!
+//! While it is not always possible to convert such a string losslessly into
+//! a valid UTF-16 string (or even UTF-8), it is often desirable to be
+//! able to round-trip such a string from and to Windows APIs
+//! losslessly.  For example, some Rust code may be "bridging" some
+//! Windows APIs together, just passing `WCHAR` strings among those
+//! APIs without ever really looking into the strings.
+//!
+//! If Rust code *does* need to look into those strings, it can
+//! convert them to valid UTF-8, possibly lossily, by substituting
+//! invalid sequences with U+FFFD REPLACEMENT CHARACTER, as is
+//! conventionally done in other Rust APIs that deal with string
+//! encodings.
+//!
+//! # `OsStringExt` and `OsStrExt`
+//!
+//! [`OsString`] is the Rust wrapper for owned strings in the
+//! preferred representation of the operating system.  On Windows,
+//! this struct gets augmented with an implementation of the
+//! [`OsStringExt`] trait, which has a [`from_wide`] method.  This
+//! lets you create an [`OsString`] from a `&[u16]` slice; presumably
+//! you get such a slice out of a `WCHAR` Windows API.
+//!
+//! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from
+//! preferred representation of the operating system.  On Windows, the
+//! [`OsStrExt`] trait provides the [`encode_wide`] method, which
+//! outputs an [`EncodeWide`] iterator.  You can [`collect`] this
+//! iterator, for example, to obtain a `Vec<u16>`; you can later get a
+//! pointer to this vector's contents and feed it to Windows APIs.
+//!
+//! These traits, along with [`OsString`] and [`OsStr`], work in
+//! conjunction so that it is possible to **round-trip** strings from
+//! Windows and back, with no loss of data, even if the strings are
+//! ill-formed UTF-16.
+//!
+//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16
+//! [`OsString`]: ../../../ffi/struct.OsString.html
+//! [`OsStr`]: ../../../ffi/struct.OsStr.html
+//! [`OsStringExt`]: trait.OsStringExt.html
+//! [`OsStrExt`]: trait.OsStrExt.html
+//! [`EncodeWide`]: struct.EncodeWide.html
+//! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide
+//! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide
+//! [`collect`]: ../../../iter/trait.Iterator.html#method.collect
 
 #![stable(feature = "rust1", since = "1.0.0")]
 
diff --git a/src/libstd/sys_common/remutex.rs b/src/libstd/sys_common/remutex.rs
index 4d0407ccf6c..ce43ec6d9ab 100644
--- a/src/libstd/sys_common/remutex.rs
+++ b/src/libstd/sys_common/remutex.rs
@@ -116,11 +116,18 @@ impl<T> Drop for ReentrantMutex<T> {
 impl<T: fmt::Debug + 'static> fmt::Debug for ReentrantMutex<T> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match self.try_lock() {
-            Ok(guard) => write!(f, "ReentrantMutex {{ data: {:?} }}", &*guard),
+            Ok(guard) => f.debug_struct("ReentrantMutex").field("data", &*guard).finish(),
             Err(TryLockError::Poisoned(err)) => {
-                write!(f, "ReentrantMutex {{ data: Poisoned({:?}) }}", &**err.get_ref())
+                f.debug_struct("ReentrantMutex").field("data", &**err.get_ref()).finish()
             },
-            Err(TryLockError::WouldBlock) => write!(f, "ReentrantMutex {{ <locked> }}")
+            Err(TryLockError::WouldBlock) => {
+                struct LockedPlaceholder;
+                impl fmt::Debug for LockedPlaceholder {
+                    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_str("<locked>") }
+                }
+
+                f.debug_struct("ReentrantMutex").field("data", &LockedPlaceholder).finish()
+            }
         }
     }
 }
diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs
index 30887b16c60..07bbddc62b9 100644
--- a/src/libstd/thread/mod.rs
+++ b/src/libstd/thread/mod.rs
@@ -485,15 +485,17 @@ impl Builder {
 /// let (tx, rx) = channel();
 ///
 /// let sender = thread::spawn(move || {
-///     let _ = tx.send("Hello, thread".to_owned());
+///     tx.send("Hello, thread".to_owned())
+///         .expect("Unable to send on channel");
 /// });
 ///
 /// let receiver = thread::spawn(move || {
-///     println!("{}", rx.recv().unwrap());
+///     let value = rx.recv().expect("Unable to receive from channel");
+///     println!("{}", value);
 /// });
 ///
-/// let _ = sender.join();
-/// let _ = receiver.join();
+/// sender.join().expect("The sender thread has panicked");
+/// receiver.join().expect("The receiver thread has panicked");
 /// ```
 ///
 /// A thread can also return a value through its [`JoinHandle`], you can use
@@ -1192,7 +1194,7 @@ impl<T> JoinInner<T> {
 ///     });
 /// });
 ///
-/// let _ = original_thread.join();
+/// original_thread.join().expect("The thread being joined has panicked");
 /// println!("Original thread is joined.");
 ///
 /// // We make sure that the new thread has time to run, before the main