diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/compositing/compositor.rs | 116 | ||||
-rw-r--r-- | components/compositing/compositor_task.rs | 3 | ||||
-rw-r--r-- | components/compositing/constellation.rs | 25 | ||||
-rw-r--r-- | components/compositing/headless.rs | 1 | ||||
-rw-r--r-- | components/compositing/lib.rs | 2 | ||||
-rw-r--r-- | components/compositing/pipeline.rs | 20 | ||||
-rw-r--r-- | components/gfx/paint_task.rs | 57 | ||||
-rw-r--r-- | components/layout/layout_task.rs | 22 | ||||
-rw-r--r-- | components/layout_traits/lib.rs | 5 | ||||
-rw-r--r-- | components/msg/constellation_msg.rs | 7 | ||||
-rw-r--r-- | components/script/layout_interface.rs | 4 | ||||
-rw-r--r-- | components/script/script_task.rs | 18 | ||||
-rw-r--r-- | components/script_traits/lib.rs | 3 |
13 files changed, 180 insertions, 103 deletions
diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 0e5294ae2f3..71a37ddbc4f 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -129,6 +129,9 @@ pub struct IOCompositor<Window: WindowMethods> { /// Pending scroll events. pending_scroll_events: Vec<ScrollEvent>, + + /// PaintTask channels that we know about, used to return unused buffers. + paint_channels: HashMap<PipelineId, PaintChan>, } pub struct ScrollEvent { @@ -198,6 +201,7 @@ impl<Window: WindowMethods> IOCompositor<Window> { fragment_point: None, outstanding_paint_msgs: 0, last_composite_time: 0, + paint_channels: HashMap::new(), } } @@ -341,6 +345,12 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.window.set_cursor(cursor) } + (Msg::PaintTaskExited(pipeline_id), ShutdownState::NotShuttingDown) => { + if self.paint_channels.remove(&pipeline_id).is_none() { + panic!("Saw PaintTaskExited message from an unknown pipeline!"); + } + } + // When we are shutting_down, we need to avoid performing operations // such as Paint that may crash because we have begun tearing down // the rest of our resources. @@ -456,6 +466,38 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.composite_if_necessary(); } + fn create_root_layer_for_pipeline_and_rect(&mut self, + pipeline: &CompositionPipeline, + frame_rect: Option<TypedRect<PagePx, f32>>) + -> Rc<Layer<CompositorData>> { + let layer_properties = LayerProperties { + pipeline_id: pipeline.id, + epoch: Epoch(0), + id: LayerId::null(), + rect: Rect::zero(), + background_color: azure_hl::Color::new(0., 0., 0., 0.), + scroll_policy: Scrollable, + }; + + let root_layer = CompositorData::new_layer(pipeline.clone(), + layer_properties, + WantsScrollEventsFlag::WantsScrollEvents, + opts::get().tile_size); + if !self.paint_channels.contains_key(&pipeline.id) { + self.paint_channels.insert(pipeline.id, pipeline.paint_chan.clone()); + } + + // All root layers mask to bounds. + *root_layer.masks_to_bounds.borrow_mut() = true; + + if let Some(ref frame_rect) = frame_rect { + let frame_rect = frame_rect.to_untyped(); + *root_layer.bounds.borrow_mut() = Rect::from_untyped(&frame_rect); + } + + return root_layer; + } + fn create_frame_tree_root_layers(&mut self, frame_tree: &SendableFrameTree, frame_rect: Option<TypedRect<PagePx, f32>>) @@ -464,7 +506,8 @@ impl<Window: WindowMethods> IOCompositor<Window> { self.ready_states.insert(frame_tree.pipeline.id, Blank); self.paint_states.insert(frame_tree.pipeline.id, PaintingPaintState); - let root_layer = create_root_layer_for_pipeline_and_rect(&frame_tree.pipeline, frame_rect); + let root_layer = self.create_root_layer_for_pipeline_and_rect(&frame_tree.pipeline, + frame_rect); for kid in frame_tree.children.iter() { root_layer.add_child(self.create_frame_tree_root_layers(&kid.frame_tree, kid.rect)); } @@ -474,8 +517,8 @@ impl<Window: WindowMethods> IOCompositor<Window> { fn update_frame_tree(&mut self, frame_tree_diff: &FrameTreeDiff) { let parent_layer = self.find_pipeline_root_layer(frame_tree_diff.parent_pipeline.id); parent_layer.add_child( - create_root_layer_for_pipeline_and_rect(&frame_tree_diff.pipeline, - frame_tree_diff.rect)); + self.create_root_layer_for_pipeline_and_rect(&frame_tree_diff.pipeline, + frame_tree_diff.rect)); } fn find_pipeline_root_layer(&self, pipeline_id: PipelineId) -> Rc<Layer<CompositorData>> { @@ -614,6 +657,24 @@ impl<Window: WindowMethods> IOCompositor<Window> { layer_id: LayerId, new_layer_buffer_set: Box<LayerBufferSet>, epoch: Epoch) { + match self.find_layer_with_pipeline_and_layer_id(pipeline_id, layer_id) { + Some(layer) => self.paint_to_layer(layer, new_layer_buffer_set, epoch), + None => { + match self.paint_channels.entry(pipeline_id) { + Occupied(entry) => { + let message = UnusedBufferMsg(new_layer_buffer_set.buffers); + let _ = entry.get().send_opt(message); + }, + Vacant(_) => panic!("Received a buffer from an unknown pipeline!"), + } + } + } + } + + fn paint_to_layer(&mut self, + layer: Rc<Layer<CompositorData>>, + new_layer_buffer_set: Box<LayerBufferSet>, + epoch: Epoch) { debug!("compositor received new frame at size {}x{}", self.window_size.width.get(), self.window_size.height.get()); @@ -622,20 +683,10 @@ impl<Window: WindowMethods> IOCompositor<Window> { let mut new_layer_buffer_set = new_layer_buffer_set; new_layer_buffer_set.mark_will_leak(); - match self.find_layer_with_pipeline_and_layer_id(pipeline_id, layer_id) { - Some(ref layer) => { - // FIXME(pcwalton): This is going to cause problems with inconsistent frames since - // we only composite one layer at a time. - assert!(layer.add_buffers(new_layer_buffer_set, epoch)); - self.composite_if_necessary(); - } - None => { - // FIXME: This may potentially be triggered by a race condition where a - // buffers are being painted but the layer is removed before painting - // completes. - panic!("compositor given paint command for non-existent layer"); - } - } + // FIXME(pcwalton): This is going to cause problems with inconsistent frames since + // we only composite one layer at a time. + assert!(layer.add_buffers(new_layer_buffer_set, epoch)); + self.composite_if_necessary(); } fn scroll_fragment_to_point(&mut self, @@ -1196,37 +1247,6 @@ fn find_layer_with_pipeline_and_layer_id_for_layer(layer: Rc<Layer<CompositorDat return None; } -fn create_root_layer_for_pipeline_and_rect(pipeline: &CompositionPipeline, - frame_rect: Option<TypedRect<PagePx, f32>>) - -> Rc<Layer<CompositorData>> { - let layer_properties = LayerProperties { - pipeline_id: pipeline.id, - epoch: Epoch(0), - id: LayerId::null(), - rect: Rect::zero(), - background_color: azure_hl::Color::new(0., 0., 0., 0.), - scroll_policy: Scrollable, - }; - - let root_layer = CompositorData::new_layer(pipeline.clone(), - layer_properties, - WantsScrollEventsFlag::WantsScrollEvents, - opts::get().tile_size); - - // All root layers mask to bounds. - *root_layer.masks_to_bounds.borrow_mut() = true; - - match frame_rect { - Some(ref frame_rect) => { - let frame_rect = frame_rect.to_untyped(); - *root_layer.bounds.borrow_mut() = Rect::from_untyped(&frame_rect); - } - None => {} - } - - return root_layer; -} - impl<Window> CompositorEventListener for IOCompositor<Window> where Window: WindowMethods { fn handle_event(&mut self, msg: WindowEvent) -> bool { // Check for new messages coming from the other tasks in the system. diff --git a/components/compositing/compositor_task.rs b/components/compositing/compositor_task.rs index c8e8932b956..147bbe4b211 100644 --- a/components/compositing/compositor_task.rs +++ b/components/compositing/compositor_task.rs @@ -216,6 +216,8 @@ pub enum Msg { KeyEvent(Key, KeyModifiers), /// Changes the cursor. SetCursor(Cursor), + /// Informs the compositor that the paint task for the given pipeline has exited. + PaintTaskExited(PipelineId), } impl Show for Msg { @@ -240,6 +242,7 @@ impl Show for Msg { Msg::ScrollTimeout(..) => write!(f, "ScrollTimeout"), Msg::KeyEvent(..) => write!(f, "KeyEvent"), Msg::SetCursor(..) => write!(f, "SetCursor"), + Msg::PaintTaskExited(..) => write!(f, "PaintTaskExited"), } } } diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index 118f33bc3f3..6ec526d1b90 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -11,11 +11,10 @@ use devtools_traits::DevtoolsControlChan; use geom::rect::{Rect, TypedRect}; use geom::scale_factor::ScaleFactor; use gfx::font_cache_task::FontCacheTask; -use gfx::paint_task; use layers::geometry::DevicePixel; -use layout_traits::{LayoutControlChan, LayoutTaskFactory, ExitNowMsg}; +use layout_traits::LayoutTaskFactory; use libc; -use script_traits::{mod, GetTitleMsg, ResizeMsg, ResizeInactiveMsg, ExitPipelineMsg, SendEventMsg}; +use script_traits::{mod, GetTitleMsg, ResizeMsg, ResizeInactiveMsg, SendEventMsg}; use script_traits::{ScriptControlChan, ScriptTaskFactory}; use servo_msg::compositor_msg::LayerId; use servo_msg::constellation_msg::{mod, ConstellationChan, ExitMsg, FailureMsg, Failure}; @@ -23,7 +22,7 @@ use servo_msg::constellation_msg::{FrameRectMsg, GetPipelineTitleMsg}; use servo_msg::constellation_msg::{IFrameSandboxState, IFrameUnsandboxed, InitLoadUrlMsg}; use servo_msg::constellation_msg::{KeyEvent, Key, KeyState, KeyModifiers, LoadCompleteMsg}; use servo_msg::constellation_msg::{LoadData, LoadUrlMsg, NavigateMsg, NavigationType}; -use servo_msg::constellation_msg::{PainterReadyMsg, PipelineId, ResizedWindowMsg}; +use servo_msg::constellation_msg::{PainterReadyMsg, PipelineExitType, PipelineId, ResizedWindowMsg}; use servo_msg::constellation_msg::{ScriptLoadedURLInIFrameMsg, SetCursorMsg, SubpageId}; use servo_msg::constellation_msg::{WindowSizeData}; use servo_msg::constellation_msg::Msg as ConstellationMsg; @@ -515,7 +514,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { fn handle_exit(&mut self) { for (_id, ref pipeline) in self.pipelines.iter() { - pipeline.exit(); + pipeline.exit(PipelineExitType::Complete); } self.image_cache_task.exit(); self.resource_task.send(resource_task::Exit); @@ -547,14 +546,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { Some(pipeline) => pipeline.clone() }; - fn force_pipeline_exit(old_pipeline: &Rc<Pipeline>) { - let ScriptControlChan(ref old_script) = old_pipeline.script_chan; - let _ = old_script.send_opt(ExitPipelineMsg(old_pipeline.id)); - let _ = old_pipeline.paint_chan.send_opt(paint_task::ExitMsg(None)); - let LayoutControlChan(ref old_layout) = old_pipeline.layout_chan; - let _ = old_layout.send_opt(ExitNowMsg); - } - force_pipeline_exit(&old_pipeline); + old_pipeline.force_exit(); + self.compositor_proxy.send(CompositorMsg::PaintTaskExited(old_pipeline.id)); self.pipelines.remove(&pipeline_id); loop { @@ -564,7 +557,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { match idx { Some(idx) => { debug!("removing pending frame change for failed pipeline"); - force_pipeline_exit(&self.pending_frames[idx].after.pipeline); + self.pending_frames[idx].after.pipeline.force_exit(); + self.compositor_proxy.send(CompositorMsg::PaintTaskExited(old_pipeline.id)); self.pending_frames.remove(idx); }, None => break, @@ -987,7 +981,8 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> { // TODO(tkuehn): should only exit once per unique script task, // and then that script task will handle sub-exits for frame_tree in frame_tree.iter() { - frame_tree.pipeline.exit(); + frame_tree.pipeline.exit(PipelineExitType::PipelineOnly); + self.compositor_proxy.send(CompositorMsg::PaintTaskExited(frame_tree.pipeline.id)); self.pipelines.remove(&frame_tree.pipeline.id); } } diff --git a/components/compositing/headless.rs b/components/compositing/headless.rs index 9651ec7de78..e2ed207b274 100644 --- a/components/compositing/headless.rs +++ b/components/compositing/headless.rs @@ -111,6 +111,7 @@ impl CompositorEventListener for NullCompositor { Msg::ChangePageLoadData(..) | Msg::KeyEvent(..) | Msg::SetCursor(..) => {} + Msg::PaintTaskExited(..) => {} } true } diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index 4e906b83133..ea0405a3045 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -5,7 +5,7 @@ #![comment = "The Servo Parallel Browser Project"] #![license = "MPL"] -#![feature(globs, phase, macro_rules)] +#![feature(globs, phase, macro_rules, if_let)] #![deny(unused_imports)] #![deny(unused_variables)] diff --git a/components/compositing/pipeline.rs b/components/compositing/pipeline.rs index 6dd9dabb0bf..e90bf221e1d 100644 --- a/components/compositing/pipeline.rs +++ b/components/compositing/pipeline.rs @@ -3,15 +3,16 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use CompositorProxy; -use layout_traits::{LayoutTaskFactory, LayoutControlChan}; +use layout_traits::{ExitNowMsg, LayoutTaskFactory, LayoutControlChan}; use script_traits::{ScriptControlChan, ScriptTaskFactory}; use script_traits::{AttachLayoutMsg, LoadMsg, NewLayoutInfo, ExitPipelineMsg}; use devtools_traits::DevtoolsControlChan; +use gfx::paint_task; use gfx::paint_task::{PaintPermissionGranted, PaintPermissionRevoked}; use gfx::paint_task::{PaintChan, PaintTask}; -use servo_msg::constellation_msg::{ConstellationChan, Failure, PipelineId, SubpageId}; -use servo_msg::constellation_msg::{LoadData, WindowSizeData}; +use servo_msg::constellation_msg::{ConstellationChan, ExitMsg, Failure, PipelineId, SubpageId}; +use servo_msg::constellation_msg::{LoadData, WindowSizeData, PipelineExitType}; use servo_net::image_cache_task::ImageCacheTask; use gfx::font_cache_task::FontCacheTask; use servo_net::resource_task::ResourceTask; @@ -173,18 +174,27 @@ impl Pipeline { let _ = self.paint_chan.send_opt(PaintPermissionRevoked); } - pub fn exit(&self) { + pub fn exit(&self, exit_type: PipelineExitType) { debug!("pipeline {} exiting", self.id); // Script task handles shutting down layout, and layout handles shutting down the painter. // For now, if the script task has failed, we give up on clean shutdown. let ScriptControlChan(ref chan) = self.script_chan; - if chan.send_opt(ExitPipelineMsg(self.id)).is_ok() { + if chan.send_opt(ExitPipelineMsg(self.id, exit_type)).is_ok() { // 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 let _ = self.paint_shutdown_port.recv_opt(); let _ = self.layout_shutdown_port.recv_opt(); } + + } + + pub fn force_exit(&self) { + let ScriptControlChan(ref script_channel) = self.script_chan; + let _ = script_channel.send_opt( ExitPipelineMsg(self.id, PipelineExitType::PipelineOnly)); + let _ = self.paint_chan.send_opt(paint_task::ExitMsg(None, PipelineExitType::PipelineOnly)); + let LayoutControlChan(ref layout_channel) = self.layout_chan; + let _ = layout_channel.send_opt(ExitNowMsg(PipelineExitType::PipelineOnly)); } pub fn to_sendable(&self) -> CompositionPipeline { diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs index d5008bf355d..676e0ec5d6b 100644 --- a/components/gfx/paint_task.rs +++ b/components/gfx/paint_task.rs @@ -23,8 +23,8 @@ use layers; use native::task::NativeTaskBuilder; use servo_msg::compositor_msg::{Epoch, IdlePaintState, LayerId}; use servo_msg::compositor_msg::{LayerMetadata, PaintListener, PaintingPaintState, ScrollPolicy}; -use servo_msg::constellation_msg::{ConstellationChan, Failure, FailureMsg, PipelineId}; -use servo_msg::constellation_msg::{PainterReadyMsg}; +use servo_msg::constellation_msg::{ConstellationChan, Failure, FailureMsg, PipelineExitType}; +use servo_msg::constellation_msg::{PipelineId, PainterReadyMsg}; use servo_msg::platform::surface::NativeSurfaceAzureMethods; use servo_util::geometry::{Au, ZERO_POINT}; use servo_util::opts; @@ -73,7 +73,7 @@ pub enum Msg { UnusedBufferMsg(Vec<Box<LayerBuffer>>), PaintPermissionGranted, PaintPermissionRevoked, - ExitMsg(Option<Sender<()>>), + ExitMsg(Option<Sender<()>>, PipelineExitType), } #[deriving(Clone)] @@ -122,6 +122,10 @@ pub struct PaintTask<C> { /// Communication handles to each of the worker threads. worker_threads: Vec<WorkerThreadProxy>, + + /// Tracks the number of buffers that the compositor currently owns. The + /// PaintTask waits to exit until all buffers are returned. + used_buffer_count: uint, } // If we implement this as a function, we get borrowck errors from borrowing @@ -201,6 +205,7 @@ impl<C> PaintTask<C> where C: PaintListener + Send { epoch: Epoch(0), buffer_map: BufferMap::new(10000000), worker_threads: worker_threads, + used_buffer_count: 0, }; paint_task.start(); @@ -223,8 +228,10 @@ impl<C> PaintTask<C> where C: PaintListener + Send { } fn start(&mut self) { - debug!("paint_task: beginning painting loop"); + debug!("PaintTask: beginning painting loop"); + let mut exit_response_channel : Option<Sender<()>> = None; + let mut waiting_for_compositor_buffers_to_exit = false; loop { match self.port.recv() { Msg::PaintInitMsg(stacking_context) => { @@ -232,7 +239,7 @@ impl<C> PaintTask<C> where C: PaintListener + Send { self.root_stacking_context = Some(stacking_context.clone()); if !self.paint_permission { - debug!("paint_task: paint ready msg"); + debug!("PaintTask: paint ready msg"); let ConstellationChan(ref mut c) = self.constellation_chan; c.send(PainterReadyMsg(self.id)); continue; @@ -245,7 +252,7 @@ impl<C> PaintTask<C> where C: PaintListener + Send { } Msg::PaintMsg(requests) => { if !self.paint_permission { - debug!("paint_task: paint ready msg"); + debug!("PaintTask: paint ready msg"); let ConstellationChan(ref mut c) = self.constellation_chan; c.send(PainterReadyMsg(self.id)); self.compositor.paint_msg_discarded(); @@ -265,13 +272,27 @@ impl<C> PaintTask<C> where C: PaintListener + Send { self.compositor.set_paint_state(self.id, IdlePaintState); - debug!("paint_task: returning surfaces"); + for reply in replies.iter() { + let &(_, ref buffer_set) = reply; + self.used_buffer_count += (*buffer_set).buffers.len(); + } + + debug!("PaintTask: returning surfaces"); self.compositor.paint(self.id, self.epoch, replies); } Msg::UnusedBufferMsg(unused_buffers) => { + debug!("PaintTask: Received {} unused buffers", unused_buffers.len()); + self.used_buffer_count -= unused_buffers.len(); + for buffer in unused_buffers.into_iter().rev() { self.buffer_map.insert(native_graphics_context!(self), buffer); } + + if waiting_for_compositor_buffers_to_exit && self.used_buffer_count == 0 { + debug!("PaintTask: Received all loaned buffers, exiting."); + exit_response_channel.map(|channel| channel.send(())); + break; + } } Msg::PaintPermissionGranted => { self.paint_permission = true; @@ -290,10 +311,24 @@ impl<C> PaintTask<C> where C: PaintListener + Send { Msg::PaintPermissionRevoked => { self.paint_permission = false; } - Msg::ExitMsg(response_ch) => { - debug!("paint_task: exitmsg response send"); - response_ch.map(|ch| ch.send(())); - break; + Msg::ExitMsg(response_channel, exit_type) => { + let should_wait_for_compositor_buffers = match exit_type { + PipelineExitType::Complete => false, + PipelineExitType::PipelineOnly => self.used_buffer_count != 0 + }; + + if !should_wait_for_compositor_buffers { + debug!("PaintTask: Exiting without waiting for compositor buffers."); + response_channel.map(|channel| channel.send(())); + break; + } + + // If we own buffers in the compositor and we are not exiting completely, wait + // for the compositor to return buffers, so that we can release them properly. + // When doing a complete exit, the compositor lets all buffers leak. + println!("PaintTask: Saw ExitMsg, {} buffers in use", self.used_buffer_count); + waiting_for_compositor_buffers_to_exit = true; + exit_response_channel = response_channel; } } } diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index 2eeeb31409f..fae8dbb070a 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -42,8 +42,8 @@ use script::layout_interface::{Reflow, ReflowGoal, ScriptLayoutChan, TrustedNode use script_traits::{SendEventMsg, ReflowEvent, ReflowCompleteMsg, OpaqueScriptLayoutChannel}; use script_traits::{ScriptControlChan, UntrustedNodeAddress}; use servo_msg::compositor_msg::Scrollable; -use servo_msg::constellation_msg::{ConstellationChan, PipelineId, Failure, FailureMsg}; -use servo_msg::constellation_msg::{SetCursorMsg}; +use servo_msg::constellation_msg::{ConstellationChan, Failure, FailureMsg, PipelineExitType}; +use servo_msg::constellation_msg::{PipelineId, SetCursorMsg}; use servo_net::image_cache_task::{ImageCacheTask, ImageResponseMsg}; use servo_net::local_image_cache::{ImageResponder, LocalImageCache}; use servo_net::resource_task::{ResourceTask, load_bytes_iter}; @@ -343,8 +343,8 @@ impl LayoutTask { match port_to_read { PortToRead::Pipeline => { match self.pipeline_port.recv() { - layout_traits::ExitNowMsg => { - self.handle_script_request(Msg::ExitNow, possibly_locked_rw_data) + layout_traits::ExitNowMsg(exit_type) => { + self.handle_script_request(Msg::ExitNow(exit_type), possibly_locked_rw_data) } } }, @@ -411,9 +411,9 @@ impl LayoutTask { self.prepare_to_exit(response_chan, possibly_locked_rw_data); return false }, - Msg::ExitNow => { + Msg::ExitNow(exit_type) => { debug!("layout: ExitNowMsg received"); - self.exit_now(possibly_locked_rw_data); + self.exit_now(possibly_locked_rw_data, exit_type); return false } } @@ -435,9 +435,9 @@ impl LayoutTask { LayoutTask::handle_reap_layout_data(dead_layout_data) } } - Msg::ExitNow => { + Msg::ExitNow(exit_type) => { debug!("layout task is exiting..."); - self.exit_now(possibly_locked_rw_data); + self.exit_now(possibly_locked_rw_data, exit_type); break } _ => { @@ -450,7 +450,9 @@ impl LayoutTask { /// Shuts down the layout task now. If there are any DOM nodes left, layout will now (safely) /// crash. - fn exit_now<'a>(&'a self, possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>) { + fn exit_now<'a>(&'a self, + possibly_locked_rw_data: &mut Option<MutexGuard<'a, LayoutTaskData>>, + exit_type: PipelineExitType) { let (response_chan, response_port) = channel(); { @@ -462,7 +464,7 @@ impl LayoutTask { LayoutTask::return_rw_data(possibly_locked_rw_data, rw_data); } - self.paint_chan.send(paint_task::ExitMsg(Some(response_chan))); + self.paint_chan.send(paint_task::ExitMsg(Some(response_chan), exit_type)); response_port.recv() } diff --git a/components/layout_traits/lib.rs b/components/layout_traits/lib.rs index 229791ff928..acc5587ab5a 100644 --- a/components/layout_traits/lib.rs +++ b/components/layout_traits/lib.rs @@ -21,8 +21,7 @@ extern crate "util" as servo_util; use gfx::font_cache_task::FontCacheTask; use gfx::paint_task::PaintChan; -use servo_msg::constellation_msg::{ConstellationChan, PipelineId}; -use servo_msg::constellation_msg::Failure; +use servo_msg::constellation_msg::{ConstellationChan, Failure, PipelineId, PipelineExitType}; use servo_net::image_cache_task::ImageCacheTask; use servo_net::resource_task::ResourceTask; use servo_util::time::TimeProfilerChan; @@ -31,7 +30,7 @@ use std::comm::Sender; /// Messages sent to the layout task from the constellation pub enum LayoutControlMsg { - ExitNowMsg, + ExitNowMsg(PipelineExitType), } /// A channel wrapper for constellation messages diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index 78cda641aef..e9e69c669c7 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -253,3 +253,10 @@ pub struct PipelineId(pub uint); #[deriving(Clone, PartialEq, Eq, Hash, Show)] pub struct SubpageId(pub uint); + +// The type of pipeline exit. During complete shutdowns, pipelines do not have to +// release resources automatically released on process termination. +pub enum PipelineExitType { + PipelineOnly, + Complete, +} diff --git a/components/script/layout_interface.rs b/components/script/layout_interface.rs index b19e789a4ed..2856930b073 100644 --- a/components/script/layout_interface.rs +++ b/components/script/layout_interface.rs @@ -11,7 +11,7 @@ use dom::node::LayoutDataRef; use geom::point::Point2D; use geom::rect::Rect; use script_traits::{ScriptControlChan, OpaqueScriptLayoutChannel, UntrustedNodeAddress}; -use servo_msg::constellation_msg::WindowSizeData; +use servo_msg::constellation_msg::{PipelineExitType, WindowSizeData}; use servo_util::geometry::Au; use std::any::{Any, AnyRefExt}; use std::comm::{channel, Receiver, Sender}; @@ -50,7 +50,7 @@ pub enum Msg { /// Requests that the layout task immediately shut down. There must be no more nodes left after /// this, or layout will crash. - ExitNow, + ExitNow(PipelineExitType), } /// Synchronous messages that script can send to layout. diff --git a/components/script/script_task.rs b/components/script/script_task.rs index 918d776c59f..4840dab2a3b 100644 --- a/components/script/script_task.rs +++ b/components/script/script_task.rs @@ -50,6 +50,7 @@ use servo_msg::constellation_msg::{LoadData, LoadUrlMsg, NavigationDirection, Pi use servo_msg::constellation_msg::{Failure, FailureMsg, WindowSizeData, Key, KeyState}; use servo_msg::constellation_msg::{KeyModifiers, SUPER, SHIFT, CONTROL, ALT, Repeated, Pressed}; use servo_msg::constellation_msg::{Released}; +use servo_msg::constellation_msg::{PipelineExitType}; use servo_msg::constellation_msg; use servo_net::image_cache_task::ImageCacheTask; use servo_net::resource_task::{ResourceTask, Load}; @@ -545,8 +546,11 @@ impl ScriptTask { // Process the gathered events. for msg in sequential.into_iter() { match msg { - MixedMessage::FromConstellation(ExitPipelineMsg(id)) => - if self.handle_exit_pipeline_msg(id) { return false }, + MixedMessage::FromConstellation(ExitPipelineMsg(id, exit_type)) => { + if self.handle_exit_pipeline_msg(id, exit_type) { + return false + } + }, MixedMessage::FromConstellation(inner_msg) => self.handle_msg_from_constellation(inner_msg), MixedMessage::FromScript(inner_msg) => self.handle_msg_from_script(inner_msg), MixedMessage::FromDevtools(inner_msg) => self.handle_msg_from_devtools(inner_msg), @@ -713,20 +717,20 @@ impl ScriptTask { /// Handles a request to exit the script task and shut down layout. /// Returns true if the script task should shut down and false otherwise. - fn handle_exit_pipeline_msg(&self, id: PipelineId) -> bool { + fn handle_exit_pipeline_msg(&self, id: PipelineId, exit_type: PipelineExitType) -> bool { // If root is being exited, shut down all pages let page = self.page.borrow_mut(); if page.id == id { debug!("shutting down layout for root page {}", id); *self.js_context.borrow_mut() = None; - shut_down_layout(&*page, (*self.js_runtime).ptr); + shut_down_layout(&*page, (*self.js_runtime).ptr, exit_type); return true } // otherwise find just the matching page and exit all sub-pages match page.remove(id) { Some(ref mut page) => { - shut_down_layout(&*page, (*self.js_runtime).ptr); + shut_down_layout(&*page, (*self.js_runtime).ptr, exit_type); false } // TODO(tkuehn): pipeline closing is currently duplicated across @@ -1261,7 +1265,7 @@ impl ScriptTask { } /// Shuts down layout for the given page tree. -fn shut_down_layout(page_tree: &Rc<Page>, rt: *mut JSRuntime) { +fn shut_down_layout(page_tree: &Rc<Page>, rt: *mut JSRuntime, exit_type: PipelineExitType) { for page in page_tree.iter() { // Tell the layout task to begin shutting down, and wait until it // processed this message. @@ -1290,7 +1294,7 @@ fn shut_down_layout(page_tree: &Rc<Page>, rt: *mut JSRuntime) { // Destroy the layout task. If there were node leaks, layout will now crash safely. for page in page_tree.iter() { let LayoutChan(ref chan) = page.layout_chan; - chan.send(layout_interface::Msg::ExitNow); + chan.send(layout_interface::Msg::ExitNow(exit_type)); } } diff --git a/components/script_traits/lib.rs b/components/script_traits/lib.rs index 59a1447a75a..ada4ba7cfbf 100644 --- a/components/script_traits/lib.rs +++ b/components/script_traits/lib.rs @@ -26,6 +26,7 @@ use devtools_traits::DevtoolsControlChan; use libc::c_void; use servo_msg::constellation_msg::{ConstellationChan, PipelineId, Failure, WindowSizeData}; use servo_msg::constellation_msg::{LoadData, SubpageId, Key, KeyState, KeyModifiers}; +use servo_msg::constellation_msg::PipelineExitType; use servo_msg::compositor_msg::ScriptListener; use servo_net::image_cache_task::ImageCacheTask; use servo_net::resource_task::ResourceTask; @@ -60,7 +61,7 @@ pub enum ConstellationControlMsg { /// Notifies script that window has been resized but to not take immediate action. ResizeInactiveMsg(PipelineId, WindowSizeData), /// Notifies the script that a pipeline should be closed. - ExitPipelineMsg(PipelineId), + ExitPipelineMsg(PipelineId, PipelineExitType), /// Sends a DOM event. SendEventMsg(PipelineId, CompositorEvent), /// Notifies script that reflow is finished. |