Skip to content
Permalink
Browse files

Auto merge of #23934 - gterzian:add_process_name_space, r=<try>

Introduce a process namespace

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: -->
- [ ] `./mach build -d` does not report any errors
- [ ] `./mach test-tidy` does not report any errors
- [ ] These changes fix #23932 (GitHub issue number if applicable)

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because ___

<!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.-->

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/23934)
<!-- Reviewable:end -->
  • Loading branch information...
bors-servo committed Aug 13, 2019
2 parents 9b24798 + b103e9d commit 0ca1d0f2eeca84413b0b7dfb1cef904c39d21b8d

Some generated files are not rendered by default. Learn more.

@@ -129,7 +129,9 @@ use msg::constellation_msg::{
BrowsingContextGroupId, BrowsingContextId, HistoryStateId, PipelineId,
TopLevelBrowsingContextId,
};
use msg::constellation_msg::{PipelineNamespace, PipelineNamespaceId, TraversalDirection};
use msg::constellation_msg::{
PipelineNamespace, PipelineNamespaceId, PipelineNamespaceRequest, TraversalDirection,
};
use net_traits::pub_domains::reg_host;
use net_traits::request::RequestBuilder;
use net_traits::storage_thread::{StorageThreadMsg, StorageType};
@@ -217,6 +219,12 @@ struct BrowsingContextGroup {
/// the `script` crate). Script and layout communicate using a `Message`
/// type.
pub struct Constellation<Message, LTF, STF> {
/// An ipc-sender/threaded-receiver pair
/// to facilitate installing pipeline namespaces in threads
/// via a per-process installer.
namespace_receiver: Receiver<Result<PipelineNamespaceRequest, IpcError>>,
namespace_sender: IpcSender<PipelineNamespaceRequest>,

/// An IPC channel for script threads to send messages to the constellation.
/// This is the script threads' view of `script_receiver`.
script_sender: IpcSender<(PipelineId, FromScriptMsg)>,
@@ -672,6 +680,12 @@ where
let script_receiver =
route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(ipc_script_receiver);

let (namespace_sender, ipc_namespace_receiver) =
ipc::channel().expect("ipc channel failure");
let namespace_receiver = route_ipc_receiver_to_new_mpsc_receiver_preserving_errors(
ipc_namespace_receiver,
);

let (background_hang_monitor_sender, ipc_bhm_receiver) =
ipc::channel().expect("ipc channel failure");
let background_hang_monitor_receiver =
@@ -709,6 +723,8 @@ where
PipelineNamespace::install(PipelineNamespaceId(1));

let mut constellation: Constellation<Message, LTF, STF> = Constellation {
namespace_receiver,
namespace_sender,
script_sender: ipc_script_sender,
background_hang_monitor_sender,
background_hang_monitor_receiver,
@@ -987,6 +1003,7 @@ where
sender: self.script_sender.clone(),
pipeline_id: pipeline_id,
},
namespace_request_sender: self.namespace_sender.clone(),
background_monitor_register: self.background_monitor_register.clone(),
background_hang_monitor_to_constellation_chan: self
.background_hang_monitor_sender
@@ -1005,7 +1022,6 @@ where
event_loop,
load_data,
device_pixel_ratio: self.window_size.device_pixel_ratio,
pipeline_namespace_id: self.next_pipeline_namespace_id(),
prev_visibility: is_visible,
webrender_api_sender: self.webrender_api_sender.clone(),
webrender_document: self.webrender_document,
@@ -1155,6 +1171,7 @@ where
fn handle_request(&mut self) {
#[derive(Debug)]
enum Request {
PipelineNamespace(PipelineNamespaceRequest),
Script((PipelineId, FromScriptMsg)),
BackgroundHangMonitor(HangMonitorAlert),
Compositor(FromCompositorMsg),
@@ -1175,6 +1192,9 @@ where
// being called. If this happens, there's not much we can do
// other than panic.
let request = select! {
recv(self.namespace_receiver) -> msg => {
msg.expect("Unexpected script channel panic in constellation").map(Request::PipelineNamespace)
}
recv(self.script_receiver) -> msg => {
msg.expect("Unexpected script channel panic in constellation").map(Request::Script)
}
@@ -1203,6 +1223,9 @@ where
};

match request {
Request::PipelineNamespace(message) => {
self.handle_request_for_pipeline_namespace(message)
},
Request::Compositor(message) => self.handle_request_from_compositor(message),
Request::Script(message) => {
self.handle_request_from_script(message);
@@ -1222,6 +1245,11 @@ where
}
}

fn handle_request_for_pipeline_namespace(&mut self, request: PipelineNamespaceRequest) {
let PipelineNamespaceRequest(sender) = request;
let _ = sender.send(self.next_pipeline_namespace_id());
}

fn handle_request_from_background_hang_monitor(&self, message: HangMonitorAlert) {
match message {
HangMonitorAlert::Profile(bytes) => self
@@ -22,7 +22,8 @@ use media::WindowGLContext;
use metrics::PaintTimeMetrics;
use msg::constellation_msg::TopLevelBrowsingContextId;
use msg::constellation_msg::{BackgroundHangMonitorRegister, HangMonitorAlert, SamplerControlMsg};
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespaceId};
use msg::constellation_msg::{BrowsingContextId, HistoryStateId};
use msg::constellation_msg::{PipelineId, PipelineNamespace, PipelineNamespaceRequest};
use net::image_cache::ImageCacheImpl;
use net_traits::image_cache::ImageCache;
use net_traits::{IpcSend, ResourceThreads};
@@ -121,6 +122,9 @@ pub struct InitialPipelineState {
/// A channel to the associated constellation.
pub script_to_constellation_chan: ScriptToConstellationChan,

/// A sender to request pipeline namespace ids.
pub namespace_request_sender: IpcSender<PipelineNamespaceRequest>,

/// A handle to register components for hang monitoring.
/// None when in multiprocess mode.
pub background_monitor_register: Option<Box<dyn BackgroundHangMonitorRegister>>,
@@ -170,9 +174,6 @@ pub struct InitialPipelineState {
/// Information about the page to load.
pub load_data: LoadData,

/// The ID of the pipeline namespace for this script thread.
pub pipeline_namespace_id: PipelineNamespaceId,

/// Whether the browsing context in which pipeline is embedded is visible
/// for the purposes of scheduling and resource management. This field is
/// only used to notify script and compositor threads after spawning
@@ -285,6 +286,7 @@ impl Pipeline {
parent_pipeline_id: state.parent_pipeline_id,
opener: state.opener,
script_to_constellation_chan: state.script_to_constellation_chan.clone(),
namespace_request_sender: state.namespace_request_sender,
background_hang_monitor_to_constellation_chan: state
.background_hang_monitor_to_constellation_chan
.clone(),
@@ -305,7 +307,6 @@ impl Pipeline {
opts: (*opts::get()).clone(),
prefs: prefs::pref_map().iter().collect(),
pipeline_port: pipeline_port,
pipeline_namespace_id: state.pipeline_namespace_id,
layout_content_process_shutdown_chan: layout_content_process_shutdown_chan,
layout_content_process_shutdown_port: layout_content_process_shutdown_port,
script_content_process_shutdown_chan: script_content_process_shutdown_chan,
@@ -495,6 +496,7 @@ pub struct UnprivilegedPipelineContent {
browsing_context_id: BrowsingContextId,
parent_pipeline_id: Option<PipelineId>,
opener: Option<BrowsingContextId>,
namespace_request_sender: IpcSender<PipelineNamespaceRequest>,
script_to_constellation_chan: ScriptToConstellationChan,
background_hang_monitor_to_constellation_chan: IpcSender<HangMonitorAlert>,
sampling_profiler_port: Option<IpcReceiver<SamplerControlMsg>>,
@@ -514,7 +516,6 @@ pub struct UnprivilegedPipelineContent {
opts: Opts,
prefs: HashMap<String, PrefValue>,
pipeline_port: IpcReceiver<LayoutControlMsg>,
pipeline_namespace_id: PipelineNamespaceId,
layout_content_process_shutdown_chan: IpcSender<()>,
layout_content_process_shutdown_port: IpcReceiver<()>,
script_content_process_shutdown_chan: IpcSender<()>,
@@ -537,6 +538,10 @@ impl UnprivilegedPipelineContent {
LTF: LayoutThreadFactory<Message = Message>,
STF: ScriptThreadFactory<Message = Message>,
{
// Setup pipeline-namespace-installing for all threads in this process.
// Idempotent in single-process mode.
PipelineNamespace::set_installer_sender(self.namespace_request_sender);

let image_cache = Arc::new(ImageCacheImpl::new(self.webrender_api_sender.create_api()));
let paint_time_metrics = PaintTimeMetrics::new(
self.id,
@@ -566,7 +571,6 @@ impl UnprivilegedPipelineContent {
mem_profiler_chan: self.mem_profiler_chan.clone(),
devtools_chan: self.devtools_chan,
window_size: self.window_size,
pipeline_namespace_id: self.pipeline_namespace_id,
content_process_shutdown_chan: self.script_content_process_shutdown_chan,
webgl_chan: self.webgl_chan,
webvr_chan: self.webvr_chan,
@@ -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"]}

@@ -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 fetch_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!")
@@ -4,6 +4,8 @@

#![deny(unsafe_code)]

#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate malloc_size_of;
#[macro_use]
@@ -742,7 +742,7 @@ impl ScriptThreadFactory for ScriptThread {
.name(format!("ScriptThread {:?}", state.id))
.spawn(move || {
thread_state::initialize(ThreadState::SCRIPT);
PipelineNamespace::install(state.pipeline_namespace_id);
PipelineNamespace::fetch_install();
TopLevelBrowsingContextId::install(state.top_level_browsing_context_id);
let roots = RootCollection::new();
let _stack_roots = ThreadLocalStackRoots::new(&roots);
@@ -40,7 +40,7 @@ use libc::c_void;
use media::WindowGLContext;
use msg::constellation_msg::BackgroundHangMonitorRegister;
use msg::constellation_msg::{BrowsingContextId, HistoryStateId, PipelineId};
use msg::constellation_msg::{PipelineNamespaceId, TopLevelBrowsingContextId, TraversalDirection};
use msg::constellation_msg::{TopLevelBrowsingContextId, TraversalDirection};
use net_traits::image::base::Image;
use net_traits::image_cache::ImageCache;
use net_traits::request::Referrer;
@@ -648,8 +648,6 @@ pub struct InitialScriptState {
pub devtools_chan: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
/// Information about the initial window size.
pub window_size: WindowSizeData,
/// The ID of the pipeline namespace for this script thread.
pub pipeline_namespace_id: PipelineNamespaceId,
/// A ping will be sent on this channel once the script thread shuts down.
pub content_process_shutdown_chan: IpcSender<()>,
/// A channel to the WebGL thread used in this pipeline.

0 comments on commit 0ca1d0f

Please sign in to comment.
You can’t perform that action at this time.