From ed3f7f5818156229b7af4e5b1c4834745ffa7342 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 1 Apr 2016 07:34:59 +0530 Subject: [PATCH 1/3] Skip printing the backtrace for RecvError/SendError We currently get tons of useless backtraces clogging up the output when we have a panic cascade. This adds a handler that outputs a single line when a thread panics due to a sender or receiver hanging up, since this is almost always due to a panic cascade. --- components/util/lib.rs | 1 + components/util/thread.rs | 29 +++++++++++++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/components/util/lib.rs b/components/util/lib.rs index 9a06ee1b725..3f9755c4306 100644 --- a/components/util/lib.rs +++ b/components/util/lib.rs @@ -9,6 +9,7 @@ #![cfg_attr(feature = "non-geckolib", feature(decode_utf16))] #![feature(optin_builtin_traits)] #![feature(plugin)] +#![feature(panic_handler)] #![feature(reflect_marker)] #![feature(step_by)] diff --git a/components/util/thread.rs b/components/util/thread.rs index f17d6985867..d51fd3dfa37 100644 --- a/components/util/thread.rs +++ b/components/util/thread.rs @@ -5,16 +5,41 @@ use ipc_channel::ipc::IpcSender; use serde::Serialize; use std::borrow::ToOwned; +use std::io::{Write, stderr}; +use std::panic::{PanicInfo, take_handler, set_handler}; use std::sync::mpsc::Sender; use std::thread; use std::thread::Builder; use thread_state; - +#[allow(unused_must_use)] pub fn spawn_named(name: String, f: F) where F: FnOnce() + Send + 'static { let builder = thread::Builder::new().name(name); - builder.spawn(f).unwrap(); + + let f_with_handler = move || { + let hook = take_handler(); + + let new_handler = move |info: &PanicInfo| { + let payload = info.payload(); + if let Some(s) = payload.downcast_ref::() { + if s.contains("SendError") { + write!(stderr(), "Thread \"{}\" panicked with an unwrap of `SendError` (backtrace skipped)\n", + thread::current().name().unwrap_or("")); + return; + } else if s.contains("RecvError") { + write!(stderr(), "Thread \"{}\" panicked with an unwrap of `RecvError` (backtrace skipped)\n", + thread::current().name().unwrap_or("")); + return; + } + } + hook(&info); + }; + set_handler(new_handler); + f(); + }; + + builder.spawn(f_with_handler).unwrap(); } /// An abstraction over `Sender` and `IpcSender`, for use in From 1aa6d558ac4d613c1ca7093bc34feade795f2a52 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Fri, 1 Apr 2016 10:18:10 +0530 Subject: [PATCH 2/3] Lock stderr in custom panic handler --- components/util/thread.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/components/util/thread.rs b/components/util/thread.rs index d51fd3dfa37..9175996a4b2 100644 --- a/components/util/thread.rs +++ b/components/util/thread.rs @@ -11,7 +11,7 @@ use std::sync::mpsc::Sender; use std::thread; use std::thread::Builder; use thread_state; -#[allow(unused_must_use)] + pub fn spawn_named(name: String, f: F) where F: FnOnce() + Send + 'static { @@ -24,11 +24,15 @@ pub fn spawn_named(name: String, f: F) let payload = info.payload(); if let Some(s) = payload.downcast_ref::() { if s.contains("SendError") { - write!(stderr(), "Thread \"{}\" panicked with an unwrap of `SendError` (backtrace skipped)\n", + let err = stderr(); + let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \ + `SendError` (backtrace skipped)\n", thread::current().name().unwrap_or("")); return; } else if s.contains("RecvError") { - write!(stderr(), "Thread \"{}\" panicked with an unwrap of `RecvError` (backtrace skipped)\n", + let err = stderr(); + let _ = write!(err.lock(), "Thread \"{}\" panicked with an unwrap of \ + `RecvError` (backtrace skipped)\n", thread::current().name().unwrap_or("")); return; } From a2c82a03ba613a32d6ad8e31111178083ab7da7b Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 2 Apr 2016 05:56:41 +0530 Subject: [PATCH 3/3] Add option for printing full backtraces --- components/util/opts.rs | 10 ++++++++++ components/util/thread.rs | 6 ++++++ 2 files changed, 16 insertions(+) diff --git a/components/util/opts.rs b/components/util/opts.rs index e8d5283b9b4..c2b2faefbcd 100644 --- a/components/util/opts.rs +++ b/components/util/opts.rs @@ -201,6 +201,9 @@ pub struct Opts { // Which rendering API to use. pub render_api: RenderApi, + + // don't skip any backtraces on panic + pub full_backtraces: bool, } fn print_usage(app: &str, opts: &Options) { @@ -291,6 +294,9 @@ pub struct DebugOptions { /// Use multisample antialiasing in WebRender. pub use_msaa: bool, + // don't skip any backtraces on panic + pub full_backtraces: bool, + } @@ -326,6 +332,7 @@ impl DebugOptions { "disable-vsync" => debug_options.disable_vsync = true, "wr-stats" => debug_options.webrender_stats = true, "msaa" => debug_options.use_msaa = true, + "full-backtraces" => debug_options.full_backtraces = true, "" => {}, _ => return Err(option) }; @@ -373,6 +380,7 @@ pub fn print_debug_usage(app: &str) -> ! { "Disable vsync mode in the compositor to allow profiling at more than monitor refresh rate"); print_option("wr-stats", "Show WebRender profiler on screen."); print_option("msaa", "Use multisample antialiasing in WebRender."); + print_option("full-backtraces", "Print full backtraces for all errors"); println!(""); @@ -515,6 +523,7 @@ pub fn default_opts() -> Opts { use_msaa: false, render_api: DEFAULT_RENDER_API, profile_dir: None, + full_backtraces: false, } } @@ -795,6 +804,7 @@ pub fn from_cmdline_args(args: &[String]) -> ArgumentParsingResult { webrender_stats: debug_options.webrender_stats, use_msaa: debug_options.use_msaa, profile_dir: opt_match.opt_str("profile-dir"), + full_backtraces: debug_options.full_backtraces, }; set_defaults(opts); diff --git a/components/util/thread.rs b/components/util/thread.rs index 9175996a4b2..f32e6ccd4f7 100644 --- a/components/util/thread.rs +++ b/components/util/thread.rs @@ -3,6 +3,7 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use ipc_channel::ipc::IpcSender; +use opts; use serde::Serialize; use std::borrow::ToOwned; use std::io::{Write, stderr}; @@ -17,6 +18,11 @@ pub fn spawn_named(name: String, f: F) { let builder = thread::Builder::new().name(name); + if opts::get().full_backtraces { + builder.spawn(f).unwrap(); + return; + } + let f_with_handler = move || { let hook = take_handler();