]> git.lizzy.rs Git - rust.git/blob - src/libstd/failure.rs
std: Add a new top-level thread_local module
[rust.git] / src / libstd / failure.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![experimental]
12
13 use alloc::boxed::Box;
14 use any::{Any, AnyRefExt};
15 use cell::RefCell;
16 use fmt;
17 use io::{Writer, IoResult};
18 use kinds::Send;
19 use option::{Some, None, Option};
20 use result::Ok;
21 use rt::backtrace;
22 use rustrt::{Stderr, Stdio};
23 use rustrt::local::Local;
24 use rustrt::task::Task;
25 use str::Str;
26 use string::String;
27
28 // Defined in this module instead of io::stdio so that the unwinding
29 thread_local!(pub static LOCAL_STDERR: RefCell<Option<Box<Writer + Send>>> = {
30     RefCell::new(None)
31 })
32
33 impl Writer for Stdio {
34     fn write(&mut self, bytes: &[u8]) -> IoResult<()> {
35         fn fmt_write<F: fmt::FormatWriter>(f: &mut F, bytes: &[u8]) {
36             let _ = f.write(bytes);
37         }
38         fmt_write(self, bytes);
39         Ok(())
40     }
41 }
42
43 pub fn on_fail(obj: &Any + Send, file: &'static str, line: uint) {
44     let msg = match obj.downcast_ref::<&'static str>() {
45         Some(s) => *s,
46         None => match obj.downcast_ref::<String>() {
47             Some(s) => s.as_slice(),
48             None => "Box<Any>",
49         }
50     };
51     let mut err = Stderr;
52
53     // It is assumed that all reasonable rust code will have a local task at
54     // all times. This means that this `exists` will return true almost all of
55     // the time. There are border cases, however, when the runtime has
56     // *almost* set up the local task, but hasn't quite gotten there yet. In
57     // order to get some better diagnostics, we print on panic and
58     // immediately abort the whole process if there is no local task
59     // available.
60     if !Local::exists(None::<Task>) {
61         let _ = writeln!(&mut err, "panicked at '{}', {}:{}", msg, file, line);
62         if backtrace::log_enabled() {
63             let _ = backtrace::write(&mut err);
64         } else {
65             let _ = writeln!(&mut err, "run with `RUST_BACKTRACE=1` to \
66                                         see a backtrace");
67         }
68         return
69     }
70
71     // Peel the name out of local task so we can print it. We've got to be sure
72     // that the local task is in TLS while we're printing as I/O may occur.
73     let (name, unwinding) = {
74         let mut t = Local::borrow(None::<Task>);
75         (t.name.take(), t.unwinder.unwinding())
76     };
77     {
78         let n = name.as_ref().map(|n| n.as_slice()).unwrap_or("<unnamed>");
79
80         let prev = LOCAL_STDERR.with(|s| s.borrow_mut().take());
81         match prev {
82             Some(mut stderr) => {
83                 // FIXME: what to do when the task printing panics?
84                 let _ = writeln!(stderr,
85                                  "task '{}' panicked at '{}', {}:{}\n",
86                                  n, msg, file, line);
87                 if backtrace::log_enabled() {
88                     let _ = backtrace::write(&mut *stderr);
89                 }
90                 let mut s = Some(stderr);
91                 LOCAL_STDERR.with(|slot| {
92                     *slot.borrow_mut() = s.take();
93                 });
94             }
95             None => {
96                 let _ = writeln!(&mut err, "task '{}' panicked at '{}', {}:{}",
97                                  n, msg, file, line);
98                 if backtrace::log_enabled() {
99                     let _ = backtrace::write(&mut err);
100                 }
101             }
102         }
103
104         // If this is a double panic, make sure that we printed a backtrace
105         // for this panic.
106         if unwinding && !backtrace::log_enabled() {
107             let _ = backtrace::write(&mut err);
108         }
109     }
110     Local::borrow(None::<Task>).name = name;
111 }