From e945e38a2d1d8ced73d553a707b1f0659858d1f9 Mon Sep 17 00:00:00 2001 From: Alan Jeffrey Date: Thu, 17 Nov 2016 08:38:55 -0600 Subject: [PATCH] Renamed ScriptChan in constellation to EventLoop. --- components/constellation/constellation.rs | 91 +++++++++-------------- components/constellation/event_loop.rs | 46 ++++++++++++ components/constellation/lib.rs | 1 + components/constellation/pipeline.rs | 39 +++++----- 4 files changed, 100 insertions(+), 77 deletions(-) create mode 100644 components/constellation/event_loop.rs diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 2e6b5071d41..b19523a3194 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -21,6 +21,7 @@ use debugger; use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg}; use euclid::scale_factor::ScaleFactor; use euclid::size::{Size2D, TypedSize2D}; +use event_loop::EventLoop; use gfx::font_cache_thread::FontCacheThread; use gfx_traits::Epoch; use ipc_channel::ipc::{self, IpcSender}; @@ -134,10 +135,10 @@ pub struct Constellation { /// to receive sw manager message swmanager_receiver: Receiver, - /// A map from top-level frame id and registered domain name to script channels. - /// This double indirection ensures that separate tabs do not share script threads, + /// A map from top-level frame id and registered domain name to event loops. + /// This double indirection ensures that separate tabs do not share event loops, /// even if the same domain is loaded in each. - script_channels: HashMap>>, + event_loops: HashMap>>, /// A list of all the pipelines. (See the `pipeline` module for more details.) pipelines: HashMap, @@ -368,30 +369,6 @@ enum ExitPipelineMode { Force, } -/// A script channel, that closes the script thread down when it is dropped -pub struct ScriptChan { - chan: IpcSender, - dont_send_or_sync: PhantomData>, -} - -impl Drop for ScriptChan { - fn drop(&mut self) { - let _ = self.chan.send(ConstellationControlMsg::ExitScriptThread); - } -} - -impl ScriptChan { - pub fn send(&self, msg: ConstellationControlMsg) -> Result<(), IOError> { - self.chan.send(msg) - } - pub fn new(chan: IpcSender) -> Rc { - Rc::new(ScriptChan { chan: chan, dont_send_or_sync: PhantomData }) - } - pub fn sender(&self) -> IpcSender { - self.chan.clone() - } -} - /// A logger directed at the constellation from content processes #[derive(Clone)] pub struct FromScriptLogger { @@ -533,7 +510,7 @@ impl Constellation swmanager_chan: None, swmanager_receiver: swmanager_receiver, swmanager_sender: sw_mgr_clone, - script_channels: HashMap::new(), + event_loops: HashMap::new(), pipelines: HashMap::new(), frames: HashMap::new(), pending_frames: vec!(), @@ -608,17 +585,17 @@ impl Constellation None => self.root_frame_id, }; - let (script_channel, host) = match sandbox { + let (event_loop, host) = match sandbox { IFrameSandboxState::IFrameSandboxed => (None, None), IFrameSandboxState::IFrameUnsandboxed => match reg_host(&load_data.url) { None => (None, None), Some(host) => { - let script_channel = self.script_channels.get(&top_level_frame_id) + let event_loop = self.event_loops.get(&top_level_frame_id) .and_then(|map| map.get(host)) .and_then(|weak| weak.upgrade()); - match script_channel { + match event_loop { None => (None, Some(String::from(host))), - Some(script_channel) => (Some(script_channel.clone()), None), + Some(event_loop) => (Some(event_loop.clone()), None), } }, }, @@ -665,7 +642,7 @@ impl Constellation time_profiler_chan: self.time_profiler_chan.clone(), mem_profiler_chan: self.mem_profiler_chan.clone(), window_size: initial_window_size, - script_chan: script_channel, + event_loop: event_loop, load_data: load_data, device_pixel_ratio: self.window_size.device_pixel_ratio, pipeline_namespace_id: self.next_pipeline_namespace_id(), @@ -680,9 +657,9 @@ impl Constellation }; if let Some(host) = host { - self.script_channels.entry(top_level_frame_id) + self.event_loops.entry(top_level_frame_id) .or_insert_with(HashMap::new) - .insert(host, Rc::downgrade(&pipeline.script_chan)); + .insert(host, Rc::downgrade(&pipeline.event_loop)); } assert!(!self.pipelines.contains_key(&pipeline_id)); @@ -970,7 +947,7 @@ impl Constellation let msg = ConstellationControlMsg::SendEvent(pipeline_id, event); let result = match self.pipelines.get(&pipeline_id) { None => { debug!("Pipeline {:?} got event after closure.", pipeline_id); return; } - Some(pipeline) => pipeline.script_chan.send(msg), + Some(pipeline) => pipeline.event_loop.send(msg), }; if let Err(e) = result { self.handle_send_error(pipeline_id, e); @@ -1118,7 +1095,7 @@ impl Constellation let msg = ConstellationControlMsg::DispatchStorageEvent( pipeline.id, storage, url.clone(), key.clone(), old_value.clone(), new_value.clone() ); - if let Err(err) = pipeline.script_chan.send(msg) { + if let Err(err) = pipeline.event_loop.send(msg) { warn!("Failed to broadcast storage event to pipeline {} ({:?}).", pipeline.id, err); } } @@ -1327,7 +1304,7 @@ impl Constellation match self.pipelines.get_mut(&pipeline_id) { Some(pipeline) => { pipeline.size = Some(*size); - pipeline.script_chan.send(msg) + pipeline.event_loop.send(msg) } None => return, } @@ -1352,7 +1329,7 @@ impl Constellation child: pipeline_id, }; let result = match self.pipelines.get(&parent_id) { - Some(parent) => parent.script_chan.send(msg), + Some(parent) => parent.event_loop.send(msg), None => return warn!("Parent {} frame loaded after closure.", parent_id), }; if let Err(e) = result { @@ -1432,7 +1409,7 @@ impl Constellation None => return warn!("Script loaded url in closed iframe {}.", parent_pipeline_id), }; - let script_sender = parent_pipeline.script_chan.clone(); + let script_sender = parent_pipeline.event_loop.clone(); let url = ServoUrl::parse("about:blank").expect("infallible"); Pipeline::new(new_pipeline_id, @@ -1475,7 +1452,7 @@ impl Constellation AnimationTickType::Script => { let msg = ConstellationControlMsg::TickAllAnimations(pipeline_id); match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.script_chan.send(msg), + Some(pipeline) => pipeline.event_loop.send(msg), None => return warn!("Pipeline {:?} got script tick after closure.", pipeline_id), } } @@ -1548,7 +1525,7 @@ impl Constellation // and issue an iframe load through there. let msg = ConstellationControlMsg::Navigate(parent_pipeline_id, frame_id, load_data, replace); let result = match self.pipelines.get(&parent_pipeline_id) { - Some(parent_pipeline) => parent_pipeline.script_chan.send(msg), + Some(parent_pipeline) => parent_pipeline.event_loop.send(msg), None => { warn!("Pipeline {:?} child loaded after closure", parent_pipeline_id); return None; @@ -1694,7 +1671,7 @@ impl Constellation let event = CompositorEvent::KeyEvent(ch, key, state, mods); let msg = ConstellationControlMsg::SendEvent(pipeline_id, event); let result = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.script_chan.send(msg), + Some(pipeline) => pipeline.event_loop.send(msg), None => return debug!("Pipeline {:?} got key event after closure.", pipeline_id), }; if let Err(e) = result { @@ -1716,7 +1693,7 @@ impl Constellation if let Some(pipeline_id) = root_pipeline_id { let msg = ConstellationControlMsg::Reload(pipeline_id); let result = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.script_chan.send(msg), + Some(pipeline) => pipeline.event_loop.send(msg), None => return debug!("Pipeline {:?} got reload event after closure.", pipeline_id), }; if let Err(e) = result { @@ -1728,7 +1705,7 @@ impl Constellation fn handle_get_pipeline_title_msg(&mut self, pipeline_id: PipelineId) { let result = match self.pipelines.get(&pipeline_id) { None => return self.compositor_proxy.send(ToCompositorMsg::ChangePageTitle(pipeline_id, None)), - Some(pipeline) => pipeline.script_chan.send(ConstellationControlMsg::GetTitle(pipeline_id)), + Some(pipeline) => pipeline.event_loop.send(ConstellationControlMsg::GetTitle(pipeline_id)), }; if let Err(e) = result { self.handle_send_error(pipeline_id, e); @@ -1791,7 +1768,7 @@ impl Constellation // telling it to mark the iframe element as focused. let msg = ConstellationControlMsg::FocusIFrame(parent_pipeline_id, frame_id); let result = match self.pipelines.get(&parent_pipeline_id) { - Some(pipeline) => pipeline.script_chan.send(msg), + Some(pipeline) => pipeline.event_loop.send(msg), None => return warn!("Pipeline {:?} focus after closure.", parent_pipeline_id), }; if let Err(e) = result { @@ -1853,7 +1830,7 @@ impl Constellation visibility); let result = match self.pipelines.get(&parent_pipeline_id) { None => return warn!("Parent pipeline {:?} closed", parent_pipeline_id), - Some(parent_pipeline) => parent_pipeline.script_chan.send(visibility_msg), + Some(parent_pipeline) => parent_pipeline.event_loop.send(visibility_msg), }; if let Err(e) = result { @@ -1911,7 +1888,7 @@ impl Constellation WebDriverCommandMsg::ScriptCommand(pipeline_id, cmd) => { let control_msg = ConstellationControlMsg::WebDriverScriptCommand(pipeline_id, cmd); let result = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.script_chan.send(control_msg), + Some(pipeline) => pipeline.event_loop.send(control_msg), None => return warn!("Pipeline {:?} ScriptCommand after closure.", pipeline_id), }; if let Err(e) = result { @@ -1919,14 +1896,14 @@ impl Constellation } }, WebDriverCommandMsg::SendKeys(pipeline_id, cmd) => { - let script_channel = match self.pipelines.get(&pipeline_id) { - Some(pipeline) => pipeline.script_chan.clone(), + let event_loop = match self.pipelines.get(&pipeline_id) { + Some(pipeline) => pipeline.event_loop.clone(), None => return warn!("Pipeline {:?} SendKeys after closure.", pipeline_id), }; for (key, mods, state) in cmd { let event = CompositorEvent::KeyEvent(None, key, state, mods); let control_msg = ConstellationControlMsg::SendEvent(pipeline_id, event); - if let Err(e) = script_channel.send(control_msg) { + if let Err(e) = event_loop.send(control_msg) { return self.handle_send_error(pipeline_id, e); } } @@ -2015,7 +1992,7 @@ impl Constellation next_pipeline_id); let result = match self.pipelines.get(&parent_pipeline_id) { None => return warn!("Pipeline {:?} child traversed after closure.", parent_pipeline_id), - Some(pipeline) => pipeline.script_chan.send(msg), + Some(pipeline) => pipeline.event_loop.send(msg), }; if let Err(e) = result { self.handle_send_error(parent_pipeline_id, e); @@ -2112,7 +2089,7 @@ impl Constellation if let Some((parent_pipeline_id, _)) = pipeline.parent_info { if let Some(parent_pipeline) = self.pipelines.get(&parent_pipeline_id) { let msg = ConstellationControlMsg::FramedContentChanged(parent_pipeline_id, pipeline.frame_id); - let _ = parent_pipeline.script_chan.send(msg); + let _ = parent_pipeline.event_loop.send(msg); } } } @@ -2143,7 +2120,7 @@ impl Constellation None => return warn!("Pipeline {:?} resized after closing.", pipeline_id), Some(pipeline) => pipeline, }; - let _ = pipeline.script_chan.send(ConstellationControlMsg::Resize( + let _ = pipeline.event_loop.send(ConstellationControlMsg::Resize( pipeline.id, new_size, size_type @@ -2156,7 +2133,7 @@ impl Constellation }, Some(pipeline) => pipeline, }; - let _ = pipeline.script_chan.send(ConstellationControlMsg::ResizeInactive( + let _ = pipeline.event_loop.send(ConstellationControlMsg::ResizeInactive( pipeline.id, new_size )); @@ -2171,7 +2148,7 @@ impl Constellation Some(pipeline) => pipeline, }; if pipeline.parent_info.is_none() { - let _ = pipeline.script_chan.send(ConstellationControlMsg::Resize( + let _ = pipeline.event_loop.send(ConstellationControlMsg::Resize( pipeline.id, new_size, size_type @@ -2340,7 +2317,7 @@ impl Constellation self.close_frame_children(frame_id, exit_mode); - self.script_channels.remove(&frame_id); + self.event_loops.remove(&frame_id); if self.frames.remove(&frame_id).is_none() { warn!("Closing frame {:?} twice.", frame_id); } diff --git a/components/constellation/event_loop.rs b/components/constellation/event_loop.rs new file mode 100644 index 00000000000..476df9e91ae --- /dev/null +++ b/components/constellation/event_loop.rs @@ -0,0 +1,46 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! This module contains the `EventLoop` type, which is the constellation's +//! view of a script thread. When an `EventLoop` is dropped, an `ExitScriptThread` +//! message is sent to the script thread, asking it to shut down. + +use ipc_channel::ipc::IpcSender; +use script_traits::ConstellationControlMsg; +use std::io::Error as IOError; +use std::marker::PhantomData; +use std::rc::Rc; + +/// https://html.spec.whatwg.org/multipage/#event-loop +pub struct EventLoop { + script_chan: IpcSender, + dont_send_or_sync: PhantomData>, +} + +impl Drop for EventLoop { + fn drop(&mut self) { + let _ = self.script_chan.send(ConstellationControlMsg::ExitScriptThread); + } +} + +impl EventLoop { + /// Create a new event loop from the channel to its script thread. + pub fn new(script_chan: IpcSender) -> Rc { + Rc::new(EventLoop { + script_chan: script_chan, + dont_send_or_sync: PhantomData, + }) + } + + /// Send a message to the event loop. + pub fn send(&self, msg: ConstellationControlMsg) -> Result<(), IOError> { + self.script_chan.send(msg) + } + + /// The underlying channel to the script thread. + pub fn sender(&self) -> IpcSender { + self.script_chan.clone() + } +} + diff --git a/components/constellation/lib.rs b/components/constellation/lib.rs index 7d455d954b2..f4aef725c16 100644 --- a/components/constellation/lib.rs +++ b/components/constellation/lib.rs @@ -43,6 +43,7 @@ extern crate util; extern crate webrender_traits; mod constellation; +mod event_loop; mod pipeline; #[cfg(not(target_os = "windows"))] mod sandboxing; diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index 9784a68d57d..31debe4be34 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -6,10 +6,10 @@ use bluetooth_traits::BluetoothRequest; use compositing::CompositionPipeline; use compositing::CompositorProxy; use compositing::compositor_thread::Msg as CompositorMsg; -use constellation::ScriptChan; use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg}; use euclid::scale_factor::ScaleFactor; use euclid::size::TypedSize2D; +use event_loop::EventLoop; use gfx::font_cache_thread::FontCacheThread; use gfx_traits::DevicePixel; use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; @@ -43,7 +43,7 @@ pub struct Pipeline { /// The ID of the frame that contains this Pipeline. pub frame_id: FrameId, pub parent_info: Option<(PipelineId, FrameType)>, - pub script_chan: Rc, + pub event_loop: Rc, /// A channel to layout, for performing reflows and shutdown. pub layout_chan: IpcSender, /// A channel to the compositor. @@ -106,10 +106,9 @@ pub struct InitialPipelineState { pub window_size: Option>, /// Information about the device pixel ratio. pub device_pixel_ratio: ScaleFactor, - /// A channel to the script thread, if applicable. - /// If this is `None`, create a new script thread. - /// If this is `Some`, then reuse an existing script thread. - pub script_chan: Option>, + /// The event loop to run in, if applicable. If this is `Some`, + /// then `parent_info` must also be `Some`. + pub event_loop: Option>, /// Information about the page to load. pub load_data: LoadData, /// The ID of the pipeline namespace for this script thread. @@ -146,7 +145,7 @@ impl Pipeline { } }); - let (script_chan, content_ports) = match state.script_chan { + let (script_chan, content_ports) = match state.event_loop { Some(script_chan) => { let new_layout_info = NewLayoutInfo { parent_info: state.parent_info, @@ -166,7 +165,7 @@ impl Pipeline { } None => { let (script_chan, script_port) = ipc::channel().expect("Pipeline script chan"); - (ScriptChan::new(script_chan), Some((script_port, pipeline_port))) + (EventLoop::new(script_chan), Some((script_port, pipeline_port))) } }; @@ -248,7 +247,7 @@ impl Pipeline { pub fn new(id: PipelineId, frame_id: FrameId, parent_info: Option<(PipelineId, FrameType)>, - script_chan: Rc, + event_loop: Rc, layout_chan: IpcSender, compositor_proxy: Box, is_private: bool, @@ -260,7 +259,7 @@ impl Pipeline { id: id, frame_id: frame_id, parent_info: parent_info, - script_chan: script_chan, + event_loop: event_loop, layout_chan: layout_chan, compositor_proxy: compositor_proxy, url: url, @@ -294,25 +293,25 @@ impl Pipeline { // Script thread handles shutting down layout, and layout handles shutting down the painter. // For now, if the script thread has failed, we give up on clean shutdown. - if let Err(e) = self.script_chan.send(ConstellationControlMsg::ExitPipeline(self.id)) { + if let Err(e) = self.event_loop.send(ConstellationControlMsg::ExitPipeline(self.id)) { warn!("Sending script exit message failed ({}).", e); } } pub fn freeze(&self) { - if let Err(e) = self.script_chan.send(ConstellationControlMsg::Freeze(self.id)) { + if let Err(e) = self.event_loop.send(ConstellationControlMsg::Freeze(self.id)) { warn!("Sending freeze message failed ({}).", e); } } pub fn thaw(&self) { - if let Err(e) = self.script_chan.send(ConstellationControlMsg::Thaw(self.id)) { + if let Err(e) = self.event_loop.send(ConstellationControlMsg::Thaw(self.id)) { warn!("Sending freeze message failed ({}).", e); } } pub fn force_exit(&self) { - if let Err(e) = self.script_chan.send(ConstellationControlMsg::ExitPipeline(self.id)) { + if let Err(e) = self.event_loop.send(ConstellationControlMsg::ExitPipeline(self.id)) { warn!("Sending script exit message failed ({}).", e); } if let Err(e) = self.layout_chan.send(LayoutControlMsg::ExitNow) { @@ -323,7 +322,7 @@ impl Pipeline { pub fn to_sendable(&self) -> CompositionPipeline { CompositionPipeline { id: self.id.clone(), - script_chan: self.script_chan.sender(), + script_chan: self.event_loop.sender(), layout_chan: self.layout_chan.clone(), } } @@ -347,16 +346,16 @@ impl Pipeline { let event = ConstellationControlMsg::MozBrowserEvent(self.id, child_id, event); - if let Err(e) = self.script_chan.send(event) { + if let Err(e) = self.event_loop.send(event) { warn!("Sending mozbrowser event to script failed ({}).", e); } } fn notify_visibility(&self) { - self.script_chan.send(ConstellationControlMsg::ChangeFrameVisibilityStatus(self.id, self.visible)) - .expect("Pipeline script chan"); - - self.compositor_proxy.send(CompositorMsg::PipelineVisibilityChanged(self.id, self.visible)); + let script_msg = ConstellationControlMsg::ChangeFrameVisibilityStatus(self.id, self.visible); + let compositor_msg = CompositorMsg::PipelineVisibilityChanged(self.id, self.visible); + self.event_loop.send(script_msg).expect("Pipeline script chan"); + self.compositor_proxy.send(compositor_msg); } pub fn change_visibility(&mut self, visible: bool) {