mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-26 16:54:01 +00:00
Auto merge of #23267 - alexcrichton:issue-20012, r=aturon
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.
This commit is contained in:
commit
68d6941563
@ -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;
|
||||
|
||||
@ -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.
|
||||
@ -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
|
||||
@ -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,
|
||||
@ -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 _;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
@ -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();
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
@ -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.
|
||||
//
|
||||
|
@ -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};
|
||||
@ -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();
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
||||
@ -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
|
||||
///
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -138,9 +138,9 @@ 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();
|
||||
});
|
||||
}
|
||||
@ -148,6 +148,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();
|
||||
}
|
||||
@ -155,6 +158,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();
|
||||
@ -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()
|
||||
|
@ -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
|
||||
|
@ -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!();
|
||||
|
@ -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<_>>();
|
||||
|
Loading…
Reference in New Issue
Block a user