diff options
-rw-r--r-- | components/config/opts.rs | 6 | ||||
-rw-r--r-- | components/constellation/constellation.rs | 56 | ||||
-rw-r--r-- | components/constellation/pipeline.rs | 51 | ||||
-rw-r--r-- | components/layout_thread/lib.rs | 24 | ||||
-rw-r--r-- | components/layout_thread_2020/lib.rs | 24 | ||||
-rw-r--r-- | components/layout_traits/lib.rs | 2 | ||||
-rw-r--r-- | components/script/script_thread.rs | 33 | ||||
-rw-r--r-- | components/script_layout_interface/message.rs | 2 | ||||
-rw-r--r-- | components/script_traits/lib.rs | 2 |
9 files changed, 126 insertions, 74 deletions
diff --git a/components/config/opts.rs b/components/config/opts.rs index a56e8e27172..9bdd7bc9061 100644 --- a/components/config/opts.rs +++ b/components/config/opts.rs @@ -136,6 +136,9 @@ pub struct Opts { /// Whether we're running in multiprocess mode. pub multiprocess: bool, + /// Whether we want background hang monitor enabled or not + pub background_hang_monitor: bool, + /// Whether we're running inside the sandbox. pub sandbox: bool, @@ -545,6 +548,7 @@ pub fn default_opts() -> Opts { initial_window_size: Size2D::new(1024, 740), user_agent: default_user_agent_string(DEFAULT_USER_AGENT).into(), multiprocess: false, + background_hang_monitor: false, random_pipeline_closure_probability: None, random_pipeline_closure_seed: None, sandbox: false, @@ -669,6 +673,7 @@ pub fn from_cmdline_args(mut opts: Options, args: &[String]) -> ArgumentParsingR "NCSA Mosaic/1.0 (X11;SunOS 4.1.4 sun4m)", ); opts.optflag("M", "multiprocess", "Run in multiprocess mode"); + opts.optflag("B", "bhm", "Background Hang Monitor enabled"); opts.optflag("S", "sandbox", "Run in a sandbox if multiprocess"); opts.optopt( "", @@ -965,6 +970,7 @@ pub fn from_cmdline_args(mut opts: Options, args: &[String]) -> ArgumentParsingR initial_window_size: initial_window_size, user_agent: user_agent, multiprocess: opt_match.opt_present("M"), + background_hang_monitor: opt_match.opt_present("B"), sandbox: opt_match.opt_present("S"), random_pipeline_closure_probability: random_pipeline_closure_probability, random_pipeline_closure_seed: random_pipeline_closure_seed, diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 4036d3b392e..0df1a28c15c 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -282,11 +282,11 @@ pub struct Constellation<Message, LTF, STF> { /// A channel for the background hang monitor to send messages /// to the constellation. - background_hang_monitor_sender: IpcSender<HangMonitorAlert>, + background_hang_monitor_sender: Option<IpcSender<HangMonitorAlert>>, /// A channel for the constellation to receiver messages /// from the background hang monitor. - background_hang_monitor_receiver: Receiver<Result<HangMonitorAlert, IpcError>>, + background_hang_monitor_receiver: Option<Receiver<Result<HangMonitorAlert, IpcError>>>, /// An IPC channel for layout threads to send messages to the constellation. /// This is the layout threads' view of `layout_receiver`. @@ -849,28 +849,42 @@ where ipc_scheduler_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); + let (background_hang_monitor_sender, background_hang_monitor_receiver) = + if opts::get().background_hang_monitor { + let (bhm_sender, ipc_bhm_receiver) = + ipc::channel().expect("ipc channel failure"); + ( + Some(bhm_sender), + Some(route_ipc_receiver_to_new_mpsc_receiver_preserving_errors( + ipc_bhm_receiver, + )), + ) + } else { + (None, None) + }; // 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, sampler_chan) = if opts::multiprocess() { - (None, vec![]) - } else { - let (sampling_profiler_control, sampling_profiler_port) = - ipc::channel().expect("ipc channel failure"); - - ( - Some(HangMonitorRegister::init( - background_hang_monitor_sender.clone(), - sampling_profiler_port, - )), - vec![sampling_profiler_control], - ) - }; + let (background_monitor_register, sampler_chan) = + if opts::multiprocess() || !opts::get().background_hang_monitor { + (None, vec![]) + } else { + let (sampling_profiler_control, sampling_profiler_port) = + ipc::channel().expect("ipc channel failure"); + if let Some(bhm_sender) = background_hang_monitor_sender.clone() { + ( + Some(HangMonitorRegister::init( + bhm_sender, + sampling_profiler_port, + )), + vec![sampling_profiler_control], + ) + } else { + warn!("No BHM sender found in BHM mode."); + (None, vec![]) + } + }; let (ipc_layout_sender, ipc_layout_receiver) = ipc::channel().expect("ipc channel failure"); @@ -1413,7 +1427,7 @@ where recv(self.script_receiver) -> msg => { msg.expect("Unexpected script channel panic in constellation").map(Request::Script) } - recv(self.background_hang_monitor_receiver) -> msg => { + recv(self.background_hang_monitor_receiver.as_ref().unwrap_or(&never())) -> msg => { msg.expect("Unexpected BHM channel panic in constellation").map(Request::BackgroundHangMonitor) } recv(self.compositor_receiver) -> msg => { diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index c56d49962ee..665ea177e79 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -131,7 +131,7 @@ pub struct InitialPipelineState { pub background_monitor_register: Option<Box<dyn BackgroundHangMonitorRegister>>, /// A channel for the background hang monitor to send messages to the constellation. - pub background_hang_monitor_to_constellation_chan: IpcSender<HangMonitorAlert>, + pub background_hang_monitor_to_constellation_chan: Option<IpcSender<HangMonitorAlert>>, /// A channel for the layout thread to send messages to the constellation. pub layout_to_constellation_chan: IpcSender<LayoutMsg>, @@ -319,15 +319,24 @@ impl Pipeline { Some(sampler_chan) } else { // 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, - state.event_loop_waker, - ); - None + if opts::get().background_hang_monitor { + 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, + Some(register), + state.event_loop_waker, + ); + None + } else { + unprivileged_pipeline_content.start_all::<Message, LTF, STF>( + false, + None, + state.event_loop_waker, + ); + None + } }; (EventLoop::new(script_chan), sampler_chan) @@ -488,7 +497,7 @@ pub struct UnprivilegedPipelineContent { opener: Option<BrowsingContextId>, namespace_request_sender: IpcSender<PipelineNamespaceRequest>, script_to_constellation_chan: ScriptToConstellationChan, - background_hang_monitor_to_constellation_chan: IpcSender<HangMonitorAlert>, + background_hang_monitor_to_constellation_chan: Option<IpcSender<HangMonitorAlert>>, sampling_profiler_port: Option<IpcReceiver<SamplerControlMsg>>, layout_to_constellation_chan: IpcSender<LayoutMsg>, scheduler_chan: IpcSender<TimerSchedulerMsg>, @@ -520,7 +529,7 @@ impl UnprivilegedPipelineContent { pub fn start_all<Message, LTF, STF>( self, wait_for_completion: bool, - background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>, + background_hang_monitor_register: Option<Box<dyn BackgroundHangMonitorRegister>>, event_loop_waker: Option<Box<dyn EventLoopWaker>>, ) where LTF: LayoutThreadFactory<Message = Message>, @@ -730,13 +739,17 @@ impl UnprivilegedPipelineContent { pub fn register_with_background_hang_monitor( &mut self, - ) -> Box<dyn BackgroundHangMonitorRegister> { - HangMonitorRegister::init( - self.background_hang_monitor_to_constellation_chan.clone(), - self.sampling_profiler_port - .take() - .expect("no sampling profiler?"), - ) + ) -> Option<Box<dyn BackgroundHangMonitorRegister>> { + self.background_hang_monitor_to_constellation_chan + .clone() + .map(|bhm| { + HangMonitorRegister::init( + bhm.clone(), + self.sampling_profiler_port + .take() + .expect("no sampling profiler?"), + ) + }) } pub fn script_to_constellation_chan(&self) -> &ScriptToConstellationChan { diff --git a/components/layout_thread/lib.rs b/components/layout_thread/lib.rs index b5b45993c2b..127eab08914 100644 --- a/components/layout_thread/lib.rs +++ b/components/layout_thread/lib.rs @@ -159,7 +159,7 @@ pub struct LayoutThread { font_cache_sender: IpcSender<()>, /// A means of communication with the background hang monitor. - background_hang_monitor: Box<dyn BackgroundHangMonitor>, + background_hang_monitor: Option<Box<dyn BackgroundHangMonitor>>, /// The channel on which messages can be sent to the constellation. constellation_chan: IpcSender<ConstellationMsg>, @@ -292,7 +292,7 @@ impl LayoutThreadFactory for LayoutThread { is_iframe: bool, chan: (Sender<Msg>, Receiver<Msg>), pipeline_port: IpcReceiver<LayoutControlMsg>, - background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>, + background_hang_monitor_register: Option<Box<dyn BackgroundHangMonitorRegister>>, constellation_chan: IpcSender<ConstellationMsg>, script_chan: IpcSender<ConstellationControlMsg>, image_cache: Arc<dyn ImageCache>, @@ -326,12 +326,13 @@ impl LayoutThreadFactory for LayoutThread { // Ensures layout thread is destroyed before we send shutdown message let sender = chan.0; - let background_hang_monitor = background_hang_monitor_register - .register_component( + let background_hang_monitor = background_hang_monitor_register.map(|bhm| { + bhm.register_component( MonitoredComponentId(id, MonitoredComponentType::Layout), Duration::from_millis(1000), Duration::from_millis(5000), - ); + ) + }); let layout = LayoutThread::new( id, @@ -510,7 +511,7 @@ impl LayoutThread { is_iframe: bool, port: Receiver<Msg>, pipeline_port: IpcReceiver<LayoutControlMsg>, - background_hang_monitor: Box<dyn BackgroundHangMonitor>, + background_hang_monitor: Option<Box<dyn BackgroundHangMonitor>>, constellation_chan: IpcSender<ConstellationMsg>, script_chan: IpcSender<ConstellationControlMsg>, image_cache: Arc<dyn ImageCache>, @@ -708,7 +709,8 @@ impl LayoutThread { Msg::GetRunningAnimations(..) => LayoutHangAnnotation::GetRunningAnimations, }; self.background_hang_monitor - .notify_activity(HangAnnotation::Layout(hang_annotation)); + .as_ref() + .map(|bhm| bhm.notify_activity(HangAnnotation::Layout(hang_annotation))); } /// Receives and dispatches messages from the script and constellation threads @@ -720,7 +722,9 @@ impl LayoutThread { } // Notify the background-hang-monitor we are waiting for an event. - self.background_hang_monitor.notify_wait(); + self.background_hang_monitor + .as_ref() + .map(|bhm| bhm.notify_wait()); let request = select! { recv(self.pipeline_port) -> msg => Request::FromPipeline(msg.unwrap()), @@ -995,7 +999,9 @@ impl LayoutThread { ); self.root_flow.borrow_mut().take(); - self.background_hang_monitor.unregister(); + self.background_hang_monitor + .as_ref() + .map(|bhm| bhm.unregister()); } fn handle_add_stylesheet(&self, stylesheet: &Stylesheet, guard: &SharedRwLockReadGuard) { diff --git a/components/layout_thread_2020/lib.rs b/components/layout_thread_2020/lib.rs index be24d768595..2972f7ef46f 100644 --- a/components/layout_thread_2020/lib.rs +++ b/components/layout_thread_2020/lib.rs @@ -137,7 +137,7 @@ pub struct LayoutThread { font_cache_sender: IpcSender<()>, /// A means of communication with the background hang monitor. - background_hang_monitor: Box<dyn BackgroundHangMonitor>, + background_hang_monitor: Option<Box<dyn BackgroundHangMonitor>>, /// The channel on which messages can be sent to the script thread. script_chan: IpcSender<ConstellationControlMsg>, @@ -247,7 +247,7 @@ impl LayoutThreadFactory for LayoutThread { is_iframe: bool, chan: (Sender<Msg>, Receiver<Msg>), pipeline_port: IpcReceiver<LayoutControlMsg>, - background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>, + background_hang_monitor_register: Option<Box<dyn BackgroundHangMonitorRegister>>, constellation_chan: IpcSender<ConstellationMsg>, script_chan: IpcSender<ConstellationControlMsg>, image_cache: Arc<dyn ImageCache>, @@ -281,12 +281,13 @@ impl LayoutThreadFactory for LayoutThread { // Ensures layout thread is destroyed before we send shutdown message let sender = chan.0; - let background_hang_monitor = background_hang_monitor_register - .register_component( + let background_hang_monitor = background_hang_monitor_register.map(|bhm| { + bhm.register_component( MonitoredComponentId(id, MonitoredComponentType::Layout), Duration::from_millis(1000), Duration::from_millis(5000), - ); + ) + }); let layout = LayoutThread::new( id, @@ -463,7 +464,7 @@ impl LayoutThread { is_iframe: bool, port: Receiver<Msg>, pipeline_port: IpcReceiver<LayoutControlMsg>, - background_hang_monitor: Box<dyn BackgroundHangMonitor>, + background_hang_monitor: Option<Box<dyn BackgroundHangMonitor>>, constellation_chan: IpcSender<ConstellationMsg>, script_chan: IpcSender<ConstellationControlMsg>, image_cache: Arc<dyn ImageCache>, @@ -648,7 +649,8 @@ impl LayoutThread { Msg::GetRunningAnimations(..) => LayoutHangAnnotation::GetRunningAnimations, }; self.background_hang_monitor - .notify_activity(HangAnnotation::Layout(hang_annotation)); + .as_ref() + .map(|bhm| bhm.notify_activity(HangAnnotation::Layout(hang_annotation))); } /// Receives and dispatches messages from the script and constellation threads @@ -660,7 +662,9 @@ impl LayoutThread { } // Notify the background-hang-monitor we are waiting for an event. - self.background_hang_monitor.notify_wait(); + self.background_hang_monitor + .as_ref() + .map(|bhm| bhm.notify_wait()); let request = select! { recv(self.pipeline_port) -> msg => Request::FromPipeline(msg.unwrap()), @@ -895,7 +899,9 @@ impl LayoutThread { } fn exit_now(&mut self) { - self.background_hang_monitor.unregister(); + self.background_hang_monitor + .as_ref() + .map(|bhm| bhm.unregister()); } fn handle_add_stylesheet(&self, stylesheet: &Stylesheet, guard: &SharedRwLockReadGuard) { diff --git a/components/layout_traits/lib.rs b/components/layout_traits/lib.rs index 942d37a8c87..2ee0021df96 100644 --- a/components/layout_traits/lib.rs +++ b/components/layout_traits/lib.rs @@ -36,7 +36,7 @@ pub trait LayoutThreadFactory { is_iframe: bool, chan: (Sender<Self::Message>, Receiver<Self::Message>), pipeline_port: IpcReceiver<LayoutControlMsg>, - background_hang_monitor: Box<dyn BackgroundHangMonitorRegister>, + background_hang_monitor: Option<Box<dyn BackgroundHangMonitorRegister>>, constellation_chan: IpcSender<ConstellationMsg>, script_chan: IpcSender<ConstellationControlMsg>, image_cache: Arc<dyn ImageCache>, diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index bcc7b10f8c7..118b4b4f653 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -545,9 +545,9 @@ pub struct ScriptThread { task_queue: TaskQueue<MainThreadScriptMsg>, /// A handle to register associated layout threads for hang-monitoring. - background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>, + background_hang_monitor_register: Option<Box<dyn BackgroundHangMonitorRegister>>, /// The dedicated means of communication with the background-hang-monitor for this script-thread. - background_hang_monitor: Box<dyn BackgroundHangMonitor>, + background_hang_monitor: Option<Box<dyn BackgroundHangMonitor>>, /// A channel to hand out to script thread-based entities that need to be able to enqueue /// events in the event queue. @@ -1262,18 +1262,20 @@ impl ScriptThread { let devtools_port = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(ipc_devtools_receiver); - // Ask the router to proxy IPC messages from the control port to us. - let control_port = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(state.control_port); - let (image_cache_channel, image_cache_port) = unbounded(); let task_queue = TaskQueue::new(port, chan.clone()); - let background_hang_monitor = state.background_hang_monitor_register.register_component( - MonitoredComponentId(state.id, MonitoredComponentType::Script), - Duration::from_millis(1000), - Duration::from_millis(5000), - ); + let background_hang_monitor = state.background_hang_monitor_register.clone().map(|bhm| { + bhm.register_component( + MonitoredComponentId(state.id.clone(), MonitoredComponentType::Script), + Duration::from_millis(1000), + Duration::from_millis(5000), + ) + }); + + // Ask the router to proxy IPC messages from the control port to us. + let control_port = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(state.control_port); ScriptThread { documents: DomRefCell::new(Documents::new()), @@ -1408,7 +1410,9 @@ impl ScriptThread { let mut sequential = vec![]; // Notify the background-hang-monitor we are waiting for an event. - self.background_hang_monitor.notify_wait(); + self.background_hang_monitor + .as_ref() + .map(|bhm| bhm.notify_wait()); // Receive at least one message so we don't spinloop. debug!("Waiting for event."); @@ -1662,7 +1666,8 @@ impl ScriptThread { ScriptThreadEventCategory::PortMessage => ScriptHangAnnotation::PortMessage, }; self.background_hang_monitor - .notify_activity(HangAnnotation::Script(hang_annotation)); + .as_ref() + .map(|bhm| bhm.notify_activity(HangAnnotation::Script(hang_annotation))); } fn message_to_pipeline(&self, msg: &MixedMessage) -> Option<PipelineId> { @@ -2882,7 +2887,9 @@ impl ScriptThread { self.handle_exit_pipeline_msg(pipeline_id, DiscardBrowsingContext::Yes); } - self.background_hang_monitor.unregister(); + self.background_hang_monitor + .as_ref() + .map(|bhm| bhm.unregister()); debug!("Exited script thread."); } diff --git a/components/script_layout_interface/message.rs b/components/script_layout_interface/message.rs index 9e52083c9d4..e48ac42f509 100644 --- a/components/script_layout_interface/message.rs +++ b/components/script_layout_interface/message.rs @@ -226,7 +226,7 @@ pub struct LayoutThreadInit { pub is_parent: bool, pub layout_pair: (Sender<Msg>, Receiver<Msg>), pub pipeline_port: IpcReceiver<LayoutControlMsg>, - pub background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>, + pub background_hang_monitor_register: Option<Box<dyn BackgroundHangMonitorRegister>>, pub constellation_chan: IpcSender<ConstellationMsg>, pub script_chan: IpcSender<ConstellationControlMsg>, pub image_cache: Arc<dyn ImageCache>, diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 7f6ecece10b..d928335f8e3 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -644,7 +644,7 @@ pub struct InitialScriptState { /// A channel on which messages can be sent to the constellation from script. pub script_to_constellation_chan: ScriptToConstellationChan, /// A handle to register script-(and associated layout-)threads for hang monitoring. - pub background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>, + pub background_hang_monitor_register: Option<Box<dyn BackgroundHangMonitorRegister>>, /// A sender for the layout thread to communicate to the constellation. pub layout_to_constellation_chan: IpcSender<LayoutMsg>, /// A channel to schedule timer events. |