Skip to content

Commit 24dbfdb

Browse files
author
bors-servo
committed
Auto merge of #8599 - jdm:e10s-redux, r=metajack
compositing: Split Servo up into multiple sandboxed processes. Multiprocess mode is enabled with the `-M` switch, and sandboxing is enabled with the `-S` switch. Rebase of #6884. <!-- Reviewable:start --> [<img src="https://reviewable.io/review_button.png" height=40 alt="Review on Reviewable"/>](https://reviewable.io/reviews/servo/servo/8599) <!-- Reviewable:end -->
2 parents ff41711 + 3327234 commit 24dbfdb

File tree

33 files changed

+686
-262
lines changed

33 files changed

+686
-262
lines changed

components/compositing/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,14 +68,20 @@ features = ["texture_surface"]
6868
version = "0.2"
6969
features = [ "serde_serialization" ]
7070

71+
[dependencies.gaol]
72+
git = "https://github.com/pcwalton/gaol"
73+
7174
[dependencies]
7275
app_units = {version = "0.1", features = ["plugins"]}
7376
image = "0.4.0"
77+
libc = "0.1"
7478
log = "0.3"
7579
num = "0.1.24"
7680
time = "0.1.17"
7781
gleam = "0.1"
7882
euclid = {version = "0.3", features = ["plugins"]}
83+
serde = "0.6"
84+
serde_macros = "0.6"
7985

8086
[target.x86_64-apple-darwin.dependencies]
8187
core-graphics = "0.1"

components/compositing/compositor.rs

Lines changed: 16 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use gfx_traits::color;
1717
use gleam::gl;
1818
use gleam::gl::types::{GLint, GLsizei};
1919
use image::{DynamicImage, ImageFormat, RgbImage};
20-
use ipc_channel::ipc::{self, IpcSharedMemory};
20+
use ipc_channel::ipc::{self, IpcSender, IpcSharedMemory};
2121
use ipc_channel::router::ROUTER;
2222
use layers::geometry::{DevicePixel, LayerPixel};
2323
use layers::layers::{BufferRequest, Layer, LayerBuffer, LayerBufferSet};
@@ -30,7 +30,7 @@ use msg::compositor_msg::{Epoch, EventResult, FrameTreeId, LayerId, LayerKind};
3030
use msg::compositor_msg::{LayerProperties, ScrollPolicy};
3131
use msg::constellation_msg::CompositorMsg as ConstellationMsg;
3232
use msg::constellation_msg::{AnimationState, Image, PixelFormat};
33-
use msg::constellation_msg::{ConstellationChan, Key, KeyModifiers, KeyState, LoadData};
33+
use msg::constellation_msg::{Key, KeyModifiers, KeyState, LoadData};
3434
use msg::constellation_msg::{NavigationDirection, PipelineId, WindowSizeData};
3535
use pipeline::CompositionPipeline;
3636
use profile_traits::mem::{self, ReportKind, Reporter, ReporterRequest};
@@ -168,7 +168,7 @@ pub struct IOCompositor<Window: WindowMethods> {
168168
frame_tree_id: FrameTreeId,
169169

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

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

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

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

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

703702
fn set_frame_tree(&mut self,
704703
frame_tree: &SendableFrameTree,
705-
response_chan: Sender<()>,
706-
new_constellation_chan: ConstellationChan<ConstellationMsg>) {
704+
response_chan: IpcSender<()>,
705+
new_constellation_chan: Sender<ConstellationMsg>) {
707706
response_chan.send(()).unwrap();
708707

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

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

962-
let ConstellationChan(ref chan) = self.constellation_chan;
963-
chan.send(ConstellationMsg::FrameSize(*subpage_pipeline_id,
964-
layer_properties.rect.size)).unwrap();
960+
self.constellation_chan.send(ConstellationMsg::FrameSize(
961+
*subpage_pipeline_id,
962+
layer_properties.rect.size)).unwrap();
965963
}
966964

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

1171-
let ConstellationChan(ref chan) = self.constellation_chan;
1172-
chan.send(msg).unwrap()
1169+
self.constellation_chan.send(msg).unwrap()
11731170
}
11741171

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

14481445
fn tick_animations_for_pipeline(&self, pipeline_id: PipelineId) {
1449-
self.constellation_chan.0.send(ConstellationMsg::TickAnimation(pipeline_id)).unwrap()
1446+
self.constellation_chan.send(ConstellationMsg::TickAnimation(pipeline_id)).unwrap()
14501447
}
14511448

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

15451541
fn on_key_event(&self, key: Key, state: KeyState, modifiers: KeyModifiers) {
1546-
let ConstellationChan(ref chan) = self.constellation_chan;
1547-
chan.send(ConstellationMsg::KeyEvent(key, state, modifiers)).unwrap()
1542+
self.constellation_chan.send(ConstellationMsg::KeyEvent(key, state, modifiers)).unwrap()
15481543
}
15491544

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

17451740
// Pass the pipeline/epoch states to the constellation and check
17461741
// if it's safe to output the image.
1747-
let ConstellationChan(ref chan) = self.constellation_chan;
1748-
chan.send(ConstellationMsg::IsReadyToSaveImage(pipeline_epochs)).unwrap();
1742+
self.constellation_chan.send(ConstellationMsg::IsReadyToSaveImage(pipeline_epochs)).unwrap();
17491743
self.ready_to_save_state = ReadyState::WaitingForConstellationReply;
17501744
Err(NotReadyToPaint::JustNotifiedConstellation)
17511745
}
@@ -2167,8 +2161,7 @@ impl<Window> CompositorEventListener for IOCompositor<Window> where Window: Wind
21672161
None => return,
21682162
Some(ref root_pipeline) => root_pipeline.id,
21692163
};
2170-
let ConstellationChan(ref chan) = self.constellation_chan;
2171-
chan.send(ConstellationMsg::GetPipelineTitle(root_pipeline_id)).unwrap();
2164+
self.constellation_chan.send(ConstellationMsg::GetPipelineTitle(root_pipeline_id)).unwrap();
21722165
}
21732166
}
21742167

components/compositing/compositor_task.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@
55
//! Communication with the compositor task.
66
77
use compositor;
8-
use euclid::{Point2D, Size2D};
8+
use euclid::point::Point2D;
9+
use euclid::size::Size2D;
910
use headless;
10-
use ipc_channel::ipc::{IpcReceiver, IpcSender};
11+
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
1112
use layers::layers::{BufferRequest, LayerBufferSet};
1213
use layers::platform::surface::{NativeDisplay, NativeSurface};
1314
use msg::compositor_msg::{Epoch, EventResult, FrameTreeId, LayerId, LayerProperties};
1415
use msg::compositor_msg::{PaintListener, ScriptToCompositorMsg};
1516
use msg::constellation_msg::CompositorMsg as ConstellationMsg;
16-
use msg::constellation_msg::{AnimationState, ConstellationChan, PipelineId};
17+
use msg::constellation_msg::{AnimationState, PipelineId};
1718
use msg::constellation_msg::{Image, Key, KeyModifiers, KeyState};
1819
use profile_traits::mem;
1920
use profile_traits::time;
@@ -60,11 +61,11 @@ pub fn run_script_listener_thread(compositor_proxy: Box<CompositorProxy + 'stati
6061
receiver: IpcReceiver<ScriptToCompositorMsg>) {
6162
while let Ok(msg) = receiver.recv() {
6263
match msg {
63-
ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point, _smooth) => {
64+
ScriptToCompositorMsg::ScrollFragmentPoint(pipeline_id, layer_id, point, smooth) => {
6465
compositor_proxy.send(Msg::ScrollFragmentPoint(pipeline_id,
6566
layer_id,
6667
point,
67-
_smooth));
68+
smooth));
6869
}
6970

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

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

157158
/// Informs the compositor that the constellation has completed shutdown.
158159
/// Required because the constellation can have pending calls to make
@@ -180,7 +181,7 @@ pub enum Msg {
180181
/// Alerts the compositor that the given pipeline has changed whether it is running animations.
181182
ChangeRunningAnimationsState(PipelineId, AnimationState),
182183
/// Replaces the current frame tree, typically called during main frame navigation.
183-
SetFrameTree(SendableFrameTree, Sender<()>, ConstellationChan<ConstellationMsg>),
184+
SetFrameTree(SendableFrameTree, IpcSender<()>, Sender<ConstellationMsg>),
184185
/// The load of a page has begun: (can go back, can go forward).
185186
LoadStart(bool, bool),
186187
/// The load of a page has completed: (can go back, can go forward).
@@ -296,7 +297,7 @@ pub struct InitialCompositorState {
296297
/// A port on which messages inbound to the compositor can be received.
297298
pub receiver: Box<CompositorReceiver>,
298299
/// A channel to the constellation.
299-
pub constellation_chan: ConstellationChan<ConstellationMsg>,
300+
pub constellation_chan: Sender<ConstellationMsg>,
300301
/// A channel to the time profiler thread.
301302
pub time_profiler_chan: time::ProfilerChan,
302303
/// A channel to the memory profiler thread.

components/compositing/constellation.rs

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,11 @@ use compositor_task::Msg as ToCompositorMsg;
1818
use devtools_traits::{ChromeToDevtoolsControlMsg, DevtoolsControlMsg};
1919
use euclid::scale_factor::ScaleFactor;
2020
use euclid::size::{Size2D, TypedSize2D};
21+
use gaol;
22+
use gaol::sandbox::{self, Sandbox, SandboxMethods};
2123
use gfx::font_cache_task::FontCacheTask;
22-
use ipc_channel::ipc::{self, IpcSender};
24+
use ipc_channel::ipc::{self, IpcOneShotServer, IpcSender};
25+
use ipc_channel::router::ROUTER;
2326
use layout_traits::{LayoutControlChan, LayoutTaskFactory};
2427
use msg::compositor_msg::Epoch;
2528
use msg::constellation_msg::AnimationState;
@@ -37,19 +40,21 @@ use net_traits::image_cache_task::ImageCacheTask;
3740
use net_traits::storage_task::{StorageTask, StorageTaskMsg};
3841
use net_traits::{self, ResourceTask};
3942
use offscreen_gl_context::GLContextAttributes;
40-
use pipeline::{CompositionPipeline, InitialPipelineState, Pipeline};
43+
use pipeline::{CompositionPipeline, InitialPipelineState, Pipeline, UnprivilegedPipelineContent};
4144
use profile_traits::mem;
4245
use profile_traits::time;
46+
use sandboxing;
4347
use script_traits::{CompositorEvent, ConstellationControlMsg, LayoutControlMsg};
4448
use script_traits::{ScriptState, ScriptTaskFactory};
4549
use script_traits::{TimerEventRequest};
4650
use std::borrow::ToOwned;
4751
use std::collections::HashMap;
52+
use std::env;
4853
use std::io::{self, Write};
4954
use std::marker::PhantomData;
5055
use std::mem::replace;
5156
use std::process;
52-
use std::sync::mpsc::{Receiver, Sender, channel};
57+
use std::sync::mpsc::{Sender, channel, Receiver};
5358
use style_traits::viewport::ViewportConstraints;
5459
use timer_scheduler::TimerScheduler;
5560
use url::Url;
@@ -79,7 +84,7 @@ pub struct Constellation<LTF, STF> {
7984
pub script_sender: ConstellationChan<FromScriptMsg>,
8085

8186
/// A channel through which compositor messages can be sent to this object.
82-
pub compositor_sender: ConstellationChan<FromCompositorMsg>,
87+
pub compositor_sender: Sender<FromCompositorMsg>,
8388

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

158163
scheduler_chan: IpcSender<TimerEventRequest>,
164+
165+
/// A list of child content processes.
166+
child_processes: Vec<ChildProcess>,
159167
}
160168

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

270+
enum ChildProcess {
271+
Sandboxed(gaol::platform::process::Process),
272+
Unsandboxed(process::Child),
273+
}
274+
262275
impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
263-
pub fn start(state: InitialConstellationState) -> ConstellationChan<FromCompositorMsg> {
264-
let (script_receiver, script_sender) = ConstellationChan::<FromScriptMsg>::new();
265-
let (compositor_receiver, compositor_sender) = ConstellationChan::<FromCompositorMsg>::new();
276+
pub fn start(state: InitialConstellationState) -> Sender<FromCompositorMsg> {
277+
let (ipc_script_receiver, ipc_script_sender) = ConstellationChan::<FromScriptMsg>::new();
278+
//let (script_receiver, script_sender) = channel();
279+
let script_receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_script_receiver);
280+
let (compositor_sender, compositor_receiver) = channel();
266281
let compositor_sender_clone = compositor_sender.clone();
267282
spawn_named("Constellation".to_owned(), move || {
268283
let mut constellation: Constellation<LTF, STF> = Constellation {
269-
script_sender: script_sender,
284+
script_sender: ipc_script_sender,
270285
compositor_sender: compositor_sender_clone,
271286
script_receiver: script_receiver,
272287
compositor_receiver: compositor_receiver,
@@ -305,6 +320,7 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
305320
canvas_paint_tasks: Vec::new(),
306321
webgl_paint_tasks: Vec::new(),
307322
scheduler_chan: TimerScheduler::start(),
323+
child_processes: Vec::new(),
308324
};
309325
let namespace_id = constellation.next_pipeline_namespace_id();
310326
PipelineNamespace::install(namespace_id);
@@ -333,10 +349,10 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
333349
pipeline_id: PipelineId,
334350
parent_info: Option<(PipelineId, SubpageId)>,
335351
initial_window_size: Option<TypedSize2D<PagePx, f32>>,
336-
script_channel: Option<Sender<ConstellationControlMsg>>,
352+
script_channel: Option<IpcSender<ConstellationControlMsg>>,
337353
load_data: LoadData) {
338354
let spawning_paint_only = script_channel.is_some();
339-
let (pipeline, mut pipeline_content) =
355+
let (pipeline, unprivileged_pipeline_content, mut privileged_pipeline_content) =
340356
Pipeline::create::<LTF, STF>(InitialPipelineState {
341357
id: pipeline_id,
342358
parent_info: parent_info,
@@ -357,12 +373,39 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
357373
pipeline_namespace_id: self.next_pipeline_namespace_id(),
358374
});
359375

360-
// TODO(pcwalton): In multiprocess mode, send that `PipelineContent` instance over to
361-
// the content process and call this over there.
362376
if spawning_paint_only {
363-
pipeline_content.start_paint_task();
377+
privileged_pipeline_content.start_paint_task();
364378
} else {
365-
pipeline_content.start_all::<LTF, STF>();
379+
privileged_pipeline_content.start_all();
380+
381+
// Spawn the child process.
382+
//
383+
// Yes, that's all there is to it!
384+
if opts::multiprocess() {
385+
let (server, token) =
386+
IpcOneShotServer::<IpcSender<UnprivilegedPipelineContent>>::new().unwrap();
387+
388+
// If there is a sandbox, use the `gaol` API to create the child process.
389+
let child_process = if opts::get().sandbox {
390+
let mut command = sandbox::Command::me().unwrap();
391+
command.arg("--content-process").arg(token);
392+
let profile = sandboxing::content_process_sandbox_profile();
393+
ChildProcess::Sandboxed(Sandbox::new(profile).start(&mut command).expect(
394+
"Failed to start sandboxed child process!"))
395+
} else {
396+
let path_to_self = env::current_exe().unwrap();
397+
let mut child_process = process::Command::new(path_to_self);
398+
child_process.arg("--content-process");
399+
child_process.arg(token);
400+
ChildProcess::Unsandboxed(child_process.spawn().unwrap())
401+
};
402+
self.child_processes.push(child_process);
403+
404+
let (_receiver, sender) = server.accept().unwrap();
405+
sender.send(unprivileged_pipeline_content).unwrap();
406+
} else {
407+
unprivileged_pipeline_content.start_all::<LTF, STF>(false);
408+
}
366409
}
367410

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

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

1448-
let (chan, port) = channel();
1491+
let (chan, port) = ipc::channel().unwrap();
14491492
self.compositor_proxy.send(ToCompositorMsg::SetFrameTree(frame_tree,
14501493
chan,
14511494
self.compositor_sender.clone()));

0 commit comments

Comments
 (0)