Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

compositing: Split Servo up into multiple sandboxed processes. #8599

Merged
merged 1 commit into from Nov 19, 2015
Merged
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

compositing: Split Servo up into multiple sandboxed processes.

Multiprocess mode is enabled with the `-M` switch, and sandboxing is
enabled with the `-S` switch.
  • Loading branch information
pcwalton authored and jdm committed Nov 19, 2015
commit 1c130819ca6fdcef66495ea3dabf9d9575774d52
@@ -68,14 +68,20 @@ features = ["texture_surface"]
version = "0.2"
features = [ "serde_serialization" ]

[dependencies.gaol]
git = "https://github.com/pcwalton/gaol"

[dependencies]
app_units = {version = "0.1", features = ["plugins"]}
image = "0.4.0"
libc = "0.1"
log = "0.3"
num = "0.1.24"
time = "0.1.17"
gleam = "0.1"
euclid = {version = "0.3", features = ["plugins"]}
serde = "0.6"
serde_macros = "0.6"

[target.x86_64-apple-darwin.dependencies]
core-graphics = "0.1"
@@ -17,7 +17,7 @@ use gfx_traits::color;
use gleam::gl;
use gleam::gl::types::{GLint, GLsizei};
use image::{DynamicImage, ImageFormat, RgbImage};
use ipc_channel::ipc::{self, IpcSharedMemory};
use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
use ipc_channel::router::ROUTER;
use layers::geometry::{DevicePixel, LayerPixel};
use layers::layers::{BufferRequest, Layer, LayerBuffer, LayerBufferSet};
@@ -30,7 +30,7 @@ use msg::compositor_msg::{Epoch, EventResult, FrameTreeId, LayerId, LayerKind};
use msg::compositor_msg::{LayerProperties, ScrollPolicy};
use msg::constellation_msg::CompositorMsg as ConstellationMsg;
use msg::constellation_msg::{AnimationState, Image, PixelFormat};
use msg::constellation_msg::{ConstellationChan, Key, KeyModifiers, KeyState, LoadData};
use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData};
use msg::constellation_msg::{NavigationDirection, PipelineId, WindowSizeData};
use pipeline::CompositionPipeline;
use profile_traits::mem::{self, ReportKind, Reporter, ReporterRequest};
@@ -168,7 +168,7 @@ pub struct IOCompositor<Window: WindowMethods> {
frame_tree_id: FrameTreeId,

/// The channel on which messages can be sent to the constellation.
constellation_chan: ConstellationChan<ConstellationMsg>,
constellation_chan: Sender<ConstellationMsg>,

/// The channel on which messages can be sent to the time profiler.
time_profiler_chan: time::ProfilerChan,
@@ -385,8 +385,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {

pub fn start_shutting_down(&mut self) {
debug!("Compositor sending Exit message to Constellation");
let ConstellationChan(ref constellation_channel) = self.constellation_chan;
constellation_channel.send(ConstellationMsg::Exit).unwrap();
self.constellation_chan.send(ConstellationMsg::Exit).unwrap();

self.mem_profiler_chan.send(mem::ProfilerMsg::UnregisterReporter(reporter_name()));

@@ -702,8 +701,8 @@ impl<Window: WindowMethods> IOCompositor<Window> {

fn set_frame_tree(&mut self,
frame_tree: &SendableFrameTree,
response_chan: Sender<()>,
new_constellation_chan: ConstellationChan<ConstellationMsg>) {
response_chan: IpcSender<()>,
new_constellation_chan: Sender<ConstellationMsg>) {
response_chan.send(()).unwrap();

// There are now no more pending iframes.
@@ -943,8 +942,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
let initial_viewport = self.window_size.as_f32() / dppx;
let visible_viewport = initial_viewport / self.viewport_zoom;

let ConstellationChan(ref chan) = self.constellation_chan;
chan.send(ConstellationMsg::ResizedWindow(WindowSizeData {
self.constellation_chan.send(ConstellationMsg::ResizedWindow(WindowSizeData {
device_pixel_ratio: dppx,
initial_viewport: initial_viewport,
visible_viewport: visible_viewport,
@@ -959,9 +957,9 @@ impl<Window: WindowMethods> IOCompositor<Window> {
None => return,
};

let ConstellationChan(ref chan) = self.constellation_chan;
chan.send(ConstellationMsg::FrameSize(*subpage_pipeline_id,
layer_properties.rect.size)).unwrap();
self.constellation_chan.send(ConstellationMsg::FrameSize(
*subpage_pipeline_id,
layer_properties.rect.size)).unwrap();
}

pub fn move_layer(&self,
@@ -1168,8 +1166,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
None => ConstellationMsg::InitLoadUrl(url)
};

let ConstellationChan(ref chan) = self.constellation_chan;
chan.send(msg).unwrap()
self.constellation_chan.send(msg).unwrap()
}

fn on_mouse_window_event_class(&mut self, mouse_window_event: MouseWindowEvent) {
@@ -1446,7 +1443,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {
}

fn tick_animations_for_pipeline(&self, pipeline_id: PipelineId) {
self.constellation_chan.0.send(ConstellationMsg::TickAnimation(pipeline_id)).unwrap()
self.constellation_chan.send(ConstellationMsg::TickAnimation(pipeline_id)).unwrap()
}

fn constrain_viewport(&mut self, pipeline_id: PipelineId, constraints: ViewportConstraints) {
@@ -1538,13 +1535,11 @@ impl<Window: WindowMethods> IOCompositor<Window> {
windowing::WindowNavigateMsg::Forward => NavigationDirection::Forward,
windowing::WindowNavigateMsg::Back => NavigationDirection::Back,
};
let ConstellationChan(ref chan) = self.constellation_chan;
chan.send(ConstellationMsg::Navigate(None, direction)).unwrap()
self.constellation_chan.send(ConstellationMsg::Navigate(None, direction)).unwrap()
}

fn on_key_event(&self, key: Key, state: KeyState, modifiers: KeyModifiers) {
let ConstellationChan(ref chan) = self.constellation_chan;
chan.send(ConstellationMsg::KeyEvent(key, state, modifiers)).unwrap()
self.constellation_chan.send(ConstellationMsg::KeyEvent(key, state, modifiers)).unwrap()
}

fn fill_paint_request_with_cached_layer_buffers(&mut self, paint_request: &mut PaintRequest) {
@@ -1744,8 +1739,7 @@ impl<Window: WindowMethods> IOCompositor<Window> {

// Pass the pipeline/epoch states to the constellation and check
// if it's safe to output the image.
let ConstellationChan(ref chan) = self.constellation_chan;
chan.send(ConstellationMsg::IsReadyToSaveImage(pipeline_epochs)).unwrap();
self.constellation_chan.send(ConstellationMsg::IsReadyToSaveImage(pipeline_epochs)).unwrap();
self.ready_to_save_state = ReadyState::WaitingForConstellationReply;
Err(NotReadyToPaint::JustNotifiedConstellation)
}
@@ -2167,8 +2161,7 @@ impl<Window> CompositorEventListener for IOCompositor<Window> where Window: Wind
None => return,
Some(ref root_pipeline) => root_pipeline.id,
};
let ConstellationChan(ref chan) = self.constellation_chan;
chan.send(ConstellationMsg::GetPipelineTitle(root_pipeline_id)).unwrap();
self.constellation_chan.send(ConstellationMsg::GetPipelineTitle(root_pipeline_id)).unwrap();
}
}

@@ -5,15 +5,16 @@
//! Communication with the compositor task.

use compositor;
use euclid::{Point2D, Size2D};
use euclid::point::Point2D;
use euclid::size::Size2D;
use headless;
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
use layers::layers::{BufferRequest, LayerBufferSet};
use layers::platform::surface::{NativeDisplay, NativeSurface};
use msg::compositor_msg::{Epoch, EventResult, FrameTreeId, LayerId, LayerProperties};
use msg::compositor_msg::{PaintListener, ScriptToCompositorMsg};
use msg::constellation_msg::CompositorMsg as ConstellationMsg;
use msg::constellation_msg::{AnimationState, ConstellationChan, PipelineId};
use msg::constellation_msg::{AnimationState, PipelineId};
use msg::constellation_msg::{Image, Key, KeyModifiers, KeyState};
use profile_traits::mem;
use profile_traits::time;
@@ -60,11 +61,11 @@ pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'stati
receiver: IpcReceiver<ScriptToCompositorMsg>) {
while let Ok(msg) = receiver.recv() {
match msg {
ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point, _smooth) => {
ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point, smooth) => {
compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id,
layer_id,
point,
_smooth));
smooth));
}

ScriptToCompositorMsg::GetClientWindow(send) => {
@@ -80,7 +81,7 @@ pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'stati
}

ScriptToCompositorMsg::Exit => {
let (chan, port) = channel();
let (chan, port) = ipc::channel().unwrap();
compositor_proxy.send(Msg::Exit(chan));
port.recv().unwrap();
}
@@ -152,7 +153,7 @@ impl PaintListener for Box<CompositorProxy + 'static + Send> {
/// Messages from the painting task and the constellation task to the compositor task.
pub enum Msg {
/// Requests that the compositor shut down.
Exit(Sender<()>),
Exit(IpcSender<()>),

/// Informs the compositor that the constellation has completed shutdown.
/// Required because the constellation can have pending calls to make
@@ -180,7 +181,7 @@ pub enum Msg {
/// Alerts the compositor that the given pipeline has changed whether it is running animations.
ChangeRunningAnimationsState(PipelineId, AnimationState),
/// Replaces the current frame tree, typically called during main frame navigation.
SetFrameTree(SendableFrameTree, Sender<()>, ConstellationChan<ConstellationMsg>),
SetFrameTree(SendableFrameTree, IpcSender<()>, Sender<ConstellationMsg>),
/// The load of a page has begun: (can go back, can go forward).
LoadStart(bool, bool),
/// The load of a page has completed: (can go back, can go forward).
@@ -296,7 +297,7 @@ pub struct InitialCompositorState {
/// A port on which messages inbound to the compositor can be received.
pub receiver: Box<CompositorReceiver>,
/// A channel to the constellation.
pub constellation_chan: ConstellationChan<ConstellationMsg>,
pub constellation_chan: Sender<ConstellationMsg>,
/// A channel to the time profiler thread.
pub time_profiler_chan: time::ProfilerChan,
/// A channel to the memory profiler thread.
@@ -18,8 +18,11 @@ use compositor_task::Msg as ToCompositorMsg;
use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg};
use euclid::scale_factor::ScaleFactor;
use euclid::size::{Size2D, TypedSize2D};
use gaol;
use gaol::sandbox::{self, Sandbox, SandboxMethods};
use gfx::font_cache_task::FontCacheTask;
use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::ipc::{self, IpcOneShotServer, IpcSender};
use ipc_channel::router::ROUTER;
use layout_traits::{LayoutControlChan, LayoutTaskFactory};
use msg::compositor_msg::Epoch;
use msg::constellation_msg::AnimationState;
@@ -37,19 +40,21 @@ use net_traits::image_cache_task::ImageCacheTask;
use net_traits::storage_task::{StorageTask, StorageTaskMsg};
use net_traits::{self, ResourceTask};
use offscreen_gl_context::GLContextAttributes;
use pipeline::{CompositionPipeline, InitialPipelineState, Pipeline};
use pipeline::{CompositionPipeline, InitialPipelineState, Pipeline, UnprivilegedPipelineContent};
use profile_traits::mem;
use profile_traits::time;
use sandboxing;
use script_traits::{CompositorEvent, ConstellationControlMsg, LayoutControlMsg};
use script_traits::{ScriptState, ScriptTaskFactory};
use script_traits::{TimerEventRequest};
use std::borrow::ToOwned;
use std::collections::HashMap;
use std::env;
use std::io::{self, Write};
use std::marker::PhantomData;
use std::mem::replace;
use std::process;
use std::sync::mpsc::{Receiver, Sender, channel};
use std::sync::mpsc::{Sender, channel, Receiver};
use style_traits::viewport::ViewportConstraints;
use timer_scheduler::TimerScheduler;
use url::Url;
@@ -79,7 +84,7 @@ pub struct Constellation<LTF, STF> {
pub script_sender: ConstellationChan<FromScriptMsg>,

/// A channel through which compositor messages can be sent to this object.
pub compositor_sender: ConstellationChan<FromCompositorMsg>,
pub compositor_sender: Sender<FromCompositorMsg>,

/// Receives messages from scripts.
pub script_receiver: Receiver<FromScriptMsg>,
@@ -156,6 +161,9 @@ pub struct Constellation<LTF, STF> {
webgl_paint_tasks: Vec<Sender<CanvasMsg>>,

scheduler_chan: IpcSender<TimerEventRequest>,

/// A list of child content processes.
child_processes: Vec<ChildProcess>,
}

/// State needed to construct a constellation.
@@ -259,14 +267,21 @@ enum ExitPipelineMode {
Force,
}

enum ChildProcess {
Sandboxed(gaol::platform::process::Process),
Unsandboxed(process::Child),
}

impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
pub fn start(state: InitialConstellationState) -> ConstellationChan<FromCompositorMsg> {
let (script_receiver, script_sender) = ConstellationChan::<FromScriptMsg>::new();
let (compositor_receiver, compositor_sender) = ConstellationChan::<FromCompositorMsg>::new();
pub fn start(state: InitialConstellationState) -> Sender<FromCompositorMsg> {
let (ipc_script_receiver, ipc_script_sender) = ConstellationChan::<FromScriptMsg>::new();
//let (script_receiver, script_sender) = channel();
let script_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_script_receiver);
let (compositor_sender, compositor_receiver) = channel();
let compositor_sender_clone = compositor_sender.clone();
spawn_named("Constellation".to_owned(), move || {
let mut constellation: Constellation<LTF, STF> = Constellation {
script_sender: script_sender,
script_sender: ipc_script_sender,
compositor_sender: compositor_sender_clone,
script_receiver: script_receiver,
compositor_receiver: compositor_receiver,
@@ -305,6 +320,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
canvas_paint_tasks: Vec::new(),
webgl_paint_tasks: Vec::new(),
scheduler_chan: TimerScheduler::start(),
child_processes: Vec::new(),
};
let namespace_id = constellation.next_pipeline_namespace_id();
PipelineNamespace::install(namespace_id);
@@ -333,10 +349,10 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
pipeline_id: PipelineId,
parent_info: Option<(PipelineId, SubpageId)>,
initial_window_size: Option<TypedSize2D<PagePx, f32>>,
script_channel: Option<Sender<ConstellationControlMsg>>,
script_channel: Option<IpcSender<ConstellationControlMsg>>,
load_data: LoadData) {
let spawning_paint_only = script_channel.is_some();
let (pipeline, mut pipeline_content) =
let (pipeline, unprivileged_pipeline_content, mut privileged_pipeline_content) =
Pipeline::create::<LTF, STF>(InitialPipelineState {
id: pipeline_id,
parent_info: parent_info,
@@ -357,12 +373,39 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
pipeline_namespace_id: self.next_pipeline_namespace_id(),
});

// TODO(pcwalton): In multiprocess mode, send that `PipelineContent` instance over to
// the content process and call this over there.
if spawning_paint_only {
pipeline_content.start_paint_task();
privileged_pipeline_content.start_paint_task();
} else {
pipeline_content.start_all::<LTF, STF>();
privileged_pipeline_content.start_all();

// Spawn the child process.
//
// Yes, that's all there is to it!
if opts::multiprocess() {
let (server, token) =
IpcOneShotServer::<IpcSender<UnprivilegedPipelineContent>>::new().unwrap();

// If there is a sandbox, use the `gaol` API to create the child process.
let child_process = if opts::get().sandbox {
let mut command = sandbox::Command::me().unwrap();
command.arg("--content-process").arg(token);
let profile = sandboxing::content_process_sandbox_profile();
ChildProcess::Sandboxed(Sandbox::new(profile).start(&mut command).expect(
"Failed to start sandboxed child process!"))
} else {
let path_to_self = env::current_exe().unwrap();
let mut child_process = process::Command::new(path_to_self);
child_process.arg("--content-process");
child_process.arg(token);
ChildProcess::Unsandboxed(child_process.spawn().unwrap())
};
self.child_processes.push(child_process);

let (_receiver, sender) = server.accept().unwrap();
sender.send(unprivileged_pipeline_content).unwrap();
} else {
unprivileged_pipeline_content.start_all::<LTF, STF>(false);
}
}

assert!(!self.pipelines.contains_key(&pipeline_id));
@@ -1290,7 +1333,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {

// Synchronously query the script task for this pipeline
// to see if it is idle.
let (sender, receiver) = channel();
let (sender, receiver) = ipc::channel().unwrap();
let msg = ConstellationControlMsg::GetCurrentState(sender, frame.current);
pipeline.script_chan.send(msg).unwrap();
let result = receiver.recv().unwrap();
@@ -1445,7 +1488,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
if let Some(root_frame_id) = self.root_frame_id {
let frame_tree = self.frame_to_sendable(root_frame_id);

let (chan, port) = channel();
let (chan, port) = ipc::channel().unwrap();
self.compositor_proxy.send(ToCompositorMsg::SetFrameTree(frame_tree,
chan,
self.compositor_sender.clone()));
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.