diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index 4ee5b2d5e8349..7642c866d6081 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -177,7 +177,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; @@ -193,6 +193,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. @@ -279,9 +281,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 @@ -363,9 +374,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, @@ -421,14 +438,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 cd991c5f884f5..af6daaf261ef2 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 kinds::{Sync, Send}; +use io::{IoResult, IoError, OtherIoError}; +use io::{standard_error, EndOfFile, 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 7c8aab2b31dae..078aed003242d 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -230,13 +230,13 @@ pub mod task; pub mod thread; pub mod sync; +#[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 68aaa1b3ae55d..5df702dde1e91 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -93,9 +93,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 @@ -134,20 +132,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)); } @@ -163,8 +155,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 6f6be2e111df4..b34195c9d7e0d 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; -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 bdf1bf3dfd02c..09d22387c4478 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -20,6 +20,8 @@ //! can be created in the future and there must be no active timers at that //! time. +#![macro_escape] + use prelude::v1::*; use cell::UnsafeCell; @@ -69,6 +71,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 +98,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 +107,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() }).detach(); - 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 +132,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 +147,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 97015f74a4a10..fe9f669789566 100644 --- a/src/libstd/sys/common/mod.rs +++ b/src/libstd/sys/common/mod.rs @@ -9,7 +9,7 @@ // except according to those terms. #![allow(missing_docs)] -#![allow(dead_code)] +#![macro_escape] use io::{mod, IoError, IoResult}; use prelude::v1::*; diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys/common/mutex.rs index 567c26956efe9..322d2f202f772 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 94a2c9b78faef..2132f2b2b6d64 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -24,7 +24,9 @@ use ptr::{mod, null, null_mut}; use sys::{mod, 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::{mod, keep_going, short_write, timeout}; use cmp; use io; @@ -611,11 +613,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 2a88e20c8fa1f..1966a9544e1a5 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 9d7188a37bcdf..1ca64d288f803 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::{mod, AtomicUint}; -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 9e26475f814b7..b0fca87d73630 100644 --- a/src/libstd/sys/unix/backtrace.rs +++ b/src/libstd/sys/unix/backtrace.rs @@ -83,12 +83,12 @@ /// to symbols. This is a bit of a hokey implementation as-is, but it works for /// all unix platforms we support right now, so it at least gets the job done. +use prelude::v1::*; + use c_str::CString; -use io::{IoResult, Writer}; +use io::IoResult; use libc; use mem; -use option::Option::{mod, Some, None}; -use result::Result::{Ok, Err}; use sync::{StaticMutex, MUTEX_INIT}; use sys_common::backtrace::*; @@ -151,7 +151,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:")); @@ -241,12 +241,8 @@ fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { #[cfg(not(any(target_os = "macos", target_os = "ios")))] fn print(w: &mut Writer, idx: int, addr: *mut libc::c_void) -> IoResult<()> { - use iter::{Iterator, IteratorExt}; use os; - use path::GenericPath; - use ptr::PtrExt; use ptr; - use slice::SliceExt; //////////////////////////////////////////////////////////////////////// // libbacktrace.h API diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 4199cbc1bb9f5..46a1bf31c00b4 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -10,30 +10,14 @@ #![allow(missing_docs)] #![allow(non_camel_case_types)] -#![allow(unused_imports)] -#![allow(dead_code)] -#![allow(unused_unsafe)] -#![allow(unused_mut)] extern crate libc; -use num; use num::{Int, SignedInt}; use prelude::v1::*; use io::{mod, IoResult, IoError}; 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 81f8659d6ae08..c9cb46b0289f1 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -11,7 +11,6 @@ use cell::UnsafeCell; use kinds::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 6a8f55e79c872..d838ff82905fe 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -10,17 +10,16 @@ //! Implementation of `std::os` functionality for unix systems +#![allow(unused_imports)] // lots of cfg code here + use prelude::v1::*; use c_str::ToCStr; -use error::{FromError, Error}; -use fmt; use io::{IoError, IoResult}; -use libc::{mod, c_int, c_char, c_void}; +use libc::{mod, c_int, c_char}; use os; -use path::{BytesContainer}; +use path::BytesContainer; use ptr; -use sync::atomic::{AtomicInt, SeqCst}; use sys::fs::FileDesc; use os::TMPBUF_SZ; diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 623f3f6a89c9d..e4fd36d8abc12 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -142,7 +142,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 af09bf4fbd0a2..b9b43389be7c1 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -12,10 +12,10 @@ use prelude::v1::*; use self::Req::*; use c_str::{CString, ToCStr}; -use collections; +use collections::HashMap; use hash::Hash; use io::process::{ProcessExit, ExitStatus, ExitSignal}; -use io::{mod, IoResult, IoError, EndOfFile}; +use io::{IoResult, EndOfFile}; use libc::{mod, pid_t, c_void, c_int}; use mem; use os; @@ -328,7 +328,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), @@ -336,7 +336,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")), @@ -420,8 +420,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, @@ -553,7 +560,7 @@ fn with_argv(prog: &CString, args: &[CString], cb(ptrs.as_ptr()) } -fn with_envp(env: Option<&collections::HashMap>, +fn with_envp(env: Option<&HashMap>, cb: F) -> T where F : FnOnce(*const c_void) -> T, 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 95ab9b459d671..647619fa23161 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 13ccf685fd7fc..26c2bb8ed600e 100644 --- a/src/libstd/sys/unix/tcp.rs +++ b/src/libstd/sys/unix/tcp.rs @@ -136,10 +136,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 80f93dd2f618c..8cd69f236cf34 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 4ef687d41d8ee..d8cb067b946a6 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 319a458087b9b..ee80ae731a36d 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 c_str::CString; use intrinsics; @@ -294,7 +297,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 1ee57434fb91a..b563c356a7634 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 523d60c71aa8b..e893a7dea6b78 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -10,21 +10,17 @@ //! Blocking Windows-based file I/O -use alloc::arc::Arc; use libc::{mod, c_int}; -use c_str::CString; +use io; use mem; -use sys::os::fill_utf16_buf_and_decode; -use path; use ptr; -use str; -use io; +use sys::os::fill_utf16_buf_and_decode; use prelude::v1::*; use sys; use sys::os; -use sys_common::{keep_going, eof, mkerr_libc}; +use sys_common::{unimpl, mkerr_libc}; use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; use io::{IoResult, IoError, FileStat, SeekStyle}; @@ -445,7 +441,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 1034f0615d994..797a4db2de39c 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -11,31 +11,14 @@ #![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::{mod, IoResult, IoError}; +use libc; +use mem; 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 +164,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 dfdee0e0385c5..825d5699ab7d2 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 f173d5fc6d4cb..17fe8d5ce76e0 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -365,7 +365,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()) } @@ -441,7 +441,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()) } @@ -516,14 +516,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, atomic::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, atomic::SeqCst); self.cancel_io() } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index cb99a886ce4fc..42086106f7708 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -10,24 +10,22 @@ use prelude::v1::*; -use libc::{pid_t, c_void, c_int}; +use libc::{pid_t, c_void}; use libc; use c_str::{CString, ToCStr}; use io; use mem; use os; use ptr; -use io::process::{ProcessExit, ExitStatus, ExitSignal}; +use io::process::{ProcessExit, ExitStatus}; use collections; use path::BytesContainer; use hash::Hash; use io::{IoResult, IoError}; -use sys::fs; -use sys::{mod, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer}; +use sys::timer; use sys::fs::FileDesc; -use sys_common::helper_thread::Helper; -use sys_common::{AsInner, mkerr_libc, timeout}; +use sys_common::{AsInner, timeout}; use io::fs::PathExtensions; @@ -122,8 +120,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 5a929f6b2b5ff..ce241f05a533b 100644 --- a/src/libstd/sys/windows/tcp.rs +++ b/src/libstd/sys/windows/tcp.rs @@ -8,17 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use prelude::v1::*; + use io::net::ip; use io::IoResult; 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, atomic}; -use sys::fs::FileDesc; use sys::{mod, c, set_nonblocking, wouldblock, timer}; -use sys_common::{mod, timeout, eof, net}; +use sys_common::{timeout, eof, net}; pub use sys_common::net::TcpStream; @@ -205,10 +205,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 4498f56c00a1e..59ab5f5c4d990 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 b96e26c7a86a6..8d0f413b4db08 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 343b78543bfd0..f026cf72cb92f 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 7591025d76d6f..393e3cd4f2a85 100644 --- a/src/libstd/sys/windows/tty.rs +++ b/src/libstd/sys/windows/tty.rs @@ -37,9 +37,10 @@ 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}; use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode}; +use sys_common::unimpl; + fn invalid_encoding() -> IoError { IoError { kind: io::InvalidInput, @@ -151,11 +152,8 @@ impl TTY { // Make a CONSOLE_SCREEN_BUFFER_INFO // Call GetConsoleScreenBufferInfo // Maybe call GetLargestConsoleWindowSize instead? - Err(super::unimpl()) + Err(unimpl()) } - - // 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 3c87309dabcf3..97f61b08bcbcc 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -232,13 +232,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() {