mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +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
|
||||
# The evaluation of these prints & their arguments is controlled
|
||||
# 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
|
||||
$(info cfg: disabling rustc optimization (CFG_DISABLE_OPTIMIZE))
|
||||
|
|
|
@ -486,7 +486,12 @@ impl CompositorLayer {
|
|||
} else {
|
||||
// ID does not match ours, so recurse on descendents (including hidden children).
|
||||
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 gfx::opts::Opts;
|
||||
use pipeline::Pipeline;
|
||||
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FrameRectMsg, IFrameSandboxState};
|
||||
use servo_msg::constellation_msg::{InitLoadUrlMsg, LoadIframeUrlMsg, LoadUrlMsg};
|
||||
use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, FrameRectMsg};
|
||||
use servo_msg::constellation_msg::{IFrameSandboxState, InitLoadUrlMsg, LoadIframeUrlMsg, LoadUrlMsg};
|
||||
use servo_msg::constellation_msg::{Msg, NavigateMsg, NavigationType, IFrameUnsandboxed};
|
||||
use servo_msg::constellation_msg::{PipelineId, RendererReadyMsg, ResizedWindowMsg, SubpageId};
|
||||
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;
|
||||
use servo_util::time::ProfilerChan;
|
||||
use servo_util::url::make_url;
|
||||
use std::hashmap::{HashMap, HashSet};
|
||||
use std::util::replace;
|
||||
use extra::url::Url;
|
||||
|
@ -312,6 +313,15 @@ impl Constellation {
|
|||
&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
|
||||
fn handle_request(&mut self, request: Msg) -> bool {
|
||||
match request {
|
||||
|
@ -319,6 +329,9 @@ impl Constellation {
|
|||
self.handle_exit(sender);
|
||||
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
|
||||
InitLoadUrlMsg(url) => {
|
||||
self.handle_init_load(url);
|
||||
|
@ -363,6 +376,32 @@ impl Constellation {
|
|||
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) {
|
||||
let pipeline = @mut Pipeline::create(self.get_next_pipeline_id(),
|
||||
None,
|
||||
|
@ -420,14 +459,8 @@ impl Constellation {
|
|||
}
|
||||
}
|
||||
// Traverse the navigation context and pending frames and tell each associated pipeline to resize.
|
||||
let frame_trees: ~[@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()
|
||||
};
|
||||
for frame_tree in frame_trees.iter() {
|
||||
let frames = self.find_all(pipeline_id);
|
||||
for frame_tree in frames.iter() {
|
||||
for child_frame_tree in frame_tree.children.mut_iter() {
|
||||
let pipeline = &child_frame_tree.frame_tree.pipeline;
|
||||
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 script::layout_interface::LayoutChan;
|
||||
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::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan};
|
||||
use script::script_task;
|
||||
|
@ -20,9 +20,11 @@ use servo_net::resource_task::ResourceTask;
|
|||
use servo_util::time::ProfilerChan;
|
||||
use geom::size::Size2D;
|
||||
use extra::future::Future;
|
||||
use std::cell::Cell;
|
||||
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)]
|
||||
pub struct Pipeline {
|
||||
id: PipelineId,
|
||||
|
@ -94,37 +96,81 @@ impl Pipeline {
|
|||
let (script_port, script_chan) = special_stream!(ScriptChan);
|
||||
let (layout_port, layout_chan) = special_stream!(LayoutChan);
|
||||
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>();
|
||||
|
||||
let script_port = Cell::new(script_port);
|
||||
let resource_task = Cell::new(resource_task);
|
||||
let size = Cell::new(size);
|
||||
let render_port = Cell::new(render_port);
|
||||
let layout_port = Cell::new(layout_port);
|
||||
let constellation_chan_handler = Cell::new(constellation_chan.clone());
|
||||
let constellation_chan = Cell::new(constellation_chan);
|
||||
let image_cache_task = Cell::new(image_cache_task);
|
||||
let profiler_chan = Cell::new(profiler_chan);
|
||||
|
||||
ScriptTask::create(id,
|
||||
compositor_chan.clone(),
|
||||
layout_chan.clone(),
|
||||
script_port,
|
||||
script_chan.clone(),
|
||||
constellation_chan.clone(),
|
||||
resource_task,
|
||||
image_cache_task.clone(),
|
||||
size);
|
||||
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();
|
||||
|
||||
ScriptTask::create(id,
|
||||
compositor_chan.clone(),
|
||||
layout_chan.clone(),
|
||||
script_port,
|
||||
script_chan.clone(),
|
||||
constellation_chan.clone(),
|
||||
resource_task,
|
||||
image_cache_task.clone(),
|
||||
size);
|
||||
|
||||
RenderTask::create(id,
|
||||
render_port,
|
||||
compositor_chan.clone(),
|
||||
opts.clone(),
|
||||
profiler_chan.clone());
|
||||
RenderTask::create(id,
|
||||
render_port,
|
||||
compositor_chan.clone(),
|
||||
opts.clone(),
|
||||
profiler_chan.clone());
|
||||
|
||||
LayoutTask::create(id,
|
||||
layout_port,
|
||||
constellation_chan,
|
||||
script_chan.clone(),
|
||||
render_chan.clone(),
|
||||
image_cache_task,
|
||||
opts.clone(),
|
||||
profiler_chan);
|
||||
Pipeline::new(id,
|
||||
subpage_id,
|
||||
script_chan,
|
||||
layout_chan,
|
||||
render_chan)
|
||||
LayoutTask::create(id,
|
||||
layout_port,
|
||||
constellation_chan,
|
||||
script_chan.clone(),
|
||||
render_chan.clone(),
|
||||
image_cache_task,
|
||||
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,
|
||||
|
|
|
@ -35,6 +35,7 @@ pub enum IFrameSandboxState {
|
|||
|
||||
pub enum Msg {
|
||||
ExitMsg(Chan<()>),
|
||||
FailureMsg(PipelineId, Option<SubpageId>),
|
||||
InitLoadUrlMsg(Url),
|
||||
FrameRectMsg(PipelineId, SubpageId, Rect<f32>),
|
||||
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
|
||||
|
||||
*/
|
||||
// TODO: about:failure->
|
||||
pub fn make_url(str_url: ~str, current_url: Option<Url>) -> Url {
|
||||
let schm = url::get_scheme(str_url);
|
||||
let str_url = if schm.is_err() {
|
||||
if current_url.is_none() {
|
||||
// Assume we've been given a file path. If it's absolute just return
|
||||
// it, otherwise make it absolute with the cwd.
|
||||
if str_url.starts_with("/") {
|
||||
~"file://" + str_url
|
||||
} 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 str_url = match schm {
|
||||
Err(_) => {
|
||||
if current_url.is_none() {
|
||||
// Assume we've been given a file path. If it's absolute just return
|
||||
// it, otherwise make it absolute with the cwd.
|
||||
if str_url.starts_with("/") {
|
||||
~"file://" + str_url
|
||||
} else {
|
||||
~"file://" + os::getcwd().push(str_url).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
|
||||
} 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();
|
||||
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
|
||||
}
|
||||
}
|
||||
},
|
||||
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
|
||||
|
|
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