diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/components/gfx/render_task.rs | 14 | ||||
-rw-r--r-- | src/components/main/compositing/compositor.rs | 2 | ||||
-rw-r--r-- | src/components/main/compositing/compositor_layer.rs | 20 | ||||
-rw-r--r-- | src/components/main/constellation.rs | 51 | ||||
-rw-r--r-- | src/components/main/layout/layout_task.rs | 13 | ||||
-rw-r--r-- | src/components/main/pipeline.rs | 32 | ||||
-rw-r--r-- | src/components/msg/constellation_msg.rs | 9 | ||||
-rw-r--r-- | src/components/script/script_task.rs | 11 | ||||
-rw-r--r-- | src/components/util/task.rs | 14 | ||||
-rw-r--r-- | src/components/util/url.rs | 5 | ||||
-rw-r--r-- | src/test/harness/reftest/reftest.rs | 4 | ||||
-rw-r--r-- | src/test/html/summit-bad-page.html | 13 | ||||
-rw-r--r-- | src/test/html/summit-crash.html | 2 |
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> |