diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index a166dc369cb1b..1cb247d4b44b0 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -181,7 +181,7 @@ use std::mem; use std::os; use std::rt; use std::slice; -use std::sync::{Once, ONCE_INIT}; +use std::sync::{Once, ONCE_INIT, StaticMutex, MUTEX_INIT}; use regex::Regex; @@ -199,6 +199,8 @@ pub const MAX_LOG_LEVEL: u32 = 255; /// The default logging level of a crate if no other is specified. const DEFAULT_LOG_LEVEL: u32 = 1; +static LOCK: StaticMutex = MUTEX_INIT; + /// An unsafe constant that is the maximum logging level of any module /// specified. This is the first line of defense to determining whether a /// logging statement should be run. @@ -291,9 +293,18 @@ impl Drop for DefaultLogger { pub fn log(level: u32, loc: &'static LogLocation, args: fmt::Arguments) { // Test the literal string from args against the current filter, if there // is one. - match unsafe { FILTER.as_ref() } { - Some(filter) if !filter.is_match(&args.to_string()[]) => return, - _ => {} + unsafe { + let _g = LOCK.lock(); + match FILTER as uint { + 0 => {} + 1 => panic!("cannot log after main thread has exited"), + n => { + let filter = mem::transmute::<_, &Regex>(n); + if !filter.is_match(args.to_string().as_slice()) { + return + } + } + } } // Completely remove the local logger from TLS in case anyone attempts to @@ -375,9 +386,15 @@ pub fn mod_enabled(level: u32, module: &str) -> bool { // This assertion should never get tripped unless we're in an at_exit // handler after logging has been torn down and a logging attempt was made. - assert!(unsafe { !DIRECTIVES.is_null() }); - enabled(level, module, unsafe { (*DIRECTIVES).iter() }) + let _g = LOCK.lock(); + unsafe { + assert!(DIRECTIVES as uint != 0); + assert!(DIRECTIVES as uint != 1, + "cannot log after the main thread has exited"); + + enabled(level, module, (*DIRECTIVES).iter()) + } } fn enabled(level: u32, @@ -433,14 +450,15 @@ fn init() { // Schedule the cleanup for the globals for when the runtime exits. rt::at_exit(move |:| { + let _g = LOCK.lock(); assert!(!DIRECTIVES.is_null()); let _directives: Box> = mem::transmute(DIRECTIVES); - DIRECTIVES = 0 as *const Vec; + DIRECTIVES = 1 as *const Vec; if !FILTER.is_null() { let _filter: Box = mem::transmute(FILTER); - FILTER = 0 as *const _; + FILTER = 1 as *const _; } }); } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index 9ee2f5705b828..1cdea4f6445d4 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -25,30 +25,21 @@ //! out.write(b"Hello, world!"); //! ``` +use prelude::v1::*; use self::StdSource::*; -use boxed::Box; use cell::RefCell; -use clone::Clone; use failure::LOCAL_STDERR; use fmt; -use io::{Reader, Writer, IoResult, IoError, OtherIoError, Buffer, - standard_error, EndOfFile, LineBufferedWriter, BufferedReader}; -use marker::{Sync, Send}; +use io::{IoResult, IoError, OtherIoError, standard_error, EndOfFile}; +use io::{LineBufferedWriter, BufferedReader}; use libc; use mem; -use option::Option; -use option::Option::{Some, None}; -use ops::{Deref, DerefMut, FnOnce}; -use result::Result::{Ok, Err}; +use ops::{Deref, DerefMut}; use rt; -use slice::SliceExt; -use str::StrExt; -use string::String; +use sync::{Arc, Mutex, MutexGuard, StaticMutex, MUTEX_INIT}; use sys::{fs, tty}; -use sync::{Arc, Mutex, MutexGuard, Once, ONCE_INIT}; use uint; -use vec::Vec; // And so begins the tale of acquiring a uv handle to a stdio stream on all // platforms in all situations. Our story begins by splitting the world into two @@ -217,14 +208,15 @@ impl Reader for StdinReader { pub fn stdin() -> StdinReader { // We're following the same strategy as kimundi's lazy_static library static mut STDIN: *const StdinReader = 0 as *const StdinReader; - static ONCE: Once = ONCE_INIT; + static LOCK: StaticMutex = MUTEX_INIT; unsafe { - ONCE.call_once(|| { - // 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. + let _g = LOCK.lock(); + if STDIN as uint == 0 { + // 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. let stdin = if cfg!(windows) { BufferedReader::with_capacity(8 * 1024, stdin_raw()) } else { @@ -237,11 +229,15 @@ pub fn stdin() -> StdinReader { // Make sure to free it at exit rt::at_exit(|| { - mem::transmute::<_, Box>(STDIN); - STDIN = 0 as *const _; + let g = LOCK.lock(); + let stdin = STDIN; + STDIN = 1 as *const _; + drop(g); + mem::transmute::<_, Box>(stdin); }); - }); - + } else if STDIN as uint == 1 { + panic!("accessing stdin after the main thread has exited") + } (*STDIN).clone() } } diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index dc157c7d67660..d7d7d8915cf8d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -251,13 +251,14 @@ pub mod collections; pub mod thread; pub mod sync; +#[macro_use] +#[path = "sys/common/mod.rs"] mod sys_common; + #[cfg(unix)] #[path = "sys/unix/mod.rs"] mod sys; #[cfg(windows)] #[path = "sys/windows/mod.rs"] mod sys; -#[path = "sys/common/mod.rs"] mod sys_common; - pub mod rt; mod failure; diff --git a/src/libstd/rt/at_exit_imp.rs b/src/libstd/rt/at_exit_imp.rs index 5823f8453d84a..08dabd3b0b603 100644 --- a/src/libstd/rt/at_exit_imp.rs +++ b/src/libstd/rt/at_exit_imp.rs @@ -29,6 +29,8 @@ type Queue = Vec; static LOCK: Mutex = MUTEX_INIT; static mut QUEUE: *mut Queue = 0 as *mut Queue; +const DTOR_RUN_ITERS: uint = 10; + unsafe fn init() { if QUEUE.is_null() { let state: Box = box Vec::new(); @@ -49,7 +51,7 @@ pub fn cleanup() { unsafe { LOCK.lock(); let queue = QUEUE; - QUEUE = 1 as *mut _; + QUEUE = 1u as *mut _; LOCK.unlock(); // make sure we're not recursively cleaning up diff --git a/src/libstd/rt/mod.rs b/src/libstd/rt/mod.rs index e3e4e132b8172..9137edfef1d72 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -94,9 +94,7 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { // but we just do this to name the main thread and to give it correct // info about the stack bounds. let thread: Thread = NewThread::new(Some("
".to_string())); - thread_info::set((my_stack_bottom, my_stack_top), - sys::thread::guard::main(), - thread); + thread_info::set(sys::thread::guard::main(), thread); // By default, some platforms will send a *signal* when a EPIPE error // would otherwise be delivered. This runtime doesn't install a SIGPIPE @@ -135,20 +133,14 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { } } -/// Enqueues a procedure to run when the runtime is cleaned up -/// -/// The procedure passed to this function will be executed as part of the -/// runtime cleanup phase. For normal rust programs, this means that it will run -/// after all other threads have exited. -/// -/// The procedure is *not* executed with a local `Thread` available to it, so -/// primitives like logging, I/O, channels, spawning, etc, are *not* available. -/// This is meant for "bare bones" usage to clean up runtime details, this is -/// not meant as a general-purpose "let's clean everything up" function. +/// Enqueues a procedure to run when the main thread exits. /// /// It is forbidden for procedures to register more `at_exit` handlers when they /// are running, and doing so will lead to a process abort. -pub fn at_exit(f: F) { +/// +/// Note that other threads may still be running when `at_exit` routines start +/// running. +pub fn at_exit(f: F) { at_exit_imp::push(Thunk::new(f)); } @@ -164,8 +156,5 @@ pub fn at_exit(f: F) { pub unsafe fn cleanup() { args::cleanup(); sys::stack_overflow::cleanup(); - // FIXME: (#20012): the resources being cleaned up by at_exit - // currently are not prepared for cleanup to happen asynchronously - // with detached threads using the resources; for now, we leak. - // at_exit_imp::cleanup(); + at_exit_imp::cleanup(); } diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index 4cd0b29688a70..1269e5c83234b 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -68,7 +68,7 @@ use intrinsics; use libc::c_void; use mem; use sync::atomic::{self, Ordering}; -use sync::{Once, ONCE_INIT}; +use sys_common::mutex::{Mutex, MUTEX_INIT}; use rt::libunwind as uw; @@ -529,11 +529,20 @@ pub fn begin_unwind(msg: M, file_line: &(&'static str, uint)) -> /// Doing this split took the LLVM IR line counts of `fn main() { panic!() /// }` from ~1900/3700 (-O/no opts) to 180/590. #[inline(never)] #[cold] // this is the slow path, please never inline this -fn begin_unwind_inner(msg: Box, file_line: &(&'static str, uint)) -> ! { +fn begin_unwind_inner(msg: Box, + file_line: &(&'static str, uint)) -> ! { // Make sure the default failure handler is registered before we look at the // callbacks. - static INIT: Once = ONCE_INIT; - INIT.call_once(|| unsafe { register(failure::on_fail); }); + unsafe { + static LOCK: Mutex = MUTEX_INIT; + static mut INIT: bool = false; + LOCK.lock(); + if !INIT { + register(failure::on_fail); + INIT = true; + } + LOCK.unlock(); + } // First, invoke call the user-defined callbacks triggered on thread panic. // diff --git a/src/libstd/sys/common/helper_thread.rs b/src/libstd/sys/common/helper_thread.rs index f940b6ed3682e..a01baf9fd413d 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -69,6 +69,17 @@ struct RaceBox(helper_signal::signal); unsafe impl Send for RaceBox {} unsafe impl Sync for RaceBox {} +macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => ( + static $name: Helper<$m> = Helper { + lock: ::sync::MUTEX_INIT, + cond: ::sync::CONDVAR_INIT, + chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> }, + signal: ::cell::UnsafeCell { value: 0 }, + initialized: ::cell::UnsafeCell { value: false }, + shutdown: ::cell::UnsafeCell { value: false }, + }; +) } + impl Helper { /// Lazily boots a helper thread, becoming a no-op if the helper has already /// been spawned. @@ -85,7 +96,7 @@ impl Helper { { unsafe { let _guard = self.lock.lock().unwrap(); - if !*self.initialized.get() { + if *self.chan.get() as uint == 0 { let (tx, rx) = channel(); *self.chan.get() = mem::transmute(box tx); let (receive, send) = helper_signal::new(); @@ -94,15 +105,17 @@ impl Helper { let receive = RaceBox(receive); let t = f(); - Thread::spawn(move |:| { + Thread::spawn(move || { helper(receive.0, rx, t); let _g = self.lock.lock().unwrap(); *self.shutdown.get() = true; self.cond.notify_one() }); - rt::at_exit(move|:| { self.shutdown() }); + rt::at_exit(move || { self.shutdown() }); *self.initialized.get() = true; + } else if *self.chan.get() as uint == 1 { + panic!("cannot continue usage after shutdown"); } } } @@ -117,7 +130,9 @@ impl Helper { // Must send and *then* signal to ensure that the child receives the // message. Otherwise it could wake up and go to sleep before we // send the message. - assert!(!self.chan.get().is_null()); + assert!(*self.chan.get() as uint != 0); + assert!(*self.chan.get() as uint != 1, + "cannot continue usage after shutdown"); (**self.chan.get()).send(msg).unwrap(); helper_signal::signal(*self.signal.get() as helper_signal::signal); } @@ -130,9 +145,13 @@ impl Helper { // returns. let mut guard = self.lock.lock().unwrap(); + let ptr = *self.chan.get(); + if ptr as uint == 1 { + panic!("cannot continue usage after shutdown"); + } // Close the channel by destroying it let chan: Box> = mem::transmute(*self.chan.get()); - *self.chan.get() = 0 as *mut Sender; + *self.chan.get() = 1 as *mut Sender; drop(chan); helper_signal::signal(*self.signal.get() as helper_signal::signal); diff --git a/src/libstd/sys/common/mod.rs b/src/libstd/sys/common/mod.rs index a31dcc9884f46..861069ffcc495 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -9,7 +9,6 @@ // except according to those terms. #![allow(missing_docs)] -#![allow(dead_code)] use io::{self, IoError, IoResult}; use prelude::v1::*; @@ -19,9 +18,10 @@ use num::Int; use path::BytesContainer; use collections; +#[macro_use] pub mod helper_thread; + pub mod backtrace; pub mod condvar; -pub mod helper_thread; pub mod mutex; pub mod net; pub mod rwlock; diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys/common/mutex.rs index 9aea0fb3b3172..1c35936ec96f8 100644 --- a/src/libstd/sys/common/mutex.rs +++ b/src/libstd/sys/common/mutex.rs @@ -29,6 +29,7 @@ impl Mutex { /// Behavior is undefined if the mutex is moved after the first method is /// called on the mutex. #[inline] + #[allow(dead_code)] // sys is not exported yet pub unsafe fn new() -> Mutex { Mutex(imp::Mutex::new()) } /// Lock the mutex blocking the current thread until it is available. diff --git a/src/libstd/sys/common/net.rs b/src/libstd/sys/common/net.rs index 4cf891ac4985e..dbb3e385504b2 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -25,7 +25,9 @@ use str; use sys::{self, retry, c, sock_t, last_error, last_net_error, last_gai_error, close_sock, wrlen, msglen_t, os, wouldblock, set_nonblocking, timer, ms_to_timeval, decode_error_detailed}; -use sync::{Arc, Mutex, MutexGuard}; +use sync::{Arc, Mutex}; +#[cfg(not(target_os = "linux"))] +use sync::MutexGuard; use sys_common::{self, keep_going, short_write, timeout}; use cmp; use io; @@ -613,11 +615,13 @@ impl Drop for Inner { fn drop(&mut self) { unsafe { close_sock(self.fd); } } } +#[cfg(not(target_os = "linux"))] pub struct Guard<'a> { pub fd: sock_t, pub guard: MutexGuard<'a, ()>, } +#[cfg(not(target_os = "linux"))] #[unsafe_destructor] impl<'a> Drop for Guard<'a> { fn drop(&mut self) { diff --git a/src/libstd/sys/common/rwlock.rs b/src/libstd/sys/common/rwlock.rs index df016b9e293b7..b7c4cfcd0f5fe 100644 --- a/src/libstd/sys/common/rwlock.rs +++ b/src/libstd/sys/common/rwlock.rs @@ -26,6 +26,7 @@ impl RWLock { /// Usage of an RWLock is undefined if it is moved after its first use (any /// function calls below). #[inline] + #[allow(dead_code)] // sys is not exported yet pub unsafe fn new() -> RWLock { RWLock(imp::RWLock::new()) } /// Acquire shared access to the underlying lock, blocking the current diff --git a/src/libstd/sys/common/stack.rs b/src/libstd/sys/common/stack.rs index ce5ab67ae613c..e956a81d94ed4 100644 --- a/src/libstd/sys/common/stack.rs +++ b/src/libstd/sys/common/stack.rs @@ -121,37 +121,6 @@ pub unsafe fn record_os_managed_stack_bounds(stack_lo: uint, _stack_hi: uint) { record_sp_limit(stack_lo + RED_ZONE); } -#[inline(always)] -pub unsafe fn record_rust_managed_stack_bounds(stack_lo: uint, stack_hi: uint) { - // When the old runtime had segmented stacks, it used a calculation that was - // "limit + RED_ZONE + FUDGE". The red zone was for things like dynamic - // symbol resolution, llvm function calls, etc. In theory this red zone - // value is 0, but it matters far less when we have gigantic stacks because - // we don't need to be so exact about our stack budget. The "fudge factor" - // was because LLVM doesn't emit a stack check for functions < 256 bytes in - // size. Again though, we have giant stacks, so we round all these - // calculations up to the nice round number of 20k. - record_sp_limit(stack_lo + RED_ZONE); - - return target_record_stack_bounds(stack_lo, stack_hi); - - #[cfg(not(windows))] #[inline(always)] - unsafe fn target_record_stack_bounds(_stack_lo: uint, _stack_hi: uint) {} - - #[cfg(all(windows, target_arch = "x86"))] #[inline(always)] - unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) { - // stack range is at TIB: %fs:0x04 (top) and %fs:0x08 (bottom) - asm!("mov $0, %fs:0x04" :: "r"(stack_hi) :: "volatile"); - asm!("mov $0, %fs:0x08" :: "r"(stack_lo) :: "volatile"); - } - #[cfg(all(windows, target_arch = "x86_64"))] #[inline(always)] - unsafe fn target_record_stack_bounds(stack_lo: uint, stack_hi: uint) { - // stack range is at TIB: %gs:0x08 (top) and %gs:0x10 (bottom) - asm!("mov $0, %gs:0x08" :: "r"(stack_hi) :: "volatile"); - asm!("mov $0, %gs:0x10" :: "r"(stack_lo) :: "volatile"); - } -} - /// Records the current limit of the stack as specified by `end`. /// /// This is stored in an OS-dependent location, likely inside of the thread diff --git a/src/libstd/sys/common/thread_info.rs b/src/libstd/sys/common/thread_info.rs index 92b936e74f654..dd1106fe0b192 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys/common/thread_info.rs @@ -8,6 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +#![allow(dead_code)] // stack_guard isn't used right now on all platforms + use core::prelude::*; use cell::RefCell; @@ -16,10 +18,6 @@ use thread::Thread; use thread_local::State; struct ThreadInfo { - // This field holds the known bounds of the stack in (lo, hi) - // form. Not all threads necessarily know their precise bounds, - // hence this is optional. - stack_bounds: (uint, uint), stack_guard: uint, thread: Thread, } @@ -36,7 +34,6 @@ impl ThreadInfo { THREAD_INFO.with(move |c| { if c.borrow().is_none() { *c.borrow_mut() = Some(ThreadInfo { - stack_bounds: (0, 0), stack_guard: 0, thread: NewThread::new(None), }) @@ -54,10 +51,9 @@ pub fn stack_guard() -> uint { ThreadInfo::with(|info| info.stack_guard) } -pub fn set(stack_bounds: (uint, uint), stack_guard: uint, thread: Thread) { +pub fn set(stack_guard: uint, thread: Thread) { THREAD_INFO.with(|c| assert!(c.borrow().is_none())); THREAD_INFO.with(move |c| *c.borrow_mut() = Some(ThreadInfo{ - stack_bounds: stack_bounds, stack_guard: stack_guard, thread: thread, })); diff --git a/src/libstd/sys/common/thread_local.rs b/src/libstd/sys/common/thread_local.rs index e9af796c6745c..8612e9a87a097 100644 --- a/src/libstd/sys/common/thread_local.rs +++ b/src/libstd/sys/common/thread_local.rs @@ -55,11 +55,11 @@ //! ``` #![allow(non_camel_case_types)] +#![allow(dead_code)] // sys isn't exported yet use prelude::v1::*; use sync::atomic::{self, AtomicUint, Ordering}; -use sync::{Mutex, Once, ONCE_INIT}; use sys::thread_local as imp; @@ -140,9 +140,6 @@ pub const INIT_INNER: StaticKeyInner = StaticKeyInner { key: atomic::ATOMIC_UINT_INIT, }; -static INIT_KEYS: Once = ONCE_INIT; -static mut KEYS: *mut Mutex> = 0 as *mut _; - impl StaticKey { /// Gets the value associated with this TLS key /// diff --git a/src/libstd/sys/unix/backtrace.rs b/src/libstd/sys/unix/backtrace.rs index 7164931c55acd..bad9865eb8c14 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -150,7 +150,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> { // I/O done here is blocking I/O, not green I/O, so we don't have to // worry about this being a native vs green mutex. static LOCK: StaticMutex = MUTEX_INIT; - let _g = unsafe { LOCK.lock() }; + let _g = LOCK.lock(); try!(writeln!(w, "stack backtrace:")); diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 6a408aa60f0bf..a8f642ccdbfa0 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -10,10 +10,6 @@ #![allow(missing_docs)] #![allow(non_camel_case_types)] -#![allow(unused_imports)] -#![allow(dead_code)] -#![allow(unused_unsafe)] -#![allow(unused_mut)] use prelude::v1::*; @@ -21,21 +17,9 @@ use ffi; use io::{self, IoResult, IoError}; use libc; use num::{Int, SignedInt}; -use num; use str; use sys_common::mkerr_libc; -macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => ( - static $name: Helper<$m> = Helper { - lock: ::sync::MUTEX_INIT, - cond: ::sync::CONDVAR_INIT, - chan: ::cell::UnsafeCell { value: 0 as *mut Sender<$m> }, - signal: ::cell::UnsafeCell { value: 0 }, - initialized: ::cell::UnsafeCell { value: false }, - shutdown: ::cell::UnsafeCell { value: false }, - }; -) } - pub mod backtrace; pub mod c; pub mod ext; diff --git a/src/libstd/sys/unix/mutex.rs b/src/libstd/sys/unix/mutex.rs index ada8a7f2349bb..0468db5f7bc9e 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -11,7 +11,6 @@ use cell::UnsafeCell; use marker::Sync; use sys::sync as ffi; -use sys_common::mutex; pub struct Mutex { inner: UnsafeCell } @@ -26,6 +25,7 @@ pub const MUTEX_INIT: Mutex = Mutex { unsafe impl Sync for Mutex {} +#[allow(dead_code)] // sys isn't exported yet impl Mutex { #[inline] pub unsafe fn new() -> Mutex { diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 175c4e2e353f9..484966f82c3bf 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -10,6 +10,8 @@ //! Implementation of `std::os` functionality for unix systems +#![allow(unused_imports)] // lots of cfg code here + use prelude::v1::*; use error::{FromError, Error}; @@ -19,7 +21,7 @@ use io::{IoError, IoResult}; use libc::{self, c_int, c_char, c_void}; use os::TMPBUF_SZ; use os; -use path::{BytesContainer}; +use path::BytesContainer; use ptr; use str; use sys::fs::FileDesc; diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 158a1ce220411..a26584c6105f0 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -143,7 +143,7 @@ impl UnixStream { fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { let ret = Guard { fd: self.fd(), - guard: unsafe { self.inner.lock.lock().unwrap() }, + guard: self.inner.lock.lock().unwrap(), }; assert!(set_nonblocking(self.fd(), true).is_ok()); ret diff --git a/src/libstd/sys/unix/process.rs b/src/libstd/sys/unix/process.rs index 36bf696dba550..f58ee6154c4b8 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -16,7 +16,7 @@ use collections::hash_map::Hasher; use ffi::CString; use hash::Hash; use io::process::{ProcessExit, ExitStatus, ExitSignal}; -use io::{self, IoResult, IoError, EndOfFile}; +use io::{IoResult, EndOfFile}; use libc::{self, pid_t, c_void, c_int}; use mem; use os; @@ -329,7 +329,7 @@ impl Process { // The actual communication between the helper thread and this thread is // quite simple, just a channel moving data around. - unsafe { HELPER.boot(register_sigchld, waitpid_helper) } + HELPER.boot(register_sigchld, waitpid_helper); match self.try_wait() { Some(ret) => return Ok(ret), @@ -337,7 +337,7 @@ impl Process { } let (tx, rx) = channel(); - unsafe { HELPER.send(NewChild(self.pid, tx, deadline)); } + HELPER.send(NewChild(self.pid, tx, deadline)); return match rx.recv() { Ok(e) => Ok(e), Err(..) => Err(timeout("wait timed out")), @@ -421,8 +421,15 @@ impl Process { Ok(NewChild(pid, tx, deadline)) => { active.push((pid, tx, deadline)); } + // Once we've been disconnected it means the main + // thread is exiting (at_exit has run). We could + // still have active waiter for other threads, so + // we're just going to drop them all on the floor. + // This means that they won't receive a "you're + // done" message in which case they'll be considered + // as timed out, but more generally errors will + // start propagating. Err(TryRecvError::Disconnected) => { - assert!(active.len() == 0); break 'outer; } Err(TryRecvError::Empty) => break, diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs index 0d63ff14ff26b..4f9b06685ec0c 100644 --- a/src/libstd/sys/unix/rwlock.rs +++ b/src/libstd/sys/unix/rwlock.rs @@ -17,6 +17,7 @@ pub const RWLOCK_INIT: RWLock = RWLock { inner: UnsafeCell { value: ffi::PTHREAD_RWLOCK_INITIALIZER }, }; +#[allow(dead_code)] // sys isn't exported yet impl RWLock { #[inline] pub unsafe fn new() -> RWLock { diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 48a51813ba4ab..86e9e2f225c15 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -34,7 +34,6 @@ impl Drop for Handler { #[cfg(any(target_os = "linux", target_os = "macos"))] mod imp { - use core::prelude::*; use sys_common::stack; use super::Handler; diff --git a/src/libstd/sys/unix/tcp.rs b/src/libstd/sys/unix/tcp.rs index 59eebd3f28eca..dc4a793fb4caa 100644 --- a/src/libstd/sys/unix/tcp.rs +++ b/src/libstd/sys/unix/tcp.rs @@ -137,10 +137,6 @@ impl TcpAcceptor { Err(sys_common::eof()) } - pub fn socket_name(&mut self) -> IoResult { - net::sockname(self.fd(), libc::getsockname) - } - pub fn set_timeout(&mut self, timeout: Option) { self.deadline = timeout.map(|a| sys::timer::now() + a).unwrap_or(0); } diff --git a/src/libstd/sys/unix/timer.rs b/src/libstd/sys/unix/timer.rs index 62f3242a20625..b9490885be4a6 100644 --- a/src/libstd/sys/unix/timer.rs +++ b/src/libstd/sys/unix/timer.rs @@ -100,7 +100,7 @@ pub fn now() -> u64 { fn helper(input: libc::c_int, messages: Receiver, _: ()) { let mut set: c::fd_set = unsafe { mem::zeroed() }; - let mut fd = FileDesc::new(input, true); + let fd = FileDesc::new(input, true); let mut timeout: libc::timeval = unsafe { mem::zeroed() }; // active timers are those which are able to be selected upon (and it's a @@ -168,8 +168,15 @@ fn helper(input: libc::c_int, messages: Receiver, _: ()) { 1 => { loop { match messages.try_recv() { + // Once we've been disconnected it means the main thread + // is exiting (at_exit has run). We could still have + // active timers for other threads, so we're just going + // to drop them all on the floor. This is all we can + // really do, however, to prevent resource leakage. The + // remaining timers will likely start panicking quickly + // as they attempt to re-use this thread but are + // disallowed to do so. Err(TryRecvError::Disconnected) => { - assert!(active.len() == 0); break 'outer; } diff --git a/src/libstd/sys/unix/tty.rs b/src/libstd/sys/unix/tty.rs index bee3d440a16c2..019ecfc9a81d4 100644 --- a/src/libstd/sys/unix/tty.rs +++ b/src/libstd/sys/unix/tty.rs @@ -44,5 +44,4 @@ impl TTY { pub fn get_winsize(&mut self) -> IoResult<(int, int)> { Err(sys_common::unimpl()) } - pub fn isatty(&self) -> bool { false } } diff --git a/src/libstd/sys/windows/backtrace.rs b/src/libstd/sys/windows/backtrace.rs index ee2dd14955b69..655fc773066d4 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -7,19 +7,22 @@ // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. -/// As always, windows has something very different than unix, we mainly want -/// to avoid having to depend too much on libunwind for windows. -/// -/// If you google around, you'll find a fair bit of references to built-in -/// functions to get backtraces on windows. It turns out that most of these are -/// in an external library called dbghelp. I was unable to find this library -/// via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent -/// of it. -/// -/// You'll also find that there's a function called CaptureStackBackTrace -/// mentioned frequently (which is also easy to use), but sadly I didn't have a -/// copy of that function in my mingw install (maybe it was broken?). Instead, -/// this takes the route of using StackWalk64 in order to walk the stack. + +//! As always, windows has something very different than unix, we mainly want +//! to avoid having to depend too much on libunwind for windows. +//! +//! If you google around, you'll find a fair bit of references to built-in +//! functions to get backtraces on windows. It turns out that most of these are +//! in an external library called dbghelp. I was unable to find this library +//! via `-ldbghelp`, but it is apparently normal to do the `dlopen` equivalent +//! of it. +//! +//! You'll also find that there's a function called CaptureStackBackTrace +//! mentioned frequently (which is also easy to use), but sadly I didn't have a +//! copy of that function in my mingw install (maybe it was broken?). Instead, +//! this takes the route of using StackWalk64 in order to walk the stack. + +#![allow(dead_code)] // constants/fields aren't always used on all platforms use dynamic_lib::DynamicLibrary; use ffi; @@ -295,7 +298,7 @@ pub fn write(w: &mut Writer) -> IoResult<()> { // According to windows documentation, all dbghelp functions are // single-threaded. static LOCK: StaticMutex = MUTEX_INIT; - let _g = unsafe { LOCK.lock() }; + let _g = LOCK.lock(); // Open up dbghelp.dll, we don't link to it explicitly because it can't // always be found. Additionally, it's nice having fewer dependencies. diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 37ed32fa36773..ba2d2569a744a 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -15,7 +15,6 @@ #![allow(non_camel_case_types)] use libc; -use prelude::v1::*; pub const WSADESCRIPTION_LEN: uint = 256; pub const WSASYS_STATUS_LEN: uint = 128; diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index a7330f7c67c91..0ca5fcddf7fa3 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -10,24 +10,20 @@ //! Blocking Windows-based file I/O -use alloc::arc::Arc; -use libc::{self, c_int}; - -use mem; -use sys::os::fill_utf16_buf_and_decode; -use path; -use ptr; -use str; -use io; - use prelude::v1::*; -use sys; -use sys::os; -use sys_common::{keep_going, eof, mkerr_libc}; +use alloc::arc::Arc; +use io; use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; use io::{IoResult, IoError, FileStat, SeekStyle}; use io::{Read, Truncate, SeekCur, SeekSet, ReadWrite, SeekEnd, Append}; +use libc::{self, c_int}; +use mem; +use ptr; +use sys::os::fill_utf16_buf_and_decode; +use sys::os; +use sys; +use sys_common::{unimpl, mkerr_libc}; pub type fd_t = libc::c_int; @@ -444,7 +440,7 @@ pub fn stat(p: &Path) -> IoResult { // FIXME: move this to platform-specific modules (for now)? pub fn lstat(_p: &Path) -> IoResult { // FIXME: implementation is missing - Err(super::unimpl()) + Err(unimpl()) } pub fn utime(p: &Path, atime: u64, mtime: u64) -> IoResult<()> { diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index 0e706c3cc6a57..2e9a2b9320028 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -11,31 +11,15 @@ #![allow(missing_docs)] #![allow(non_camel_case_types)] #![allow(non_snake_case)] -#![allow(unused_imports)] -#![allow(dead_code)] -#![allow(unused_unsafe)] -#![allow(unused_mut)] - -extern crate libc; use prelude::v1::*; -use num; -use mem; use io::{self, IoResult, IoError}; +use libc; +use mem; +use num; use sync::{Once, ONCE_INIT}; -macro_rules! helper_init { (static $name:ident: Helper<$m:ty>) => ( - static $name: Helper<$m> = Helper { - lock: ::sync::MUTEX_INIT, - cond: ::sync::CONDVAR_INIT, - chan: ::cell::UnsafeCell { value: 0 as *mut ::sync::mpsc::Sender<$m> }, - signal: ::cell::UnsafeCell { value: 0 }, - initialized: ::cell::UnsafeCell { value: false }, - shutdown: ::cell::UnsafeCell { value: false }, - }; -) } - pub mod backtrace; pub mod c; pub mod ext; @@ -181,14 +165,6 @@ pub fn init_net() { } } -pub fn unimpl() -> IoError { - IoError { - kind: io::IoUnavailable, - desc: "operation is not implemented", - detail: None, - } -} - pub fn to_utf16(s: Option<&str>) -> IoResult> { match s { Some(s) => Ok({ diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 064633f321c19..625254fe80de9 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -15,7 +15,6 @@ use prelude::v1::*; -use fmt; use io::{IoResult, IoError}; use iter::repeat; use libc::{c_int, c_void}; diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index 9996909f2f5bb..0ea70a574e2a0 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -371,7 +371,7 @@ impl UnixStream { // acquire the lock. // // See comments in close_read() about why this lock is necessary. - let guard = unsafe { self.inner.lock.lock() }; + let guard = self.inner.lock.lock(); if self.read_closed() { return Err(eof()) } @@ -447,7 +447,7 @@ impl UnixStream { // going after we woke up. // // See comments in close_read() about why this lock is necessary. - let guard = unsafe { self.inner.lock.lock() }; + let guard = self.inner.lock.lock(); if self.write_closed() { return Err(epipe()) } @@ -522,14 +522,14 @@ impl UnixStream { // close_read() between steps 1 and 2. By atomically executing steps 1 // and 2 with a lock with respect to close_read(), we're guaranteed that // no thread will erroneously sit in a read forever. - let _guard = unsafe { self.inner.lock.lock() }; + let _guard = self.inner.lock.lock(); self.inner.read_closed.store(true, Ordering::SeqCst); self.cancel_io() } pub fn close_write(&mut self) -> IoResult<()> { // see comments in close_read() for why this lock is necessary - let _guard = unsafe { self.inner.lock.lock() }; + let _guard = self.inner.lock.lock(); self.inner.write_closed.store(true, Ordering::SeqCst); self.cancel_io() } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 1b837385d1eb6..5da6e88271f75 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -10,28 +10,25 @@ use prelude::v1::*; +use collections::hash_map::Hasher; use collections; use ffi::CString; use hash::Hash; -use collections::hash_map::Hasher; use io::fs::PathExtensions; -use io::process::{ProcessExit, ExitStatus, ExitSignal}; +use io::process::{ProcessExit, ExitStatus}; use io::{IoResult, IoError}; use io; -use libc::{pid_t, c_void, c_int}; +use libc::{pid_t, c_void}; use libc; use mem; use os; use path::BytesContainer; use ptr; use str; -use sys::fs::FileDesc; use sync::{StaticMutex, MUTEX_INIT}; - -use sys::fs; -use sys::{self, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer}; -use sys_common::helper_thread::Helper; -use sys_common::{AsInner, mkerr_libc, timeout}; +use sys::fs::FileDesc; +use sys::timer; +use sys_common::{AsInner, timeout}; pub use sys_common::ProcessConfig; @@ -128,8 +125,6 @@ impl Process { use libc::funcs::extra::msvcrt::get_osfhandle; use mem; - use iter::{Iterator, IteratorExt}; - use str::StrExt; if cfg.gid().is_some() || cfg.uid().is_some() { return Err(IoError { diff --git a/src/libstd/sys/windows/stack_overflow.rs b/src/libstd/sys/windows/stack_overflow.rs index e8b447022cbf4..67f185a2e4d32 100644 --- a/src/libstd/sys/windows/stack_overflow.rs +++ b/src/libstd/sys/windows/stack_overflow.rs @@ -14,7 +14,7 @@ use ptr; use mem; use libc; use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL}; -use sys_common::{stack, thread_info}; +use sys_common::stack; pub struct Handler { _data: *mut libc::c_void @@ -30,14 +30,6 @@ impl Drop for Handler { fn drop(&mut self) {} } -// get_task_info is called from an exception / signal handler. -// It returns the guard page of the current task or 0 if that -// guard page doesn't exist. None is returned if there's currently -// no local task. -unsafe fn get_task_guard_page() -> uint { - thread_info::stack_guard() -} - // This is initialized in init() and only read from after static mut PAGE_SIZE: uint = 0; diff --git a/src/libstd/sys/windows/tcp.rs b/src/libstd/sys/windows/tcp.rs index 77139b52efa14..1dc2d83d7ea97 100644 --- a/src/libstd/sys/windows/tcp.rs +++ b/src/libstd/sys/windows/tcp.rs @@ -8,18 +8,18 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use io::net::ip; +use prelude::v1::*; + use io::IoResult; +use io::net::ip; use libc; use mem; use ptr; -use prelude::v1::*; -use super::{last_error, last_net_error, retry, sock_t}; +use super::{last_error, last_net_error, sock_t}; use sync::Arc; use sync::atomic::{AtomicBool, Ordering}; -use sys::fs::FileDesc; use sys::{self, c, set_nonblocking, wouldblock, timer}; -use sys_common::{self, timeout, eof, net}; +use sys_common::{timeout, eof, net}; pub use sys_common::net::TcpStream; @@ -206,10 +206,6 @@ impl TcpAcceptor { Err(eof()) } - pub fn socket_name(&mut self) -> IoResult { - net::sockname(self.socket(), libc::getsockname) - } - pub fn set_timeout(&mut self, timeout: Option) { self.deadline = timeout.map(|a| timer::now() + a).unwrap_or(0); } diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index 30707488b30ee..0b7764d524535 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use core::prelude::*; - use boxed::Box; use cmp; use mem; diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index d371023f21880..4a371b67b071a 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -137,9 +137,9 @@ unsafe fn init_dtors() { rt::at_exit(move|| { DTOR_LOCK.lock(); let dtors = DTORS; - DTORS = 0 as *mut _; + DTORS = 1 as *mut _; mem::transmute::<_, Box>>(dtors); - assert!(DTORS.is_null()); // can't re-init after destructing + assert!(DTORS as uint == 1); // can't re-init after destructing DTOR_LOCK.unlock(); }); } @@ -147,6 +147,9 @@ unsafe fn init_dtors() { unsafe fn register_dtor(key: Key, dtor: Dtor) { DTOR_LOCK.lock(); init_dtors(); + assert!(DTORS as uint != 0); + assert!(DTORS as uint != 1, + "cannot create new TLS keys after the main thread has exited"); (*DTORS).push((key, dtor)); DTOR_LOCK.unlock(); } @@ -154,6 +157,9 @@ unsafe fn register_dtor(key: Key, dtor: Dtor) { unsafe fn unregister_dtor(key: Key) -> bool { DTOR_LOCK.lock(); init_dtors(); + assert!(DTORS as uint != 0); + assert!(DTORS as uint != 1, + "cannot unregister destructors after the main thread has exited"); let ret = { let dtors = &mut *DTORS; let before = dtors.len(); @@ -232,6 +238,7 @@ unsafe extern "system" fn on_tls_callback(h: LPVOID, } } +#[allow(dead_code)] // not actually dead unsafe fn run_dtors() { let mut any_run = true; for _ in range(0, 5i) { diff --git a/src/libstd/sys/windows/timer.rs b/src/libstd/sys/windows/timer.rs index 1ae3979cd9acc..f9e0c8b91aeda 100644 --- a/src/libstd/sys/windows/timer.rs +++ b/src/libstd/sys/windows/timer.rs @@ -20,17 +20,14 @@ //! Other than that, the implementation is pretty straightforward in terms of //! the other two implementations of timers with nothing *that* new showing up. -use self::Req::*; use prelude::v1::*; +use self::Req::*; use libc; use ptr; - use io::IoResult; -use sync::mpsc::{channel, Sender, Receiver, TryRecvError}; -use sys::c; -use sys::fs::FileDesc; use sys_common::helper_thread::Helper; +use sync::mpsc::{channel, TryRecvError, Sender, Receiver}; helper_init! { static HELPER: Helper } @@ -80,9 +77,10 @@ fn helper(input: libc::HANDLE, messages: Receiver, _: ()) { None => {} } } + // See the comment in unix::timer for why we don't have any + // asserts here and why we're likely just leaving timers on + // the floor as we exit. Err(TryRecvError::Disconnected) => { - assert_eq!(objs.len(), 1); - assert_eq!(chans.len(), 0); break 'outer; } Err(..) => break diff --git a/src/libstd/sys/windows/tty.rs b/src/libstd/sys/windows/tty.rs index f9e1f0d3ed0aa..54c76a7cc1e5c 100644 --- a/src/libstd/sys/windows/tty.rs +++ b/src/libstd/sys/windows/tty.rs @@ -38,7 +38,7 @@ use str::from_utf8; use super::c::{ENABLE_ECHO_INPUT, ENABLE_EXTENDED_FLAGS}; use super::c::{ENABLE_INSERT_MODE, ENABLE_LINE_INPUT}; use super::c::{ENABLE_PROCESSED_INPUT, ENABLE_QUICK_EDIT_MODE}; -use super::c::{ERROR_ILLEGAL_CHARACTER, CONSOLE_SCREEN_BUFFER_INFO}; +use super::c::CONSOLE_SCREEN_BUFFER_INFO; use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode}; use super::c::{GetConsoleScreenBufferInfo}; @@ -155,9 +155,6 @@ impl TTY { (info.srWindow.Bottom + 1 - info.srWindow.Top) as int)), } } - - // Let us magically declare this as a TTY - pub fn isatty(&self) -> bool { true } } impl Drop for TTY { diff --git a/src/libstd/thread.rs b/src/libstd/thread.rs index 932556fe1a65d..839c2e615eefa 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -273,13 +273,10 @@ impl Builder { let my_stack_top = addr as uint; let my_stack_bottom = my_stack_top - stack_size + 1024; unsafe { - stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top); + stack::record_os_managed_stack_bounds(my_stack_bottom, + my_stack_top); + thread_info::set(imp::guard::current(), their_thread); } - thread_info::set( - (my_stack_bottom, my_stack_top), - unsafe { imp::guard::current() }, - their_thread - ); let mut output = None; let f: Thunk<(), T> = if stdout.is_some() || stderr.is_some() {