Auto merge of #36948 - brson:sys, r=brson
More refactoring to obey platform abstraction lint The most interesting things here are moving `std/sys/common` to `std/sys_common`, and `std/num/{f32,f64}.rs` to `std/{f32,f64}.rs`, and adding more documentation to `std/lib.rs`. r? @alexcrichton
This commit is contained in:
commit
0ca9967af7
@ -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
|
||||
|
@ -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)))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -210,8 +210,27 @@
|
||||
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)]
|
||||
@ -248,7 +267,6 @@
|
||||
#![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)]
|
||||
@ -284,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
|
||||
@ -326,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")]
|
||||
@ -363,14 +384,30 @@ 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 core::isize;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::i8;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::i16;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
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")]
|
||||
pub use core::u8;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::u16;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
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")]
|
||||
@ -383,89 +420,46 @@ pub use core_collections::str;
|
||||
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")]
|
||||
pub use core::i8;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::i16;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
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")]
|
||||
pub use core::u8;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::u16;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::u32;
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub use core::u64;
|
||||
|
||||
#[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;
|
||||
mod sys_common;
|
||||
mod sys;
|
||||
|
||||
#[cfg(unix)]
|
||||
#[path = "sys/unix/mod.rs"] mod sys;
|
||||
#[cfg(windows)]
|
||||
#[path = "sys/windows/mod.rs"] 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
|
||||
|
41
src/libstd/sys/mod.rs
Normal file
41
src/libstd/sys/mod.rs
Normal file
@ -0,0 +1,41 @@
|
||||
// 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(unix)]
|
||||
#[path = "unix/mod.rs"]
|
||||
mod imp;
|
||||
|
||||
#[cfg(windows)]
|
||||
#[path = "windows/mod.rs"]
|
||||
mod imp;
|
167
src/libstd/sys/unix/fast_thread_local.rs
Normal file
167
src/libstd/sys/unix/fast_thread_local.rs
Normal file
@ -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());
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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
|
@ -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;
|
||||
@ -87,6 +89,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();
|
@ -33,32 +33,6 @@ pub fn dumb_print(args: fmt::Arguments) {
|
||||
let _ = Stderr::new().map(|mut stderr| stderr.write_fmt(args));
|
||||
}
|
||||
|
||||
// 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
|
||||
@ -66,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
|
@ -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"))]
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub mod os {
|
||||
use cell::{Cell, UnsafeCell};
|
||||
|
@ -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;
|
||||
|
||||
|
@ -57,22 +57,18 @@ const EXCEPTION_PATHS: &'static [&'static str] = &[
|
||||
"src/libpanic_abort",
|
||||
"src/libpanic_unwind",
|
||||
"src/libunwind",
|
||||
"src/libstd/sys/unix", // This is where platform-specific code for std should live
|
||||
"src/libstd/sys/windows", // Ditto
|
||||
"src/libstd/sys/", // Platform-specific code for std lives here.
|
||||
// This has the trailing slash so that sys_common is not excepted.
|
||||
"src/libstd/os", // Platform-specific public interfaces
|
||||
"src/rtstartup", // Not sure what to do about this. magic stuff for mingw
|
||||
|
||||
// temporary exceptions
|
||||
"src/libstd/lib.rs", // This could probably be done within the sys directory
|
||||
"src/libstd/rtdeps.rs", // Until rustbuild replaces make
|
||||
"src/libstd/path.rs",
|
||||
"src/libstd/io/stdio.rs",
|
||||
"src/libstd/num/f32.rs",
|
||||
"src/libstd/num/f64.rs",
|
||||
"src/libstd/thread/local.rs",
|
||||
"src/libstd/sys/common/mod.rs",
|
||||
"src/libstd/sys/common/net.rs",
|
||||
"src/libstd/sys/common/util.rs",
|
||||
"src/libstd/f32.rs",
|
||||
"src/libstd/f64.rs",
|
||||
"src/libstd/sys_common/mod.rs",
|
||||
"src/libstd/sys_common/net.rs",
|
||||
"src/libterm", // Not sure how to make this crate portable, but test needs it
|
||||
"src/libtest", // Probably should defer to unstable std::sys APIs
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user