diff options
Diffstat (limited to 'components/msg')
-rw-r--r-- | components/msg/Cargo.toml | 3 | ||||
-rw-r--r-- | components/msg/constellation_msg.rs | 82 | ||||
-rw-r--r-- | components/msg/lib.rs | 2 |
3 files changed, 87 insertions, 0 deletions
diff --git a/components/msg/Cargo.toml b/components/msg/Cargo.toml index 5d8747bdfcf..0b5763ab641 100644 --- a/components/msg/Cargo.toml +++ b/components/msg/Cargo.toml @@ -13,8 +13,11 @@ test = false doctest = false [dependencies] +lazy_static = "1" +ipc-channel = "0.11" malloc_size_of = { path = "../malloc_size_of" } malloc_size_of_derive = "0.1" +parking_lot = "0.8" serde = "1.0.60" webrender_api = {git = "https://github.com/servo/webrender", features = ["ipc"]} diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index b8ba3c84e31..94370a56e2c 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -5,10 +5,13 @@ //! The high-level interface from script to constellation. Using this abstract interface helps //! reduce coupling between these two components. +use ipc_channel::ipc::{self, IpcReceiver, IpcSender}; +use parking_lot::Mutex; use std::cell::Cell; use std::fmt; use std::mem; use std::num::NonZeroU32; +use std::sync::Arc; use std::time::Duration; #[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)] @@ -17,12 +20,71 @@ pub enum TraversalDirection { Back(usize), } +#[derive(Debug, Deserialize, Serialize)] +/// Request a pipeline-namespace id from the constellation. +pub struct PipelineNamespaceRequest(pub IpcSender<PipelineNamespaceId>); + +/// A per-process installer of pipeline-namespaces. +pub struct PipelineNamespaceInstaller { + request_sender: Option<IpcSender<PipelineNamespaceRequest>>, + namespace_sender: IpcSender<PipelineNamespaceId>, + namespace_receiver: IpcReceiver<PipelineNamespaceId>, +} + +impl PipelineNamespaceInstaller { + pub fn new() -> Self { + let (namespace_sender, namespace_receiver) = + ipc::channel().expect("PipelineNamespaceInstaller ipc channel failure"); + PipelineNamespaceInstaller { + request_sender: None, + namespace_sender: namespace_sender, + namespace_receiver: namespace_receiver, + } + } + + /// Provide a request sender to send requests to the constellation. + pub fn set_sender(&mut self, sender: IpcSender<PipelineNamespaceRequest>) { + self.request_sender = Some(sender); + } + + /// Install a namespace, requesting a new Id from the constellation. + pub fn install_namespace(&self) { + match self.request_sender.as_ref() { + Some(sender) => { + let _ = sender.send(PipelineNamespaceRequest(self.namespace_sender.clone())); + let namespace_id = self + .namespace_receiver + .recv() + .expect("The constellation to make a pipeline namespace id available"); + PipelineNamespace::install(namespace_id); + }, + None => unreachable!("PipelineNamespaceInstaller should have a request_sender setup"), + } + } +} + +lazy_static! { + /// A per-process unique pipeline-namespace-installer. + /// Accessible via PipelineNamespace. + /// + /// Use PipelineNamespace::set_installer_sender to initiate with a sender to the constellation, + /// when a new process has been created. + /// + /// Use PipelineNamespace::fetch_install to install a unique pipeline-namespace from the calling thread. + static ref PIPELINE_NAMESPACE_INSTALLER: Arc<Mutex<PipelineNamespaceInstaller>> = + Arc::new(Mutex::new(PipelineNamespaceInstaller::new())); +} + /// Each pipeline ID needs to be unique. However, it also needs to be possible to /// generate the pipeline ID from an iframe element (this simplifies a lot of other /// code that makes use of pipeline IDs). /// /// To achieve this, each pipeline index belongs to a particular namespace. There is /// a namespace for the constellation thread, and also one for every script thread. +/// +/// A namespace can be installed for any other thread in a process +/// where an pipeline-installer has been initialized. +/// /// This allows pipeline IDs to be generated by any of those threads without conflicting /// with pipeline IDs created by other script threads or the constellation. The /// constellation is the only code that is responsible for creating new *namespaces*. @@ -39,6 +101,7 @@ pub struct PipelineNamespace { } impl PipelineNamespace { + /// Install a namespace for a given Id. pub fn install(namespace_id: PipelineNamespaceId) { PIPELINE_NAMESPACE.with(|tls| { assert!(tls.get().is_none()); @@ -49,6 +112,25 @@ impl PipelineNamespace { }); } + /// Setup the pipeline-namespace-installer, by providing it with a sender to the constellation. + /// Idempotent in single-process mode. + pub fn set_installer_sender(sender: IpcSender<PipelineNamespaceRequest>) { + PIPELINE_NAMESPACE_INSTALLER.lock().set_sender(sender); + } + + /// Install a namespace in the current thread, without requiring having a namespace Id ready. + /// Panics if called more than once per thread. + pub fn auto_install() { + // Note that holding the lock for the duration of the call is irrelevant to performance, + // since a thread would have to block on the ipc-response from the constellation, + // with the constellation already acting as a global lock on namespace ids, + // and only being able to handle one request at a time. + // + // Hence, any other thread attempting to concurrently install a namespace + // would have to wait for the current call to finish, regardless of the lock held here. + PIPELINE_NAMESPACE_INSTALLER.lock().install_namespace(); + } + fn next_index(&mut self) -> NonZeroU32 { self.index += 1; NonZeroU32::new(self.index).expect("pipeline id index wrapped!") diff --git a/components/msg/lib.rs b/components/msg/lib.rs index 6b5afe9ea13..4fe53230c46 100644 --- a/components/msg/lib.rs +++ b/components/msg/lib.rs @@ -5,6 +5,8 @@ #![deny(unsafe_code)] #[macro_use] +extern crate lazy_static; +#[macro_use] extern crate malloc_size_of; #[macro_use] extern crate malloc_size_of_derive; |