diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index 3b96c3a6577..720834f711b 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -1499,6 +1499,7 @@ dependencies = [ "bitflags 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cssparser 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "euclid 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ipc-channel 0.1.0 (git+https://github.com/pcwalton/ipc-channel)", "lazy_static 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/util/Cargo.toml b/components/util/Cargo.toml index a61600c8d5a..6558792b21b 100644 --- a/components/util/Cargo.toml +++ b/components/util/Cargo.toml @@ -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" diff --git a/components/util/ipc.rs b/components/util/ipc.rs new file mode 100644 index 00000000000..090ca9c0094 --- /dev/null +++ b/components/util/ipc.rs @@ -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>> = + Mutex::new(HashMap::new()); +} + +static NEXT_SENDER_ID: AtomicUsize = ATOMIC_USIZE_INIT; + +pub enum OptionalIpcSender where T: Deserialize + Serialize + Send + Any { + OutOfProcess(IpcSender), + InProcess(Sender), +} + +impl OptionalIpcSender 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 Deserialize for OptionalIpcSender where T: Deserialize + Serialize + Send + Any { + fn deserialize(deserializer: &mut D) + -> Result,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::>() + .unwrap()).clone(); + Ok(OptionalIpcSender::InProcess(sender)) + } +} + +impl Serialize for OptionalIpcSender where T: Deserialize + Serialize + Send + Any { + fn serialize(&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); + id.serialize(serializer) + } + } + } +} + +pub fn optional_ipc_channel() -> (OptionalIpcSender, Receiver) + 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) + } +} + diff --git a/components/util/lib.rs b/components/util/lib.rs index b108c516acc..8db4b17f5ec 100644 --- a/components/util/lib.rs +++ b/components/util/lib.rs @@ -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; diff --git a/components/util/opts.rs b/components/util/opts.rs index c8f65c97e54..efc580bd5e6 100644 --- a/components/util/opts.rs +++ b/components/util/opts.rs @@ -132,6 +132,9 @@ pub struct Opts { /// An optional string allowing the user agent to be set for testing. pub user_agent: Option, + /// 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"),