mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +01:00
Auto merge of #27016 - gterzian:fix_closing_window, r=jdm,paulrouget
Ensure clean shutdown of JS threads <!-- Please describe your changes on the following line: --> FIX https://github.com/servo/servo/issues/26685 FIX https://github.com/servo/servo/issues/26996 FIX https://github.com/servo/servo/issues/9672 FIX #27027 --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [ ] `./mach build -d` does not report any errors - [ ] `./mach test-tidy` does not report any errors - [ ] These changes fix #___ (GitHub issue number if applicable) <!-- Either: --> - [ ] There are tests for these changes OR - [ ] These changes do not require tests because ___ <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
commit
b9404fcd48
25 changed files with 565 additions and 232 deletions
|
@ -126,7 +126,9 @@ use keyboard_types::KeyboardEvent;
|
|||
use layout_traits::LayoutThreadFactory;
|
||||
use log::{Level, LevelFilter, Log, Metadata, Record};
|
||||
use media::{GLPlayerThreads, WindowGLContext};
|
||||
use msg::constellation_msg::{BackgroundHangMonitorRegister, HangMonitorAlert, SamplerControlMsg};
|
||||
use msg::constellation_msg::{
|
||||
BackgroundHangMonitorControlMsg, BackgroundHangMonitorRegister, HangMonitorAlert,
|
||||
};
|
||||
use msg::constellation_msg::{
|
||||
BroadcastChannelRouterId, MessagePortId, MessagePortRouterId, PipelineNamespace,
|
||||
PipelineNamespaceId, PipelineNamespaceRequest, TraversalDirection,
|
||||
|
@ -294,16 +296,18 @@ pub struct Constellation<Message, LTF, STF, SWF> {
|
|||
/// None when in multiprocess mode.
|
||||
background_monitor_register: Option<Box<dyn BackgroundHangMonitorRegister>>,
|
||||
|
||||
/// Channels to control all sampling profilers.
|
||||
sampling_profiler_control: Vec<IpcSender<SamplerControlMsg>>,
|
||||
/// Channels to control all background-hang monitors.
|
||||
/// TODO: store them on the relevant BrowsingContextGroup,
|
||||
/// so that they could be controlled on a "per-tab/event-loop" basis.
|
||||
background_monitor_control_senders: Vec<IpcSender<BackgroundHangMonitorControlMsg>>,
|
||||
|
||||
/// A channel for the background hang monitor to send messages
|
||||
/// to the constellation.
|
||||
background_hang_monitor_sender: Option<IpcSender<HangMonitorAlert>>,
|
||||
background_hang_monitor_sender: IpcSender<HangMonitorAlert>,
|
||||
|
||||
/// A channel for the constellation to receiver messages
|
||||
/// from the background hang monitor.
|
||||
background_hang_monitor_receiver: Option<Receiver<Result<HangMonitorAlert, IpcError>>>,
|
||||
background_hang_monitor_receiver: 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`.
|
||||
|
@ -783,42 +787,28 @@ where
|
|||
ipc_scheduler_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)
|
||||
};
|
||||
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, 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 (background_monitor_register, bhm_control_chans) = if opts::multiprocess() {
|
||||
(None, vec![])
|
||||
} else {
|
||||
let (bhm_control_chan, bhm_control_port) =
|
||||
ipc::channel().expect("ipc channel failure");
|
||||
(
|
||||
Some(HangMonitorRegister::init(
|
||||
background_hang_monitor_sender.clone(),
|
||||
bhm_control_port,
|
||||
opts::get().background_hang_monitor,
|
||||
)),
|
||||
vec![bhm_control_chan],
|
||||
)
|
||||
};
|
||||
|
||||
let (ipc_layout_sender, ipc_layout_receiver) =
|
||||
ipc::channel().expect("ipc channel failure");
|
||||
|
@ -871,7 +861,7 @@ where
|
|||
background_hang_monitor_sender,
|
||||
background_hang_monitor_receiver,
|
||||
background_monitor_register,
|
||||
sampling_profiler_control: sampler_chan,
|
||||
background_monitor_control_senders: bhm_control_chans,
|
||||
layout_sender: ipc_layout_sender,
|
||||
script_receiver: script_receiver,
|
||||
compositor_receiver: compositor_receiver,
|
||||
|
@ -1197,8 +1187,8 @@ where
|
|||
Err(e) => return self.handle_send_error(pipeline_id, e),
|
||||
};
|
||||
|
||||
if let Some(sampler_chan) = pipeline.sampler_control_chan {
|
||||
self.sampling_profiler_control.push(sampler_chan);
|
||||
if let Some(chan) = pipeline.bhm_control_chan {
|
||||
self.background_monitor_control_senders.push(chan);
|
||||
}
|
||||
|
||||
if let Some(host) = host {
|
||||
|
@ -1359,7 +1349,7 @@ where
|
|||
recv(self.script_receiver) -> msg => {
|
||||
msg.expect("Unexpected script channel panic in constellation").map(Request::Script)
|
||||
}
|
||||
recv(self.background_hang_monitor_receiver.as_ref().unwrap_or(&never())) -> msg => {
|
||||
recv(self.background_hang_monitor_receiver) -> msg => {
|
||||
msg.expect("Unexpected BHM channel panic in constellation").map(Request::BackgroundHangMonitor)
|
||||
}
|
||||
recv(self.compositor_receiver) -> msg => {
|
||||
|
@ -1625,15 +1615,18 @@ where
|
|||
},
|
||||
FromCompositorMsg::SetCursor(cursor) => self.handle_set_cursor_msg(cursor),
|
||||
FromCompositorMsg::EnableProfiler(rate, max_duration) => {
|
||||
for chan in &self.sampling_profiler_control {
|
||||
if let Err(e) = chan.send(SamplerControlMsg::Enable(rate, max_duration)) {
|
||||
for chan in &self.background_monitor_control_senders {
|
||||
if let Err(e) = chan.send(BackgroundHangMonitorControlMsg::EnableSampler(
|
||||
rate,
|
||||
max_duration,
|
||||
)) {
|
||||
warn!("error communicating with sampling profiler: {}", e);
|
||||
}
|
||||
}
|
||||
},
|
||||
FromCompositorMsg::DisableProfiler => {
|
||||
for chan in &self.sampling_profiler_control {
|
||||
if let Err(e) = chan.send(SamplerControlMsg::Disable) {
|
||||
for chan in &self.background_monitor_control_senders {
|
||||
if let Err(e) = chan.send(BackgroundHangMonitorControlMsg::DisableSampler) {
|
||||
warn!("error communicating with sampling profiler: {}", e);
|
||||
}
|
||||
}
|
||||
|
@ -2654,6 +2647,22 @@ where
|
|||
|
||||
self.mem_profiler_chan.send(mem::ProfilerMsg::Exit);
|
||||
|
||||
// Tell all BHMs to exit,
|
||||
// and to ensure their monitored components exit
|
||||
// even when currently hanging(on JS or sync XHR).
|
||||
// This must be done before starting the process of closing all pipelines.
|
||||
for chan in &self.background_monitor_control_senders {
|
||||
let (exit_sender, exit_receiver) =
|
||||
ipc::channel().expect("Failed to create IPC channel!");
|
||||
if let Err(e) = chan.send(BackgroundHangMonitorControlMsg::Exit(exit_sender)) {
|
||||
warn!("error communicating with bhm: {}", e);
|
||||
continue;
|
||||
}
|
||||
if exit_receiver.recv().is_err() {
|
||||
warn!("Failed to receive exit confirmation from BHM.");
|
||||
}
|
||||
}
|
||||
|
||||
// Close the top-level browsing contexts
|
||||
let browsing_context_ids: Vec<BrowsingContextId> = self
|
||||
.browsing_contexts
|
||||
|
|
|
@ -21,7 +21,9 @@ use layout_traits::LayoutThreadFactory;
|
|||
use media::WindowGLContext;
|
||||
use metrics::PaintTimeMetrics;
|
||||
use msg::constellation_msg::TopLevelBrowsingContextId;
|
||||
use msg::constellation_msg::{BackgroundHangMonitorRegister, HangMonitorAlert, SamplerControlMsg};
|
||||
use msg::constellation_msg::{
|
||||
BackgroundHangMonitorControlMsg, BackgroundHangMonitorRegister, HangMonitorAlert,
|
||||
};
|
||||
use msg::constellation_msg::{BrowsingContextId, HistoryStateId};
|
||||
use msg::constellation_msg::{
|
||||
PipelineId, PipelineNamespace, PipelineNamespaceId, PipelineNamespaceRequest,
|
||||
|
@ -128,7 +130,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: Option<IpcSender<HangMonitorAlert>>,
|
||||
pub background_hang_monitor_to_constellation_chan: IpcSender<HangMonitorAlert>,
|
||||
|
||||
/// A channel for the layout thread to send messages to the constellation.
|
||||
pub layout_to_constellation_chan: IpcSender<LayoutMsg>,
|
||||
|
@ -205,7 +207,7 @@ pub struct InitialPipelineState {
|
|||
|
||||
pub struct NewPipeline {
|
||||
pub pipeline: Pipeline,
|
||||
pub sampler_control_chan: Option<IpcSender<SamplerControlMsg>>,
|
||||
pub bhm_control_chan: Option<IpcSender<BackgroundHangMonitorControlMsg>>,
|
||||
}
|
||||
|
||||
impl Pipeline {
|
||||
|
@ -220,7 +222,7 @@ impl Pipeline {
|
|||
// probably requires a general low-memory strategy.
|
||||
let (pipeline_chan, pipeline_port) = ipc::channel().expect("Pipeline main chan");
|
||||
|
||||
let (script_chan, sampler_chan) = match state.event_loop {
|
||||
let (script_chan, bhm_control_chan) = match state.event_loop {
|
||||
Some(script_chan) => {
|
||||
let new_layout_info = NewLayoutInfo {
|
||||
parent_info: state.parent_pipeline_id,
|
||||
|
@ -279,7 +281,7 @@ impl Pipeline {
|
|||
background_hang_monitor_to_constellation_chan: state
|
||||
.background_hang_monitor_to_constellation_chan
|
||||
.clone(),
|
||||
sampling_profiler_port: None,
|
||||
bhm_control_port: None,
|
||||
scheduler_chan: state.scheduler_chan,
|
||||
devtools_chan: script_to_devtools_chan,
|
||||
bluetooth_thread: state.bluetooth_thread,
|
||||
|
@ -309,34 +311,26 @@ impl Pipeline {
|
|||
// Spawn the child process.
|
||||
//
|
||||
// Yes, that's all there is to it!
|
||||
let sampler_chan = if opts::multiprocess() {
|
||||
let (sampler_chan, sampler_port) = ipc::channel().expect("Sampler chan");
|
||||
unprivileged_pipeline_content.sampling_profiler_port = Some(sampler_port);
|
||||
let bhm_control_chan = if opts::multiprocess() {
|
||||
let (bhm_control_chan, bhm_control_port) =
|
||||
ipc::channel().expect("Sampler chan");
|
||||
unprivileged_pipeline_content.bhm_control_port = Some(bhm_control_port);
|
||||
let _ = unprivileged_pipeline_content.spawn_multiprocess()?;
|
||||
Some(sampler_chan)
|
||||
Some(bhm_control_chan)
|
||||
} else {
|
||||
// Should not be None in single-process mode.
|
||||
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
|
||||
}
|
||||
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
|
||||
};
|
||||
|
||||
(EventLoop::new(script_chan), sampler_chan)
|
||||
(EventLoop::new(script_chan), bhm_control_chan)
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -353,7 +347,7 @@ impl Pipeline {
|
|||
);
|
||||
Ok(NewPipeline {
|
||||
pipeline,
|
||||
sampler_control_chan: sampler_chan,
|
||||
bhm_control_chan,
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -494,8 +488,8 @@ pub struct UnprivilegedPipelineContent {
|
|||
opener: Option<BrowsingContextId>,
|
||||
namespace_request_sender: IpcSender<PipelineNamespaceRequest>,
|
||||
script_to_constellation_chan: ScriptToConstellationChan,
|
||||
background_hang_monitor_to_constellation_chan: Option<IpcSender<HangMonitorAlert>>,
|
||||
sampling_profiler_port: Option<IpcReceiver<SamplerControlMsg>>,
|
||||
background_hang_monitor_to_constellation_chan: IpcSender<HangMonitorAlert>,
|
||||
bhm_control_port: Option<IpcReceiver<BackgroundHangMonitorControlMsg>>,
|
||||
layout_to_constellation_chan: IpcSender<LayoutMsg>,
|
||||
scheduler_chan: IpcSender<TimerSchedulerMsg>,
|
||||
devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
|
||||
|
@ -526,7 +520,7 @@ impl UnprivilegedPipelineContent {
|
|||
pub fn start_all<Message, LTF, STF>(
|
||||
self,
|
||||
wait_for_completion: bool,
|
||||
background_hang_monitor_register: Option<Box<dyn BackgroundHangMonitorRegister>>,
|
||||
background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>,
|
||||
event_loop_waker: Option<Box<dyn EventLoopWaker>>,
|
||||
) where
|
||||
LTF: LayoutThreadFactory<Message = Message>,
|
||||
|
@ -634,17 +628,12 @@ impl UnprivilegedPipelineContent {
|
|||
|
||||
pub fn register_with_background_hang_monitor(
|
||||
&mut self,
|
||||
) -> 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?"),
|
||||
)
|
||||
})
|
||||
) -> Box<dyn BackgroundHangMonitorRegister> {
|
||||
HangMonitorRegister::init(
|
||||
self.background_hang_monitor_to_constellation_chan.clone(),
|
||||
self.bhm_control_port.take().expect("no sampling profiler?"),
|
||||
opts::get().background_hang_monitor,
|
||||
)
|
||||
}
|
||||
|
||||
pub fn script_to_constellation_chan(&self) -> &ScriptToConstellationChan {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue