Compare commits

...

1 Commits

Author SHA1 Message Date
Simon Sapin
9afca9eb7b WIP 2019-07-15 11:45:33 +02:00
2 changed files with 209 additions and 30 deletions

View File

@@ -17,6 +17,7 @@ gfx = {path = "../gfx"}
ipc-channel = "0.11"
layout = {path = "../layout_2020", package = "layout_2020"}
layout_traits = {path = "../layout_traits"}
log = "0.4"
metrics = {path = "../metrics"}
msg = {path = "../msg"}
net_traits = {path = "../net_traits"}
@@ -25,4 +26,5 @@ script_layout_interface = {path = "../script_layout_interface"}
script_traits = {path = "../script_traits"}
servo_url = {path = "../url"}
servo_geometry = {path = "../geometry"}
style = {path = "../style"}
webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]}

View File

@@ -2,58 +2,235 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use crossbeam_channel::{Receiver, Sender};
use crossbeam_channel::{select, Receiver, Sender};
use euclid::TypedSize2D;
use gfx::font_cache_thread::FontCacheThread;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use metrics::PaintTimeMetrics;
use msg::constellation_msg::TopLevelBrowsingContextId;
use msg::constellation_msg::{BackgroundHangMonitorRegister, PipelineId};
use ipc_channel::router::ROUTER;
use log::{debug, error};
use metrics::{PaintTimeMetrics, ProgressiveWebMetric};
use msg::constellation_msg::{BackgroundHangMonitor, BackgroundHangMonitorRegister};
use msg::constellation_msg::{HangAnnotation, LayoutHangAnnotation};
use msg::constellation_msg::{MonitoredComponentId, MonitoredComponentType};
use msg::constellation_msg::{PipelineId, TopLevelBrowsingContextId};
use net_traits::image_cache::ImageCache;
use profile_traits::{mem, time};
use script_layout_interface::message::Msg;
use script_traits::LayoutMsg as ConstellationMsg;
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
use servo_geometry::DeviceIndependentPixel;
use servo_url::ServoUrl;
use std::sync::atomic::AtomicBool;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use style::thread_state::{self, ThreadState};
pub struct LayoutThread;
pub struct LayoutThread {
/// The receiver on which we receive messages from the script thread.
script_receiver: Receiver<Msg>,
/// The receiver on which we receive messages from the constellation.
pipeline_receiver: Receiver<LayoutControlMsg>,
/// Flag that indicates if LayoutThread is busy handling a request.
busy: Arc<AtomicBool>,
paint_time_metrics: PaintTimeMetrics,
background_hang_monitor: Box<dyn BackgroundHangMonitor>,
}
impl layout_traits::LayoutThreadFactory for LayoutThread {
type Message = script_layout_interface::message::Msg;
type Message = Msg;
#[allow(unused)]
fn create(
id: PipelineId,
top_level_browsing_context_id: TopLevelBrowsingContextId,
url: ServoUrl,
is_iframe: bool,
chan: (Sender<Self::Message>, Receiver<Self::Message>),
_url: ServoUrl,
_is_iframe: bool,
(script_sender, script_receiver): (Sender<Self::Message>, Receiver<Self::Message>),
pipeline_port: IpcReceiver<LayoutControlMsg>,
background_hang_monitor: Box<dyn BackgroundHangMonitorRegister>,
constellation_chan: IpcSender<ConstellationMsg>,
script_chan: IpcSender<ConstellationControlMsg>,
image_cache: Arc<dyn ImageCache>,
font_cache_thread: FontCacheThread,
time_profiler_chan: time::ProfilerChan,
background_hang_monitor_register: Box<dyn BackgroundHangMonitorRegister>,
_constellation_chan: IpcSender<ConstellationMsg>,
_script_chan: IpcSender<ConstellationControlMsg>,
_image_cache: Arc<dyn ImageCache>,
_font_cache_thread: FontCacheThread,
_time_profiler_chan: time::ProfilerChan,
mem_profiler_chan: mem::ProfilerChan,
content_process_shutdown_chan: Option<IpcSender<()>>,
webrender_api_sender: webrender_api::RenderApiSender,
webrender_document: webrender_api::DocumentId,
_webrender_api_sender: webrender_api::RenderApiSender,
_webrender_document: webrender_api::DocumentId,
paint_time_metrics: PaintTimeMetrics,
busy: Arc<AtomicBool>,
load_webfonts_synchronously: bool,
initial_window_size: TypedSize2D<u32, DeviceIndependentPixel>,
device_pixels_per_px: Option<f32>,
dump_display_list: bool,
dump_display_list_json: bool,
dump_style_tree: bool,
dump_rule_tree: bool,
relayout_event: bool,
nonincremental_layout: bool,
trace_layout: bool,
dump_flow_tree: bool,
_load_webfonts_synchronously: bool,
_initial_window_size: TypedSize2D<u32, DeviceIndependentPixel>,
_device_pixels_per_px: Option<f32>,
_dump_display_list: bool,
_dump_display_list_json: bool,
_dump_style_tree: bool,
_dump_rule_tree: bool,
_relayout_event: bool,
_nonincremental_layout: bool,
_trace_layout: bool,
_dump_flow_tree: bool,
) {
thread::Builder::new()
.name(format!("LayoutThread {:?}", id))
.spawn(move || {
thread_state::initialize(ThreadState::LAYOUT);
// In order to get accurate crash reports, we install the top-level bc id.
TopLevelBrowsingContextId::install(top_level_browsing_context_id);
let background_hang_monitor = background_hang_monitor_register.register_component(
MonitoredComponentId(id, MonitoredComponentType::Layout),
Duration::from_millis(1000),
Duration::from_millis(5000),
);
// Proxy IPC messages from the pipeline to the layout thread.
let pipeline_receiver =
ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(pipeline_port);
let mut layout = LayoutThread {
script_receiver,
pipeline_receiver,
paint_time_metrics,
background_hang_monitor,
busy,
};
let reporter_name = format!("layout-reporter-{}", id);
mem_profiler_chan.run_with_memory_reporting(
|| while layout.wait_for_message() {},
reporter_name,
script_sender,
Msg::CollectReports,
);
if let Some(content_process_shutdown_chan) = content_process_shutdown_chan {
let _ = content_process_shutdown_chan.send(());
}
})
.expect("Thread spawning failed");
}
}
impl LayoutThread {
fn wait_for_message(&mut self) -> bool {
// Notify the background-hang-monitor we are waiting for an event.
self.background_hang_monitor.notify_wait();
let continue_ = select! {
recv(self.pipeline_receiver) -> msg => {
let msg = msg.unwrap();
self.busy.store(true, Ordering::Relaxed);
self.handle_pipeline_message(msg)
}
recv(self.script_receiver) -> msg => {
let msg = msg.unwrap();
self.busy.store(true, Ordering::Relaxed);
self.handle_message(msg)
}
};
self.busy.store(false, Ordering::Relaxed);
continue_
}
fn handle_pipeline_message(&mut self, msg: LayoutControlMsg) -> bool {
match msg {
LayoutControlMsg::SetScrollStates(new_scroll_states) => {
self.handle_message(Msg::SetScrollStates(new_scroll_states))
},
LayoutControlMsg::TickAnimations => self.handle_message(Msg::TickAnimations),
LayoutControlMsg::GetCurrentEpoch(sender) => {
self.handle_message(Msg::GetCurrentEpoch(sender))
},
LayoutControlMsg::GetWebFontLoadState(sender) => {
self.handle_message(Msg::GetWebFontLoadState(sender))
},
LayoutControlMsg::ExitNow => self.handle_message(Msg::ExitNow),
LayoutControlMsg::PaintMetric(epoch, paint_time) => {
self.paint_time_metrics.maybe_set_metric(epoch, paint_time);
true
},
}
}
fn handle_message(&mut self, msg: Msg) -> bool {
#![allow(unused, unreachable_code)]
self.notify_activity_to_hang_monitor(&msg);
match msg {
Msg::AddStylesheet(stylesheet, before_stylesheet) => {
error!("unhandled: Msg::AddStylesheet")
},
Msg::RemoveStylesheet(stylesheet) => error!("unhandled: Msg::RemoveStylesheet"),
Msg::SetQuirksMode(mode) => error!("unhandled: Msg::SetQuirksMode"),
Msg::GetRPC(response_chan) => error!("unhandled: Msg::GetRPC"),
Msg::Reflow(data) => error!("unhandled: Msg::Reflow"),
Msg::TickAnimations => error!("unhandled: Msg::TickAnimations"),
Msg::SetScrollStates(new_scroll_states) => {
error!("unhandled: Msg::SetScrollStates")
},
Msg::UpdateScrollStateFromScript(state) => {
error!("unhandled: Msg::UpdateScrollStateFromScript")
},
Msg::ReapStyleAndLayoutData(dead_data) => {
error!("unhandled: Msg::ReapStyleAndLayoutData")
},
Msg::CollectReports(reports_chan) => error!("unhandled: Msg::CollectReports"),
Msg::GetCurrentEpoch(sender) => error!("unhandled: Msg::GetCurrentEpoch"),
Msg::AdvanceClockMs(how_many, do_tick) => error!("unhandled: Msg::AdvanceClockMs"),
Msg::GetWebFontLoadState(sender) => error!("unhandled: Msg::GetWebFontLoadState"),
Msg::CreateLayoutThread(info) => error!("unhandled: Msg::CreateLayoutThread"),
Msg::SetFinalUrl(final_url) => error!("unhandled: Msg::SetFinalUrl"),
Msg::RegisterPaint(name, properties, painter) => {
error!("unhandled: Msg::RegisterPaint")
},
Msg::PrepareToExit(response_chan) => {
error!("unhandled: Msg::PrepareToExit");
return false;
},
// Receiving the Exit message at this stage only happens when layout is undergoing a "force exit".
Msg::ExitNow => {
debug!("layout: ExitNow received");
error!("unhandled: Msg::ExitNow");
return false;
},
Msg::SetNavigationStart(time) => self.paint_time_metrics.set_navigation_start(time),
Msg::GetRunningAnimations(sender) => error!("unhandled: Msg::GetRunningAnimations"),
}
true
}
fn notify_activity_to_hang_monitor(&self, request: &Msg) {
let hang_annotation = match request {
Msg::AddStylesheet(..) => LayoutHangAnnotation::AddStylesheet,
Msg::RemoveStylesheet(..) => LayoutHangAnnotation::RemoveStylesheet,
Msg::SetQuirksMode(..) => LayoutHangAnnotation::SetQuirksMode,
Msg::Reflow(..) => LayoutHangAnnotation::Reflow,
Msg::GetRPC(..) => LayoutHangAnnotation::GetRPC,
Msg::TickAnimations => LayoutHangAnnotation::TickAnimations,
Msg::AdvanceClockMs(..) => LayoutHangAnnotation::AdvanceClockMs,
Msg::ReapStyleAndLayoutData(..) => LayoutHangAnnotation::ReapStyleAndLayoutData,
Msg::CollectReports(..) => LayoutHangAnnotation::CollectReports,
Msg::PrepareToExit(..) => LayoutHangAnnotation::PrepareToExit,
Msg::ExitNow => LayoutHangAnnotation::ExitNow,
Msg::GetCurrentEpoch(..) => LayoutHangAnnotation::GetCurrentEpoch,
Msg::GetWebFontLoadState(..) => LayoutHangAnnotation::GetWebFontLoadState,
Msg::CreateLayoutThread(..) => LayoutHangAnnotation::CreateLayoutThread,
Msg::SetFinalUrl(..) => LayoutHangAnnotation::SetFinalUrl,
Msg::SetScrollStates(..) => LayoutHangAnnotation::SetScrollStates,
Msg::UpdateScrollStateFromScript(..) => {
LayoutHangAnnotation::UpdateScrollStateFromScript
},
Msg::RegisterPaint(..) => LayoutHangAnnotation::RegisterPaint,
Msg::SetNavigationStart(..) => LayoutHangAnnotation::SetNavigationStart,
Msg::GetRunningAnimations(..) => LayoutHangAnnotation::GetRunningAnimations,
};
self.background_hang_monitor
.notify_activity(HangAnnotation::Layout(hang_annotation));
}
}