Report errors using the top-level frame id rather than the pipeline id.

This commit is contained in:
Alan Jeffrey 2016-11-10 15:34:04 -06:00
parent 22aebdf5d4
commit c228a4cf03
9 changed files with 203 additions and 195 deletions

View file

@ -419,9 +419,9 @@ impl Log for FromScriptLogger {
fn log(&self, record: &LogRecord) {
if let Some(entry) = log_entry(record) {
debug!("Sending log entry {:?}.", entry);
let pipeline_id = PipelineId::installed();
let top_level_frame_id = FrameId::installed();
let thread_name = thread::current().name().map(ToOwned::to_owned);
let msg = FromScriptMsg::LogEntry(pipeline_id, thread_name, entry);
let msg = FromScriptMsg::LogEntry(top_level_frame_id, thread_name, entry);
let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner());
let _ = chan.send(msg);
}
@ -457,9 +457,9 @@ impl Log for FromCompositorLogger {
fn log(&self, record: &LogRecord) {
if let Some(entry) = log_entry(record) {
debug!("Sending log entry {:?}.", entry);
let pipeline_id = PipelineId::installed();
let top_level_frame_id = FrameId::installed();
let thread_name = thread::current().name().map(ToOwned::to_owned);
let msg = FromCompositorMsg::LogEntry(pipeline_id, thread_name, entry);
let msg = FromCompositorMsg::LogEntry(top_level_frame_id, thread_name, entry);
let chan = self.constellation_chan.lock().unwrap_or_else(|err| err.into_inner());
let _ = chan.send(msg);
}
@ -605,9 +605,18 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
None
};
// TODO: think about the case where the child pipeline is created
// before the parent is part of the frame tree.
let top_level_frame_id = match parent_info {
Some((_, FrameType::MozBrowserIFrame)) => frame_id,
Some((parent_id, _)) => self.get_top_level_frame_for_pipeline(parent_id),
None => self.root_frame_id,
};
let result = Pipeline::spawn::<Message, LTF, STF>(InitialPipelineState {
id: pipeline_id,
frame_id: frame_id,
top_level_frame_id: top_level_frame_id,
parent_info: parent_info,
constellation_chan: self.script_sender.clone(),
layout_to_constellation_chan: self.layout_sender.clone(),
@ -847,8 +856,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
debug!("constellation got reload message");
self.handle_reload_msg();
}
FromCompositorMsg::LogEntry(pipeline_id, thread_name, entry) => {
self.handle_log_entry(pipeline_id, thread_name, entry);
FromCompositorMsg::LogEntry(top_level_frame_id, thread_name, entry) => {
self.handle_log_entry(top_level_frame_id, thread_name, entry);
}
}
}
@ -999,8 +1008,8 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
FromScriptMsg::Exit => {
self.compositor_proxy.send(ToCompositorMsg::Exit);
}
FromScriptMsg::LogEntry(pipeline_id, thread_name, entry) => {
self.handle_log_entry(pipeline_id, thread_name, entry);
FromScriptMsg::LogEntry(top_level_frame_id, thread_name, entry) => {
self.handle_log_entry(top_level_frame_id, thread_name, entry);
}
FromScriptMsg::SetTitle(pipeline_id, title) => {
@ -1172,10 +1181,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn handle_send_error(&mut self, pipeline_id: PipelineId, err: IOError) {
// Treat send error the same as receiving a panic message
debug!("Pipeline {:?} send error ({}).", pipeline_id, err);
self.handle_panic(Some(pipeline_id), format!("Send failed ({})", err), None);
let top_level_frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
let reason = format!("Send failed ({})", err);
self.handle_panic(top_level_frame_id, reason, None);
}
fn handle_panic(&mut self, pipeline_id: Option<PipelineId>, reason: String, backtrace: Option<String>) {
fn handle_panic(&mut self, top_level_frame_id: FrameId, reason: String, backtrace: Option<String>) {
if opts::get().hard_fail {
// It's quite difficult to make Servo exit cleanly if some threads have failed.
// Hard fail exists for test runners so we crash and that's good enough.
@ -1183,26 +1194,18 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
process::exit(1);
}
debug!("Panic handler for pipeline {:?}: {}.", pipeline_id, reason);
debug!("Panic handler for top-level frame {}: {}.", top_level_frame_id, reason);
// Notify the browser chrome that the pipeline has failed
self.trigger_mozbrowsererror(pipeline_id, reason, backtrace);
self.trigger_mozbrowsererror(top_level_frame_id, reason, backtrace);
if let Some(pipeline_id) = pipeline_id {
let pipeline_url = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.url.clone());
let parent_info = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.parent_info);
let window_size = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.size);
let frame_id = self.pipelines.get(&pipeline_id).map(|pipeline| pipeline.frame_id);
let frame_id = FrameId::from(top_level_frame_id);
let pipeline_id = self.frames.get(&frame_id).map(|frame| frame.current.pipeline_id);
let pipeline_url = pipeline_id.and_then(|id| self.pipelines.get(&id).map(|pipeline| pipeline.url.clone()));
let parent_info = pipeline_id.and_then(|id| self.pipelines.get(&id).and_then(|pipeline| pipeline.parent_info));
let window_size = pipeline_id.and_then(|id| self.pipelines.get(&id).and_then(|pipeline| pipeline.size));
self.close_pipeline(pipeline_id, ExitPipelineMode::Force);
self.pipelines.remove(&pipeline_id);
while let Some(pending_pipeline_id) = self.pending_frames.iter().find(|pending| {
pending.old_pipeline_id == Some(pipeline_id)
}).map(|frame| frame.new_pipeline_id) {
warn!("removing pending frame change for failed pipeline");
self.close_pipeline(pending_pipeline_id, ExitPipelineMode::Force);
}
self.close_frame_children(frame_id, ExitPipelineMode::Force);
let failure_url = ServoUrl::parse("about:failure").expect("infallible");
@ -1214,27 +1217,27 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
warn!("creating replacement pipeline for about:failure");
if let Some(frame_id) = frame_id {
let new_pipeline_id = PipelineId::new();
let load_data = LoadData::new(failure_url, None, None);
self.new_pipeline(new_pipeline_id, frame_id, parent_info, Some(pipeline_id),
self.new_pipeline(new_pipeline_id, frame_id, parent_info, pipeline_id,
window_size, None, load_data, false);
self.pending_frames.push(FrameChange {
frame_id: frame_id,
old_pipeline_id: Some(pipeline_id),
old_pipeline_id: pipeline_id,
new_pipeline_id: new_pipeline_id,
document_ready: false,
replace: false,
});
}
}
}
fn handle_log_entry(&mut self, pipeline_id: Option<PipelineId>, thread_name: Option<String>, entry: LogEntry) {
fn handle_log_entry(&mut self, top_level_frame_id: Option<FrameId>, thread_name: Option<String>, entry: LogEntry) {
debug!("Received log entry {:?}.", entry);
match entry {
LogEntry::Panic(reason, backtrace) => self.handle_panic(pipeline_id, reason, Some(backtrace)),
LogEntry::Panic(reason, backtrace) => {
let top_level_frame_id = top_level_frame_id.unwrap_or(self.root_frame_id);
self.handle_panic(top_level_frame_id, reason, Some(backtrace));
},
LogEntry::Error(reason) | LogEntry::Warn(reason) => {
// VecDeque::truncate is unstable
if WARNINGS_BUFFER_SIZE <= self.handled_warnings.len() {
@ -1291,25 +1294,24 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
fn handle_subframe_loaded(&mut self, pipeline_id: PipelineId) {
let (frame_id, parent_info) = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => (pipeline.frame_id, pipeline.parent_info),
None => return warn!("Pipeline {:?} loaded after closure.", pipeline_id),
};
let subframe_parent_id = match parent_info {
Some(ref parent) => parent.0,
None => return warn!("Pipeline {:?} has no parent.", pipeline_id),
let (frame_id, parent_id) = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => match pipeline.parent_info {
Some((parent_id, _)) => (pipeline.frame_id, parent_id),
None => return warn!("Pipeline {} has no parent.", pipeline_id),
},
None => return warn!("Pipeline {} loaded after closure.", pipeline_id),
};
let msg = ConstellationControlMsg::DispatchFrameLoadEvent {
target: frame_id,
parent: subframe_parent_id,
parent: parent_id,
child: pipeline_id,
};
let result = match self.pipelines.get(&subframe_parent_id) {
Some(pipeline) => pipeline.script_chan.send(msg),
None => return warn!("Pipeline {:?} subframe loaded after closure.", subframe_parent_id),
let result = match self.pipelines.get(&parent_id) {
Some(parent) => parent.script_chan.send(msg),
None => return warn!("Parent {} frame loaded after closure.", parent_id),
};
if let Err(e) = result {
self.handle_send_error(subframe_parent_id, e);
self.handle_send_error(parent_id, e);
}
}
@ -1371,7 +1373,6 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
(load_data, script_chan, window_size, is_private)
};
// Create the new pipeline, attached to the parent and push to pending frames
self.new_pipeline(load_info.new_pipeline_id,
load_info.frame_id,
@ -1428,37 +1429,27 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
pipeline_id: PipelineId,
message: String,
sender: IpcSender<bool>) {
let display_alert_dialog = if PREFS.is_mozbrowser_enabled() {
let parent_pipeline_info = self.pipelines.get(&pipeline_id).and_then(|source| source.parent_info);
if parent_pipeline_info.is_some() {
let root_pipeline_id = self.frames.get(&self.root_frame_id)
.map(|root_frame| root_frame.current.pipeline_id);
let pipeline_isnt_root = self.pipelines.get(&pipeline_id).and_then(|pipeline| pipeline.parent_info).is_some();
let mozbrowser_modal_prompt = pipeline_isnt_root && PREFS.is_mozbrowser_enabled();
let ancestor_info = self.get_mozbrowser_ancestor_info(pipeline_id);
if let Some((ancestor_id, mozbrowser_iframe_id)) = ancestor_info {
if root_pipeline_id == Some(ancestor_id) {
match root_pipeline_id.and_then(|pipeline_id| self.pipelines.get(&pipeline_id)) {
Some(root_pipeline) => {
if mozbrowser_modal_prompt {
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsershowmodalprompt
let event = MozBrowserEvent::ShowModalPrompt("alert".to_owned(), "Alert".to_owned(),
String::from(message), "".to_owned());
root_pipeline.trigger_mozbrowser_event(Some(mozbrowser_iframe_id), event);
}
None => return warn!("Alert sent to Pipeline {:?} after closure.", root_pipeline_id),
}
} else {
warn!("A non-current frame is trying to show an alert.")
}
}
false
} else {
true
}
} else {
true
};
let prompt_type = String::from("alert");
let title = String::from("Alert");
let return_value = String::from("");
let event = MozBrowserEvent::ShowModalPrompt(prompt_type, title, message, return_value);
let top_level_frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
let result = sender.send(display_alert_dialog);
match self.frames.get(&self.root_frame_id) {
None => warn!("Alert sent after root frame closure."),
Some(root_frame) => match self.pipelines.get(&root_frame.current.pipeline_id) {
None => warn!("Alert sent after root pipeline closure."),
Some(root_pipeline) => root_pipeline.trigger_mozbrowser_event(Some(top_level_frame_id), event),
}
}
}
let result = sender.send(!mozbrowser_modal_prompt);
if let Err(e) = result {
self.handle_send_error(pipeline_id, e);
}
@ -1546,7 +1537,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
fn handle_load_start_msg(&mut self, pipeline_id: PipelineId) {
let frame_id = self.get_top_level_frame_for_pipeline(Some(pipeline_id));
let frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
let forward = !self.joint_session_future_is_empty(frame_id);
let back = !self.joint_session_past_is_empty(frame_id);
self.compositor_proxy.send(ToCompositorMsg::LoadStart(back, forward));
@ -1564,7 +1555,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
if webdriver_reset {
self.webdriver.load_channel = None;
}
let frame_id = self.get_top_level_frame_for_pipeline(Some(pipeline_id));
let frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
let forward = !self.joint_session_future_is_empty(frame_id);
let back = !self.joint_session_past_is_empty(frame_id);
let root = self.root_frame_id == frame_id;
@ -1575,13 +1566,15 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
fn handle_traverse_history_msg(&mut self,
pipeline_id: Option<PipelineId>,
direction: TraversalDirection) {
let frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
let top_level_frame_id = pipeline_id
.map(|pipeline_id| self.get_top_level_frame_for_pipeline(pipeline_id))
.unwrap_or(self.root_frame_id);
let mut traversal_info = HashMap::new();
match direction {
TraversalDirection::Forward(delta) => {
let mut future = self.joint_session_future(frame_id);
let mut future = self.joint_session_future(top_level_frame_id);
for _ in 0..delta {
match future.pop() {
Some((_, frame_id, pipeline_id)) => {
@ -1592,7 +1585,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
},
TraversalDirection::Back(delta) => {
let mut past = self.joint_session_past(frame_id);
let mut past = self.joint_session_past(top_level_frame_id);
for _ in 0..delta {
match past.pop() {
Some((_, frame_id, pipeline_id)) => {
@ -1609,7 +1602,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
fn handle_joint_session_history_length(&self, pipeline_id: PipelineId, sender: IpcSender<u32>) {
let frame_id = self.get_top_level_frame_for_pipeline(Some(pipeline_id));
let frame_id = self.get_top_level_frame_for_pipeline(pipeline_id);
// Initialize length at 1 to count for the current active entry
let mut length = 1;
@ -1966,11 +1959,21 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
fn get_top_level_frame_for_pipeline(&self, pipeline_id: Option<PipelineId>) -> FrameId {
fn get_top_level_frame_for_pipeline(&self, mut pipeline_id: PipelineId) -> FrameId {
if PREFS.is_mozbrowser_enabled() {
pipeline_id.and_then(|id| self.get_mozbrowser_ancestor_info(id))
.map(|(_, mozbrowser_iframe_id)| mozbrowser_iframe_id)
.unwrap_or(self.root_frame_id)
loop {
match self.pipelines.get(&pipeline_id) {
Some(pipeline) => match pipeline.parent_info {
Some((_, FrameType::MozBrowserIFrame)) => return pipeline.frame_id,
Some((parent_id, _)) => pipeline_id = parent_id,
None => return self.root_frame_id,
},
None => {
warn!("Finding top-level ancestor for pipeline {} after closure.", pipeline_id);
return self.root_frame_id;
},
}
}
} else {
// If mozbrowser is not enabled, the root frame is the only top-level frame
self.root_frame_id
@ -2025,7 +2028,7 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// This is the result of a link being clicked and a navigation completing.
self.trigger_mozbrowserlocationchange(frame_change.new_pipeline_id);
let top_level_frame_id = self.get_top_level_frame_for_pipeline(Some(frame_change.new_pipeline_id));
let top_level_frame_id = self.get_top_level_frame_for_pipeline(frame_change.new_pipeline_id);
self.clear_joint_session_future(top_level_frame_id);
}
@ -2262,30 +2265,12 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
// Close a frame (and all children)
fn close_frame(&mut self, frame_id: FrameId, exit_mode: ExitPipelineMode) {
debug!("Closing frame {:?}.", frame_id);
// Store information about the pipelines to be closed. Then close the
// pipelines, before removing ourself from the frames hash map. This
// ordering is vital - so that if close_pipeline() ends up closing
// any child frames, they can be removed from the parent frame correctly.
debug!("Closing frame {}.", frame_id);
let parent_info = self.frames.get(&frame_id)
.and_then(|frame| self.pipelines.get(&frame.current.pipeline_id))
.and_then(|pipeline| pipeline.parent_info);
let pipelines_to_close = {
let mut pipelines_to_close = vec!();
if let Some(frame) = self.frames.get(&frame_id) {
pipelines_to_close.extend_from_slice(&frame.next);
pipelines_to_close.push(frame.current.clone());
pipelines_to_close.extend_from_slice(&frame.prev);
}
pipelines_to_close
};
for entry in pipelines_to_close {
self.close_pipeline(entry.pipeline_id, exit_mode);
}
self.close_frame_children(frame_id, exit_mode);
if self.frames.remove(&frame_id).is_none() {
warn!("Closing frame {:?} twice.", frame_id);
@ -2301,6 +2286,31 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
debug!("Closed frame {:?}.", frame_id);
}
// Close the children of a frame
fn close_frame_children(&mut self, frame_id: FrameId, exit_mode: ExitPipelineMode) {
debug!("Closing frame children {}.", frame_id);
// Store information about the pipelines to be closed. Then close the
// pipelines, before removing ourself from the frames hash map. This
// ordering is vital - so that if close_pipeline() ends up closing
// any child frames, they can be removed from the parent frame correctly.
let mut pipelines_to_close: Vec<PipelineId> = self.pending_frames.iter()
.filter(|frame_change| frame_change.frame_id == frame_id)
.map(|frame_change| frame_change.new_pipeline_id)
.collect();
if let Some(frame) = self.frames.get(&frame_id) {
pipelines_to_close.extend(frame.next.iter().map(|state| state.pipeline_id));
pipelines_to_close.push(frame.current.pipeline_id);
pipelines_to_close.extend(frame.prev.iter().map(|state| state.pipeline_id));
}
for pipeline_id in pipelines_to_close {
self.close_pipeline(pipeline_id, exit_mode);
}
debug!("Closed frame children {}.", frame_id);
}
// Close all pipelines at and beneath a given frame
fn close_pipeline(&mut self, pipeline_id: PipelineId, exit_mode: ExitPipelineMode) {
debug!("Closing pipeline {:?}.", pipeline_id);
@ -2410,49 +2420,29 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
}
}
/// For a given pipeline, determine the mozbrowser iframe that transitively contains
/// it. There could be arbitrary levels of nested iframes in between them.
fn get_mozbrowser_ancestor_info(&self, original_pipeline_id: PipelineId) -> Option<(PipelineId, FrameId)> {
let mut pipeline_id = original_pipeline_id;
loop {
match self.pipelines.get(&pipeline_id) {
Some(pipeline) => match pipeline.parent_info {
Some((parent_id, FrameType::MozBrowserIFrame)) => return Some((parent_id, pipeline.frame_id)),
Some((parent_id, _)) => pipeline_id = parent_id,
None => return None,
},
None => {
warn!("Finding mozbrowser ancestor for pipeline {} after closure.", pipeline_id);
return None;
},
}
}
}
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowserlocationchange
// Note that this is a no-op if the pipeline is not a mozbrowser iframe
fn trigger_mozbrowserlocationchange(&self, pipeline_id: PipelineId) {
if !PREFS.is_mozbrowser_enabled() { return; }
let url = match self.pipelines.get(&pipeline_id) {
Some(pipeline) => pipeline.url.to_string(),
None => return warn!("triggered mozbrowser location change on closed pipeline {:?}", pipeline_id),
};
// If this is a mozbrowser iframe, then send the event with new url
if let Some((ancestor_id, mozbrowser_frame_id)) = self.get_mozbrowser_ancestor_info(pipeline_id) {
if let Some(ancestor) = self.pipelines.get(&ancestor_id) {
let can_go_forward = !self.joint_session_future(mozbrowser_frame_id).is_empty();
let can_go_back = !self.joint_session_past(mozbrowser_frame_id).is_empty();
match self.pipelines.get(&pipeline_id) {
Some(pipeline) => if let Some((parent_id, FrameType::MozBrowserIFrame)) = pipeline.parent_info {
match self.pipelines.get(&parent_id) {
Some(parent) => {
let can_go_forward = !self.joint_session_future_is_empty(pipeline.frame_id);
let can_go_back = !self.joint_session_past_is_empty(pipeline.frame_id);
let url = pipeline.url.to_string();
let event = MozBrowserEvent::LocationChange(url, can_go_back, can_go_forward);
ancestor.trigger_mozbrowser_event(Some(mozbrowser_frame_id), event);
parent.trigger_mozbrowser_event(Some(pipeline.frame_id), event);
},
None => warn!("triggered mozbrowser location change on closed parent {}", parent_id),
}
},
None => warn!("triggered mozbrowser location change on closed pipeline {}", pipeline_id),
}
}
// https://developer.mozilla.org/en-US/docs/Web/Events/mozbrowsererror
// Note that this does not require the pipeline to be an immediate child of the root
fn trigger_mozbrowsererror(&mut self, pipeline_id: Option<PipelineId>, reason: String, backtrace: Option<String>) {
fn trigger_mozbrowsererror(&mut self, top_level_frame_id: FrameId, reason: String, backtrace: Option<String>) {
if !PREFS.is_mozbrowser_enabled() { return; }
let mut report = String::new();
@ -2474,21 +2464,19 @@ impl<Message, LTF, STF> Constellation<Message, LTF, STF>
let event = MozBrowserEvent::Error(MozBrowserErrorType::Fatal, reason, report);
if let Some(pipeline_id) = pipeline_id {
if let Some((ancestor_id, mozbrowser_iframe_id)) = self.get_mozbrowser_ancestor_info(pipeline_id) {
if let Some(ancestor) = self.pipelines.get(&ancestor_id) {
return ancestor.trigger_mozbrowser_event(Some(mozbrowser_iframe_id), event);
}
}
}
if let Some(root_frame) = self.frames.get(&self.root_frame_id) {
if let Some(root_pipeline) = self.pipelines.get(&root_frame.current.pipeline_id) {
return root_pipeline.trigger_mozbrowser_event(None, event);
}
}
warn!("Mozbrowser error after root pipeline closed.");
match self.frames.get(&top_level_frame_id) {
None => warn!("Mozbrowser error after top-level frame closed."),
Some(frame) => match self.pipelines.get(&frame.current.pipeline_id) {
None => warn!("Mozbrowser error after top-level pipeline closed."),
Some(pipeline) => match pipeline.parent_info {
None => pipeline.trigger_mozbrowser_event(None, event),
Some((parent_id, _)) => match self.pipelines.get(&parent_id) {
None => warn!("Mozbrowser error after root pipeline closed."),
Some(parent) => parent.trigger_mozbrowser_event(Some(top_level_frame_id), event),
},
},
},
};
}
fn focused_pipeline_in_tree(&self, frame_id: FrameId) -> bool {

View file

@ -82,6 +82,8 @@ pub struct InitialPipelineState {
pub id: PipelineId,
/// The ID of the frame that contains this Pipeline.
pub frame_id: FrameId,
/// The ID of the top-level frame that contains this Pipeline.
pub top_level_frame_id: FrameId,
/// The ID of the parent pipeline and frame type, if any.
/// If `None`, this is the root.
pub parent_info: Option<(PipelineId, FrameType)>,
@ -204,6 +206,7 @@ impl Pipeline {
let unprivileged_pipeline_content = UnprivilegedPipelineContent {
id: state.id,
frame_id: state.frame_id,
top_level_frame_id: state.top_level_frame_id,
parent_info: state.parent_info,
constellation_chan: state.constellation_chan,
scheduler_chan: state.scheduler_chan,
@ -381,6 +384,7 @@ impl Pipeline {
pub struct UnprivilegedPipelineContent {
id: PipelineId,
frame_id: FrameId,
top_level_frame_id: FrameId,
parent_info: Option<(PipelineId, FrameType)>,
constellation_chan: IpcSender<ScriptMsg>,
layout_to_constellation_chan: IpcSender<LayoutMsg>,
@ -416,6 +420,7 @@ impl UnprivilegedPipelineContent {
let layout_pair = STF::create(InitialScriptState {
id: self.id,
frame_id: self.frame_id,
top_level_frame_id: self.top_level_frame_id,
parent_info: self.parent_info,
control_chan: self.script_chan.clone(),
control_port: self.script_port,
@ -433,6 +438,7 @@ impl UnprivilegedPipelineContent {
}, self.load_data.clone());
LTF::create(self.id,
Some(self.top_level_frame_id),
self.load_data.url,
self.parent_info.is_some(),
layout_pair,

View file

@ -42,7 +42,6 @@ extern crate selectors;
extern crate serde_json;
extern crate servo_url;
extern crate style;
extern crate style_traits;
extern crate util;
extern crate webrender_traits;
@ -80,7 +79,7 @@ use layout::webrender_helpers::{WebRenderDisplayListConverter, WebRenderFrameBui
use layout::wrapper::LayoutNodeLayoutData;
use layout::wrapper::drop_style_and_layout_data;
use layout_traits::LayoutThreadFactory;
use msg::constellation_msg::PipelineId;
use msg::constellation_msg::{FrameId, PipelineId};
use net_traits::image_cache_thread::{ImageCacheChan, ImageCacheResult, ImageCacheThread};
use net_traits::image_cache_thread::UsePlaceholder;
use parking_lot::RwLock;
@ -235,6 +234,7 @@ impl LayoutThreadFactory for LayoutThread {
/// Spawns a new layout thread.
fn create(id: PipelineId,
top_level_frame_id: Option<FrameId>,
url: ServoUrl,
is_iframe: bool,
chan: (Sender<Msg>, Receiver<Msg>),
@ -251,7 +251,11 @@ impl LayoutThreadFactory for LayoutThread {
thread::spawn_named(format!("LayoutThread {:?}", id),
move || {
thread_state::initialize(thread_state::LAYOUT);
PipelineId::install(id);
if let Some(top_level_frame_id) = top_level_frame_id {
FrameId::install(top_level_frame_id);
}
{ // Ensures layout thread is destroyed before we send shutdown message
let sender = chan.0;
let layout = LayoutThread::new(id,
@ -718,6 +722,7 @@ impl LayoutThread {
fn create_layout_thread(&self, info: NewLayoutThreadInfo) {
LayoutThread::create(info.id,
FrameId::installed(),
info.url.clone(),
info.is_parent,
info.layout_pair,

View file

@ -20,7 +20,7 @@ extern crate webrender_traits;
use gfx::font_cache_thread::FontCacheThread;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use msg::constellation_msg::PipelineId;
use msg::constellation_msg::{FrameId, PipelineId};
use net_traits::image_cache_thread::ImageCacheThread;
use profile_traits::{mem, time};
use script_traits::{ConstellationControlMsg, LayoutControlMsg};
@ -33,6 +33,7 @@ use std::sync::mpsc::{Receiver, Sender};
pub trait LayoutThreadFactory {
type Message;
fn create(id: PipelineId,
top_level_frame_id: Option<FrameId>,
url: ServoUrl,
is_iframe: bool,
chan: (Sender<Self::Message>, Receiver<Self::Message>),

View file

@ -217,8 +217,6 @@ impl PipelineNamespace {
thread_local!(pub static PIPELINE_NAMESPACE: Cell<Option<PipelineNamespace>> = Cell::new(None));
thread_local!(pub static PIPELINE_ID: Cell<Option<PipelineId>> = Cell::new(None));
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct PipelineNamespaceId(pub u32);
@ -246,15 +244,6 @@ impl PipelineId {
let PipelineIndex(index) = self.index;
webrender_traits::PipelineId(namespace_id, index)
}
pub fn install(id: PipelineId) {
PIPELINE_ID.with(|tls| tls.set(Some(id)))
}
pub fn installed() -> Option<PipelineId> {
PIPELINE_ID.with(|tls| tls.get())
}
}
impl fmt::Display for PipelineId {
@ -265,6 +254,8 @@ impl fmt::Display for PipelineId {
}
}
thread_local!(pub static TOP_LEVEL_FRAME_ID: Cell<Option<FrameId>> = Cell::new(None));
#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Copy, Hash, Debug, Deserialize, Serialize, HeapSizeOf)]
pub struct FrameIndex(pub u32);
@ -283,6 +274,16 @@ impl FrameId {
new_frame_id
})
}
/// Each script and layout thread should have the top-level frame id installed,
/// since it is used by crash reporting.
pub fn install(id: FrameId) {
TOP_LEVEL_FRAME_ID.with(|tls| tls.set(Some(id)))
}
pub fn installed() -> Option<FrameId> {
TOP_LEVEL_FRAME_ID.with(|tls| tls.get())
}
}
impl fmt::Display for FrameId {

View file

@ -26,7 +26,7 @@ use js::jsapi::{HandleValue, JS_SetInterruptCallback};
use js::jsapi::{JSAutoCompartment, JSContext};
use js::jsval::UndefinedValue;
use js::rust::Runtime;
use msg::constellation_msg::PipelineId;
use msg::constellation_msg::FrameId;
use net_traits::{IpcSend, load_whole_resource};
use net_traits::request::{CredentialsMode, Destination, RequestInit, Type as RequestType};
use rand::random;
@ -158,9 +158,14 @@ impl DedicatedWorkerGlobalScope {
closing: Arc<AtomicBool>) {
let serialized_worker_url = worker_url.to_string();
let name = format!("WebWorker for {}", serialized_worker_url);
let top_level_frame_id = FrameId::installed();
spawn_named(name, move || {
thread_state::initialize(thread_state::SCRIPT | thread_state::IN_WORKER);
PipelineId::install(init.pipeline_id);
if let Some(top_level_frame_id) = top_level_frame_id {
FrameId::install(top_level_frame_id);
}
let roots = RootCollection::new();
let _stack_roots_tls = StackRootTLS::new(&roots);

View file

@ -517,8 +517,8 @@ impl ScriptThreadFactory for ScriptThread {
thread::spawn_named(format!("ScriptThread {:?}", state.id),
move || {
thread_state::initialize(thread_state::SCRIPT);
PipelineId::install(state.id);
PipelineNamespace::install(state.pipeline_namespace_id);
FrameId::install(state.top_level_frame_id);
let roots = RootCollection::new();
let _stack_roots_tls = StackRootTLS::new(&roots);
let id = state.id;

View file

@ -442,6 +442,8 @@ pub struct InitialScriptState {
pub parent_info: Option<(PipelineId, FrameType)>,
/// The ID of the frame this script is part of.
pub frame_id: FrameId,
/// The ID of the top-level frame this script is part of.
pub top_level_frame_id: FrameId,
/// A channel with which messages can be sent to us (the script thread).
pub control_chan: IpcSender<ConstellationControlMsg>,
/// A port on which messages sent by the constellation to script can be received.
@ -699,8 +701,8 @@ pub enum ConstellationMsg {
WebDriverCommand(WebDriverCommandMsg),
/// Reload the current page.
Reload,
/// A log entry, with the pipeline id and thread name
LogEntry(Option<PipelineId>, Option<String>, LogEntry),
/// A log entry, with the top-level frame id and thread name
LogEntry(Option<FrameId>, Option<String>, LogEntry),
}
/// Resources required by workerglobalscopes

View file

@ -15,8 +15,8 @@ use devtools_traits::{ScriptToDevtoolsControlMsg, WorkerId};
use euclid::point::Point2D;
use euclid::size::Size2D;
use ipc_channel::ipc::IpcSender;
use msg::constellation_msg::{FrameId, PipelineId, TraversalDirection};
use msg::constellation_msg::{Key, KeyModifiers, KeyState};
use msg::constellation_msg::{PipelineId, TraversalDirection};
use net_traits::CoreResourceMsg;
use net_traits::storage_thread::StorageType;
use offscreen_gl_context::{GLContextAttributes, GLLimits};
@ -131,8 +131,8 @@ pub enum ScriptMsg {
ResizeTo(Size2D<u32>),
/// Script has handled a touch event, and either prevented or allowed default actions.
TouchEventProcessed(EventResult),
/// A log entry, with the pipeline id and thread name
LogEntry(Option<PipelineId>, Option<String>, LogEntry),
/// A log entry, with the top-level frame id and thread name
LogEntry(Option<FrameId>, Option<String>, LogEntry),
/// Notifies the constellation that this pipeline has exited.
PipelineExited(PipelineId),
/// Send messages from postMessage calls from serviceworker