diff options
Diffstat (limited to 'src/libstd')
| -rw-r--r-- | src/libstd/collections/hash/table.rs | 73 | ||||
| -rw-r--r-- | src/libstd/error.rs | 4 | ||||
| -rw-r--r-- | src/libstd/f32.rs (renamed from src/libstd/num/f32.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/f64.rs (renamed from src/libstd/num/f64.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/io/cursor.rs | 16 | ||||
| -rw-r--r-- | src/libstd/io/mod.rs | 2 | ||||
| -rw-r--r-- | src/libstd/io/stdio.rs | 10 | ||||
| -rw-r--r-- | src/libstd/lib.rs | 150 | ||||
| -rw-r--r-- | src/libstd/num.rs (renamed from src/libstd/num/mod.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/panic.rs | 42 | ||||
| -rw-r--r-- | src/libstd/path.rs | 1 | ||||
| -rw-r--r-- | src/libstd/rand/mod.rs | 2 | ||||
| -rw-r--r-- | src/libstd/sys/mod.rs | 45 | ||||
| -rw-r--r-- | src/libstd/sys/unix/fast_thread_local.rs | 167 | ||||
| -rw-r--r-- | src/libstd/sys/unix/mod.rs | 12 | ||||
| -rw-r--r-- | src/libstd/sys/unix/stdio.rs | 1 | ||||
| -rw-r--r-- | src/libstd/sys/windows/mod.rs | 20 | ||||
| -rw-r--r-- | src/libstd/sys/windows/stdio.rs | 5 | ||||
| -rw-r--r-- | src/libstd/sys_common/at_exit_imp.rs (renamed from src/libstd/sys/common/at_exit_imp.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/backtrace.rs (renamed from src/libstd/sys/common/backtrace.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/condvar.rs (renamed from src/libstd/sys/common/condvar.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/gnu/libbacktrace.rs (renamed from src/libstd/sys/common/gnu/libbacktrace.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/gnu/mod.rs (renamed from src/libstd/sys/common/gnu/mod.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/io.rs (renamed from src/libstd/sys/common/io.rs) | 2 | ||||
| -rw-r--r-- | src/libstd/sys_common/memchr.rs (renamed from src/libstd/sys/common/memchr.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/mod.rs (renamed from src/libstd/sys/common/mod.rs) | 30 | ||||
| -rw-r--r-- | src/libstd/sys_common/mutex.rs (renamed from src/libstd/sys/common/mutex.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/net.rs (renamed from src/libstd/sys/common/net.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/poison.rs (renamed from src/libstd/sys/common/poison.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/remutex.rs (renamed from src/libstd/sys/common/remutex.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/rwlock.rs (renamed from src/libstd/sys/common/rwlock.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/thread.rs (renamed from src/libstd/sys/common/thread.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/thread_info.rs (renamed from src/libstd/sys/common/thread_info.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/thread_local.rs (renamed from src/libstd/sys/common/thread_local.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/sys_common/util.rs (renamed from src/libstd/sys/common/util.rs) | 34 | ||||
| -rw-r--r-- | src/libstd/sys_common/wtf8.rs (renamed from src/libstd/sys/common/wtf8.rs) | 0 | ||||
| -rw-r--r-- | src/libstd/thread/local.rs | 163 | ||||
| -rw-r--r-- | src/libstd/thread/mod.rs | 11 |
38 files changed, 452 insertions, 338 deletions
diff --git a/src/libstd/collections/hash/table.rs b/src/libstd/collections/hash/table.rs index b357bc3552a..a784d8e50f9 100644 --- a/src/libstd/collections/hash/table.rs +++ b/src/libstd/collections/hash/table.rs @@ -21,7 +21,18 @@ use ptr::{self, Unique, Shared}; use self::BucketState::*; -const EMPTY_BUCKET: u64 = 0; +/// Integer type used for stored hash values. +/// +/// No more than bit_width(usize) bits are needed to select a bucket. +/// +/// The most significant bit is ours to use for tagging `SafeHash`. +/// +/// (Even if we could have usize::MAX bytes allocated for buckets, +/// each bucket stores at least a `HashUint`, so there can be no more than +/// usize::MAX / size_of(usize) buckets.) +type HashUint = usize; + +const EMPTY_BUCKET: HashUint = 0; /// The raw hashtable, providing safe-ish access to the unzipped and highly /// optimized arrays of hashes, and key-value pairs. @@ -64,7 +75,7 @@ const EMPTY_BUCKET: u64 = 0; pub struct RawTable<K, V> { capacity: usize, size: usize, - hashes: Unique<u64>, + hashes: Unique<HashUint>, // Because K/V do not appear directly in any of the types in the struct, // inform rustc that in fact instances of K and V are reachable from here. @@ -75,7 +86,7 @@ unsafe impl<K: Send, V: Send> Send for RawTable<K, V> {} unsafe impl<K: Sync, V: Sync> Sync for RawTable<K, V> {} struct RawBucket<K, V> { - hash: *mut u64, + hash: *mut HashUint, // We use *const to ensure covariance with respect to K and V pair: *const (K, V), _marker: marker::PhantomData<(K, V)>, @@ -113,10 +124,6 @@ pub struct FullBucket<K, V, M> { table: M, } -pub type EmptyBucketImm<'table, K, V> = EmptyBucket<K, V, &'table RawTable<K, V>>; -pub type FullBucketImm<'table, K, V> = FullBucket<K, V, &'table RawTable<K, V>>; - -pub type EmptyBucketMut<'table, K, V> = EmptyBucket<K, V, &'table mut RawTable<K, V>>; pub type FullBucketMut<'table, K, V> = FullBucket<K, V, &'table mut RawTable<K, V>>; pub enum BucketState<K, V, M> { @@ -136,15 +143,27 @@ pub struct GapThenFull<K, V, M> { /// buckets. #[derive(PartialEq, Copy, Clone)] pub struct SafeHash { - hash: u64, + hash: HashUint, } impl SafeHash { /// Peek at the hash value, which is guaranteed to be non-zero. #[inline(always)] - pub fn inspect(&self) -> u64 { + pub fn inspect(&self) -> HashUint { self.hash } + + #[inline(always)] + pub fn new(hash: u64) -> Self { + // We need to avoid 0 in order to prevent collisions with + // EMPTY_HASH. We can maintain our precious uniform distribution + // of initial indexes by unconditionally setting the MSB, + // effectively reducing the hashes by one bit. + // + // Truncate hash to fit in `HashUint`. + let hash_bits = size_of::<HashUint>() * 8; + SafeHash { hash: (1 << (hash_bits - 1)) | (hash as HashUint) } + } } /// We need to remove hashes of 0. That's reserved for empty buckets. @@ -156,25 +175,21 @@ pub fn make_hash<T: ?Sized, S>(hash_state: &S, t: &T) -> SafeHash { let mut state = hash_state.build_hasher(); t.hash(&mut state); - // We need to avoid 0 in order to prevent collisions with - // EMPTY_HASH. We can maintain our precious uniform distribution - // of initial indexes by unconditionally setting the MSB, - // effectively reducing 64-bits hashes to 63 bits. - SafeHash { hash: 0x8000_0000_0000_0000 | state.finish() } + SafeHash::new(state.finish()) } -// `replace` casts a `*u64` to a `*SafeHash`. Since we statically +// `replace` casts a `*HashUint` to a `*SafeHash`. Since we statically // ensure that a `FullBucket` points to an index with a non-zero hash, -// and a `SafeHash` is just a `u64` with a different name, this is +// and a `SafeHash` is just a `HashUint` with a different name, this is // safe. // // This test ensures that a `SafeHash` really IS the same size as a -// `u64`. If you need to change the size of `SafeHash` (and +// `HashUint`. If you need to change the size of `SafeHash` (and // consequently made this test fail), `replace` needs to be // modified to no longer assume this. #[test] -fn can_alias_safehash_as_u64() { - assert_eq!(size_of::<SafeHash>(), size_of::<u64>()) +fn can_alias_safehash_as_hash() { + assert_eq!(size_of::<SafeHash>(), size_of::<HashUint>()) } impl<K, V> RawBucket<K, V> { @@ -605,14 +620,14 @@ impl<K, V> RawTable<K, V> { return RawTable { size: 0, capacity: 0, - hashes: Unique::new(EMPTY as *mut u64), + hashes: Unique::new(EMPTY as *mut HashUint), marker: marker::PhantomData, }; } // No need for `checked_mul` before a more restrictive check performed // later in this method. - let hashes_size = capacity.wrapping_mul(size_of::<u64>()); + let hashes_size = capacity.wrapping_mul(size_of::<HashUint>()); let pairs_size = capacity.wrapping_mul(size_of::<(K, V)>()); // Allocating hashmaps is a little tricky. We need to allocate two @@ -624,13 +639,13 @@ impl<K, V> RawTable<K, V> { // 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::<u64>(), + align_of::<HashUint>(), pairs_size, align_of::<(K, V)>()); assert!(!oflo, "capacity overflow"); // One check for overflow that covers calculation and rounding of size. - let size_of_bucket = size_of::<u64>().checked_add(size_of::<(K, V)>()).unwrap(); + let size_of_bucket = size_of::<HashUint>().checked_add(size_of::<(K, V)>()).unwrap(); assert!(size >= capacity.checked_mul(size_of_bucket) .expect("capacity overflow"), @@ -641,7 +656,7 @@ impl<K, V> RawTable<K, V> { ::alloc::oom() } - let hashes = buffer.offset(hash_offset as isize) as *mut u64; + let hashes = buffer.offset(hash_offset as isize) as *mut HashUint; RawTable { capacity: capacity, @@ -652,7 +667,7 @@ impl<K, V> RawTable<K, V> { } fn first_bucket_raw(&self) -> RawBucket<K, V> { - let hashes_size = self.capacity * size_of::<u64>(); + let hashes_size = self.capacity * size_of::<HashUint>(); let pairs_size = self.capacity * size_of::<(K, V)>(); let buffer = *self.hashes as *mut u8; @@ -756,7 +771,7 @@ impl<K, V> RawTable<K, V> { /// this interface is safe, it's not used outside this module. struct RawBuckets<'a, K, V> { raw: RawBucket<K, V>, - hashes_end: *mut u64, + hashes_end: *mut HashUint, // Strictly speaking, this should be &'a (K,V), but that would // require that K:'a, and we often use RawBuckets<'static...> for @@ -802,7 +817,7 @@ impl<'a, K, V> Iterator for RawBuckets<'a, K, V> { /// the table's remaining entries. It's used in the implementation of Drop. struct RevMoveBuckets<'a, K, V> { raw: RawBucket<K, V>, - hashes_end: *mut u64, + hashes_end: *mut HashUint, elems_left: usize, // As above, `&'a (K,V)` would seem better, but we often use @@ -1036,10 +1051,10 @@ impl<K, V> Drop for RawTable<K, V> { } } - let hashes_size = self.capacity * size_of::<u64>(); + 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::<u64>(), + align_of::<HashUint>(), pairs_size, align_of::<(K, V)>()); diff --git a/src/libstd/error.rs b/src/libstd/error.rs index a1909b0f957..454fa47cfbc 100644 --- a/src/libstd/error.rs +++ b/src/libstd/error.rs @@ -69,7 +69,9 @@ pub trait Error: Debug + Display { /// It should not contain newlines or sentence-ending punctuation, /// to facilitate embedding in larger user-facing strings. /// For showing formatted error messages with more information see - /// [Display](https://doc.rust-lang.org/std/fmt/trait.Display.html). + /// [`Display`]. + /// + /// [`Display`]: ../fmt/trait.Display.html /// /// # Examples /// diff --git a/src/libstd/num/f32.rs b/src/libstd/f32.rs index 7a676c041ad..7a676c041ad 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/f32.rs diff --git a/src/libstd/num/f64.rs b/src/libstd/f64.rs index 67a1c302483..67a1c302483 100644 --- a/src/libstd/num/f64.rs +++ b/src/libstd/f64.rs diff --git a/src/libstd/io/cursor.rs b/src/libstd/io/cursor.rs index ca9452ffe3e..1b5023380a7 100644 --- a/src/libstd/io/cursor.rs +++ b/src/libstd/io/cursor.rs @@ -23,7 +23,7 @@ use io::{self, SeekFrom, Error, ErrorKind}; /// /// The standard library implements some I/O traits on various types which /// are commonly used as a buffer, like `Cursor<`[`Vec`]`<u8>>` and -/// `Cursor<`[`&[u8]`]`>`. +/// `Cursor<`[`&[u8]`][bytes]`>`. /// /// # Examples /// @@ -35,7 +35,7 @@ use io::{self, SeekFrom, Error, ErrorKind}; /// [`Read`]: ../../std/io/trait.Read.html /// [`Write`]: ../../std/io/trait.Write.html /// [`Vec`]: ../../std/vec/struct.Vec.html -/// [`&[u8]`]: ../../std/primitive.slice.html +/// [bytes]: ../../std/primitive.slice.html /// [`File`]: ../fs/struct.File.html /// /// ```no_run @@ -392,7 +392,7 @@ mod tests { #[test] fn test_mem_reader() { - let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7)); + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); let mut buf = []; assert_eq!(reader.read(&mut buf).unwrap(), 0); assert_eq!(reader.position(), 0); @@ -414,7 +414,7 @@ mod tests { #[test] fn test_boxed_slice_reader() { - let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7).into_boxed_slice()); + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); let mut buf = []; assert_eq!(reader.read(&mut buf).unwrap(), 0); assert_eq!(reader.position(), 0); @@ -436,7 +436,7 @@ mod tests { #[test] fn read_to_end() { - let mut reader = Cursor::new(vec!(0, 1, 2, 3, 4, 5, 6, 7)); + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); let mut v = Vec::new(); reader.read_to_end(&mut v).unwrap(); assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]); @@ -512,7 +512,7 @@ mod tests { assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); assert_eq!(r.read(&mut [0]).unwrap(), 0); - let mut r = Cursor::new(vec!(10)); + let mut r = Cursor::new(vec![10]); assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); assert_eq!(r.read(&mut [0]).unwrap(), 0); @@ -532,14 +532,14 @@ mod tests { let mut r = Cursor::new(&buf[..]); assert!(r.seek(SeekFrom::End(-2)).is_err()); - let mut r = Cursor::new(vec!(10)); + let mut r = Cursor::new(vec![10]); assert!(r.seek(SeekFrom::End(-2)).is_err()); let mut buf = [0]; let mut r = Cursor::new(&mut buf[..]); assert!(r.seek(SeekFrom::End(-2)).is_err()); - let mut r = Cursor::new(vec!(10).into_boxed_slice()); + let mut r = Cursor::new(vec![10].into_boxed_slice()); assert!(r.seek(SeekFrom::End(-2)).is_err()); } diff --git a/src/libstd/io/mod.rs b/src/libstd/io/mod.rs index 37c3f70d54d..193f396c0d4 100644 --- a/src/libstd/io/mod.rs +++ b/src/libstd/io/mod.rs @@ -289,7 +289,7 @@ mod lazy; mod util; mod stdio; -const DEFAULT_BUF_SIZE: usize = 8 * 1024; +const DEFAULT_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; // A few methods below (read_to_string, read_line) will append data into a // `String` buffer, but we need to be pretty careful when doing this. The diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index c24ee8ff303..1777b79ea1b 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -214,15 +214,7 @@ pub fn stdin() -> Stdin { _ => Maybe::Fake }; - // The default buffer capacity is 64k, but apparently windows - // doesn't like 64k reads on stdin. See #13304 for details, but the - // idea is that on windows we use a slightly smaller buffer that's - // been seen to be acceptable. - Arc::new(Mutex::new(if cfg!(windows) { - BufReader::with_capacity(8 * 1024, stdin) - } else { - BufReader::new(stdin) - })) + Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin))) } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 82a719693ec..8d973fc1ade 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -210,14 +210,34 @@ test(no_crate_inject, attr(deny(warnings))), test(attr(allow(dead_code, deprecated, unused_variables, unused_mut))))] +// Don't link to std. We are std. +#![no_std] + +#![deny(missing_docs)] + +// Tell the compiler to link to either panic_abort or panic_unwind #![needs_panic_runtime] +// Always use alloc_system during stage0 since jemalloc might be unavailable or +// disabled (Issue #30592) +#![cfg_attr(stage0, feature(alloc_system))] + +// 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))] + +// std may use features in a platform-specific way +#![allow(unused_features)] + +// std is implemented with unstable features, many of which are internal +// compiler details that will never be stable #![feature(alloc)] #![feature(allow_internal_unstable)] #![feature(asm)] #![feature(associated_consts)] #![feature(borrow_state)] #![feature(box_syntax)] +#![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] #![feature(cfg_target_vendor)] #![feature(char_escape_debug)] @@ -240,13 +260,13 @@ #![feature(heap_api)] #![feature(inclusive_range)] #![feature(int_error_internals)] +#![feature(integer_atomics)] #![feature(into_cow)] #![feature(lang_items)] #![feature(libc)] #![feature(link_args)] #![feature(linkage)] #![feature(macro_reexport)] -#![cfg_attr(test, feature(map_values_mut))] #![feature(needs_panic_runtime)] #![feature(num_bits_bytes)] #![feature(old_wrapping)] @@ -282,21 +302,13 @@ #![feature(zero_one)] #![cfg_attr(test, feature(update_panic_count))] -// Issue# 30592: Systematically use alloc_system during stage0 since jemalloc -// might be unavailable or disabled -#![cfg_attr(stage0, feature(alloc_system))] - -// Don't link to std. We are std. -#![no_std] - -#![deny(missing_docs)] -#![allow(unused_features)] // std may use features in a platform-specific way -#![cfg_attr(not(stage0), deny(warnings))] - +// Explicitly import the prelude. The compiler uses this same unstable attribute +// to import the prelude implicitly when building crates that depend on std. #[prelude_import] #[allow(unused)] use prelude::v1::*; +// Access to Bencher, etc. #[cfg(test)] extern crate test; // We want to reexport a few macros from core but libcore has already been @@ -324,11 +336,22 @@ extern crate alloc_system; // compiler-rt intrinsics extern crate compiler_builtins; -// Make std testable by not duplicating lang items and other globals. See #2912 +// During testing, this crate is not actually the "real" std library, but rather +// it links to the real std library, which was compiled from this same source +// code. So any lang items std defines are conditionally excluded (or else they +// wolud generate duplicate lang item errors), and any globals it defines are +// _not_ the globals used by "real" std. So this import, defined only during +// testing gives test-std access to real-std lang items and globals. See #2912 #[cfg(test)] extern crate std as realstd; -// NB: These reexports are in the order they should be listed in rustdoc +// The standard macros that are not built-in to the compiler. +#[macro_use] +mod macros; + +// The Rust prelude +pub mod prelude; +// Public module declarations and reexports #[stable(feature = "rust1", since = "1.0.0")] pub use core::any; #[stable(feature = "rust1", since = "1.0.0")] @@ -361,48 +384,6 @@ pub use core::raw; pub use core::result; #[stable(feature = "rust1", since = "1.0.0")] pub use core::option; - -pub mod error; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::boxed; -#[stable(feature = "rust1", since = "1.0.0")] -pub use alloc::rc; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::borrow; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::fmt; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::slice; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::str; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::string; -#[stable(feature = "rust1", since = "1.0.0")] -pub use core_collections::vec; - -#[stable(feature = "rust1", since = "1.0.0")] -pub use rustc_unicode::char; - -/* Exported macros */ - -#[macro_use] -mod macros; - -mod rtdeps; - -/* The Prelude. */ - -pub mod prelude; - - -/* Primitive types */ - -// NB: slice and str are primitive types too, but their module docs + primitive -// doc pages are inlined from the public re-exports of core_collections::{slice, -// str} above. - #[stable(feature = "rust1", since = "1.0.0")] pub use core::isize; #[stable(feature = "rust1", since = "1.0.0")] @@ -413,7 +394,6 @@ pub use core::i16; pub use core::i32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::i64; - #[stable(feature = "rust1", since = "1.0.0")] pub use core::usize; #[stable(feature = "rust1", since = "1.0.0")] @@ -424,48 +404,62 @@ pub use core::u16; pub use core::u32; #[stable(feature = "rust1", since = "1.0.0")] pub use core::u64; +#[stable(feature = "rust1", since = "1.0.0")] +pub use alloc::boxed; +#[stable(feature = "rust1", since = "1.0.0")] +pub use alloc::rc; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::borrow; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::fmt; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::slice; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::str; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::string; +#[stable(feature = "rust1", since = "1.0.0")] +pub use core_collections::vec; +#[stable(feature = "rust1", since = "1.0.0")] +pub use rustc_unicode::char; -#[path = "num/f32.rs"] pub mod f32; -#[path = "num/f64.rs"] pub mod f64; - -pub mod ascii; - -/* Common traits */ - -pub mod num; - -/* Runtime and platform support */ +pub mod f32; +pub mod f64; #[macro_use] pub mod thread; - +pub mod ascii; pub mod collections; pub mod env; +pub mod error; pub mod ffi; pub mod fs; pub mod io; pub mod net; +pub mod num; pub mod os; pub mod panic; pub mod path; pub mod process; pub mod sync; pub mod time; -mod memchr; +// Platform-abstraction modules #[macro_use] -#[path = "sys/common/mod.rs"] mod sys_common; - -#[cfg(redox)] -#[path = "sys/redox/mod.rs"] mod sys; -#[cfg(unix)] -#[path = "sys/unix/mod.rs"] mod sys; -#[cfg(windows)] -#[path = "sys/windows/mod.rs"] mod sys; +mod sys_common; +mod sys; -pub mod rt; +// Private support modules mod panicking; mod rand; +mod memchr; + +// This module just defines per-platform native library dependencies +mod rtdeps; + +// The runtime entry point and a few unstable public functions used by the +// compiler +pub mod rt; // Some external utilities of the standard library rely on randomness (aka // rustc_back::TempDir and tests) and need a way to get at the OS rng we've got diff --git a/src/libstd/num/mod.rs b/src/libstd/num.rs index d1c2fc3d3fc..d1c2fc3d3fc 100644 --- a/src/libstd/num/mod.rs +++ b/src/libstd/num.rs diff --git a/src/libstd/panic.rs b/src/libstd/panic.rs index 3788568a2fd..a7e8c4fab37 100644 --- a/src/libstd/panic.rs +++ b/src/libstd/panic.rs @@ -18,7 +18,7 @@ use ops::{Deref, DerefMut}; use panicking; use ptr::{Unique, Shared}; use rc::Rc; -use sync::{Arc, Mutex, RwLock}; +use sync::{Arc, Mutex, RwLock, atomic}; use thread::Result; #[stable(feature = "panic_hooks", since = "1.10.0")] @@ -231,6 +231,46 @@ impl<T: ?Sized> RefUnwindSafe for Mutex<T> {} #[stable(feature = "unwind_safe_lock_refs", since = "1.12.0")] impl<T: ?Sized> RefUnwindSafe for RwLock<T> {} +#[cfg(target_has_atomic = "ptr")] +#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] +impl RefUnwindSafe for atomic::AtomicIsize {} +#[cfg(target_has_atomic = "8")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicI8 {} +#[cfg(target_has_atomic = "16")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicI16 {} +#[cfg(target_has_atomic = "32")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicI32 {} +#[cfg(target_has_atomic = "64")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicI64 {} + +#[cfg(target_has_atomic = "ptr")] +#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] +impl RefUnwindSafe for atomic::AtomicUsize {} +#[cfg(target_has_atomic = "8")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicU8 {} +#[cfg(target_has_atomic = "16")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicU16 {} +#[cfg(target_has_atomic = "32")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicU32 {} +#[cfg(target_has_atomic = "64")] +#[unstable(feature = "integer_atomics", issue = "32976")] +impl RefUnwindSafe for atomic::AtomicU64 {} + +#[cfg(target_has_atomic = "8")] +#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] +impl RefUnwindSafe for atomic::AtomicBool {} + +#[cfg(target_has_atomic = "ptr")] +#[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] +impl<T> RefUnwindSafe for atomic::AtomicPtr<T> {} + #[stable(feature = "catch_unwind", since = "1.9.0")] impl<T> Deref for AssertUnwindSafe<T> { type Target = T; diff --git a/src/libstd/path.rs b/src/libstd/path.rs index a55318d3883..9b7f9980cc0 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -914,6 +914,7 @@ impl<'a> cmp::Ord for Components<'a> { /// [`Path`]: struct.Path.html /// [`push`]: struct.PathBuf.html#method.push /// [`set_extension`]: struct.PathBuf.html#method.set_extension +/// [`Deref`]: ../ops/trait.Deref.html /// /// More details about the overall approach can be found in /// the module documentation. diff --git a/src/libstd/rand/mod.rs b/src/libstd/rand/mod.rs index 69cd37651d5..f48325218fb 100644 --- a/src/libstd/rand/mod.rs +++ b/src/libstd/rand/mod.rs @@ -245,7 +245,7 @@ mod tests { #[cfg_attr(target_os = "emscripten", ignore)] fn test_os_rng_tasks() { - let mut txs = vec!(); + let mut txs = vec![]; for _ in 0..20 { let (tx, rx) = channel(); txs.push(tx); diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs new file mode 100644 index 00000000000..c196bf39432 --- /dev/null +++ b/src/libstd/sys/mod.rs @@ -0,0 +1,45 @@ +// Copyright 2016 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. + +//! Platform-dependent platform abstraction +//! +//! The `std::sys` module is the abstracted interface through which +//! `std` talks to the underlying operating system. It has different +//! implementations for different operating system families, today +//! just Unix and Windows. +//! +//! The centralization of platform-specific code in this module is +//! enforced by the "platform abstraction layer" tidy script in +//! `tools/tidy/pal.rs`. +//! +//! This module is closely related to the platform-independent system +//! integration code in `std::sys_common`. See that module's +//! documentation for details. +//! +//! In the future it would be desirable for the indepedent +//! implementations of this module to be extracted to their own crates +//! that `std` can link to, thus enabling their implementation +//! out-of-tree via crate replacement. Though due to the complex +//! inter-dependencies within `std` that will be a challenging goal to +//! achieve. + +pub use self::imp::*; + +#[cfg(redox)] +#[path = "redox/mod.rs"] +mod imp; + +#[cfg(unix)] +#[path = "unix/mod.rs"] +mod imp; + +#[cfg(windows)] +#[path = "windows/mod.rs"] +mod imp; diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs new file mode 100644 index 00000000000..0c625e7add9 --- /dev/null +++ b/src/libstd/sys/unix/fast_thread_local.rs @@ -0,0 +1,167 @@ +// Copyright 2014-2015 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. + +#![cfg(target_thread_local)] +#![unstable(feature = "thread_local_internals", issue = "0")] + +use cell::{Cell, UnsafeCell}; +use intrinsics; +use ptr; + +pub struct Key<T> { + inner: UnsafeCell<Option<T>>, + + // Metadata to keep track of the state of the destructor. Remember that + // these variables are thread-local, not global. + dtor_registered: Cell<bool>, + dtor_running: Cell<bool>, +} + +unsafe impl<T> ::marker::Sync for Key<T> { } + +impl<T> Key<T> { + pub const fn new() -> Key<T> { + Key { + inner: UnsafeCell::new(None), + dtor_registered: Cell::new(false), + dtor_running: Cell::new(false) + } + } + + pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> { + unsafe { + if intrinsics::needs_drop::<T>() && self.dtor_running.get() { + return None + } + self.register_dtor(); + } + Some(&self.inner) + } + + unsafe fn register_dtor(&self) { + if !intrinsics::needs_drop::<T>() || self.dtor_registered.get() { + return + } + + register_dtor(self as *const _ as *mut u8, + destroy_value::<T>); + self.dtor_registered.set(true); + } +} + +#[cfg(any(target_os = "linux", target_os = "fuchsia"))] +unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + // The fallback implementation uses a vanilla OS-based TLS key to track + // the list of destructors that need to be run for this thread. The key + // then has its own destructor which runs all the other destructors. + // + // The destructor for DTORS is a little special in that it has a `while` + // loop to continuously drain the list of registered destructors. It + // *should* be the case that this loop always terminates because we + // provide the guarantee that a TLS key cannot be set after it is + // flagged for destruction. + use sys_common::thread_local as os; + + static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors)); + type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; + if DTORS.get().is_null() { + let v: Box<List> = box Vec::new(); + DTORS.set(Box::into_raw(v) as *mut u8); + } + let list: &mut List = &mut *(DTORS.get() as *mut List); + list.push((t, dtor)); + + unsafe extern fn run_dtors(mut ptr: *mut u8) { + while !ptr.is_null() { + let list: Box<List> = Box::from_raw(ptr as *mut List); + for &(ptr, dtor) in list.iter() { + dtor(ptr); + } + ptr = DTORS.get(); + DTORS.set(ptr::null_mut()); + } + } +} + +// Since what appears to be glibc 2.18 this symbol has been shipped which +// GCC and clang both use to invoke destructors in thread_local globals, so +// let's do the same! +// +// Note, however, that we run on lots older linuxes, as well as cross +// compiling from a newer linux to an older linux, so we also have a +// fallback implementation to use as well. +// +// Due to rust-lang/rust#18804, make sure this is not generic! +#[cfg(target_os = "linux")] +unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + use mem; + use libc; + + extern { + #[linkage = "extern_weak"] + static __dso_handle: *mut u8; + #[linkage = "extern_weak"] + static __cxa_thread_atexit_impl: *const libc::c_void; + } + if !__cxa_thread_atexit_impl.is_null() { + type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), + arg: *mut u8, + dso_handle: *mut u8) -> libc::c_int; + mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl) + (dtor, t, &__dso_handle as *const _ as *mut _); + return + } + register_dtor_fallback(t, dtor); +} + +// OSX's analog of the above linux function is this _tlv_atexit function. +// The disassembly of thread_local globals in C++ (at least produced by +// clang) will have this show up in the output. +#[cfg(target_os = "macos")] +unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + extern { + fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), + arg: *mut u8); + } + _tlv_atexit(dtor, t); +} + +// Just use the thread_local fallback implementation, at least until there's +// a more direct implementation. +#[cfg(target_os = "fuchsia")] +unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { + register_dtor_fallback(t, dtor); +} + +pub unsafe extern fn destroy_value<T>(ptr: *mut u8) { + let ptr = ptr as *mut Key<T>; + // Right before we run the user destructor be sure to flag the + // destructor as running for this thread so calls to `get` will return + // `None`. + (*ptr).dtor_running.set(true); + + // The OSX implementation of TLS apparently had an odd aspect to it + // where the pointer we have may be overwritten while this destructor + // is running. Specifically if a TLS destructor re-accesses TLS it may + // trigger a re-initialization of all TLS variables, paving over at + // least some destroyed ones with initial values. + // + // This means that if we drop a TLS value in place on OSX that we could + // revert the value to its original state halfway through the + // destructor, which would be bad! + // + // Hence, we use `ptr::read` on OSX (to move to a "safe" location) + // instead of drop_in_place. + if cfg!(target_os = "macos") { + ptr::read((*ptr).inner.get()); + } else { + ptr::drop_in_place((*ptr).inner.get()); + } +} diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 66bc9d4a491..fd7dc17cccd 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -38,6 +38,7 @@ pub mod backtrace; pub mod condvar; pub mod env; pub mod ext; +pub mod fast_thread_local; pub mod fd; pub mod fs; pub mod memchr; @@ -162,3 +163,14 @@ pub fn cvt_r<T, F>(mut f: F) -> io::Result<T> } } } + +// On Unix-like platforms, libc::abort will unregister signal handlers +// including the SIGABRT handler, preventing the abort from being blocked, and +// fclose streams, with the side effect of flushing them so libc bufferred +// output will be printed. Additionally the shell will generally print a more +// understandable error message like "Abort trap" rather than "Illegal +// instruction" that intrinsics::abort would cause, as intrinsics::abort is +// implemented as an illegal instruction. +pub unsafe fn abort_internal() -> ! { + ::libc::abort() +} diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index 947ba2cc752..273341b1918 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -67,3 +67,4 @@ impl io::Write for Stderr { } pub const EBADF_ERR: i32 = ::libc::EBADF as i32; +pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 9cd6e6ca176..defc41c5f46 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -179,7 +179,7 @@ pub fn truncate_utf16_at_nul<'a>(v: &'a [u16]) -> &'a [u16] { } } -trait IsZero { +pub trait IsZero { fn is_zero(&self) -> bool; } @@ -193,7 +193,7 @@ macro_rules! impl_is_zero { impl_is_zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } -fn cvt<I: IsZero>(i: I) -> io::Result<I> { +pub fn cvt<I: IsZero>(i: I) -> io::Result<I> { if i.is_zero() { Err(io::Error::last_os_error()) } else { @@ -201,7 +201,7 @@ fn cvt<I: IsZero>(i: I) -> io::Result<I> { } } -fn dur2timeout(dur: Duration) -> c::DWORD { +pub fn dur2timeout(dur: Duration) -> c::DWORD { // Note that a duration is a (u64, u32) (seconds, nanoseconds) pair, and the // timeouts in windows APIs are typically u32 milliseconds. To translate, we // have two pieces to take care of: @@ -221,3 +221,17 @@ fn dur2timeout(dur: Duration) -> c::DWORD { } }).unwrap_or(c::INFINITE) } + +// On Windows, use the processor-specific __fastfail mechanism. In Windows 8 +// and later, this will terminate the process immediately without running any +// in-process exception handlers. In earlier versions of Windows, this +// sequence of instructions will be treated as an access violation, +// terminating the process but without necessarily bypassing all exception +// handlers. +// +// https://msdn.microsoft.com/en-us/library/dn774154.aspx +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub unsafe fn abort_internal() -> ! { + asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT + ::intrinsics::unreachable(); +} diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index 5f097d2631d..72788776ded 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -207,3 +207,8 @@ fn invalid_encoding() -> io::Error { } pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32; +// The default buffer capacity is 64k, but apparently windows +// doesn't like 64k reads on stdin. See #13304 for details, but the +// idea is that on windows we use a slightly smaller buffer that's +// been seen to be acceptable. +pub const STDIN_BUF_SIZE: usize = 8 * 1024; diff --git a/src/libstd/sys/common/at_exit_imp.rs b/src/libstd/sys_common/at_exit_imp.rs index ce6fd4cb075..ce6fd4cb075 100644 --- a/src/libstd/sys/common/at_exit_imp.rs +++ b/src/libstd/sys_common/at_exit_imp.rs diff --git a/src/libstd/sys/common/backtrace.rs b/src/libstd/sys_common/backtrace.rs index a8540fed928..a8540fed928 100644 --- a/src/libstd/sys/common/backtrace.rs +++ b/src/libstd/sys_common/backtrace.rs diff --git a/src/libstd/sys/common/condvar.rs b/src/libstd/sys_common/condvar.rs index b6f29dd5fc3..b6f29dd5fc3 100644 --- a/src/libstd/sys/common/condvar.rs +++ b/src/libstd/sys_common/condvar.rs diff --git a/src/libstd/sys/common/gnu/libbacktrace.rs b/src/libstd/sys_common/gnu/libbacktrace.rs index b5802afc109..b5802afc109 100644 --- a/src/libstd/sys/common/gnu/libbacktrace.rs +++ b/src/libstd/sys_common/gnu/libbacktrace.rs diff --git a/src/libstd/sys/common/gnu/mod.rs b/src/libstd/sys_common/gnu/mod.rs index 3a8cf2d8425..3a8cf2d8425 100644 --- a/src/libstd/sys/common/gnu/mod.rs +++ b/src/libstd/sys_common/gnu/mod.rs diff --git a/src/libstd/sys/common/io.rs b/src/libstd/sys_common/io.rs index 0483725dd83..23daeeb5187 100644 --- a/src/libstd/sys/common/io.rs +++ b/src/libstd/sys_common/io.rs @@ -12,6 +12,8 @@ use io::ErrorKind; use io::Read; use slice::from_raw_parts_mut; +pub const DEFAULT_BUF_SIZE: usize = 8 * 1024; + // Provides read_to_end functionality over an uninitialized buffer. // This function is unsafe because it calls the underlying // read function with a slice into uninitialized memory. The default diff --git a/src/libstd/sys/common/memchr.rs b/src/libstd/sys_common/memchr.rs index 3824a5fb528..3824a5fb528 100644 --- a/src/libstd/sys/common/memchr.rs +++ b/src/libstd/sys_common/memchr.rs diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys_common/mod.rs index 274f3c10d9c..bbd2f679bca 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys_common/mod.rs @@ -8,23 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +//! Platform-independent platform abstraction +//! +//! This is the platform-independent portion of the standard libraries +//! platform abstraction layer, whereas `std::sys` is the +//! platform-specific portion. +//! +//! The relationship between `std::sys_common`, `std::sys` and the +//! rest of `std` is complex, with dependencies going in all +//! directions: `std` depending on `sys_common`, `sys_common` +//! depending on `sys`, and `sys` depending on `sys_common` and `std`. +//! Ideally `sys_common` would be split into two and the dependencies +//! between them all would form a dag, facilitating the extraction of +//! `std::sys` from the standard library. + #![allow(missing_docs)] use sync::Once; use sys; -macro_rules! rtabort { - ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*))) -} - -macro_rules! rtassert { - ($e:expr) => ({ - if !$e { - rtabort!(concat!("assertion failed: ", stringify!($e))) - } - }) -} - pub mod at_exit_imp; #[cfg(any(not(cargobuild), feature = "backtrace"))] pub mod backtrace; @@ -92,6 +94,10 @@ pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) -> Result<(), ()> { if at_exit_imp::push(Box::new(f)) {Ok(())} else {Err(())} } +macro_rules! rtabort { + ($($t:tt)*) => (::sys_common::util::abort(format_args!($($t)*))) +} + /// One-time runtime cleanup. pub fn cleanup() { static CLEANUP: Once = Once::new(); diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys_common/mutex.rs index d1a738770d3..d1a738770d3 100644 --- a/src/libstd/sys/common/mutex.rs +++ b/src/libstd/sys_common/mutex.rs diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys_common/net.rs index 10ad61f4c80..10ad61f4c80 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys_common/net.rs diff --git a/src/libstd/sys/common/poison.rs b/src/libstd/sys_common/poison.rs index bdc727f1dfc..bdc727f1dfc 100644 --- a/src/libstd/sys/common/poison.rs +++ b/src/libstd/sys_common/poison.rs diff --git a/src/libstd/sys/common/remutex.rs b/src/libstd/sys_common/remutex.rs index 4d0407ccf6c..4d0407ccf6c 100644 --- a/src/libstd/sys/common/remutex.rs +++ b/src/libstd/sys_common/remutex.rs diff --git a/src/libstd/sys/common/rwlock.rs b/src/libstd/sys_common/rwlock.rs index 71a4f01ec4c..71a4f01ec4c 100644 --- a/src/libstd/sys/common/rwlock.rs +++ b/src/libstd/sys_common/rwlock.rs diff --git a/src/libstd/sys/common/thread.rs b/src/libstd/sys_common/thread.rs index 3ee160da5fa..3ee160da5fa 100644 --- a/src/libstd/sys/common/thread.rs +++ b/src/libstd/sys_common/thread.rs diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys_common/thread_info.rs index 95d8b6cc951..95d8b6cc951 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys_common/thread_info.rs diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys_common/thread_local.rs index 25a9d5720d9..25a9d5720d9 100644 --- a/src/libstd/sys/common/thread_local.rs +++ b/src/libstd/sys_common/thread_local.rs diff --git a/src/libstd/sys/common/util.rs b/src/libstd/sys_common/util.rs index dda0abb4c0c..daa0c15920b 100644 --- a/src/libstd/sys/common/util.rs +++ b/src/libstd/sys_common/util.rs @@ -33,38 +33,6 @@ pub fn dumb_print(args: fmt::Arguments) { let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args)); } -// On Redox, use an illegal instruction -#[cfg(redox)] -unsafe fn abort_internal() -> ! { - ::intrinsics::abort() -} - -// On Unix-like platforms, libc::abort will unregister signal handlers -// including the SIGABRT handler, preventing the abort from being blocked, and -// fclose streams, with the side effect of flushing them so libc bufferred -// output will be printed. Additionally the shell will generally print a more -// understandable error message like "Abort trap" rather than "Illegal -// instruction" that intrinsics::abort would cause, as intrinsics::abort is -// implemented as an illegal instruction. -#[cfg(unix)] -unsafe fn abort_internal() -> ! { - ::libc::abort() -} - -// On Windows, use the processor-specific __fastfail mechanism. In Windows 8 -// and later, this will terminate the process immediately without running any -// in-process exception handlers. In earlier versions of Windows, this -// sequence of instructions will be treated as an access violation, -// terminating the process but without necessarily bypassing all exception -// handlers. -// -// https://msdn.microsoft.com/en-us/library/dn774154.aspx -#[cfg(all(windows, any(target_arch = "x86", target_arch = "x86_64")))] -unsafe fn abort_internal() -> ! { - asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT - ::intrinsics::unreachable(); -} - // Other platforms should use the appropriate platform-specific mechanism for // aborting the process. If no platform-specific mechanism is available, // ::intrinsics::abort() may be used instead. The above implementations cover @@ -72,7 +40,7 @@ unsafe fn abort_internal() -> ! { pub fn abort(args: fmt::Arguments) -> ! { dumb_print(format_args!("fatal runtime error: {}\n", args)); - unsafe { abort_internal(); } + unsafe { ::sys::abort_internal(); } } #[allow(dead_code)] // stack overflow detection not enabled on all platforms diff --git a/src/libstd/sys/common/wtf8.rs b/src/libstd/sys_common/wtf8.rs index 0a94ff1e958..0a94ff1e958 100644 --- a/src/libstd/sys/common/wtf8.rs +++ b/src/libstd/sys_common/wtf8.rs diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs index a1ae2c1cb42..f74dd592495 100644 --- a/src/libstd/thread/local.rs +++ b/src/libstd/thread/local.rs @@ -166,8 +166,8 @@ macro_rules! __thread_local_inner { { #[thread_local] #[cfg(target_thread_local)] - static __KEY: $crate::thread::__ElfLocalKeyInner<$t> = - $crate::thread::__ElfLocalKeyInner::new(); + static __KEY: $crate::thread::__FastLocalKeyInner<$t> = + $crate::thread::__FastLocalKeyInner::new(); #[cfg(not(target_thread_local))] static __KEY: $crate::thread::__OsLocalKeyInner<$t> = @@ -310,165 +310,6 @@ impl<T: 'static> LocalKey<T> { } } -#[cfg(target_thread_local)] -#[doc(hidden)] -pub mod elf { - use cell::{Cell, UnsafeCell}; - use intrinsics; - use ptr; - - pub struct Key<T> { - inner: UnsafeCell<Option<T>>, - - // Metadata to keep track of the state of the destructor. Remember that - // these variables are thread-local, not global. - dtor_registered: Cell<bool>, - dtor_running: Cell<bool>, - } - - unsafe impl<T> ::marker::Sync for Key<T> { } - - impl<T> Key<T> { - pub const fn new() -> Key<T> { - Key { - inner: UnsafeCell::new(None), - dtor_registered: Cell::new(false), - dtor_running: Cell::new(false) - } - } - - pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> { - unsafe { - if intrinsics::needs_drop::<T>() && self.dtor_running.get() { - return None - } - self.register_dtor(); - } - Some(&self.inner) - } - - unsafe fn register_dtor(&self) { - if !intrinsics::needs_drop::<T>() || self.dtor_registered.get() { - return - } - - register_dtor(self as *const _ as *mut u8, - destroy_value::<T>); - self.dtor_registered.set(true); - } - } - - #[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "redox"))] - unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - // The fallback implementation uses a vanilla OS-based TLS key to track - // the list of destructors that need to be run for this thread. The key - // then has its own destructor which runs all the other destructors. - // - // The destructor for DTORS is a little special in that it has a `while` - // loop to continuously drain the list of registered destructors. It - // *should* be the case that this loop always terminates because we - // provide the guarantee that a TLS key cannot be set after it is - // flagged for destruction. - use sys_common::thread_local as os; - - static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors)); - type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>; - if DTORS.get().is_null() { - let v: Box<List> = box Vec::new(); - DTORS.set(Box::into_raw(v) as *mut u8); - } - let list: &mut List = &mut *(DTORS.get() as *mut List); - list.push((t, dtor)); - - unsafe extern fn run_dtors(mut ptr: *mut u8) { - while !ptr.is_null() { - let list: Box<List> = Box::from_raw(ptr as *mut List); - for &(ptr, dtor) in list.iter() { - dtor(ptr); - } - ptr = DTORS.get(); - DTORS.set(ptr::null_mut()); - } - } - } - - // Since what appears to be glibc 2.18 this symbol has been shipped which - // GCC and clang both use to invoke destructors in thread_local globals, so - // let's do the same! - // - // Note, however, that we run on lots older linuxes, as well as cross - // compiling from a newer linux to an older linux, so we also have a - // fallback implementation to use as well. - // - // Due to rust-lang/rust#18804, make sure this is not generic! - #[cfg(target_os = "linux")] - unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - use mem; - use libc; - - extern { - #[linkage = "extern_weak"] - static __dso_handle: *mut u8; - #[linkage = "extern_weak"] - static __cxa_thread_atexit_impl: *const libc::c_void; - } - if !__cxa_thread_atexit_impl.is_null() { - type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8), - arg: *mut u8, - dso_handle: *mut u8) -> libc::c_int; - mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl) - (dtor, t, &__dso_handle as *const _ as *mut _); - return - } - register_dtor_fallback(t, dtor); - } - - // OSX's analog of the above linux function is this _tlv_atexit function. - // The disassembly of thread_local globals in C++ (at least produced by - // clang) will have this show up in the output. - #[cfg(target_os = "macos")] - unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - extern { - fn _tlv_atexit(dtor: unsafe extern fn(*mut u8), - arg: *mut u8); - } - _tlv_atexit(dtor, t); - } - - // Just use the thread_local fallback implementation, at least until there's - // a more direct implementation. - #[cfg(any(target_os = "fuchsia", target_os = "redox"))] - unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { - register_dtor_fallback(t, dtor); - } - - pub unsafe extern fn destroy_value<T>(ptr: *mut u8) { - let ptr = ptr as *mut Key<T>; - // Right before we run the user destructor be sure to flag the - // destructor as running for this thread so calls to `get` will return - // `None`. - (*ptr).dtor_running.set(true); - - // The OSX implementation of TLS apparently had an odd aspect to it - // where the pointer we have may be overwritten while this destructor - // is running. Specifically if a TLS destructor re-accesses TLS it may - // trigger a re-initialization of all TLS variables, paving over at - // least some destroyed ones with initial values. - // - // This means that if we drop a TLS value in place on OSX that we could - // revert the value to its original state halfway through the - // destructor, which would be bad! - // - // Hence, we use `ptr::read` on OSX (to move to a "safe" location) - // instead of drop_in_place. - if cfg!(target_os = "macos") { - ptr::read((*ptr).inner.get()); - } else { - ptr::drop_in_place((*ptr).inner.get()); - } - } -} - #[doc(hidden)] pub mod os { use cell::{Cell, UnsafeCell}; diff --git a/src/libstd/thread/mod.rs b/src/libstd/thread/mod.rs index 150482e4af4..255cd2a9bc0 100644 --- a/src/libstd/thread/mod.rs +++ b/src/libstd/thread/mod.rs @@ -181,9 +181,18 @@ use time::Duration; #[stable(feature = "rust1", since = "1.0.0")] pub use self::local::{LocalKey, LocalKeyState}; +// The types used by the thread_local! macro to access TLS keys. Note that there +// are two types, the "OS" type and the "fast" type. The OS thread local key +// type is accessed via platform-specific API calls and is slow, while the fast +// key type is accessed via code generated via LLVM, where TLS keys are set up +// by the elf linker. Note that the OS TLS type is always available: on macOS +// the standard library is compiled with support for older platform versions +// where fast TLS was not available; end-user code is compiled with fast TLS +// where available, but both are needed. + #[unstable(feature = "libstd_thread_internals", issue = "0")] #[cfg(target_thread_local)] -#[doc(hidden)] pub use self::local::elf::Key as __ElfLocalKeyInner; +#[doc(hidden)] pub use sys::fast_thread_local::Key as __FastLocalKeyInner; #[unstable(feature = "libstd_thread_internals", issue = "0")] #[doc(hidden)] pub use self::local::os::Key as __OsLocalKeyInner; |
