mirror of
https://github.com/servo/servo.git
synced 2025-08-05 21:50:18 +01:00
auto merge of #917 : larsbergstrom/servo/task_failure, r=metajack
Pipeline construction now creates a task that supervises all of the child tasks created by script, render, and layout. If any of those fail, it sends a message back to the constellation, which re-creates the pipeline and threads it into the appropriate spot in either the FrameTree or set of pending frame updates. Also, turn on debug_info for symbols in the Makefile.
This commit is contained in:
commit
49aa4a568c
11 changed files with 211 additions and 72 deletions
|
@ -32,7 +32,7 @@ MKFILE_DEPS := config.stamp $(call rwildcard,$(S)mk/,*)
|
||||||
# Enable debug!() etc even without configure --enable-debug
|
# Enable debug!() etc even without configure --enable-debug
|
||||||
# The evaluation of these prints & their arguments is controlled
|
# The evaluation of these prints & their arguments is controlled
|
||||||
# at runtime by the environment variable RUST_LOG.
|
# at runtime by the environment variable RUST_LOG.
|
||||||
CFG_RUSTC_FLAGS += --cfg debug
|
CFG_RUSTC_FLAGS += --cfg debug -Z debug-info
|
||||||
|
|
||||||
ifdef CFG_DISABLE_OPTIMIZE
|
ifdef CFG_DISABLE_OPTIMIZE
|
||||||
$(info cfg: disabling rustc optimization (CFG_DISABLE_OPTIMIZE))
|
$(info cfg: disabling rustc optimization (CFG_DISABLE_OPTIMIZE))
|
||||||
|
|
|
@ -486,7 +486,12 @@ impl CompositorLayer {
|
||||||
} else {
|
} else {
|
||||||
// ID does not match ours, so recurse on descendents (including hidden children).
|
// ID does not match ours, so recurse on descendents (including hidden children).
|
||||||
self.children.mut_iter().map(|x| &mut x.child)
|
self.children.mut_iter().map(|x| &mut x.child)
|
||||||
.any(|x| x.add_buffers(pipeline_id, cell.take(), epoch))
|
.any(|x| {
|
||||||
|
let buffers = cell.take();
|
||||||
|
let result = x.add_buffers(pipeline_id, buffers.clone(), epoch);
|
||||||
|
cell.put_back(buffers);
|
||||||
|
result
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,8 +13,8 @@ use geom::size::Size2D;
|
||||||
use geom::rect::Rect;
|
use geom::rect::Rect;
|
||||||
use gfx::opts::Opts;
|
use gfx::opts::Opts;
|
||||||
use pipeline::Pipeline;
|
use pipeline::Pipeline;
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FrameRectMsg, IFrameSandboxState};
|
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, FrameRectMsg};
|
||||||
use servo_msg::constellation_msg::{InitLoadUrlMsg, LoadIframeUrlMsg, LoadUrlMsg};
|
use servo_msg::constellation_msg::{IFrameSandboxState, InitLoadUrlMsg, LoadIframeUrlMsg, LoadUrlMsg};
|
||||||
use servo_msg::constellation_msg::{Msg, NavigateMsg, NavigationType, IFrameUnsandboxed};
|
use servo_msg::constellation_msg::{Msg, NavigateMsg, NavigationType, IFrameUnsandboxed};
|
||||||
use servo_msg::constellation_msg::{PipelineId, RendererReadyMsg, ResizedWindowMsg, SubpageId};
|
use servo_msg::constellation_msg::{PipelineId, RendererReadyMsg, ResizedWindowMsg, SubpageId};
|
||||||
use servo_msg::constellation_msg;
|
use servo_msg::constellation_msg;
|
||||||
|
@ -23,6 +23,7 @@ use servo_net::image_cache_task::{ImageCacheTask, ImageCacheTaskClient};
|
||||||
use servo_net::resource_task::ResourceTask;
|
use servo_net::resource_task::ResourceTask;
|
||||||
use servo_net::resource_task;
|
use servo_net::resource_task;
|
||||||
use servo_util::time::ProfilerChan;
|
use servo_util::time::ProfilerChan;
|
||||||
|
use servo_util::url::make_url;
|
||||||
use std::hashmap::{HashMap, HashSet};
|
use std::hashmap::{HashMap, HashSet};
|
||||||
use std::util::replace;
|
use std::util::replace;
|
||||||
use extra::url::Url;
|
use extra::url::Url;
|
||||||
|
@ -312,6 +313,15 @@ impl Constellation {
|
||||||
&self.navigation_context.current
|
&self.navigation_context.current
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns both the navigation context and pending frame trees whose keys are pipeline_id.
|
||||||
|
pub fn find_all(&mut self, pipeline_id: PipelineId) -> ~[@mut FrameTree] {
|
||||||
|
let matching_navi_frames = self.navigation_context.find_all(pipeline_id);
|
||||||
|
let matching_pending_frames = do self.pending_frames.iter().filter_map |frame_change| {
|
||||||
|
frame_change.after.find_mut(pipeline_id)
|
||||||
|
};
|
||||||
|
matching_navi_frames.move_iter().chain(matching_pending_frames).collect()
|
||||||
|
}
|
||||||
|
|
||||||
/// Handles loading pages, navigation, and granting access to the compositor
|
/// Handles loading pages, navigation, and granting access to the compositor
|
||||||
fn handle_request(&mut self, request: Msg) -> bool {
|
fn handle_request(&mut self, request: Msg) -> bool {
|
||||||
match request {
|
match request {
|
||||||
|
@ -319,6 +329,9 @@ impl Constellation {
|
||||||
self.handle_exit(sender);
|
self.handle_exit(sender);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
FailureMsg(pipeline_id, subpage_id) => {
|
||||||
|
self.handle_failure_msg(pipeline_id, subpage_id);
|
||||||
|
}
|
||||||
// This should only be called once per constellation, and only by the browser
|
// This should only be called once per constellation, and only by the browser
|
||||||
InitLoadUrlMsg(url) => {
|
InitLoadUrlMsg(url) => {
|
||||||
self.handle_init_load(url);
|
self.handle_init_load(url);
|
||||||
|
@ -363,6 +376,32 @@ impl Constellation {
|
||||||
sender.send(());
|
sender.send(());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn handle_failure_msg(&mut self, pipeline_id: PipelineId, subpage_id: Option<SubpageId>) {
|
||||||
|
let new_id = self.get_next_pipeline_id();
|
||||||
|
let pipeline = @mut Pipeline::create(new_id,
|
||||||
|
subpage_id,
|
||||||
|
self.chan.clone(),
|
||||||
|
self.compositor_chan.clone(),
|
||||||
|
self.image_cache_task.clone(),
|
||||||
|
self.resource_task.clone(),
|
||||||
|
self.profiler_chan.clone(),
|
||||||
|
self.opts.clone(),
|
||||||
|
{
|
||||||
|
let size = self.compositor_chan.get_size();
|
||||||
|
from_value(Size2D(size.width as uint, size.height as uint))
|
||||||
|
});
|
||||||
|
let failure = ~"about:failure";
|
||||||
|
let url = make_url(failure, None);
|
||||||
|
pipeline.load(url);
|
||||||
|
|
||||||
|
let frames = self.find_all(pipeline_id);
|
||||||
|
for frame_tree in frames.iter() {
|
||||||
|
frame_tree.pipeline = pipeline;
|
||||||
|
};
|
||||||
|
|
||||||
|
self.pipelines.insert(pipeline_id, pipeline);
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_init_load(&mut self, url: Url) {
|
fn handle_init_load(&mut self, url: Url) {
|
||||||
let pipeline = @mut Pipeline::create(self.get_next_pipeline_id(),
|
let pipeline = @mut Pipeline::create(self.get_next_pipeline_id(),
|
||||||
None,
|
None,
|
||||||
|
@ -420,14 +459,8 @@ impl Constellation {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Traverse the navigation context and pending frames and tell each associated pipeline to resize.
|
// Traverse the navigation context and pending frames and tell each associated pipeline to resize.
|
||||||
let frame_trees: ~[@mut FrameTree] = {
|
let frames = self.find_all(pipeline_id);
|
||||||
let matching_navi_frames = self.navigation_context.find_all(pipeline_id);
|
for frame_tree in frames.iter() {
|
||||||
let matching_pending_frames = do self.pending_frames.iter().filter_map |frame_change| {
|
|
||||||
frame_change.after.find_mut(pipeline_id)
|
|
||||||
};
|
|
||||||
matching_navi_frames.move_iter().chain(matching_pending_frames).collect()
|
|
||||||
};
|
|
||||||
for frame_tree in frame_trees.iter() {
|
|
||||||
for child_frame_tree in frame_tree.children.mut_iter() {
|
for child_frame_tree in frame_tree.children.mut_iter() {
|
||||||
let pipeline = &child_frame_tree.frame_tree.pipeline;
|
let pipeline = &child_frame_tree.frame_tree.pipeline;
|
||||||
if pipeline.subpage_id.expect("Constellation: child frame does not have a
|
if pipeline.subpage_id.expect("Constellation: child frame does not have a
|
||||||
|
|
|
@ -11,7 +11,7 @@ use gfx::opts::Opts;
|
||||||
use layout::layout_task::LayoutTask;
|
use layout::layout_task::LayoutTask;
|
||||||
use script::layout_interface::LayoutChan;
|
use script::layout_interface::LayoutChan;
|
||||||
use script::script_task::{ExecuteMsg, LoadMsg};
|
use script::script_task::{ExecuteMsg, LoadMsg};
|
||||||
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, SubpageId};
|
use servo_msg::constellation_msg::{ConstellationChan, FailureMsg, PipelineId, SubpageId};
|
||||||
use script::dom::node::AbstractNode;
|
use script::dom::node::AbstractNode;
|
||||||
use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan};
|
use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan};
|
||||||
use script::script_task;
|
use script::script_task;
|
||||||
|
@ -20,9 +20,11 @@ use servo_net::resource_task::ResourceTask;
|
||||||
use servo_util::time::ProfilerChan;
|
use servo_util::time::ProfilerChan;
|
||||||
use geom::size::Size2D;
|
use geom::size::Size2D;
|
||||||
use extra::future::Future;
|
use extra::future::Future;
|
||||||
|
use std::cell::Cell;
|
||||||
use std::comm;
|
use std::comm;
|
||||||
|
use std::task;
|
||||||
|
|
||||||
/// A uniquely-identifiable pipeline of stript task, layout task, and render task.
|
/// A uniquely-identifiable pipeline of script task, layout task, and render task.
|
||||||
#[deriving(Clone)]
|
#[deriving(Clone)]
|
||||||
pub struct Pipeline {
|
pub struct Pipeline {
|
||||||
id: PipelineId,
|
id: PipelineId,
|
||||||
|
@ -94,37 +96,81 @@ impl Pipeline {
|
||||||
let (script_port, script_chan) = special_stream!(ScriptChan);
|
let (script_port, script_chan) = special_stream!(ScriptChan);
|
||||||
let (layout_port, layout_chan) = special_stream!(LayoutChan);
|
let (layout_port, layout_chan) = special_stream!(LayoutChan);
|
||||||
let (render_port, render_chan) = special_stream!(RenderChan);
|
let (render_port, render_chan) = special_stream!(RenderChan);
|
||||||
|
let pipeline = Pipeline::new(id,
|
||||||
|
subpage_id,
|
||||||
|
script_chan.clone(),
|
||||||
|
layout_chan.clone(),
|
||||||
|
render_chan.clone());
|
||||||
|
let (port, chan) = stream::<task::TaskResult>();
|
||||||
|
|
||||||
ScriptTask::create(id,
|
let script_port = Cell::new(script_port);
|
||||||
compositor_chan.clone(),
|
let resource_task = Cell::new(resource_task);
|
||||||
layout_chan.clone(),
|
let size = Cell::new(size);
|
||||||
script_port,
|
let render_port = Cell::new(render_port);
|
||||||
script_chan.clone(),
|
let layout_port = Cell::new(layout_port);
|
||||||
constellation_chan.clone(),
|
let constellation_chan_handler = Cell::new(constellation_chan.clone());
|
||||||
resource_task,
|
let constellation_chan = Cell::new(constellation_chan);
|
||||||
image_cache_task.clone(),
|
let image_cache_task = Cell::new(image_cache_task);
|
||||||
size);
|
let profiler_chan = Cell::new(profiler_chan);
|
||||||
|
|
||||||
|
do Pipeline::spawn(chan) {
|
||||||
|
let script_port = script_port.take();
|
||||||
|
let resource_task = resource_task.take();
|
||||||
|
let size = size.take();
|
||||||
|
let render_port = render_port.take();
|
||||||
|
let layout_port = layout_port.take();
|
||||||
|
let constellation_chan = constellation_chan.take();
|
||||||
|
let image_cache_task = image_cache_task.take();
|
||||||
|
let profiler_chan = profiler_chan.take();
|
||||||
|
|
||||||
RenderTask::create(id,
|
ScriptTask::create(id,
|
||||||
render_port,
|
compositor_chan.clone(),
|
||||||
compositor_chan.clone(),
|
layout_chan.clone(),
|
||||||
opts.clone(),
|
script_port,
|
||||||
profiler_chan.clone());
|
script_chan.clone(),
|
||||||
|
constellation_chan.clone(),
|
||||||
|
resource_task,
|
||||||
|
image_cache_task.clone(),
|
||||||
|
size);
|
||||||
|
|
||||||
LayoutTask::create(id,
|
RenderTask::create(id,
|
||||||
layout_port,
|
render_port,
|
||||||
constellation_chan,
|
compositor_chan.clone(),
|
||||||
script_chan.clone(),
|
opts.clone(),
|
||||||
render_chan.clone(),
|
profiler_chan.clone());
|
||||||
image_cache_task,
|
|
||||||
opts.clone(),
|
LayoutTask::create(id,
|
||||||
profiler_chan);
|
layout_port,
|
||||||
Pipeline::new(id,
|
constellation_chan,
|
||||||
subpage_id,
|
script_chan.clone(),
|
||||||
script_chan,
|
render_chan.clone(),
|
||||||
layout_chan,
|
image_cache_task,
|
||||||
render_chan)
|
opts.clone(),
|
||||||
|
profiler_chan);
|
||||||
|
};
|
||||||
|
|
||||||
|
do spawn {
|
||||||
|
match port.recv() {
|
||||||
|
task::Success => (),
|
||||||
|
task::Failure => {
|
||||||
|
let constellation_chan = constellation_chan_handler.take();
|
||||||
|
constellation_chan.send(FailureMsg(id, subpage_id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pipeline
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This function wraps the task creation within a supervised task
|
||||||
|
/// so that failure will only tear down those tasks instead of ours.
|
||||||
|
pub fn spawn(chan: Chan<task::TaskResult>, f: ~fn()) {
|
||||||
|
let mut task = task::task();
|
||||||
|
task.opts.notify_chan = Some(chan);
|
||||||
|
task.supervised();
|
||||||
|
do task.spawn {
|
||||||
|
f();
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new(id: PipelineId,
|
pub fn new(id: PipelineId,
|
||||||
|
|
|
@ -35,6 +35,7 @@ pub enum IFrameSandboxState {
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
ExitMsg(Chan<()>),
|
ExitMsg(Chan<()>),
|
||||||
|
FailureMsg(PipelineId, Option<SubpageId>),
|
||||||
InitLoadUrlMsg(Url),
|
InitLoadUrlMsg(Url),
|
||||||
FrameRectMsg(PipelineId, SubpageId, Rect<f32>),
|
FrameRectMsg(PipelineId, SubpageId, Rect<f32>),
|
||||||
LoadUrlMsg(PipelineId, Url, Future<Size2D<uint>>),
|
LoadUrlMsg(PipelineId, Url, Future<Size2D<uint>>),
|
||||||
|
|
|
@ -16,42 +16,55 @@ Create a URL object from a string. Does various helpful browsery things like
|
||||||
is based off the current url
|
is based off the current url
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
// TODO: about:failure->
|
||||||
pub fn make_url(str_url: ~str, current_url: Option<Url>) -> Url {
|
pub fn make_url(str_url: ~str, current_url: Option<Url>) -> Url {
|
||||||
let schm = url::get_scheme(str_url);
|
let schm = url::get_scheme(str_url);
|
||||||
let str_url = if schm.is_err() {
|
let str_url = match schm {
|
||||||
if current_url.is_none() {
|
Err(_) => {
|
||||||
// Assume we've been given a file path. If it's absolute just return
|
if current_url.is_none() {
|
||||||
// it, otherwise make it absolute with the cwd.
|
// Assume we've been given a file path. If it's absolute just return
|
||||||
if str_url.starts_with("/") {
|
// it, otherwise make it absolute with the cwd.
|
||||||
~"file://" + str_url
|
if str_url.starts_with("/") {
|
||||||
} else {
|
~"file://" + str_url
|
||||||
~"file://" + os::getcwd().push(str_url).to_str()
|
} else {
|
||||||
}
|
~"file://" + os::getcwd().push(str_url).to_str()
|
||||||
} else {
|
|
||||||
let current_url = current_url.unwrap();
|
|
||||||
debug!("make_url: current_url: %?", current_url);
|
|
||||||
if str_url.starts_with("//") {
|
|
||||||
current_url.scheme + ":" + str_url
|
|
||||||
} else if current_url.path.is_empty() ||
|
|
||||||
str_url.starts_with("/") {
|
|
||||||
current_url.scheme + "://" +
|
|
||||||
current_url.host + "/" +
|
|
||||||
str_url.trim_left_chars(&'/')
|
|
||||||
} else {
|
|
||||||
let mut path = ~[];
|
|
||||||
for p in current_url.path.split_iter('/') {
|
|
||||||
path.push(p.to_str());
|
|
||||||
}
|
}
|
||||||
let path = path.init();
|
} else {
|
||||||
let mut path = path.iter().map(|x| (*x).clone()).collect::<~[~str]>();
|
let current_url = current_url.unwrap();
|
||||||
path.push(str_url);
|
debug!("make_url: current_url: %?", current_url);
|
||||||
let path = path.connect("/");
|
if str_url.starts_with("//") {
|
||||||
|
current_url.scheme + ":" + str_url
|
||||||
|
} else if current_url.path.is_empty() ||
|
||||||
|
str_url.starts_with("/") {
|
||||||
|
current_url.scheme + "://" +
|
||||||
|
current_url.host + "/" +
|
||||||
|
str_url.trim_left_chars(&'/')
|
||||||
|
} else {
|
||||||
|
let mut path = ~[];
|
||||||
|
for p in current_url.path.split_iter('/') {
|
||||||
|
path.push(p.to_str());
|
||||||
|
}
|
||||||
|
let path = path.init();
|
||||||
|
let mut path = path.iter().map(|x| (*x).clone()).collect::<~[~str]>();
|
||||||
|
path.push(str_url);
|
||||||
|
let path = path.connect("/");
|
||||||
|
|
||||||
current_url.scheme + "://" + current_url.host + path
|
current_url.scheme + "://" + current_url.host + path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Ok((scheme, page)) => {
|
||||||
|
match scheme {
|
||||||
|
~"about" => {
|
||||||
|
match page {
|
||||||
|
~"failure" => ~"file://" + os::getcwd().push("../src/test/html/failure.html").to_str(),
|
||||||
|
// TODO: handle the rest of the about: pages
|
||||||
|
_ => str_url
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => str_url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
str_url
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// FIXME: Need to handle errors
|
// FIXME: Need to handle errors
|
||||||
|
|
BIN
src/test/html/andreas.jpeg
Normal file
BIN
src/test/html/andreas.jpeg
Normal file
Binary file not shown.
After Width: | Height: | Size: 93 KiB |
8
src/test/html/failure.html
Normal file
8
src/test/html/failure.html
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>about:failure</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<img src="andreas.jpeg"/>
|
||||||
|
</body>
|
||||||
|
</html>
|
12
src/test/html/summit-crash.html
Normal file
12
src/test/html/summit-crash.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Summit demo crash page</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<audio>
|
||||||
|
<source src="horse.ogg" type="audio/ogg">
|
||||||
|
<source src="horse.mp3" type="audio/mpeg">
|
||||||
|
</audio>
|
||||||
|
<pre>pre</pre>
|
||||||
|
</body>
|
||||||
|
</html>
|
9
src/test/html/summit-link.html
Normal file
9
src/test/html/summit-link.html
Normal file
|
@ -0,0 +1,9 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Summit page linking to the crash page</title>
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<a href="summit-crash.html">Load a crashing page</a>
|
||||||
|
</body>
|
||||||
|
</html>
|
12
src/test/html/summit.html
Normal file
12
src/test/html/summit.html
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Summit demo page</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<iframe src="about-mozilla.html" style="display:block; border: 1px; width: 400px; height: 400px"
|
||||||
|
frameborder="yes" scrolling="yes"></iframe>
|
||||||
|
|
||||||
|
<iframe src="summit-link.html" style="display:block; border: 1px; width: 400px; height: 400px"
|
||||||
|
frameborder="yes" scrolling="yes"></iframe>
|
||||||
|
</body>
|
||||||
|
</html>
|
Loading…
Add table
Add a link
Reference in a new issue