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

Send display lists over IPC in multiprocess mode. #6795

Merged
merged 6 commits into from Jul 31, 2015
Next

util: Add a multiprocess command-line option and implement

`OptionalIpcSender<T>`.

`OptionalIpcSender<T>`dynamically switches between in-process and
out-of-process communication depending on whether multiprocess mode is
enabled.

The multiprocess command-line switch doesn't actually turn on
multiprocess mode yet, but it does control the behavior of
`OptionalIpcSender<T>`.
  • Loading branch information
pcwalton committed Jul 31, 2015
commit ef9fdc6e30256cb6e9cb1a190a30bc23a754aefb

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

@@ -25,6 +25,9 @@ git = "https://github.com/servo/rust-azure"
version = "0.3"
features = [ "serde-serialization" ]

[dependencies.ipc-channel]
git = "https://github.com/pcwalton/ipc-channel"

[dependencies]
log = "0.3"
bitflags = "0.3"
@@ -0,0 +1,81 @@
/* 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/. */

use opts;

use ipc_channel::ipc::{self, IpcSender};
use ipc_channel::router::ROUTER;
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use std::any::Any;
use std::collections::HashMap;
use std::sync::Mutex;
use std::sync::atomic::{ATOMIC_USIZE_INIT, AtomicUsize, Ordering};
use std::sync::mpsc::{self, Receiver, Sender};

lazy_static! {
static ref IN_PROCESS_SENDERS: Mutex<HashMap<usize,Box<Any + Send>>> =
Mutex::new(HashMap::new());
}

static NEXT_SENDER_ID: AtomicUsize = ATOMIC_USIZE_INIT;

pub enum OptionalIpcSender<T> where T: Deserialize + Serialize + Send + Any {
OutOfProcess(IpcSender<T>),
InProcess(Sender<T>),
}

impl<T> OptionalIpcSender<T> where T: Deserialize + Serialize + Send + Any {
pub fn send(&self, value: T) -> Result<(),()> {
match *self {
OptionalIpcSender::OutOfProcess(ref ipc_sender) => ipc_sender.send(value),
OptionalIpcSender::InProcess(ref sender) => sender.send(value).map_err(|_| ()),
}
}
}

impl<T> Deserialize for OptionalIpcSender<T> where T: Deserialize + Serialize + Send + Any {
fn deserialize<D>(deserializer: &mut D)
-> Result<OptionalIpcSender<T>,D::Error> where D: Deserializer {
if opts::get().multiprocess {
return Ok(OptionalIpcSender::OutOfProcess(try!(Deserialize::deserialize(
deserializer))))
}
let id: usize = try!(Deserialize::deserialize(deserializer));
let sender = (*IN_PROCESS_SENDERS.lock()
.unwrap()
.remove(&id)
.unwrap()
.downcast_ref::<Sender<T>>()
.unwrap()).clone();
Ok(OptionalIpcSender::InProcess(sender))
}
}

impl<T> Serialize for OptionalIpcSender<T> where T: Deserialize + Serialize + Send + Any {
fn serialize<S>(&self, serializer: &mut S) -> Result<(),S::Error> where S: Serializer {
match *self {
OptionalIpcSender::OutOfProcess(ref ipc_sender) => ipc_sender.serialize(serializer),
OptionalIpcSender::InProcess(ref sender) => {
let id = NEXT_SENDER_ID.fetch_add(1, Ordering::SeqCst);
IN_PROCESS_SENDERS.lock()
.unwrap()
.insert(id, Box::new((*sender).clone()) as Box<Any + Send>);
id.serialize(serializer)
}
}
}
}

pub fn optional_ipc_channel<T>() -> (OptionalIpcSender<T>, Receiver<T>)
where T: Deserialize + Serialize + Send + Any {
if opts::get().multiprocess {
let (ipc_sender, ipc_receiver) = ipc::channel().unwrap();
let receiver = ROUTER.route_ipc_receiver_to_new_mpsc_receiver(ipc_receiver);
(OptionalIpcSender::OutOfProcess(ipc_sender), receiver)
} else {
let (sender, receiver) = mpsc::channel();
(OptionalIpcSender::InProcess(sender), receiver)
}
}

@@ -31,6 +31,7 @@ extern crate alloc;
#[macro_use] extern crate cssparser;
extern crate euclid;
extern crate getopts;
extern crate ipc_channel;
extern crate libc;
extern crate num as num_lib;
extern crate num_cpus;
@@ -49,6 +50,7 @@ pub mod debug_utils;
pub mod deque;
pub mod linked_list;
pub mod geometry;
pub mod ipc;
pub mod logical_geometry;
pub mod mem;
pub mod opts;
@@ -132,6 +132,9 @@ pub struct Opts {
/// An optional string allowing the user agent to be set for testing.
pub user_agent: Option<String>,

/// Whether to run in multiprocess mode.
pub multiprocess: bool,

/// Dumps the flow tree after a layout.
pub dump_flow_tree: bool,

@@ -251,6 +254,7 @@ pub fn default_opts() -> Opts {
webdriver_port: None,
initial_window_size: Size2D::typed(800, 600),
user_agent: None,
multiprocess: false,
dump_flow_tree: false,
dump_display_list: false,
dump_display_list_json: false,
@@ -291,6 +295,7 @@ pub fn from_cmdline_args(args: &[String]) {
getopts::optflagopt("", "webdriver", "Start remote WebDriver server on port", "7000"),
getopts::optopt("", "resolution", "Set window resolution.", "800x600"),
getopts::optopt("u", "user-agent", "Set custom user agent string", "NCSA Mosaic/1.0 (X11;SunOS 4.1.4 sun4m)"),
getopts::optflag("M", "multiprocess", "Run in multiprocess mode"),
getopts::optopt("Z", "debug",
"A comma-separated string of debug options. Pass help to show available options.", ""),
getopts::optflag("h", "help", "Print this message"),
@@ -421,6 +426,7 @@ pub fn from_cmdline_args(args: &[String]) {
webdriver_port: webdriver_port,
initial_window_size: initial_window_size,
user_agent: opt_match.opt_str("u"),
multiprocess: opt_match.opt_present("M"),
show_debug_borders: debug_options.contains(&"show-compositor-borders"),
show_debug_fragment_borders: debug_options.contains(&"show-fragment-borders"),
show_debug_parallel_paint: debug_options.contains(&"show-parallel-paint"),
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.