Skip to content

std: Re-enable at_exit() #20045

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Dec 31, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions src/liblog/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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.
Expand Down Expand Up @@ -281,9 +283,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
Expand Down Expand Up @@ -401,9 +412,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,
Expand Down Expand Up @@ -459,14 +476,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<Vec<directive::LogDirective>> =
mem::transmute(DIRECTIVES);
DIRECTIVES = 0 as *const Vec<directive::LogDirective>;
DIRECTIVES = 1 as *const Vec<directive::LogDirective>;

if !FILTER.is_null() {
let _filter: Box<Regex> = mem::transmute(FILTER);
FILTER = 0 as *const _;
FILTER = 1 as *const _;
}
});
}
Expand Down
43 changes: 19 additions & 24 deletions src/libstd/io/stdio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,29 +26,19 @@
//! ```

use self::StdSource::*;
use prelude::*;

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 rt;
use slice::SliceExt;
use str::StrExt;
use string::String;
use sys::{fs, tty};
use sync::{Arc, Mutex, MutexGuard, Once, ONCE_INIT};
use sync::{Arc, Mutex, MutexGuard, StaticMutex, MUTEX_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
Expand Down Expand Up @@ -215,14 +205,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.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 _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 {
Expand All @@ -235,11 +226,15 @@ pub fn stdin() -> StdinReader {

// Make sure to free it at exit
rt::at_exit(|| {
mem::transmute::<_, Box<StdinReader>>(STDIN);
STDIN = 0 as *const _;
let g = LOCK.lock();
let stdin = STDIN;
STDIN = 1 as *const _;
drop(g);
mem::transmute::<_, Box<StdinReader>>(stdin);
});
});

} else if STDIN as uint == 1 {
panic!("accessing stdin after the main thread has exited")
}
(*STDIN).clone()
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -228,13 +228,13 @@ pub mod thread;
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;

Expand Down
4 changes: 3 additions & 1 deletion src/libstd/rt/at_exit_imp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ type Queue = Vec<Thunk>;
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<Queue> = box Vec::new();
Expand All @@ -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
Expand Down
25 changes: 7 additions & 18 deletions src/libstd/rt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,9 +92,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("<main>".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
Expand Down Expand Up @@ -133,20 +131,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:FnOnce()+Send>(f: F) {
///
/// Note that other threads may still be running when `at_exit` routines start
/// running.
pub fn at_exit<F: FnOnce() + Send>(f: F) {
at_exit_imp::push(Thunk::new(f));
}

Expand All @@ -162,8 +154,5 @@ pub fn at_exit<F:FnOnce()+Send>(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();
}
17 changes: 13 additions & 4 deletions src/libstd/rt/unwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -587,11 +587,20 @@ pub fn begin_unwind<M: Any + Send>(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<Any + Send>, file_line: &(&'static str, uint)) -> ! {
fn begin_unwind_inner(msg: Box<Any + Send>,
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.doit(|| 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.
//
Expand Down
31 changes: 26 additions & 5 deletions src/libstd/sys/common/helper_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
//! can be created in the future and there must be no active timers at that
//! time.

#![macro_escape]

use prelude::*;

use cell::UnsafeCell;
Expand Down Expand Up @@ -68,6 +70,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<M: Send> Helper<M> {
/// Lazily boots a helper thread, becoming a no-op if the helper has already
/// been spawned.
Expand All @@ -84,7 +97,7 @@ impl<M: Send> Helper<M> {
{
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();
Expand All @@ -93,15 +106,17 @@ impl<M: Send> Helper<M> {
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");
}
}
}
Expand All @@ -116,7 +131,9 @@ impl<M: Send> Helper<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().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);
helper_signal::signal(*self.signal.get() as helper_signal::signal);
}
Expand All @@ -129,9 +146,13 @@ impl<M: Send> Helper<M> {
// 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<Sender<M>> = mem::transmute(*self.chan.get());
*self.chan.get() = 0 as *mut Sender<M>;
*self.chan.get() = 1 as *mut Sender<M>;
drop(chan);
helper_signal::signal(*self.signal.get() as helper_signal::signal);

Expand Down
2 changes: 1 addition & 1 deletion src/libstd/sys/common/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
// except according to those terms.

#![allow(missing_docs)]
#![allow(dead_code)]
#![macro_escape]

use io::{mod, IoError, IoResult};
use prelude::*;
Expand Down
1 change: 1 addition & 0 deletions src/libstd/sys/common/mutex.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
6 changes: 5 additions & 1 deletion src/libstd/sys/common/net.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,9 @@ use io::{IoResult, IoError};
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, MutexGuard};
use sync::Mutex;
#[cfg(not(target_os = "linux"))]
use sync::MutexGuard;
use sys_common::{mod, keep_going, short_write, timeout};
use prelude::*;
use cmp;
Expand Down Expand Up @@ -573,11 +575,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) {
Expand Down
1 change: 1 addition & 0 deletions src/libstd/sys/common/rwlock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading