use fmt;
use io::lazy::Lazy;
use io::{self, BufReader, LineWriter};
+use libc;
use sync::{Arc, Mutex, MutexGuard};
use sys::stdio;
use sys_common::io::{read_to_end_uninitialized};
use sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard};
-use libc;
+use thread::LocalKeyState;
/// Stdout used by print! and println! macros
thread_local! {
issue = "0")]
#[doc(hidden)]
pub fn _print(args: fmt::Arguments) {
- let result = LOCAL_STDOUT.with(|s| {
- if s.borrow_state() == BorrowState::Unused {
- if let Some(w) = s.borrow_mut().as_mut() {
- return w.write_fmt(args);
- }
+ // As an implementation of the `println!` macro, we want to try our best to
+ // not panic wherever possible and get the output somewhere. There are
+ // currently two possible vectors for panics we take care of here:
+ //
+ // 1. If the TLS key for the local stdout has been destroyed, accessing it
+ // would cause a panic. Note that we just lump in the uninitialized case
+ // here for convenience, we're not trying to avoid a panic.
+ // 2. If the local stdout is currently in use (e.g. we're in the middle of
+ // already printing) then accessing again would cause a panic.
+ //
+ // If, however, the actual I/O causes an error, we do indeed panic.
+ let result = match LOCAL_STDOUT.state() {
+ LocalKeyState::Uninitialized |
+ LocalKeyState::Destroyed => stdout().write_fmt(args),
+ LocalKeyState::Valid => {
+ LOCAL_STDOUT.with(|s| {
+ if s.borrow_state() == BorrowState::Unused {
+ if let Some(w) = s.borrow_mut().as_mut() {
+ return w.write_fmt(args);
+ }
+ }
+ stdout().write_fmt(args)
+ })
}
- stdout().write_fmt(args)
- });
+ };
if let Err(e) = result {
panic!("failed printing to stdout: {}", e);
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+use std::thread;
+
+struct Foo;
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ println!("test2");
+ }
+}
+
+thread_local!(static FOO: Foo = Foo);
+
+fn main() {
+ // Off the main thread due to #28129, be sure to initialize FOO first before
+ // calling `println!`
+ thread::spawn(|| {
+ FOO.with(|_| {});
+ println!("test1");
+ }).join().unwrap();
+}