Skip to content

Commit

Permalink
Auto merge of #23267 - alexcrichton:issue-20012, r=aturon
Browse files Browse the repository at this point in the history
This reverts commit aec67c2.

Closes #20012

This is temporarily rebased on #23245 as it would otherwise conflict, the last commit is the only one relevant to this PR though.
  • Loading branch information
bors committed Mar 20, 2015
2 parents 3900c08 + 1cc9718 commit 68d6941
Show file tree
Hide file tree
Showing 10 changed files with 86 additions and 51 deletions.
40 changes: 28 additions & 12 deletions src/liblog/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,10 +183,9 @@ use std::io::{self, Stderr};
use std::io::prelude::*;
use std::mem;
use std::env;
use std::ptr;
use std::rt;
use std::slice;
use std::sync::{Once, ONCE_INIT};
use std::sync::{Once, ONCE_INIT, StaticMutex, MUTEX_INIT};

use directive::LOG_LEVEL_NAMES;

Expand All @@ -202,6 +201,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 @@ -286,9 +287,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 !args.to_string().contains(&filter[..]) => 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::<_, &String>(n);
if !args.to_string().contains(&filter[..]) {
return
}
}
}
}

// Completely remove the local logger from TLS in case anyone attempts to
Expand Down Expand Up @@ -370,9 +380,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 @@ -428,14 +444,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<Vec<directive::LogDirective>> =
Box::from_raw(DIRECTIVES);
DIRECTIVES = ptr::null_mut();
let _directives = Box::from_raw(DIRECTIVES);
DIRECTIVES = 1 as *mut _;

if !FILTER.is_null() {
let _filter: Box<String> = Box::from_raw(FILTER);
FILTER = 0 as *mut _;
let _filter = Box::from_raw(FILTER);
FILTER = 1 as *mut _;
}
});
}
Expand Down
21 changes: 6 additions & 15 deletions src/libstd/rt/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,20 +147,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+'static>(f: F) {
///
/// Note that other threads may still be running when `at_exit` routines start
/// running.
pub fn at_exit<F: FnOnce() + Send + 'static>(f: F) {
at_exit_imp::push(Thunk::new(f));
}

Expand All @@ -176,8 +170,5 @@ pub fn at_exit<F:FnOnce()+Send+'static>(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();
}
23 changes: 17 additions & 6 deletions src/libstd/rt/unwind.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ use intrinsics;
use libc::c_void;
use mem;
use sync::atomic::{self, Ordering};
use sync::{Once, ONCE_INIT};
use sys_common::mutex::{Mutex, MUTEX_INIT};

use rt::libunwind as uw;

Expand Down Expand Up @@ -534,11 +534,22 @@ 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)) -> ! {
// Make sure the default panic handler is registered before we look at the
// callbacks.
static INIT: Once = ONCE_INIT;
INIT.call_once(|| unsafe { register(panicking::on_panic); });
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. We also use a raw sys-based mutex here instead of a
// `std::sync` one as accessing TLS can cause weird recursive problems (and
// we don't need poison checking).
unsafe {
static LOCK: Mutex = MUTEX_INIT;
static mut INIT: bool = false;
LOCK.lock();
if !INIT {
register(panicking::on_panic);
INIT = true;
}
LOCK.unlock();
}

// First, invoke call the user-defined callbacks triggered on thread panic.
//
Expand Down
19 changes: 13 additions & 6 deletions src/libstd/sys/common/helper_thread.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ use prelude::v1::*;

use boxed;
use cell::UnsafeCell;
use ptr;
use rt;
use sync::{StaticMutex, StaticCondvar};
use sync::mpsc::{channel, Sender, Receiver};
Expand Down Expand Up @@ -97,7 +96,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() = boxed::into_raw(box tx);
let (receive, send) = helper_signal::new();
Expand All @@ -113,8 +112,10 @@ impl<M: Send> Helper<M> {
self.cond.notify_one()
});

rt::at_exit(move|| { self.shutdown() });
rt::at_exit(move || { self.shutdown() });
*self.initialized.get() = true;
} else if *self.chan.get() as uint == 1 {
panic!("cannot continue usage after shutdown");
}
}
}
Expand All @@ -129,7 +130,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).unwrap();
helper_signal::signal(*self.signal.get() as helper_signal::signal);
}
Expand All @@ -142,9 +145,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>> = Box::from_raw(*self.chan.get());
*self.chan.get() = ptr::null_mut();
let chan = Box::from_raw(*self.chan.get());
*self.chan.get() = 1 as *mut Sender<M>;
drop(chan);
helper_signal::signal(*self.signal.get() as helper_signal::signal);

Expand Down
4 changes: 0 additions & 4 deletions src/libstd/sys/common/thread_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@
use prelude::v1::*;

use sync::atomic::{self, AtomicUsize, Ordering};
use sync::{Mutex, Once, ONCE_INIT};

use sys::thread_local as imp;

Expand Down Expand Up @@ -142,9 +141,6 @@ pub const INIT_INNER: StaticKeyInner = StaticKeyInner {
key: atomic::ATOMIC_USIZE_INIT,
};

static INIT_KEYS: Once = ONCE_INIT;
static mut KEYS: *mut Mutex<Vec<imp::Key>> = 0 as *mut _;

impl StaticKey {
/// Gets the value associated with this TLS key
///
Expand Down
9 changes: 8 additions & 1 deletion src/libstd/sys/unix/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -170,8 +170,15 @@ fn helper(input: libc::c_int, messages: Receiver<Req>, _: ()) {
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;
}

Expand Down
12 changes: 9 additions & 3 deletions src/libstd/sys/windows/thread_local.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,29 @@ unsafe fn init_dtors() {
rt::at_exit(move|| {
DTOR_LOCK.lock();
let dtors = DTORS;
DTORS = ptr::null_mut();
DTORS = 1 as *mut _;
Box::from_raw(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();
});
}

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();
}

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();
Expand Down Expand Up @@ -241,7 +247,7 @@ unsafe fn run_dtors() {
any_run = false;
let dtors = {
DTOR_LOCK.lock();
let ret = if DTORS.is_null() {
let ret = if DTORS as usize <= 1 {
Vec::new()
} else {
(*DTORS).iter().map(|s| *s).collect()
Expand Down
5 changes: 3 additions & 2 deletions src/libstd/sys/windows/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,10 @@ fn helper(input: libc::HANDLE, messages: Receiver<Req>, _: ()) {
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
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-fail/rt-set-exit-status-panic2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ fn r(x:int) -> r {

fn main() {
error!("whatever");
let _t = thread::spawn(move|| {
let _t = thread::scoped(move|| {
let _i = r(5);
});
panic!();
Expand Down
2 changes: 1 addition & 1 deletion src/test/run-pass/unique-send-2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ pub fn main() {
let _t = (0..n).map(|i| {
expected += i;
let tx = tx.clone();
thread::spawn(move|| {
thread::scoped(move|| {
child(&tx, i)
})
}).collect::<Vec<_>>();
Expand Down

0 comments on commit 68d6941

Please sign in to comment.