aboutsummaryrefslogtreecommitdiffstats
path: root/components/constellation
diff options
context:
space:
mode:
authorGregory Terzian <gterzian@users.noreply.github.com>2018-09-11 15:49:47 +0800
committerGregory Terzian <gterzian@users.noreply.github.com>2018-11-26 14:15:33 +0800
commit4eb785cdc0446539bf5e7eb66bf7ad46ba5705dd (patch)
tree3703ffe374141ff2816b1b3adf6c54ec1bdcf722 /components/constellation
parent7c65505df3fff47f43062da20088113631ed9ae0 (diff)
downloadservo-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.toml1
-rw-r--r--components/constellation/constellation.rs49
-rw-r--r--components/constellation/pipeline.rs31
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
}