diff --git a/src/liblog/lib.rs b/src/liblog/lib.rs index bf1014d6c35..b30938ae7f5 100644 --- a/src/liblog/lib.rs +++ b/src/liblog/lib.rs @@ -177,7 +177,7 @@ use std::os; use std::rt; use std::slice; -use std::sync::{Once, ONCE_INIT, StaticMutex, MUTEX_INIT}; +use std::sync::{Once, ONCE_INIT}; use regex::Regex; @@ -193,8 +193,6 @@ /// 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. @@ -281,18 +279,9 @@ fn drop(&mut self) { 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. - 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 - } - } - } + match unsafe { FILTER.as_ref() } { + Some(filter) if !filter.is_match(args.to_string()[]) => return, + _ => {} } // Completely remove the local logger from TLS in case anyone attempts to @@ -374,15 +363,9 @@ 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() }); - 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()) - } + enabled(level, module, unsafe { (*DIRECTIVES).iter() }) } fn enabled(level: u32, @@ -438,15 +421,14 @@ 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 = 1 as *const Vec; + DIRECTIVES = 0 as *const Vec; if !FILTER.is_null() { let _filter: Box = mem::transmute(FILTER); - FILTER = 1 as *const _; + FILTER = 0 as *const _; } }); } diff --git a/src/libstd/io/stdio.rs b/src/libstd/io/stdio.rs index d009b553501..43d2e078035 100644 --- a/src/libstd/io/stdio.rs +++ b/src/libstd/io/stdio.rs @@ -26,19 +26,29 @@ //! ``` use self::StdSource::*; -use prelude::*; +use boxed::Box; use cell::RefCell; +use clone::Clone; use failure::LOCAL_STDERR; use fmt; -use io::{IoResult, IoError, OtherIoError}; -use io::{standard_error, EndOfFile, LineBufferedWriter, BufferedReader}; +use io::{Reader, Writer, IoResult, IoError, OtherIoError, Buffer, + standard_error, EndOfFile, LineBufferedWriter, BufferedReader}; +use kinds::{Sync, Send}; use libc; use mem; +use option::Option; +use option::Option::{Some, None}; +use ops::{Deref, DerefMut, FnOnce}; +use result::Result::{Ok, Err}; use rt; +use slice::SliceExt; +use str::StrExt; +use string::String; use sys::{fs, tty}; -use sync::{Arc, Mutex, MutexGuard, StaticMutex, MUTEX_INIT}; +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 @@ -205,15 +215,14 @@ fn read_be_uint_n(&mut self, nbytes: uint) -> IoResult { 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 LOCK: StaticMutex = MUTEX_INIT; + static ONCE: Once = ONCE_INIT; unsafe { - 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. + ONCE.doit(|| { + // 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 { @@ -226,15 +235,11 @@ pub fn stdin() -> StdinReader { // Make sure to free it at exit rt::at_exit(|| { - let g = LOCK.lock(); - let stdin = STDIN; - STDIN = 1 as *const _; - drop(g); - mem::transmute::<_, Box>(stdin); + mem::transmute::<_, Box>(STDIN); + STDIN = 0 as *const _; }); - } 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 181c4c04c51..74c387c5eea 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -229,13 +229,13 @@ pub mod sync; pub mod comm; -#[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 08dabd3b0b6..5823f8453d8 100644 --- a/src/libstd/rt/at_exit_imp.rs +++ b/src/libstd/rt/at_exit_imp.rs @@ -29,8 +29,6 @@ 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(); @@ -51,7 +49,7 @@ pub fn cleanup() { unsafe { LOCK.lock(); let queue = QUEUE; - QUEUE = 1u as *mut _; + QUEUE = 1 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 a4421f23c50..e877dd5c6aa 100644 --- a/src/libstd/rt/mod.rs +++ b/src/libstd/rt/mod.rs @@ -92,7 +92,9 @@ 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(sys::thread::guard::main(), thread); + thread_info::set((my_stack_bottom, my_stack_top), + 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 @@ -131,14 +133,20 @@ fn lang_start(main: *const u8, argc: int, argv: *const *const u8) -> int { } } -/// Enqueues a procedure to run when the main thread exits. +/// 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. /// /// It is forbidden for procedures to register more `at_exit` handlers when they /// are running, and doing so will lead to a process abort. -/// -/// Note that other threads may still be running when `at_exit` routines start -/// running. -pub fn at_exit(f: F) { +pub fn at_exit(f: F) { at_exit_imp::push(Thunk::new(f)); } @@ -154,5 +162,8 @@ pub fn at_exit(f: F) { pub unsafe fn cleanup() { args::cleanup(); sys::stack_overflow::cleanup(); - at_exit_imp::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(); } diff --git a/src/libstd/rt/unwind.rs b/src/libstd/rt/unwind.rs index ce284e020a6..c273c52dacc 100644 --- a/src/libstd/rt/unwind.rs +++ b/src/libstd/rt/unwind.rs @@ -68,7 +68,7 @@ use libc::c_void; use mem; use sync::atomic; -use sys_common::mutex::{Mutex, MUTEX_INIT}; +use sync::{Once, ONCE_INIT}; use rt::libunwind as uw; @@ -540,20 +540,11 @@ 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. - unsafe { - static LOCK: Mutex = MUTEX_INIT; - static mut INIT: bool = false; - LOCK.lock(); - if !INIT { - register(failure::on_fail); - INIT = true; - } - LOCK.unlock(); - } + static INIT: Once = ONCE_INIT; + INIT.doit(|| unsafe { register(failure::on_fail); }); // 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 7093c417b11..9ef1c33312f 100644 --- a/src/libstd/sys/common/helper_thread.rs +++ b/src/libstd/sys/common/helper_thread.rs @@ -20,8 +20,6 @@ //! can be created in the future and there must be no active timers at that //! time. -#![macro_escape] - use prelude::*; use cell::UnsafeCell; @@ -70,17 +68,6 @@ unsafe impl Sync for Helper { } 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. @@ -97,7 +84,7 @@ pub fn boot(&'static self, f: F, helper: fn(helper_signal::signal, Receive { unsafe { let _guard = self.lock.lock().unwrap(); - if *self.chan.get() as uint == 0 { + if !*self.initialized.get() { let (tx, rx) = channel(); *self.chan.get() = mem::transmute(box tx); let (receive, send) = helper_signal::new(); @@ -106,17 +93,15 @@ pub fn boot(&'static self, f: F, helper: fn(helper_signal::signal, Receive 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"); } } } @@ -131,9 +116,7 @@ pub fn send(&'static self, msg: M) { // 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() as uint != 0); - assert!(*self.chan.get() as uint != 1, - "cannot continue usage after shutdown"); + assert!(!self.chan.get().is_null()); (**self.chan.get()).send(msg); helper_signal::signal(*self.signal.get() as helper_signal::signal); } @@ -146,13 +129,9 @@ fn shutdown(&'static self) { // 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() = 1 as *mut Sender; + *self.chan.get() = 0 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 6b2b325e638..dc0ad08cdbe 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)] -#![macro_escape] +#![allow(dead_code)] use io::{mod, IoError, IoResult}; use prelude::*; diff --git a/src/libstd/sys/common/mutex.rs b/src/libstd/sys/common/mutex.rs index 322d2f202f7..567c26956ef 100644 --- a/src/libstd/sys/common/mutex.rs +++ b/src/libstd/sys/common/mutex.rs @@ -29,7 +29,6 @@ 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 552d1c201da..87ec20fbef8 100644 --- a/src/libstd/sys/common/net.rs +++ b/src/libstd/sys/common/net.rs @@ -23,9 +23,7 @@ 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::Mutex; -#[cfg(not(target_os = "linux"))] -use sync::MutexGuard; +use sync::{Mutex, MutexGuard}; use sys_common::{mod, keep_going, short_write, timeout}; use prelude::*; use cmp; @@ -613,13 +611,11 @@ 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 b7c4cfcd0f5..df016b9e293 100644 --- a/src/libstd/sys/common/rwlock.rs +++ b/src/libstd/sys/common/rwlock.rs @@ -26,7 +26,6 @@ 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 1966a9544e1..2a88e20c8fa 100644 --- a/src/libstd/sys/common/stack.rs +++ b/src/libstd/sys/common/stack.rs @@ -121,6 +121,37 @@ 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 f32c1ea3658..dc21feb17a8 100644 --- a/src/libstd/sys/common/thread_info.rs +++ b/src/libstd/sys/common/thread_info.rs @@ -8,8 +8,6 @@ // 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 thread::Thread; @@ -17,6 +15,10 @@ use string::String; 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, } @@ -33,6 +35,7 @@ fn with(f: |&mut ThreadInfo| -> R) -> R { THREAD_INFO.with(|c| { if c.borrow().is_none() { *c.borrow_mut() = Some(ThreadInfo { + stack_bounds: (0, 0), stack_guard: 0, thread: NewThread::new(None), }) @@ -50,9 +53,10 @@ pub fn stack_guard() -> uint { ThreadInfo::with(|info| info.stack_guard) } -pub fn set(stack_guard: uint, thread: Thread) { +pub fn set(stack_bounds: (uint, uint), 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 cc69fbceacb..fe7a7d8d037 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::*; use sync::atomic::{mod, AtomicUint}; +use sync::{Mutex, Once, ONCE_INIT}; use sys::thread_local as imp; @@ -140,6 +140,9 @@ pub struct Key { key: atomic::INIT_ATOMIC_UINT, }; +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 0ec34fb1318..ddae9a132c3 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::*; - use c_str::CString; -use io::IoResult; +use io::{IoResult, Writer}; 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 @@ struct Context<'a> { // 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 = LOCK.lock(); + let _g = unsafe { LOCK.lock() }; try!(writeln!(w, "stack backtrace:")); @@ -241,8 +241,12 @@ fn dladdr(addr: *const libc::c_void, #[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 dd4141de998..c82dacf1e44 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -10,14 +10,30 @@ #![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::*; 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 c9cb46b0289..81f8659d6ae 100644 --- a/src/libstd/sys/unix/mutex.rs +++ b/src/libstd/sys/unix/mutex.rs @@ -11,6 +11,7 @@ use cell::UnsafeCell; use kinds::Sync; use sys::sync as ffi; +use sys_common::mutex; pub struct Mutex { inner: UnsafeCell } @@ -25,7 +26,6 @@ pub unsafe fn raw(m: &Mutex) -> *mut ffi::pthread_mutex_t { 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 446960ab92f..cafe52f8403 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -10,16 +10,17 @@ //! Implementation of `std::os` functionality for unix systems -#![allow(unused_imports)] // lots of cfg code here - use prelude::*; +use error::{FromError, Error}; +use fmt; use io::{IoError, IoResult}; -use libc::{mod, c_int, c_char}; -use os; +use libc::{mod, c_int, c_char, c_void}; use path::BytesContainer; use ptr; +use sync::atomic::{AtomicInt, INIT_ATOMIC_INT, SeqCst}; use sys::fs::FileDesc; +use os; use os::TMPBUF_SZ; diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 3b868065f8f..868b460aa5e 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -145,7 +145,7 @@ fn lock_nonblocking(&self) {} fn lock_nonblocking<'a>(&'a self) -> Guard<'a> { let ret = Guard { fd: self.fd(), - guard: self.inner.lock.lock().unwrap(), + guard: unsafe { 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 48df8c4eced..835f4279d9b 100644 --- a/src/libstd/sys/unix/process.rs +++ b/src/libstd/sys/unix/process.rs @@ -11,7 +11,7 @@ use libc::{mod, pid_t, c_void, c_int}; use c_str::CString; -use io::{IoResult, EndOfFile}; +use io::{mod, IoResult, IoError, EndOfFile}; use mem; use os; use ptr; @@ -327,7 +327,7 @@ pub fn wait(&self, deadline: u64) -> IoResult { // The actual communication between the helper thread and this thread is // quite simple, just a channel moving data around. - HELPER.boot(register_sigchld, waitpid_helper); + unsafe { HELPER.boot(register_sigchld, waitpid_helper) } match self.try_wait() { Some(ret) => return Ok(ret), @@ -335,7 +335,7 @@ pub fn wait(&self, deadline: u64) -> IoResult { } let (tx, rx) = channel(); - HELPER.send(NewChild(self.pid, tx, deadline)); + unsafe { HELPER.send(NewChild(self.pid, tx, deadline)); } return match rx.recv_opt() { Ok(e) => Ok(e), Err(()) => Err(timeout("wait timed out")), @@ -419,15 +419,8 @@ fn waitpid_helper(input: libc::c_int, 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(comm::Disconnected) => { + assert!(active.len() == 0); break 'outer; } Err(comm::Empty) => break, diff --git a/src/libstd/sys/unix/rwlock.rs b/src/libstd/sys/unix/rwlock.rs index 4f9b06685ec..0d63ff14ff2 100644 --- a/src/libstd/sys/unix/rwlock.rs +++ b/src/libstd/sys/unix/rwlock.rs @@ -17,7 +17,6 @@ pub struct RWLock { inner: UnsafeCell } 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 f1d7f1784d0..bcbbb8766b7 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -34,6 +34,7 @@ fn drop(&mut self) { #[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 696d3fb676d..e2a78947e16 100644 --- a/src/libstd/sys/unix/tcp.rs +++ b/src/libstd/sys/unix/tcp.rs @@ -135,6 +135,10 @@ pub fn accept(&mut self) -> IoResult { 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 150ec6aad8a..c0ef89666c0 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 fd = FileDesc::new(input, true); + let mut 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,15 +168,8 @@ fn signal(active: &mut Vec>, 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(comm::Disconnected) => { + assert!(active.len() == 0); break 'outer; } diff --git a/src/libstd/sys/unix/tty.rs b/src/libstd/sys/unix/tty.rs index d05047a220f..28c17fd4966 100644 --- a/src/libstd/sys/unix/tty.rs +++ b/src/libstd/sys/unix/tty.rs @@ -43,4 +43,5 @@ pub fn set_raw(&mut self, _raw: bool) -> IoResult<()> { 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 e5a37e5651b..42c8f7705e1 100644 --- a/src/libstd/sys/windows/backtrace.rs +++ b/src/libstd/sys/windows/backtrace.rs @@ -7,22 +7,19 @@ // , 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. - -#![allow(dead_code)] // constants/fields aren't always used on all platforms +/// 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. use c_str::CString; use intrinsics; @@ -297,7 +294,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 = LOCK.lock(); + let _g = unsafe { 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 0aa7e539d78..06259d61fcb 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -15,6 +15,7 @@ #![allow(non_camel_case_types)] use libc; +use prelude::*; 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 523d9e9a3c2..3ad439078b9 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -10,17 +10,21 @@ //! Blocking Windows-based file I/O +use alloc::arc::Arc; use libc::{mod, c_int}; -use io; +use c_str::CString; use mem; -use ptr; use sys::os::fill_utf16_buf_and_decode; +use path; +use ptr; +use str; +use io; use prelude::*; use sys; use sys::os; -use sys_common::{unimpl, mkerr_libc}; +use sys_common::{keep_going, eof, mkerr_libc}; use io::{FilePermission, Write, UnstableFileStat, Open, FileAccess, FileMode}; use io::{IoResult, IoError, FileStat, SeekStyle}; @@ -441,7 +445,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(unimpl()) + Err(super::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 3fae03146f3..57c284ed6a3 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -11,14 +11,30 @@ #![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 num; use mem; use prelude::*; use io::{mod, IoResult, IoError}; 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 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; @@ -164,6 +180,14 @@ 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 28eca9163f6..e7194df7ac3 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -15,6 +15,7 @@ use prelude::*; +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 8b2fc3d9fb5..fc3640f2604 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -365,7 +365,7 @@ pub fn read(&mut self, buf: &mut [u8]) -> IoResult { // acquire the lock. // // See comments in close_read() about why this lock is necessary. - let guard = self.inner.lock.lock(); + let guard = unsafe { self.inner.lock.lock() }; if self.read_closed() { return Err(eof()) } @@ -441,7 +441,7 @@ pub fn write(&mut self, buf: &[u8]) -> IoResult<()> { // going after we woke up. // // See comments in close_read() about why this lock is necessary. - let guard = self.inner.lock.lock(); + let guard = unsafe { self.inner.lock.lock() }; if self.write_closed() { return Err(epipe()) } @@ -516,14 +516,14 @@ pub fn close_read(&mut self) -> IoResult<()> { // 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 = self.inner.lock.lock(); + let _guard = unsafe { 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 = self.inner.lock.lock(); + let _guard = unsafe { 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 0c5a0eb6bb9..0c2c76077dd 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -8,24 +8,25 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use prelude::*; - -use libc::{pid_t, c_void}; +use libc::{pid_t, c_void, c_int}; use libc; use c_str::CString; use io; use mem; use os; use ptr; -use io::process::{ProcessExit, ExitStatus}; +use prelude::*; +use io::process::{ProcessExit, ExitStatus, ExitSignal}; use collections; use path::BytesContainer; use hash::Hash; use io::{IoResult, IoError}; -use sys::timer; +use sys::fs; +use sys::{mod, retry, c, wouldblock, set_nonblocking, ms_to_timeval, timer}; use sys::fs::FileDesc; -use sys_common::{AsInner, timeout}; +use sys_common::helper_thread::Helper; +use sys_common::{AsInner, mkerr_libc, timeout}; use io::fs::PathExtensions; @@ -120,6 +121,8 @@ pub fn spawn(cfg: &C, in_fd: Option

, 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 ab092f5a243..bdf2e0bccb1 100644 --- a/src/libstd/sys/windows/stack_overflow.rs +++ b/src/libstd/sys/windows/stack_overflow.rs @@ -14,7 +14,7 @@ use mem; use libc; use libc::types::os::arch::extra::{LPVOID, DWORD, LONG, BOOL}; -use sys_common::stack; +use sys_common::{stack, thread_info}; pub struct Handler { _data: *mut libc::c_void @@ -30,6 +30,14 @@ 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 339c724d9a9..513c1d38e36 100644 --- a/src/libstd/sys/windows/tcp.rs +++ b/src/libstd/sys/windows/tcp.rs @@ -14,10 +14,11 @@ use mem; use ptr; use prelude::*; -use super::{last_error, last_net_error, sock_t}; +use super::{last_error, last_net_error, retry, sock_t}; use sync::{Arc, atomic}; +use sys::fs::FileDesc; use sys::{mod, c, set_nonblocking, wouldblock, timer}; -use sys_common::{timeout, eof, net}; +use sys_common::{mod, timeout, eof, net}; pub use sys_common::net::TcpStream; @@ -204,6 +205,10 @@ pub fn accept(&mut self) -> IoResult { 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 59ab5f5c4d9..4498f56c00a 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -8,6 +8,8 @@ // 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 4ac57e37117..60b0d584db3 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 = 1 as *mut _; + DTORS = 0 as *mut _; mem::transmute::<_, Box>>(dtors); - assert!(DTORS as uint == 1); // can't re-init after destructing + assert!(DTORS.is_null()); // can't re-init after destructing DTOR_LOCK.unlock(); }); } @@ -147,9 +147,6 @@ 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(); } @@ -157,9 +154,6 @@ 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(); @@ -238,7 +232,6 @@ unsafe fn unregister_dtor(key: Key) -> bool { } } -#[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 c0e67642a64..874838950cd 100644 --- a/src/libstd/sys/windows/timer.rs +++ b/src/libstd/sys/windows/timer.rs @@ -26,6 +26,8 @@ use ptr; use comm; +use sys::c; +use sys::fs::FileDesc; use sys_common::helper_thread::Helper; use prelude::*; use io::IoResult; @@ -78,10 +80,9 @@ 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(comm::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 415524733ff..a88d11eed22 100644 --- a/src/libstd/sys/windows/tty.rs +++ b/src/libstd/sys/windows/tty.rs @@ -26,6 +26,7 @@ //! to working in raw UTF-16, with such a wrapper around it. use super::c::{ReadConsoleW, WriteConsoleW, GetConsoleMode, SetConsoleMode}; +use super::c::{ERROR_ILLEGAL_CHARACTER}; 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}; @@ -38,8 +39,6 @@ use ptr; use str::from_utf8; -use sys_common::unimpl; - fn invalid_encoding() -> IoError { IoError { kind: io::InvalidInput, @@ -151,8 +150,11 @@ pub fn get_winsize(&mut self) -> IoResult<(int, int)> { // Make a CONSOLE_SCREEN_BUFFER_INFO // Call GetConsoleScreenBufferInfo // Maybe call GetLargestConsoleWindowSize instead? - Err(unimpl()) + Err(super::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 cfdb5c2ec26..a7b3ee996a3 100644 --- a/src/libstd/thread.rs +++ b/src/libstd/thread.rs @@ -232,10 +232,13 @@ fn spawn_inner(self, f: Thunk<(), T>) -> JoinGuard { 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); - thread_info::set(imp::guard::current(), their_thread); + stack::record_os_managed_stack_bounds(my_stack_bottom, my_stack_top); } + 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() {