diff options
author | Gregory Terzian <gterzian@users.noreply.github.com> | 2018-09-11 15:49:47 +0800 |
---|---|---|
committer | Gregory Terzian <gterzian@users.noreply.github.com> | 2018-11-26 14:15:33 +0800 |
commit | 4eb785cdc0446539bf5e7eb66bf7ad46ba5705dd (patch) | |
tree | 3703ffe374141ff2816b1b3adf6c54ec1bdcf722 /components/constellation | |
parent | 7c65505df3fff47f43062da20088113631ed9ae0 (diff) | |
download | servo-4eb785cdc0446539bf5e7eb66bf7ad46ba5705dd.tar.gz servo-4eb785cdc0446539bf5e7eb66bf7ad46ba5705dd.zip |
introduce a background-hang-monitor:
Mac-Os implementation of a thread sampler,
Linux and Windows skeleton implementations.
Diffstat (limited to 'components/constellation')
-rw-r--r-- | components/constellation/Cargo.toml | 1 | ||||
-rw-r--r-- | components/constellation/constellation.rs | 49 | ||||
-rw-r--r-- | components/constellation/pipeline.rs | 31 |
3 files changed, 78 insertions, 3 deletions
diff --git a/components/constellation/Cargo.toml b/components/constellation/Cargo.toml index 5ef39c5bbae..f9e9b351180 100644 --- a/components/constellation/Cargo.toml +++ b/components/constellation/Cargo.toml @@ -11,6 +11,7 @@ name = "constellation" path = "lib.rs" [dependencies] +background_hang_monitor = { path = "../background_hang_monitor"} backtrace = "0.3" bluetooth_traits = { path = "../bluetooth_traits" } canvas = {path = "../canvas"} diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 2641c946967..62ebebf9ebe 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -89,6 +89,7 @@ //! //! See https://github.com/servo/servo/issues/14704 +use background_hang_monitor::HangMonitorRegister; use backtrace::Backtrace; use bluetooth_traits::BluetoothRequest; use canvas::canvas_paint_thread::CanvasPaintThread; @@ -123,6 +124,7 @@ use keyboard_types::webdriver::Event as WebDriverInputEvent; use keyboard_types::KeyboardEvent; use layout_traits::LayoutThreadFactory; use log::{Level, LevelFilter, Log, Metadata, Record}; +use msg::constellation_msg::{BackgroundHangMonitorRegister, HangAlert}; use msg::constellation_msg::{ BrowsingContextId, HistoryStateId, PipelineId, TopLevelBrowsingContextId, }; @@ -200,6 +202,18 @@ pub struct Constellation<Message, LTF, STF> { /// This is the constellation's view of `script_sender`. script_receiver: Receiver<Result<(PipelineId, FromScriptMsg), IpcError>>, + /// A handle to register components for hang monitoring. + /// None when in multiprocess mode. + background_monitor_register: Option<Box<BackgroundHangMonitorRegister>>, + + /// A channel for the background hang monitor to send messages + /// to the constellation. + background_hang_monitor_sender: IpcSender<HangAlert>, + + /// A channel for the constellation to receiver messages + /// from the background hang monitor. + background_hang_monitor_receiver: Receiver<Result<HangAlert, IpcError>>, + /// An IPC channel for layout threads to send messages to the constellation. /// This is the layout threads' view of `layout_receiver`. layout_sender: IpcSender<FromLayoutMsg>, @@ -587,6 +601,21 @@ where let script_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(ipc_script_receiver); + let (background_hang_monitor_sender, ipc_bhm_receiver) = + ipc::channel().expect("ipc channel failure"); + let background_hang_monitor_receiver = + route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(ipc_bhm_receiver); + + // If we are in multiprocess mode, + // a dedicated per-process hang monitor will be initialized later inside the content process. + // See run_content_process in servo/lib.rs + let background_monitor_register = match opts::multiprocess() { + true => None, + false => Some(HangMonitorRegister::init( + background_hang_monitor_sender.clone(), + )), + }; + let (ipc_layout_sender, ipc_layout_receiver) = ipc::channel().expect("ipc channel failure"); let layout_receiver = @@ -602,6 +631,9 @@ where let mut constellation: Constellation<Message, LTF, STF> = Constellation { script_sender: ipc_script_sender, + background_hang_monitor_sender, + background_hang_monitor_receiver, + background_monitor_register, layout_sender: ipc_layout_sender, script_receiver: script_receiver, compositor_receiver: compositor_receiver, @@ -768,6 +800,10 @@ where sender: self.script_sender.clone(), pipeline_id: pipeline_id, }, + background_monitor_register: self.background_monitor_register.clone(), + background_hang_monitor_to_constellation_chan: self + .background_hang_monitor_sender + .clone(), layout_to_constellation_chan: self.layout_sender.clone(), scheduler_chan: self.scheduler_chan.clone(), compositor_proxy: self.compositor_proxy.clone(), @@ -889,6 +925,7 @@ where #[derive(Debug)] enum Request { Script((PipelineId, FromScriptMsg)), + BackgroundHangMonitor(HangAlert), Compositor(FromCompositorMsg), Layout(FromLayoutMsg), NetworkListener((PipelineId, FetchResponseMsg)), @@ -910,6 +947,9 @@ where recv(self.script_receiver) -> msg => { msg.expect("Unexpected script channel panic in constellation").map(Request::Script) } + recv(self.background_hang_monitor_receiver) -> msg => { + msg.expect("Unexpected BHM channel panic in constellation").map(Request::BackgroundHangMonitor) + } recv(self.compositor_receiver) -> msg => { Ok(Request::Compositor(msg.expect("Unexpected compositor channel panic in constellation"))) } @@ -936,6 +976,9 @@ where Request::Script(message) => { self.handle_request_from_script(message); }, + Request::BackgroundHangMonitor(message) => { + self.handle_request_from_background_hang_monitor(message); + }, Request::Layout(message) => { self.handle_request_from_layout(message); }, @@ -948,6 +991,12 @@ where } } + fn handle_request_from_background_hang_monitor(&self, message: HangAlert) { + // TODO: In case of a permanent hang being reported, add a "kill script" workflow, + // via the embedder? + warn!("Component hang alert: {:?}", message); + } + fn handle_request_from_network_listener(&mut self, message: (PipelineId, FetchResponseMsg)) { let (id, message_) = message; let result = match self.pipelines.get(&id) { diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index b0df616cbdf..63376315101 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -18,6 +18,7 @@ use ipc_channel::Error; use layout_traits::LayoutThreadFactory; use metrics::PaintTimeMetrics; use msg::constellation_msg::TopLevelBrowsingContextId; +use msg::constellation_msg::{BackgroundHangMonitorRegister, HangAlert}; use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespaceId}; use net::image_cache::ImageCacheImpl; use net_traits::image_cache::ImageCache; @@ -113,6 +114,13 @@ pub struct InitialPipelineState { /// A channel to the associated constellation. pub script_to_constellation_chan: ScriptToConstellationChan, + /// A handle to register components for hang monitoring. + /// None when in multiprocess mode. + pub background_monitor_register: Option<Box<BackgroundHangMonitorRegister>>, + + /// A channel for the background hang monitor to send messages to the constellation. + pub background_hang_monitor_to_constellation_chan: IpcSender<HangAlert>, + /// A channel for the layout thread to send messages to the constellation. pub layout_to_constellation_chan: IpcSender<LayoutMsg>, @@ -262,6 +270,9 @@ impl Pipeline { parent_pipeline_id: state.parent_pipeline_id, opener: state.opener, script_to_constellation_chan: state.script_to_constellation_chan.clone(), + background_hang_monitor_to_constellation_chan: state + .background_hang_monitor_to_constellation_chan + .clone(), scheduler_chan: state.scheduler_chan, devtools_chan: script_to_devtools_chan, bluetooth_thread: state.bluetooth_thread, @@ -295,7 +306,11 @@ impl Pipeline { if opts::multiprocess() { let _ = unprivileged_pipeline_content.spawn_multiprocess()?; } else { - unprivileged_pipeline_content.start_all::<Message, LTF, STF>(false); + // Should not be None in single-process mode. + let register = state + .background_monitor_register + .expect("Couldn't start content, no background monitor has been initiated"); + unprivileged_pipeline_content.start_all::<Message, LTF, STF>(false, register); } EventLoop::new(script_chan) @@ -452,6 +467,7 @@ pub struct UnprivilegedPipelineContent { parent_pipeline_id: Option<PipelineId>, opener: Option<BrowsingContextId>, script_to_constellation_chan: ScriptToConstellationChan, + background_hang_monitor_to_constellation_chan: IpcSender<HangAlert>, layout_to_constellation_chan: IpcSender<LayoutMsg>, scheduler_chan: IpcSender<TimerSchedulerMsg>, devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>, @@ -480,8 +496,11 @@ pub struct UnprivilegedPipelineContent { } impl UnprivilegedPipelineContent { - pub fn start_all<Message, LTF, STF>(self, wait_for_completion: bool) - where + pub fn start_all<Message, LTF, STF>( + self, + wait_for_completion: bool, + background_hang_monitor_register: Box<BackgroundHangMonitorRegister>, + ) where LTF: LayoutThreadFactory<Message = Message>, STF: ScriptThreadFactory<Message = Message>, { @@ -503,6 +522,7 @@ impl UnprivilegedPipelineContent { control_chan: self.script_chan.clone(), control_port: self.script_port, script_to_constellation_chan: self.script_to_constellation_chan.clone(), + background_hang_monitor_register: background_hang_monitor_register.clone(), layout_to_constellation_chan: self.layout_to_constellation_chan.clone(), scheduler_chan: self.scheduler_chan, bluetooth_thread: self.bluetooth_thread, @@ -529,6 +549,7 @@ impl UnprivilegedPipelineContent { self.parent_pipeline_id.is_some(), layout_pair, self.pipeline_port, + background_hang_monitor_register, self.layout_to_constellation_chan, self.script_chan, image_cache.clone(), @@ -626,6 +647,10 @@ impl UnprivilegedPipelineContent { } } + pub fn background_hang_monitor_to_constellation_chan(&self) -> &IpcSender<HangAlert> { + &self.background_hang_monitor_to_constellation_chan + } + pub fn script_to_constellation_chan(&self) -> &ScriptToConstellationChan { &self.script_to_constellation_chan } |