diff options
author | Alan Jeffrey <ajeffrey@mozilla.com> | 2016-04-15 09:49:13 -0500 |
---|---|---|
committer | Alan Jeffrey <ajeffrey@mozilla.com> | 2016-04-19 09:08:44 -0500 |
commit | cfb066ef2024f05a13da842cedf833a8aa2e8cbe (patch) | |
tree | ed58db7aaa3c563a07e185ccb8b350598f30cb2a /components | |
parent | a7c885706ec4bd526b00ecad5d870415ae6cc1e1 (diff) | |
download | servo-cfb066ef2024f05a13da842cedf833a8aa2e8cbe.tar.gz servo-cfb066ef2024f05a13da842cedf833a8aa2e8cbe.zip |
Added a dedicated panic channel.
Diffstat (limited to 'components')
-rw-r--r-- | components/compositing/constellation.rs | 89 | ||||
-rw-r--r-- | components/compositing/pipeline.rs | 31 | ||||
-rw-r--r-- | components/gfx/paint_thread.rs | 12 | ||||
-rw-r--r-- | components/gfx_traits/lib.rs | 14 | ||||
-rw-r--r-- | components/layout/layout_thread.rs | 12 | ||||
-rw-r--r-- | components/layout_traits/lib.rs | 4 | ||||
-rw-r--r-- | components/msg/constellation_msg.rs | 25 | ||||
-rw-r--r-- | components/script/layout_interface.rs | 4 | ||||
-rw-r--r-- | components/script/script_thread.rs | 14 | ||||
-rw-r--r-- | components/script_traits/lib.rs | 10 | ||||
-rw-r--r-- | components/script_traits/script_msg.rs | 18 | ||||
-rw-r--r-- | components/util/panicking.rs | 7 | ||||
-rw-r--r-- | components/util/thread.rs | 100 |
13 files changed, 108 insertions, 232 deletions
diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index 3cd67edcbcd..4a4aec9d8c7 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -25,7 +25,7 @@ use gaol; #[cfg(not(target_os = "windows"))] use gaol::sandbox::{self, Sandbox, SandboxMethods}; use gfx::font_cache_thread::FontCacheThread; -use gfx_traits::{Epoch, PaintMsg as FromPaintMsg}; +use gfx_traits::Epoch; use ipc_channel::ipc::{self, IpcOneShotServer, IpcSender}; use ipc_channel::router::ROUTER; use layout_traits::{LayoutControlChan, LayoutThreadFactory}; @@ -34,7 +34,7 @@ use msg::constellation_msg::{FrameId, PipelineId}; use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData}; use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, NavigationDirection}; use msg::constellation_msg::{SubpageId, WindowSizeData}; -use msg::constellation_msg::{self, ConstellationChan, Failure}; +use msg::constellation_msg::{self, ConstellationChan, PanicMsg}; use msg::webdriver_msg; use net_traits::image_cache_thread::ImageCacheThread; use net_traits::storage_thread::{StorageThread, StorageThreadMsg}; @@ -95,8 +95,8 @@ pub struct Constellation<LTF, STF> { /// A channel through which layout thread messages can be sent to this object. pub layout_sender: ConstellationChan<FromLayoutMsg>, - /// A channel through which paint thread messages can be sent to this object. - pub painter_sender: ConstellationChan<FromPaintMsg>, + /// A channel through which panic messages can be sent to this object. + pub panic_sender: ConstellationChan<PanicMsg>, /// Receives messages from scripts. pub script_receiver: Receiver<FromScriptMsg>, @@ -107,8 +107,8 @@ pub struct Constellation<LTF, STF> { /// Receives messages from the layout thread pub layout_receiver: Receiver<FromLayoutMsg>, - /// Receives messages from paint thread. - pub painter_receiver: Receiver<FromPaintMsg>, + /// Receives panic messages. + pub panic_receiver: Receiver<PanicMsg>, /// A channel (the implementation of which is port-specific) through which messages can be sent /// to the compositor. @@ -320,19 +320,19 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> let (compositor_sender, compositor_receiver) = channel(); let (ipc_layout_receiver, ipc_layout_sender) = ConstellationChan::<FromLayoutMsg>::new(); let layout_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_layout_receiver); - let (ipc_painter_receiver, ipc_painter_sender) = ConstellationChan::<FromPaintMsg>::new(); - let painter_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_painter_receiver); + let (ipc_panic_receiver, ipc_panic_sender) = ConstellationChan::<PanicMsg>::new(); + let panic_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_panic_receiver); let compositor_sender_clone = compositor_sender.clone(); spawn_named("Constellation".to_owned(), move || { let mut constellation: Constellation<LTF, STF> = Constellation { script_sender: ipc_script_sender, compositor_sender: compositor_sender_clone, layout_sender: ipc_layout_sender, - painter_sender: ipc_painter_sender, script_receiver: script_receiver, + panic_sender: ipc_panic_sender, compositor_receiver: compositor_receiver, layout_receiver: layout_receiver, - painter_receiver: painter_receiver, + panic_receiver: panic_receiver, compositor_proxy: state.compositor_proxy, devtools_chan: state.devtools_chan, resource_thread: state.resource_thread, @@ -416,7 +416,7 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> parent_info: parent_info, constellation_chan: self.script_sender.clone(), layout_to_constellation_chan: self.layout_sender.clone(), - painter_chan: self.painter_sender.clone(), + panic_chan: self.panic_sender.clone(), scheduler_chan: self.scheduler_chan.clone(), compositor_proxy: self.compositor_proxy.clone_compositor_proxy(), devtools_chan: self.devtools_chan.clone(), @@ -548,7 +548,7 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> Script(FromScriptMsg), Compositor(FromCompositorMsg), Layout(FromLayoutMsg), - Paint(FromPaintMsg) + Panic(PanicMsg) } // Get one incoming request. @@ -566,16 +566,16 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> let receiver_from_script = &self.script_receiver; let receiver_from_compositor = &self.compositor_receiver; let receiver_from_layout = &self.layout_receiver; - let receiver_from_paint = &self.painter_receiver; + let receiver_from_panic = &self.panic_receiver; select! { msg = receiver_from_script.recv() => - Request::Script(msg.expect("Unexpected script failure in constellation")), + Request::Script(msg.expect("Unexpected script channel panic in constellation")), msg = receiver_from_compositor.recv() => - Request::Compositor(msg.expect("Unexpected compositor failure in constellation")), + Request::Compositor(msg.expect("Unexpected compositor channel panic in constellation")), msg = receiver_from_layout.recv() => - Request::Layout(msg.expect("Unexpected layout failure in constellation")), - msg = receiver_from_paint.recv() => - Request::Paint(msg.expect("Unexpected paint failure in constellation")) + Request::Layout(msg.expect("Unexpected layout channel panic in constellation")), + msg = receiver_from_panic.recv() => + Request::Panic(msg.expect("Unexpected panic channel panic in constellation")) } }; @@ -655,10 +655,6 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> // Messages from script - Request::Script(FromScriptMsg::Failure(failure)) => { - debug!("handling script failure message from pipeline {:?}", failure); - self.handle_failure_msg(failure); - } Request::Script(FromScriptMsg::ScriptLoadedURLInIFrame(load_info)) => { debug!("constellation got iframe URL load message {:?} {:?} {:?}", load_info.containing_pipeline_id, @@ -803,10 +799,6 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> Request::Layout(FromLayoutMsg::ChangeRunningAnimationsState(pipeline_id, animation_state)) => { self.handle_change_running_animations_state(pipeline_id, animation_state) } - Request::Layout(FromLayoutMsg::Failure(failure)) => { - debug!("handling paint failure message from pipeline {:?}", failure); - self.handle_failure_msg(failure); - } Request::Layout(FromLayoutMsg::SetCursor(cursor)) => { self.handle_set_cursor_msg(cursor) } @@ -816,15 +808,12 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> } - // Messages from paint thread + // Panic messages - - // Notification that painting has finished and is requesting permission to paint. - Request::Paint(FromPaintMsg::Failure(failure)) => { - debug!("handling paint failure message from pipeline {:?}", failure); - self.handle_failure_msg(failure); + Request::Panic((pipeline_id, panic_reason)) => { + debug!("handling panic message ({:?})", pipeline_id); + self.handle_panic(pipeline_id, panic_reason); } - } true } @@ -851,17 +840,12 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> } fn handle_send_error(&mut self, pipeline_id: PipelineId, err: IOError) { - let parent_info = match self.pipelines.get(&pipeline_id) { - None => return warn!("Pipeline {:?} send error after closure.", pipeline_id), - Some(pipeline) => pipeline.parent_info, - }; - // Treat send error the same as receiving a failure message + // Treat send error the same as receiving a panic message debug!("Pipeline {:?} send error ({}).", pipeline_id, err); - let failure = Failure::new(pipeline_id, parent_info); - self.handle_failure_msg(failure); + self.handle_panic(Some(pipeline_id), format!("Send failed ({})", err)); } - fn handle_failure_msg(&mut self, failure: Failure) { + fn handle_panic(&mut self, pipeline_id: Option<PipelineId>, reason: String) { if opts::get().hard_fail { // It's quite difficult to make Servo exit cleanly if some threads have failed. // Hard fail exists for test runners so we crash and that's good enough. @@ -871,15 +855,26 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> process::exit(1); } - let window_size = self.pipelines.get(&failure.pipeline_id).and_then(|pipeline| pipeline.size); + debug!("Panic handler for pipeline {:?}: {}.", pipeline_id, reason); + + if let Some(pipeline_id) = pipeline_id { + self.replace_pipeline_with_about_failure(pipeline_id); + } + + } + + fn replace_pipeline_with_about_failure(&mut self, pipeline_id: PipelineId) { + + let parent_info = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.parent_info); + let window_size = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.size); // Notify the browser chrome that the pipeline has failed - self.trigger_mozbrowsererror(failure.pipeline_id); + self.trigger_mozbrowsererror(pipeline_id); - self.close_pipeline(failure.pipeline_id, ExitPipelineMode::Force); + self.close_pipeline(pipeline_id, ExitPipelineMode::Force); while let Some(pending_pipeline_id) = self.pending_frames.iter().find(|pending| { - pending.old_pipeline_id == Some(failure.pipeline_id) + pending.old_pipeline_id == Some(pipeline_id) }).map(|frame| frame.new_pipeline_id) { warn!("removing pending frame change for failed pipeline"); self.close_pipeline(pending_pipeline_id, ExitPipelineMode::Force); @@ -889,12 +884,12 @@ impl<LTF: LayoutThreadFactory, STF: ScriptThreadFactory> Constellation<LTF, STF> let new_pipeline_id = PipelineId::new(); self.new_pipeline(new_pipeline_id, - failure.parent_info, + parent_info, window_size, None, LoadData::new(Url::parse("about:failure").expect("infallible"))); - self.push_pending_frame(new_pipeline_id, Some(failure.pipeline_id)); + self.push_pending_frame(new_pipeline_id, Some(pipeline_id)); } diff --git a/components/compositing/pipeline.rs b/components/compositing/pipeline.rs index 3de923ba858..9facc11829c 100644 --- a/components/compositing/pipeline.rs +++ b/components/compositing/pipeline.rs @@ -10,12 +10,11 @@ use euclid::scale_factor::ScaleFactor; use euclid::size::TypedSize2D; use gfx::font_cache_thread::FontCacheThread; use gfx::paint_thread::{ChromeToPaintMsg, LayoutToPaintMsg, PaintThread}; -use gfx_traits::PaintMsg; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; use ipc_channel::router::ROUTER; use layers::geometry::DevicePixel; use layout_traits::{LayoutControlChan, LayoutThreadFactory}; -use msg::constellation_msg::{ConstellationChan, Failure, FrameId, PipelineId, SubpageId}; +use msg::constellation_msg::{ConstellationChan, PanicMsg, FrameId, PipelineId, SubpageId}; use msg::constellation_msg::{LoadData, WindowSizeData}; use msg::constellation_msg::{PipelineNamespaceId}; use net_traits::ResourceThread; @@ -85,8 +84,8 @@ pub struct InitialPipelineState { pub constellation_chan: ConstellationChan<ScriptMsg>, /// A channel for the layout thread to send messages to the constellation. pub layout_to_constellation_chan: ConstellationChan<LayoutMsg>, - /// A channel to the associated paint thread. - pub painter_chan: ConstellationChan<PaintMsg>, + /// A channel to report panics + pub panic_chan: ConstellationChan<PanicMsg>, /// A channel to schedule timer events. pub scheduler_chan: IpcSender<TimerEventRequest>, /// A channel to the compositor. @@ -140,8 +139,6 @@ impl Pipeline { .expect("Pipeline script to compositor chan"); let mut pipeline_port = Some(pipeline_port); - let failure = Failure::new(state.id, state.parent_info); - let window_size = state.window_size.map(|size| { WindowSizeData { visible_viewport: size, @@ -179,7 +176,7 @@ impl Pipeline { subpage_id: subpage_id, load_data: state.load_data.clone(), paint_chan: layout_to_paint_chan.clone().to_opaque(), - failure: failure.clone(), + panic_chan: state.panic_chan.clone(), pipeline_port: mem::replace(&mut pipeline_port, None) .expect("script_pipeline != None but pipeline_port == None"), layout_shutdown_chan: layout_shutdown_chan.clone(), @@ -227,7 +224,7 @@ impl Pipeline { layout_to_constellation_chan: state.layout_to_constellation_chan, script_chan: script_chan, load_data: state.load_data.clone(), - failure: failure.clone(), + panic_chan: state.panic_chan.clone(), script_port: script_port, opts: (*opts::get()).clone(), prefs: prefs::get_cloned(), @@ -246,13 +243,12 @@ impl Pipeline { let privileged_pipeline_content = PrivilegedPipelineContent { id: state.id, - painter_chan: state.painter_chan, compositor_proxy: state.compositor_proxy, font_cache_thread: state.font_cache_thread, time_profiler_chan: state.time_profiler_chan, mem_profiler_chan: state.mem_profiler_chan, load_data: state.load_data, - failure: failure, + panic_chan: state.panic_chan, layout_to_paint_port: layout_to_paint_port, chrome_to_paint_chan: chrome_to_paint_chan, chrome_to_paint_port: chrome_to_paint_port, @@ -403,7 +399,7 @@ pub struct UnprivilegedPipelineContent { window_size: Option<WindowSizeData>, script_chan: IpcSender<ConstellationControlMsg>, load_data: LoadData, - failure: Failure, + panic_chan: ConstellationChan<PanicMsg>, script_port: Option<IpcReceiver<ConstellationControlMsg>>, layout_to_paint_chan: OptionalIpcSender<LayoutToPaintMsg>, opts: Opts, @@ -433,7 +429,7 @@ impl UnprivilegedPipelineContent { constellation_chan: self.constellation_chan.clone(), layout_to_constellation_chan: self.layout_to_constellation_chan.clone(), scheduler_chan: self.scheduler_chan.clone(), - failure_info: self.failure.clone(), + panic_chan: self.panic_chan.clone(), resource_thread: self.resource_thread, storage_thread: self.storage_thread.clone(), image_cache_thread: self.image_cache_thread.clone(), @@ -452,7 +448,7 @@ impl UnprivilegedPipelineContent { layout_pair, self.pipeline_port.expect("No pipeline port."), self.layout_to_constellation_chan, - self.failure, + self.panic_chan, self.script_chan.clone(), self.layout_to_paint_chan.clone(), self.image_cache_thread, @@ -480,14 +476,13 @@ impl UnprivilegedPipelineContent { pub struct PrivilegedPipelineContent { id: PipelineId, - painter_chan: ConstellationChan<PaintMsg>, compositor_proxy: Box<CompositorProxy + Send + 'static>, script_to_compositor_port: IpcReceiver<ScriptToCompositorMsg>, font_cache_thread: FontCacheThread, time_profiler_chan: time::ProfilerChan, mem_profiler_chan: profile_mem::ProfilerChan, load_data: LoadData, - failure: Failure, + panic_chan: ConstellationChan<PanicMsg>, layout_to_paint_port: Receiver<LayoutToPaintMsg>, chrome_to_paint_chan: Sender<ChromeToPaintMsg>, chrome_to_paint_port: Receiver<ChromeToPaintMsg>, @@ -502,9 +497,8 @@ impl PrivilegedPipelineContent { self.layout_to_paint_port, self.chrome_to_paint_port, self.compositor_proxy.clone_compositor_proxy(), - self.painter_chan, + self.panic_chan, self.font_cache_thread, - self.failure, self.time_profiler_chan, self.mem_profiler_chan, self.paint_shutdown_chan); @@ -526,9 +520,8 @@ impl PrivilegedPipelineContent { self.layout_to_paint_port, self.chrome_to_paint_port, self.compositor_proxy, - self.painter_chan, + self.panic_chan, self.font_cache_thread, - self.failure, self.time_profiler_chan, self.mem_profiler_chan, self.paint_shutdown_chan); diff --git a/components/gfx/paint_thread.rs b/components/gfx/paint_thread.rs index 2ea708d39fb..fa515c44afc 100644 --- a/components/gfx/paint_thread.rs +++ b/components/gfx/paint_thread.rs @@ -15,12 +15,11 @@ use euclid::rect::Rect; use euclid::size::Size2D; use font_cache_thread::FontCacheThread; use font_context::FontContext; -use gfx_traits::PaintMsg as ConstellationMsg; use gfx_traits::{Epoch, FrameTreeId, LayerId, LayerKind, LayerProperties, PaintListener}; use ipc_channel::ipc::IpcSender; use layers::layers::{BufferRequest, LayerBuffer, LayerBufferSet}; use layers::platform::surface::{NativeDisplay, NativeSurface}; -use msg::constellation_msg::{ConstellationChan, Failure, PipelineId}; +use msg::constellation_msg::{ConstellationChan, PanicMsg, PipelineId}; use paint_context::PaintContext; use profile_traits::mem::{self, ReportsChan}; use profile_traits::time; @@ -394,14 +393,13 @@ impl<C> PaintThread<C> where C: PaintListener + Send + 'static { layout_to_paint_port: Receiver<LayoutToPaintMsg>, chrome_to_paint_port: Receiver<ChromeToPaintMsg>, compositor: C, - constellation_chan: ConstellationChan<ConstellationMsg>, + panic_chan: ConstellationChan<PanicMsg>, font_cache_thread: FontCacheThread, - failure_msg: Failure, time_profiler_chan: time::ProfilerChan, mem_profiler_chan: mem::ProfilerChan, shutdown_chan: IpcSender<()>) { - let ConstellationChan(c) = constellation_chan.clone(); - thread::spawn_named_with_send_on_failure(format!("PaintThread {:?}", id), + let ConstellationChan(c) = panic_chan.clone(); + thread::spawn_named_with_send_on_panic(format!("PaintThread {:?}", id), thread_state::PAINT, move || { { @@ -441,7 +439,7 @@ impl<C> PaintThread<C> where C: PaintListener + Send + 'static { debug!("paint_thread: shutdown_chan send"); shutdown_chan.send(()).unwrap(); - }, failure_msg, c); + }, Some(id), c); } #[allow(unsafe_code)] diff --git a/components/gfx_traits/lib.rs b/components/gfx_traits/lib.rs index e75700c379c..0d13f45f4a3 100644 --- a/components/gfx_traits/lib.rs +++ b/components/gfx_traits/lib.rs @@ -25,21 +25,9 @@ pub use paint_listener::PaintListener; use azure::azure_hl::Color; use euclid::Matrix4D; use euclid::rect::Rect; -use msg::constellation_msg::{Failure, PipelineId}; +use msg::constellation_msg::{PipelineId}; use std::fmt::{self, Debug, Formatter}; -/// Messages from the paint task to the constellation. -#[derive(Deserialize, Serialize)] -pub enum PaintMsg { - Failure(Failure), -} - -impl From<Failure> for PaintMsg { - fn from(failure: Failure) -> PaintMsg { - PaintMsg::Failure(failure) - } -} - #[derive(Clone, Copy, Debug, PartialEq)] pub enum LayerKind { NoTransform, diff --git a/components/layout/layout_thread.rs b/components/layout/layout_thread.rs index d226188f698..743e0edc526 100644 --- a/components/layout/layout_thread.rs +++ b/components/layout/layout_thread.rs @@ -37,7 +37,7 @@ use ipc_channel::router::ROUTER; use layout_debug; use layout_traits::LayoutThreadFactory; use log; -use msg::constellation_msg::{ConstellationChan, ConvertPipelineIdToWebRender, Failure, PipelineId}; +use msg::constellation_msg::{ConstellationChan, ConvertPipelineIdToWebRender, PanicMsg, PipelineId}; use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread}; use net_traits::image_cache_thread::{UsePlaceholder}; use parallel; @@ -249,7 +249,7 @@ impl LayoutThreadFactory for LayoutThread { chan: OpaqueScriptLayoutChannel, pipeline_port: IpcReceiver<LayoutControlMsg>, constellation_chan: ConstellationChan<ConstellationMsg>, - failure_msg: Failure, + panic_chan: ConstellationChan<PanicMsg>, script_chan: IpcSender<ConstellationControlMsg>, paint_chan: OptionalIpcSender<LayoutToPaintMsg>, image_cache_thread: ImageCacheThread, @@ -259,8 +259,8 @@ impl LayoutThreadFactory for LayoutThread { shutdown_chan: IpcSender<()>, content_process_shutdown_chan: IpcSender<()>, webrender_api_sender: Option<webrender_traits::RenderApiSender>) { - let ConstellationChan(con_chan) = constellation_chan.clone(); - thread::spawn_named_with_send_on_failure(format!("LayoutThread {:?}", id), + let ConstellationChan(fail_chan) = panic_chan.clone(); + thread::spawn_named_with_send_on_panic(format!("LayoutThread {:?}", id), thread_state::LAYOUT, move || { { // Ensures layout thread is destroyed before we send shutdown message @@ -286,7 +286,7 @@ impl LayoutThreadFactory for LayoutThread { } let _ = shutdown_chan.send(()); let _ = content_process_shutdown_chan.send(()); - }, failure_msg, con_chan); + }, Some(id), fail_chan); } } @@ -732,7 +732,7 @@ impl LayoutThread { info.layout_pair, info.pipeline_port, info.constellation_chan, - info.failure, + info.panic_chan, info.script_chan.clone(), info.paint_chan.to::<LayoutToPaintMsg>(), self.image_cache_thread.clone(), diff --git a/components/layout_traits/lib.rs b/components/layout_traits/lib.rs index f06dc14392d..61f9618f421 100644 --- a/components/layout_traits/lib.rs +++ b/components/layout_traits/lib.rs @@ -26,7 +26,7 @@ extern crate webrender_traits; use gfx::font_cache_thread::FontCacheThread; use gfx::paint_thread::LayoutToPaintMsg; use ipc_channel::ipc::{IpcReceiver, IpcSender}; -use msg::constellation_msg::{ConstellationChan, Failure, PipelineId}; +use msg::constellation_msg::{ConstellationChan, PanicMsg, PipelineId}; use net_traits::image_cache_thread::ImageCacheThread; use profile_traits::{mem, time}; use script_traits::LayoutMsg as ConstellationMsg; @@ -49,7 +49,7 @@ pub trait LayoutThreadFactory { chan: OpaqueScriptLayoutChannel, pipeline_port: IpcReceiver<LayoutControlMsg>, constellation_chan: ConstellationChan<ConstellationMsg>, - failure_msg: Failure, + panic_chan: ConstellationChan<PanicMsg>, script_chan: IpcSender<ConstellationControlMsg>, layout_to_paint_chan: OptionalIpcSender<LayoutToPaintMsg>, image_cache_thread: ImageCacheThread, diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index c9b8d0acd88..cfdcdfea1ab 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -16,7 +16,6 @@ use std::cell::Cell; use std::fmt; use url::Url; use util::geometry::{PagePx, ViewportPx}; -use util::thread::AddFailureDetails; use webdriver_msg::{LoadStatus, WebDriverScriptCommand}; use webrender_traits; @@ -36,29 +35,7 @@ impl<T: Serialize + Deserialize> Clone for ConstellationChan<T> { } } -// We pass this info to various threads, so it lives in a separate, cloneable struct. -#[derive(Clone, Deserialize, Serialize, Debug)] -pub struct Failure { - pub pipeline_id: PipelineId, - pub parent_info: Option<(PipelineId, SubpageId)>, - pub panic_message: Option<String>, -} - -impl Failure { - pub fn new(pipeline_id: PipelineId, parent_info: Option<(PipelineId, SubpageId)>) -> Failure { - Failure { - pipeline_id: pipeline_id, - parent_info: parent_info, - panic_message: None, - } - } -} - -impl AddFailureDetails for Failure { - fn add_panic_message(&mut self, message: String) { - self.panic_message = Some(message); - } -} +pub type PanicMsg = (Option<PipelineId>, String); #[derive(Copy, Clone, Deserialize, Serialize, HeapSizeOf)] pub struct WindowSizeData { diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index 07d8ac47edc..e72bb168f33 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -12,7 +12,7 @@ use euclid::point::Point2D; use euclid::rect::Rect; use gfx_traits::{Epoch, LayerId}; use ipc_channel::ipc::{IpcReceiver, IpcSender}; -use msg::constellation_msg::{ConstellationChan, Failure, PipelineId}; +use msg::constellation_msg::{ConstellationChan, PanicMsg, PipelineId}; use msg::constellation_msg::{WindowSizeData}; use net_traits::image_cache_thread::ImageCacheThread; use profile_traits::mem::ReportsChan; @@ -250,7 +250,7 @@ pub struct NewLayoutThreadInfo { pub layout_pair: OpaqueScriptLayoutChannel, pub pipeline_port: IpcReceiver<LayoutControlMsg>, pub constellation_chan: ConstellationChan<ConstellationMsg>, - pub failure: Failure, + pub panic_chan: ConstellationChan<PanicMsg>, pub script_chan: IpcSender<ConstellationControlMsg>, pub image_cache_thread: ImageCacheThread, pub paint_chan: OptionalOpaqueIpcSender, diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index 5f2ecd095ba..78c9aefc409 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -389,7 +389,7 @@ pub struct ScriptThread { content_process_shutdown_chan: IpcSender<()>, } -/// In the event of thread failure, all data on the stack runs its destructor. However, there +/// In the event of thread panic, all data on the stack runs its destructor. However, there /// are no reachable, owning pointers to the DOM memory, so it never gets freed by default /// when the script thread fails. The ScriptMemoryFailsafe uses the destructor bomb pattern /// to forcibly tear down the JS compartments for pages associated with the failing ScriptThread. @@ -442,11 +442,11 @@ impl ScriptThreadFactory for ScriptThread { state: InitialScriptState, layout_chan: &OpaqueScriptLayoutChannel, load_data: LoadData) { - let ConstellationChan(const_chan) = state.constellation_chan.clone(); + let ConstellationChan(panic_chan) = state.panic_chan.clone(); let (script_chan, script_port) = channel(); let layout_chan = LayoutChan(layout_chan.sender()); - let failure_info = state.failure_info.clone(); - thread::spawn_named_with_send_on_failure(format!("ScriptThread {:?}", state.id), + let pipeline_id = state.id; + thread::spawn_named_with_send_on_panic(format!("ScriptThread {:?}", state.id), thread_state::SCRIPT, move || { PipelineNamespace::install(state.pipeline_namespace_id); @@ -481,7 +481,7 @@ impl ScriptThreadFactory for ScriptThread { // This must always be the very last operation performed before the thread completes failsafe.neuter(); - }, failure_info, const_chan); + }, Some(pipeline_id), panic_chan); } } @@ -1061,7 +1061,7 @@ impl ScriptThread { subpage_id, load_data, paint_chan, - failure, + panic_chan, pipeline_port, layout_shutdown_chan, content_process_shutdown_chan, @@ -1079,7 +1079,7 @@ impl ScriptThread { layout_pair: layout_pair, pipeline_port: pipeline_port, constellation_chan: self.layout_to_constellation_chan.clone(), - failure: failure, + panic_chan: panic_chan, paint_chan: paint_chan, script_chan: self.control_chan.clone(), image_cache_thread: self.image_cache_thread.clone(), diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 7175536f280..9b3fb014516 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -41,7 +41,7 @@ use gfx_traits::Epoch; use gfx_traits::LayerId; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use libc::c_void; -use msg::constellation_msg::{ConstellationChan, Failure, PipelineId, WindowSizeData}; +use msg::constellation_msg::{ConstellationChan, PanicMsg, PipelineId, WindowSizeData}; use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData}; use msg::constellation_msg::{PipelineNamespaceId, SubpageId}; use msg::webdriver_msg::WebDriverScriptCommand; @@ -93,10 +93,10 @@ pub struct NewLayoutInfo { /// The paint channel, cast to `OptionalOpaqueIpcSender`. This is really an /// `Sender<LayoutToPaintMsg>`. pub paint_chan: OptionalOpaqueIpcSender, - /// Information on what to do on thread failure. - pub failure: Failure, /// A port on which layout can receive messages from the pipeline. pub pipeline_port: IpcReceiver<LayoutControlMsg>, + /// A channel for sending panics on + pub panic_chan: ConstellationChan<PanicMsg>, /// A shutdown channel so that layout can notify others when it's done. pub layout_shutdown_chan: IpcSender<()>, /// A shutdown channel so that layout can tell the content process to shut down when it's done. @@ -315,10 +315,10 @@ pub struct InitialScriptState { pub constellation_chan: ConstellationChan<ScriptMsg>, /// A channel for the layout thread to send messages to the constellation. pub layout_to_constellation_chan: ConstellationChan<LayoutMsg>, + /// A channel for sending panics to the constellation. + pub panic_chan: ConstellationChan<PanicMsg>, /// A channel to schedule timer events. pub scheduler_chan: IpcSender<TimerEventRequest>, - /// Information that script sends out when it panics. - pub failure_info: Failure, /// A channel to the resource manager thread. pub resource_thread: ResourceThread, /// A channel to the storage thread. diff --git a/components/script_traits/script_msg.rs b/components/script_traits/script_msg.rs index 23920d150d1..14aa50b6a83 100644 --- a/components/script_traits/script_msg.rs +++ b/components/script_traits/script_msg.rs @@ -12,8 +12,8 @@ use canvas_traits::CanvasMsg; use euclid::point::Point2D; use euclid::size::Size2D; use ipc_channel::ipc::IpcSender; -use msg::constellation_msg::{Failure, NavigationDirection, PipelineId}; use msg::constellation_msg::{LoadData, SubpageId}; +use msg::constellation_msg::{NavigationDirection, PipelineId}; use offscreen_gl_context::{GLContextAttributes, GLLimits}; use style_traits::cursor::Cursor; use style_traits::viewport::ViewportConstraints; @@ -24,20 +24,12 @@ use url::Url; pub enum LayoutMsg { /// Indicates whether this pipeline is currently running animations. ChangeRunningAnimationsState(PipelineId, AnimationState), - /// Layout thread failure. - Failure(Failure), /// Requests that the constellation inform the compositor of the a cursor change. SetCursor(Cursor), /// Notifies the constellation that the viewport has been constrained in some manner ViewportConstrained(PipelineId, ViewportConstraints), } -impl From<Failure> for LayoutMsg { - fn from(failure: Failure) -> LayoutMsg { - LayoutMsg::Failure(failure) - } -} - /// Messages from the script to the constellation. #[derive(Deserialize, Serialize)] pub enum ScriptMsg { @@ -55,8 +47,6 @@ pub enum ScriptMsg { /// Causes a `load` event to be dispatched to any enclosing frame context element /// for the given pipeline. DOMLoad(PipelineId), - /// Script thread failure. - Failure(Failure), /// Notifies the constellation that this frame has received focus. Focus(PipelineId), /// Re-send a mouse button event that was sent to the parent window. @@ -92,9 +82,3 @@ pub enum ScriptMsg { /// Update the pipeline Url, which can change after redirections. SetFinalUrl(PipelineId, Url), } - -impl From<Failure> for ScriptMsg { - fn from(failure: Failure) -> ScriptMsg { - ScriptMsg::Failure(failure) - } -} diff --git a/components/util/panicking.rs b/components/util/panicking.rs index eecfd74b97f..95abf897e19 100644 --- a/components/util/panicking.rs +++ b/components/util/panicking.rs @@ -17,11 +17,16 @@ static HOOK_SET: Once = ONCE_INIT; /// TLS data pertaining to how failures should be reported pub struct PanicHandlerLocal { /// failure handler passed through spawn_named_with_send_on_failure - pub fail: Box<(FnBox(&(Any + Send))) + Send + 'static> + pub fail: Box<FnBox(&Any)> } thread_local!(pub static LOCAL_INFO: RefCell<Option<PanicHandlerLocal>> = RefCell::new(None)); +/// Set the thread-local panic hook +pub fn set_thread_local_hook(local: Box<FnBox(&Any)>) { + LOCAL_INFO.with(|i| *i.borrow_mut() = Some(PanicHandlerLocal { fail: local })); +} + /// Initiates the custom panic hook /// Should be called in main() after arguments have been parsed pub fn initiate_panic_hook() { diff --git a/components/util/thread.rs b/components/util/thread.rs index 85a7c52adf8..f6bb72e20a3 100644 --- a/components/util/thread.rs +++ b/components/util/thread.rs @@ -6,97 +6,33 @@ use ipc_channel::ipc::IpcSender; use panicking; use serde::Serialize; use std::any::Any; -use std::borrow::ToOwned; -use std::sync::mpsc::Sender; use std::thread; use thread_state; -pub type PanicReason = Option<String>; - pub fn spawn_named<F>(name: String, f: F) where F: FnOnce() + Send + 'static { - spawn_named_with_send_on_failure_maybe(name, None, f, |_| {}); -} - -pub trait AddFailureDetails { - fn add_panic_message(&mut self, message: String); - fn add_panic_object(&mut self, object: &Any) { - if let Some(message) = object.downcast_ref::<String>() { - self.add_panic_message(message.to_owned()); - } else if let Some(&message) = object.downcast_ref::<&'static str>() { - self.add_panic_message(message.to_owned()); - } - } -} - -/// An abstraction over `Sender<T>` and `IpcSender<T>`, for use in -/// `spawn_named_with_send_on_failure`. -pub trait SendOnFailure { - type Value; - fn send_on_failure(&mut self, value: Self::Value); -} - -impl<T> SendOnFailure for Sender<T> where T: Send + 'static { - type Value = T; - fn send_on_failure(&mut self, value: T) { - // Discard any errors to avoid double-panic - let _ = self.send(value); - } -} - -impl<T> SendOnFailure for IpcSender<T> where T: Send + Serialize + 'static { - type Value = T; - fn send_on_failure(&mut self, value: T) { - // Discard any errors to avoid double-panic - let _ = self.send(value); - } + thread::Builder::new().name(name).spawn(f).expect("Thread spawn failed"); } /// Arrange to send a particular message to a channel if the thread fails. -pub fn spawn_named_with_send_on_failure<F, T, S>(name: String, - state: thread_state::ThreadState, - f: F, - mut msg: T, - mut dest: S) +pub fn spawn_named_with_send_on_panic<F, Id>(name: String, + state: thread_state::ThreadState, + f: F, + id: Id, + panic_chan: IpcSender<(Id, String)>) where F: FnOnce() + Send + 'static, - T: Send + AddFailureDetails + 'static, - S: Send + SendOnFailure + 'static, - S::Value: From<T>, + Id: Copy + Send + Serialize + 'static, { - spawn_named_with_send_on_failure_maybe(name, Some(state), f, - move |err| { - msg.add_panic_object(err); - dest.send_on_failure(S::Value::from(msg)); - }); -} - -fn spawn_named_with_send_on_failure_maybe<F, G>(name: String, - state: Option<thread_state::ThreadState>, - f: F, - fail: G) - where F: FnOnce() + Send + 'static, - G: FnOnce(&(Any + Send)) + Send + 'static { - - - let builder = thread::Builder::new().name(name.clone()); - - let local = panicking::PanicHandlerLocal { - fail: Box::new(fail), - }; - - let f_with_state = move || { - if let Some(state) = state { - thread_state::initialize(state); - } - - // set the handler - panicking::LOCAL_INFO.with(|i| { - *i.borrow_mut() = Some(local); - }); - f(); - }; - - - builder.spawn(f_with_state).unwrap(); + thread::Builder::new().name(name).spawn(move || { + thread_state::initialize(state); + panicking::set_thread_local_hook(Box::new(move |payload: &Any| { + debug!("Thread failed, notifying constellation"); + let reason = payload.downcast_ref::<String>().map(|s| String::from(&**s)) + .or(payload.downcast_ref::<&'static str>().map(|s| String::from(*s))) + .unwrap_or_else(|| String::from("<unknown reason>")); + let _ = panic_chan.send((id, reason)); + })); + f() + }).expect("Thread spawn failed"); } |