aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/gfx/render_task.rs14
-rw-r--r--src/components/main/compositing/compositor.rs2
-rw-r--r--src/components/main/compositing/compositor_layer.rs20
-rw-r--r--src/components/main/constellation.rs51
-rw-r--r--src/components/main/layout/layout_task.rs13
-rw-r--r--src/components/main/pipeline.rs32
-rw-r--r--src/components/msg/constellation_msg.rs9
-rw-r--r--src/components/script/script_task.rs11
-rw-r--r--src/components/util/task.rs14
-rw-r--r--src/components/util/url.rs5
-rw-r--r--src/test/harness/reftest/reftest.rs4
-rw-r--r--src/test/html/summit-bad-page.html13
-rw-r--r--src/test/html/summit-crash.html2
13 files changed, 130 insertions, 60 deletions
diff --git a/src/components/gfx/render_task.rs b/src/components/gfx/render_task.rs
index eb7ab90ef37..297c4f5517a 100644
--- a/src/components/gfx/render_task.rs
+++ b/src/components/gfx/render_task.rs
@@ -15,12 +15,14 @@ use layers;
use servo_msg::compositor_msg::{Epoch, IdleRenderState, LayerBuffer, LayerBufferSet};
use servo_msg::compositor_msg::{RenderListener, RenderingRenderState};
use servo_msg::constellation_msg::{ConstellationChan, PipelineId, RendererReadyMsg};
+use servo_msg::constellation_msg::{Failure, FailureMsg};
use servo_msg::platform::surface::NativeSurfaceAzureMethods;
use servo_util::time::{ProfilerChan, profile};
use servo_util::time;
-use servo_util::task::spawn_named;
+use servo_util::task::send_on_failure;
use std::comm::{Chan, Port, SharedChan};
+use std::task;
use extra::arc::Arc;
use buffer_map::BufferMap;
@@ -41,7 +43,7 @@ pub enum Msg<T> {
UnusedBufferMsg(~[~LayerBuffer]),
PaintPermissionGranted,
PaintPermissionRevoked,
- ExitMsg(Chan<()>),
+ ExitMsg(Option<Chan<()>>),
}
/// A request from the compositor to the renderer for tiles that need to be (re)displayed.
@@ -143,10 +145,14 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
port: Port<Msg<T>>,
compositor: C,
constellation_chan: ConstellationChan,
+ failure_msg: Failure,
opts: Opts,
profiler_chan: ProfilerChan,
shutdown_chan: Chan<()>) {
- spawn_named("RenderTask", proc() {
+ let mut builder = task::task();
+ send_on_failure(&mut builder, FailureMsg(failure_msg), (*constellation_chan).clone());
+ builder.name("RenderTask");
+ builder.spawn(proc() {
{ // Ensures RenderTask and graphics context are destroyed before shutdown msg
let native_graphics_context = compositor.get_graphics_metadata().map(
@@ -237,7 +243,7 @@ impl<C: RenderListener + Send,T:Send+Freeze> RenderTask<C,T> {
}
ExitMsg(response_ch) => {
debug!("render_task: exitmsg response send");
- response_ch.send(());
+ response_ch.map(|ch| ch.send(()));
break;
}
}
diff --git a/src/components/main/compositing/compositor.rs b/src/components/main/compositing/compositor.rs
index 9cdcb00d43c..390d0acde58 100644
--- a/src/components/main/compositing/compositor.rs
+++ b/src/components/main/compositing/compositor.rs
@@ -382,7 +382,7 @@ impl IOCompositor {
let world_zoom = self.world_zoom;
let page_window = Size2D(window_size.width as f32 / world_zoom,
window_size.height as f32 / world_zoom);
- assert!(layer.resize(id, new_size, page_window, epoch));
+ layer.resize(id, new_size, page_window, epoch);
let move = self.fragment_point.take().map_default(false, |point| layer.move(point, page_window));
(true, move)
diff --git a/src/components/main/compositing/compositor_layer.rs b/src/components/main/compositing/compositor_layer.rs
index bfdad4bf09e..885d0b4ddce 100644
--- a/src/components/main/compositing/compositor_layer.rs
+++ b/src/components/main/compositing/compositor_layer.rs
@@ -248,12 +248,12 @@ impl CompositorLayer {
MouseWindowMouseDownEvent(button, _) => MouseDownEvent(button, cursor),
MouseWindowMouseUpEvent(button, _) => MouseUpEvent(button, cursor),
};
- self.pipeline.script_chan.send(SendEventMsg(self.pipeline.id.clone(), message));
+ self.pipeline.script_chan.try_send(SendEventMsg(self.pipeline.id.clone(), message));
}
pub fn send_mouse_move_event(&self, cursor: Point2D<f32>) {
let message = MouseMoveEvent(cursor);
- self.pipeline.script_chan.send(SendEventMsg(self.pipeline.id.clone(), message));
+ self.pipeline.script_chan.try_send(SendEventMsg(self.pipeline.id.clone(), message));
}
// Given the current window size, determine which tiles need to be (re)rendered
@@ -277,7 +277,7 @@ impl CompositorLayer {
let (request, unused) = quadtree.get_tile_rects_page(rect, scale);
redisplay = !unused.is_empty(); // workaround to make redisplay visible outside block
if redisplay { // send back unused tiles
- self.pipeline.render_chan.send(UnusedBufferMsg(unused));
+ self.pipeline.render_chan.try_send(UnusedBufferMsg(unused));
}
if !request.is_empty() { // ask for tiles
self.pipeline.render_chan.try_send(ReRenderMsg(request, scale, self.epoch));
@@ -365,8 +365,8 @@ impl CompositorLayer {
self.page_size = Some(new_size);
match self.quadtree {
Tree(ref mut quadtree) => {
- self.pipeline.render_chan.send(UnusedBufferMsg(quadtree.resize(new_size.width as uint,
- new_size.height as uint)));
+ self.pipeline.render_chan.try_send(UnusedBufferMsg(quadtree.resize(new_size.width as uint,
+ new_size.height as uint)));
}
NoTree(tile_size, max_mem) => {
self.quadtree = Tree(Quadtree::new(Size2D(new_size.width as uint,
@@ -455,8 +455,8 @@ impl CompositorLayer {
child.page_size = Some(new_size);
match child.quadtree {
Tree(ref mut quadtree) => {
- child.pipeline.render_chan.send(UnusedBufferMsg(quadtree.resize(new_size.width as uint,
- new_size.height as uint)));
+ child.pipeline.render_chan.try_send(UnusedBufferMsg(quadtree.resize(new_size.width as uint,
+ new_size.height as uint)));
}
NoTree(tile_size, max_mem) => {
child.quadtree = Tree(Quadtree::new(Size2D(new_size.width as uint,
@@ -596,7 +596,7 @@ impl CompositorLayer {
self.epoch,
epoch,
self.pipeline.id);
- self.pipeline.render_chan.send(UnusedBufferMsg(new_buffers.buffers));
+ self.pipeline.render_chan.try_send(UnusedBufferMsg(new_buffers.buffers));
return None;
}
@@ -615,7 +615,7 @@ impl CompositorLayer {
buffer.resolution, buffer));
}
if !unused_tiles.is_empty() { // send back unused buffers
- self.pipeline.render_chan.send(UnusedBufferMsg(unused_tiles));
+ self.pipeline.render_chan.try_send(UnusedBufferMsg(unused_tiles));
}
}
self.build_layer_tree(graphics_context);
@@ -719,7 +719,7 @@ impl CompositorLayer {
tile.mark_wont_leak()
}
- self.pipeline.render_chan.send(UnusedBufferMsg(tiles))
+ self.pipeline.render_chan.try_send(UnusedBufferMsg(tiles));
}
}
}
diff --git a/src/components/main/constellation.rs b/src/components/main/constellation.rs
index 3c490894592..9758f4db2af 100644
--- a/src/components/main/constellation.rs
+++ b/src/components/main/constellation.rs
@@ -8,9 +8,11 @@ use extra::url::Url;
use geom::rect::Rect;
use geom::size::Size2D;
use gfx::opts::Opts;
+use gfx::render_task;
use pipeline::{Pipeline, CompositionPipeline};
-use script::script_task::{ResizeMsg, ResizeInactiveMsg};
-use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, FrameRectMsg};
+use script::script_task::{ResizeMsg, ResizeInactiveMsg, ExitPipelineMsg};
+use script::layout_interface;
+use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, FailureMsg, Failure, FrameRectMsg};
use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg};
use servo_msg::constellation_msg::{LoadCompleteMsg, LoadIframeUrlMsg, LoadUrlMsg, Msg, NavigateMsg};
use servo_msg::constellation_msg::{NavigationType, PipelineId, RendererReadyMsg, ResizedWindowMsg};
@@ -24,6 +26,8 @@ use servo_util::url::parse_url;
use servo_util::task::spawn_named;
use std::hashmap::{HashMap, HashSet};
use std::util::replace;
+use std::io;
+use std::libc;
/// Maintains the pipelines and navigation context and grants permission to composite
pub struct Constellation {
@@ -321,7 +325,7 @@ impl Constellation {
self.handle_exit();
return false;
}
- FailureMsg(pipeline_id, subpage_id) => {
+ FailureMsg(Failure { 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
@@ -380,6 +384,27 @@ impl Constellation {
}
fn handle_failure_msg(&mut self, pipeline_id: PipelineId, subpage_id: Option<SubpageId>) {
+ debug!("handling failure message from pipeline {:?}, {:?}", pipeline_id, subpage_id);
+
+ if self.opts.hard_fail {
+ // It's quite difficult to make Servo exit cleanly if some tasks have failed.
+ // Hard fail exists for test runners so we crash and that's good enough.
+ let mut stderr = io::stderr();
+ stderr.write_str("Pipeline failed in hard-fail mode. Crashing!\n");
+ stderr.flush();
+ unsafe { libc::exit(1); }
+ }
+
+ let old_pipeline = match self.pipelines.find(&pipeline_id) {
+ None => return, // already failed?
+ Some(id) => *id
+ };
+
+ old_pipeline.script_chan.try_send(ExitPipelineMsg(pipeline_id));
+ old_pipeline.render_chan.try_send(render_task::ExitMsg(None));
+ old_pipeline.layout_chan.try_send(layout_interface::ExitNowMsg);
+ self.pipelines.remove(&pipeline_id);
+
let new_id = self.get_next_pipeline_id();
let pipeline = @mut Pipeline::create(new_id,
subpage_id,
@@ -390,16 +415,20 @@ impl Constellation {
self.profiler_chan.clone(),
self.window_size,
self.opts.clone());
- let failure = "about:failure";
- let url = parse_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(new_id, pipeline);
+ let url = parse_url("about:failure", None);
+ pipeline.load(url);
- self.pipelines.insert(pipeline_id, pipeline);
+ self.pending_frames.push(FrameChange{
+ before: Some(pipeline_id),
+ after: @mut FrameTree {
+ pipeline: pipeline,
+ parent: None,
+ children: ~[],
+ },
+ navigation_type: constellation_msg::Navigate,
+ });
}
fn handle_init_load(&mut self, url: Url) {
diff --git a/src/components/main/layout/layout_task.rs b/src/components/main/layout/layout_task.rs
index 4480c975861..733ca093fb8 100644
--- a/src/components/main/layout/layout_task.rs
+++ b/src/components/main/layout/layout_task.rs
@@ -40,19 +40,20 @@ use script::layout_interface::{ContentChangedDocumentDamage, LayoutChan, Msg, Pr
use script::layout_interface::{QueryMsg, ReapLayoutDataMsg, Reflow, ReflowDocumentDamage, UntrustedNodeAddress};
use script::layout_interface::{ReflowForDisplay, ReflowMsg};
use script::script_task::{ReflowCompleteMsg, ScriptChan, SendEventMsg};
-use servo_msg::constellation_msg::{ConstellationChan, PipelineId};
+use servo_msg::constellation_msg::{ConstellationChan, PipelineId, Failure, FailureMsg};
use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg};
use servo_net::local_image_cache::{ImageResponder, LocalImageCache};
use servo_util::geometry::Au;
use servo_util::time::{ProfilerChan, profile};
use servo_util::time;
-use servo_util::task::spawn_named;
+use servo_util::task::send_on_failure;
use servo_util::workqueue::WorkQueue;
use std::cast::transmute;
use std::cast;
use std::cell::RefCell;
use std::comm::Port;
use std::ptr;
+use std::task;
use std::util;
use style::{AuthorOrigin, Stylesheet, Stylist};
@@ -240,13 +241,17 @@ impl LayoutTask {
port: Port<Msg>,
chan: LayoutChan,
constellation_chan: ConstellationChan,
+ failure_msg: Failure,
script_chan: ScriptChan,
render_chan: RenderChan<OpaqueNode>,
img_cache_task: ImageCacheTask,
opts: Opts,
profiler_chan: ProfilerChan,
shutdown_chan: Chan<()>) {
- spawn_named("LayoutTask", proc() {
+ let mut builder = task::task();
+ send_on_failure(&mut builder, FailureMsg(failure_msg), (*constellation_chan).clone());
+ builder.name("LayoutTask");
+ builder.spawn(proc() {
{ // Ensures layout task is destroyed before we send shutdown message
let mut layout = LayoutTask::new(id,
port,
@@ -400,7 +405,7 @@ impl LayoutTask {
Some(ref mut traversal) => traversal.shutdown(),
}
- self.render_chan.send(render_task::ExitMsg(response_chan));
+ self.render_chan.send(render_task::ExitMsg(Some(response_chan)));
response_port.recv()
}
diff --git a/src/components/main/pipeline.rs b/src/components/main/pipeline.rs
index 0fee4bdcea3..1b648688778 100644
--- a/src/components/main/pipeline.rs
+++ b/src/components/main/pipeline.rs
@@ -15,7 +15,7 @@ use script::layout_interface::LayoutChan;
use script::script_task::LoadMsg;
use script::script_task::{AttachLayoutMsg, NewLayoutInfo, ScriptTask, ScriptChan};
use script::script_task;
-use servo_msg::constellation_msg::{ConstellationChan, PipelineId, SubpageId};
+use servo_msg::constellation_msg::{ConstellationChan, Failure, PipelineId, SubpageId};
use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask;
use servo_util::time::ProfilerChan;
@@ -58,10 +58,16 @@ impl Pipeline {
let (render_shutdown_port, render_shutdown_chan) = Chan::new();
let (layout_shutdown_port, layout_shutdown_chan) = Chan::new();
+ let failure = Failure {
+ pipeline_id: id,
+ subpage_id: subpage_id,
+ };
+
RenderTask::create(id,
render_port,
compositor_chan.clone(),
constellation_chan.clone(),
+ failure.clone(),
opts.clone(),
profiler_chan.clone(),
render_shutdown_chan);
@@ -70,6 +76,7 @@ impl Pipeline {
layout_port,
layout_chan.clone(),
constellation_chan,
+ failure,
script_pipeline.script_chan.clone(),
render_chan.clone(),
image_cache_task.clone(),
@@ -117,7 +124,10 @@ impl Pipeline {
layout_shutdown_port,
render_shutdown_port);
- // FIXME(#1434): add back failure supervision
+ let failure = Failure {
+ pipeline_id: id,
+ subpage_id: subpage_id,
+ };
ScriptTask::create(id,
compositor_chan.clone(),
@@ -125,6 +135,7 @@ impl Pipeline {
script_port,
script_chan.clone(),
constellation_chan.clone(),
+ failure.clone(),
resource_task,
image_cache_task.clone(),
window_size);
@@ -133,6 +144,7 @@ impl Pipeline {
render_port,
compositor_chan.clone(),
constellation_chan.clone(),
+ failure.clone(),
opts.clone(),
profiler_chan.clone(),
render_shutdown_chan);
@@ -141,6 +153,7 @@ impl Pipeline {
layout_port,
layout_chan.clone(),
constellation_chan,
+ failure,
script_chan.clone(),
render_chan.clone(),
image_cache_task,
@@ -182,7 +195,7 @@ impl Pipeline {
pub fn revoke_paint_permission(&self) {
debug!("pipeline revoking render channel paint permission");
- self.render_chan.send(PaintPermissionRevoked);
+ self.render_chan.try_send(PaintPermissionRevoked);
}
pub fn reload(&mut self) {
@@ -193,12 +206,13 @@ impl Pipeline {
pub fn exit(&self) {
// Script task handles shutting down layout, and layout handles shutting down the renderer.
- self.script_chan.try_send(script_task::ExitPipelineMsg(self.id));
-
- // Wait until all slave tasks have terminated and run destructors
- // NOTE: We don't wait for script task as we don't always own it
- self.render_shutdown_port.recv_opt();
- self.layout_shutdown_port.recv_opt();
+ // For now, if the script task has failed, we give up on clean shutdown.
+ if self.script_chan.try_send(script_task::ExitPipelineMsg(self.id)) {
+ // Wait until all slave tasks have terminated and run destructors
+ // NOTE: We don't wait for script task as we don't always own it
+ self.render_shutdown_port.recv_opt();
+ self.layout_shutdown_port.recv_opt();
+ }
}
pub fn to_sendable(&self) -> CompositionPipeline {
diff --git a/src/components/msg/constellation_msg.rs b/src/components/msg/constellation_msg.rs
index 74c2c282d6f..9d3c1540066 100644
--- a/src/components/msg/constellation_msg.rs
+++ b/src/components/msg/constellation_msg.rs
@@ -26,10 +26,17 @@ pub enum IFrameSandboxState {
IFrameUnsandboxed
}
+// We pass this info to various tasks, so it lives in a separate, cloneable struct.
+#[deriving(Clone)]
+pub struct Failure {
+ pipeline_id: PipelineId,
+ subpage_id: Option<SubpageId>,
+}
+
/// Messages from the compositor and script to the constellation.
pub enum Msg {
ExitMsg,
- FailureMsg(PipelineId, Option<SubpageId>),
+ FailureMsg(Failure),
InitLoadUrlMsg(Url),
LoadCompleteMsg(PipelineId, Url),
FrameRectMsg(PipelineId, SubpageId, Rect<f32>),
diff --git a/src/components/script/script_task.rs b/src/components/script/script_task.rs
index 17c60cd45bf..b835798e874 100644
--- a/src/components/script/script_task.rs
+++ b/src/components/script/script_task.rs
@@ -39,17 +39,18 @@ use js;
use servo_msg::compositor_msg::{FinishedLoading, Loading, PerformingLayout, ScriptListener};
use servo_msg::constellation_msg::{ConstellationChan, IFrameSandboxed, IFrameUnsandboxed};
use servo_msg::constellation_msg::{LoadIframeUrlMsg, LoadCompleteMsg, LoadUrlMsg, NavigationDirection};
-use servo_msg::constellation_msg::{PipelineId, SubpageId};
+use servo_msg::constellation_msg::{PipelineId, SubpageId, Failure, FailureMsg};
use servo_msg::constellation_msg;
use servo_net::image_cache_task::ImageCacheTask;
use servo_net::resource_task::ResourceTask;
use servo_util::geometry::to_frac_px;
use servo_util::url::parse_url;
-use servo_util::task::spawn_named;
+use servo_util::task::send_on_failure;
use servo_util::namespace::Null;
use std::comm::{Port, SharedChan};
use std::ptr;
use std::str::eq_slice;
+use std::task;
use std::util::replace;
/// Messages used to control the script task.
@@ -463,10 +464,14 @@ impl ScriptTask {
port: Port<ScriptMsg>,
chan: ScriptChan,
constellation_chan: ConstellationChan,
+ failure_msg: Failure,
resource_task: ResourceTask,
image_cache_task: ImageCacheTask,
window_size: Size2D<uint>) {
- spawn_named("ScriptTask", proc() {
+ let mut builder = task::task();
+ send_on_failure(&mut builder, FailureMsg(failure_msg), (*constellation_chan).clone());
+ builder.name("ScriptTask");
+ builder.spawn(proc() {
let script_task = ScriptTask::new(id,
@compositor as @ScriptListener,
layout_chan,
diff --git a/src/components/util/task.rs b/src/components/util/task.rs
index 20dc2b6ad6f..49b22348dfa 100644
--- a/src/components/util/task.rs
+++ b/src/components/util/task.rs
@@ -3,9 +3,23 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use std::task;
+use std::comm::SharedChan;
+use std::task::TaskBuilder;
pub fn spawn_named<S: IntoSendStr>(name: S, f: proc()) {
let mut builder = task::task();
builder.name(name);
builder.spawn(f);
}
+
+/// Arrange to send a particular message to a channel if the task built by
+/// this `TaskBuilder` fails.
+pub fn send_on_failure<T: Send>(builder: &mut TaskBuilder, msg: T, dest: SharedChan<T>) {
+ let port = builder.future_result();
+ do spawn {
+ match port.recv() {
+ Ok(()) => (),
+ Err(..) => dest.send(msg),
+ }
+ }
+}
diff --git a/src/components/util/url.rs b/src/components/util/url.rs
index 5010c374769..6ef650a64cd 100644
--- a/src/components/util/url.rs
+++ b/src/components/util/url.rs
@@ -59,8 +59,11 @@ pub fn parse_url(str_url: &str, base_url: Option<Url>) -> Url {
match scheme.as_slice() {
"about" => {
match page.as_slice() {
+ "crash" => {
+ fail!("about:crash");
+ }
"failure" => {
- let mut path = os::getcwd();
+ let mut path = os::self_exe_path().expect("can't get exe path");
path.push("../src/test/html/failure.html");
// FIXME (#1094): not the right way to transform a path
~"file://" + path.display().to_str()
diff --git a/src/test/harness/reftest/reftest.rs b/src/test/harness/reftest/reftest.rs
index 9a55d3b1801..7f707978a1e 100644
--- a/src/test/harness/reftest/reftest.rs
+++ b/src/test/harness/reftest/reftest.rs
@@ -123,12 +123,12 @@ fn check_reftest(reftest: Reftest) {
let left_filename = format!("/tmp/servo-reftest-{:06u}-left.png", reftest.id);
let right_filename = format!("/tmp/servo-reftest-{:06u}-right.png", reftest.id);
- let args = ~[~"-o", left_filename.clone(), reftest.left.clone()];
+ let args = ~[~"-f", ~"-o", left_filename.clone(), reftest.left.clone()];
let mut process = Process::new("./servo", args, ProcessOptions::new()).unwrap();
let retval = process.finish();
assert!(retval == ExitStatus(0));
- let args = ~[~"-o", right_filename.clone(), reftest.right.clone()];
+ let args = ~[~"-f", ~"-o", right_filename.clone(), reftest.right.clone()];
let mut process = Process::new("./servo", args, ProcessOptions::new()).unwrap();
let retval = process.finish();
assert!(retval == ExitStatus(0));
diff --git a/src/test/html/summit-bad-page.html b/src/test/html/summit-bad-page.html
deleted file mode 100644
index 5ac3c134d99..00000000000
--- a/src/test/html/summit-bad-page.html
+++ /dev/null
@@ -1,13 +0,0 @@
-<!DOCTYPE html>
-<html>
- <head>
- <title>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>
diff --git a/src/test/html/summit-crash.html b/src/test/html/summit-crash.html
index 17702018b63..56360ef28c9 100644
--- a/src/test/html/summit-crash.html
+++ b/src/test/html/summit-crash.html
@@ -10,6 +10,6 @@
</style>
</head>
<body>
- <a href="summit-bad-page.html">here be dragons</a>
+ <a href="about:crash">here be dragons</a>
</body>
</html>