From 858753675537562e939725fbd36d1e10d5d63d94 Mon Sep 17 00:00:00 2001 From: Jonathan Schwender <55576758+jschwe@users.noreply.github.com> Date: Tue, 19 Aug 2025 11:59:20 +0200 Subject: [PATCH] Use GenericChannel for script_chan (#38645) Motivation: Using our GenericChannel abstraction allows us to optimize IPC in single-process mode to just use cross-beam channel. To keep the diff low, and get early feedback, this PR only tackles a single channel, but the intention is to port all ipc channels to the generic channel, which allows us to skip serializing and deserializing messages in single process mode. Based on: - https://github.com/servo/servo/pull/38638 - https://github.com/servo/servo/pull/38636 Testing: Covered by existing tests --------- Signed-off-by: Jonathan Schwender --- Cargo.lock | 1 + components/constellation/event_loop.rs | 10 ++++++---- components/constellation/pipeline.rs | 8 +++++--- components/layout/layout_impl.rs | 4 ++-- components/script/dom/window.rs | 5 +++-- components/script/messaging.rs | 3 ++- components/script/script_thread.rs | 4 +--- components/shared/base/Cargo.toml | 1 + components/shared/base/generic_channel.rs | 11 +++++++++-- components/shared/canvas/webgl.rs | 2 +- components/shared/layout/lib.rs | 4 ++-- components/shared/script/lib.rs | 5 +++-- 12 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index becaf21dc28..224c6b78777 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -727,6 +727,7 @@ dependencies = [ "malloc_size_of_derive", "parking_lot", "serde", + "servo_config", "servo_malloc_size_of", "time", "webrender_api", diff --git a/components/constellation/event_loop.rs b/components/constellation/event_loop.rs index 46542e7212f..d0889a3dcab 100644 --- a/components/constellation/event_loop.rs +++ b/components/constellation/event_loop.rs @@ -11,15 +11,15 @@ use std::marker::PhantomData; use std::rc::Rc; use std::sync::atomic::{AtomicUsize, Ordering}; +use base::generic_channel::GenericSender; use ipc_channel::Error; -use ipc_channel::ipc::IpcSender; use script_traits::ScriptThreadMessage; static CURRENT_EVENT_LOOP_ID: AtomicUsize = AtomicUsize::new(0); /// pub struct EventLoop { - script_chan: IpcSender, + script_chan: GenericSender, dont_send_or_sync: PhantomData>, id: usize, } @@ -46,7 +46,7 @@ impl Drop for EventLoop { impl EventLoop { /// Create a new event loop from the channel to its script thread. - pub fn new(script_chan: IpcSender) -> Rc { + pub fn new(script_chan: GenericSender) -> Rc { let id = CURRENT_EVENT_LOOP_ID.fetch_add(1, Ordering::Relaxed); Rc::new(EventLoop { script_chan, @@ -57,6 +57,8 @@ impl EventLoop { /// Send a message to the event loop. pub fn send(&self, msg: ScriptThreadMessage) -> Result<(), Error> { - self.script_chan.send(msg) + self.script_chan + .send(msg) + .map_err(|_err| Box::new(ipc_channel::ErrorKind::Custom("SendError".into()))) } } diff --git a/components/constellation/pipeline.rs b/components/constellation/pipeline.rs index c4f734fdd54..2a34c415e5d 100644 --- a/components/constellation/pipeline.rs +++ b/components/constellation/pipeline.rs @@ -12,6 +12,7 @@ use background_hang_monitor_api::{ BackgroundHangMonitorControlMsg, BackgroundHangMonitorRegister, HangMonitorAlert, }; use base::Epoch; +use base::generic_channel::{GenericReceiver, GenericSender}; use base::id::{ BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespace, PipelineNamespaceId, PipelineNamespaceRequest, WebViewId, @@ -239,7 +240,8 @@ impl Pipeline { (script_chan, (None, None, None)) }, None => { - let (script_chan, script_port) = ipc::channel().expect("Pipeline script chan"); + let (script_chan, script_port) = + base::generic_channel::channel().expect("Pipeline script chan"); // Route messages coming from content to devtools as appropriate. let script_to_devtools_ipc_sender = @@ -482,9 +484,9 @@ pub struct UnprivilegedPipelineContent { mem_profiler_chan: profile_mem::ProfilerChan, viewport_details: ViewportDetails, theme: Theme, - script_chan: IpcSender, + script_chan: GenericSender, load_data: LoadData, - script_port: IpcReceiver, + script_port: GenericReceiver, opts: Opts, prefs: Box, pipeline_namespace_id: PipelineNamespaceId, diff --git a/components/layout/layout_impl.rs b/components/layout/layout_impl.rs index 697ed3cf89d..3c82c9734b2 100644 --- a/components/layout/layout_impl.rs +++ b/components/layout/layout_impl.rs @@ -13,6 +13,7 @@ use std::sync::{Arc, LazyLock}; use app_units::Au; use base::Epoch; +use base::generic_channel::GenericSender; use base::id::{PipelineId, WebViewId}; use bitflags::bitflags; use compositing_traits::CrossProcessCompositorApi; @@ -25,7 +26,6 @@ use fnv::FnvHashMap; use fonts::{FontContext, FontContextWebFontMethods}; use fonts_traits::StylesheetWebFontLoadFinishedCallback; use fxhash::FxHashMap; -use ipc_channel::ipc::IpcSender; use layout_api::wrapper_traits::LayoutNode; use layout_api::{ IFrameSizes, Layout, LayoutConfig, LayoutDamage, LayoutFactory, OffsetParentResponse, @@ -135,7 +135,7 @@ pub struct LayoutThread { is_iframe: bool, /// The channel on which messages can be sent to the script thread. - script_chan: IpcSender, + script_chan: GenericSender, /// The channel on which messages can be sent to the time profiler. time_profiler_chan: profile_time::ProfilerChan, diff --git a/components/script/dom/window.rs b/components/script/dom/window.rs index f733babe41a..c5788f2b4a1 100644 --- a/components/script/dom/window.rs +++ b/components/script/dom/window.rs @@ -17,6 +17,7 @@ use std::time::{Duration, Instant}; use app_units::Au; use backtrace::Backtrace; use base::cross_process_instant::CrossProcessInstant; +use base::generic_channel::GenericSender; use base::id::{BrowsingContextId, PipelineId, WebViewId}; use base64::Engine; #[cfg(feature = "bluetooth")] @@ -3043,7 +3044,7 @@ impl Window { time_profiler_chan: TimeProfilerChan, devtools_chan: Option>, constellation_chan: ScriptToConstellationChan, - control_chan: IpcSender, + control_chan: GenericSender, pipeline_id: PipelineId, parent_info: Option, viewport_details: ViewportDetails, @@ -3292,7 +3293,7 @@ impl Window { #[derive(MallocSizeOf)] pub(crate) struct CSSErrorReporter { pub(crate) pipelineid: PipelineId, - pub(crate) script_chan: IpcSender, + pub(crate) script_chan: GenericSender, } unsafe_no_jsmanaged_fields!(CSSErrorReporter); diff --git a/components/script/messaging.rs b/components/script/messaging.rs index f35704d666c..d15a66886ba 100644 --- a/components/script/messaging.rs +++ b/components/script/messaging.rs @@ -8,6 +8,7 @@ use std::cell::RefCell; use std::option::Option; use std::result::Result; +use base::generic_channel::GenericSender; use base::id::PipelineId; #[cfg(feature = "bluetooth")] use bluetooth_traits::BluetoothRequest; @@ -331,7 +332,7 @@ pub(crate) struct ScriptThreadSenders { /// A [`Sender`] that sends messages to the `Constellation`. #[no_trace] - pub(crate) constellation_sender: IpcSender, + pub(crate) constellation_sender: GenericSender, /// A [`Sender`] that sends messages to the `Constellation` associated with /// particular pipelines. diff --git a/components/script/script_thread.rs b/components/script/script_thread.rs index ec88e3217f9..f97473d8118 100644 --- a/components/script/script_thread.rs +++ b/components/script/script_thread.rs @@ -871,9 +871,7 @@ impl ScriptThread { JS_AddInterruptCallback(cx, Some(interrupt_callback)); } - // Ask the router to proxy IPC messages from the control port to us. - let constellation_receiver = - ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(state.constellation_receiver); + let constellation_receiver = state.constellation_receiver.into_inner(); // Ask the router to proxy IPC messages from the devtools to us. let devtools_server_sender = state.devtools_server_sender; diff --git a/components/shared/base/Cargo.toml b/components/shared/base/Cargo.toml index b293fa0faf3..34dcfc7fbf7 100644 --- a/components/shared/base/Cargo.toml +++ b/components/shared/base/Cargo.toml @@ -20,6 +20,7 @@ malloc_size_of = { workspace = true } malloc_size_of_derive = { workspace = true } parking_lot = { workspace = true } serde = { workspace = true } +servo_config = { path = "../../config" } time = { workspace = true } webrender_api = { workspace = true } diff --git a/components/shared/base/generic_channel.rs b/components/shared/base/generic_channel.rs index 2cd56394abe..753b9abef14 100644 --- a/components/shared/base/generic_channel.rs +++ b/components/shared/base/generic_channel.rs @@ -7,6 +7,7 @@ use std::fmt; use ipc_channel::router::ROUTER; +use malloc_size_of::{MallocSizeOf, MallocSizeOfOps}; use serde::{Deserialize, Deserializer, Serialize, Serializer}; static GENERIC_CHANNEL_USAGE_ERROR_PANIC_MSG: &str = "May not send a crossbeam channel over an IPC channel. \ @@ -65,6 +66,12 @@ impl GenericSender { } } +impl MallocSizeOf for GenericSender { + fn size_of(&self, _ops: &mut MallocSizeOfOps) -> usize { + 0 + } +} + #[derive(Debug)] pub struct SendError; pub type SendResult = Result<(), SendError>; @@ -145,11 +152,11 @@ where /// Creates a Servo channel that can select different channel implementations based on multiprocess /// mode or not. If the scenario doesn't require message to pass process boundary, a simple /// crossbeam channel is preferred. -pub fn channel(multiprocess: bool) -> Option<(GenericSender, GenericReceiver)> +pub fn channel() -> Option<(GenericSender, GenericReceiver)> where T: for<'de> Deserialize<'de> + Serialize, { - if multiprocess { + if servo_config::opts::get().multiprocess { ipc_channel::ipc::channel() .map(|(tx, rx)| (GenericSender::Ipc(tx), GenericReceiver::Ipc(rx))) .ok() diff --git a/components/shared/canvas/webgl.rs b/components/shared/canvas/webgl.rs index 4bd62bfa5d2..7cf09468e43 100644 --- a/components/shared/canvas/webgl.rs +++ b/components/shared/canvas/webgl.rs @@ -33,7 +33,7 @@ pub fn webgl_channel() -> Option<(WebGLSender, WebGLReceiver)> where T: for<'de> Deserialize<'de> + Serialize, { - base::generic_channel::channel(servo_config::opts::get().multiprocess) + base::generic_channel::channel() } /// Entry point channel type used for sending WebGLMsg messages to the WebGL renderer. diff --git a/components/shared/layout/lib.rs b/components/shared/layout/lib.rs index 8f2aaa8a38b..68208d25cab 100644 --- a/components/shared/layout/lib.rs +++ b/components/shared/layout/lib.rs @@ -20,6 +20,7 @@ use std::thread::JoinHandle; use app_units::Au; use atomic_refcell::AtomicRefCell; use base::Epoch; +use base::generic_channel::GenericSender; use base::id::{BrowsingContextId, PipelineId, WebViewId}; use bitflags::bitflags; use compositing_traits::CrossProcessCompositorApi; @@ -30,7 +31,6 @@ use euclid::default::{Point2D as UntypedPoint2D, Rect}; use fnv::FnvHashMap; use fonts::{FontContext, SystemFontServiceProxy}; use fxhash::FxHashMap; -use ipc_channel::ipc::IpcSender; pub use layout_damage::LayoutDamage; use libc::c_void; use malloc_size_of::{MallocSizeOf as MallocSizeOfTrait, MallocSizeOfOps, malloc_size_of_is_0}; @@ -197,7 +197,7 @@ pub struct LayoutConfig { pub webview_id: WebViewId, pub url: ServoUrl, pub is_iframe: bool, - pub script_chan: IpcSender, + pub script_chan: GenericSender, pub image_cache: Arc, pub font_context: Arc, pub time_profiler_chan: time::ProfilerChan, diff --git a/components/shared/script/lib.rs b/components/shared/script/lib.rs index a1bceff8ae5..8ba181aada3 100644 --- a/components/shared/script/lib.rs +++ b/components/shared/script/lib.rs @@ -15,6 +15,7 @@ use std::sync::Arc; use background_hang_monitor_api::BackgroundHangMonitorRegister; use base::cross_process_instant::CrossProcessInstant; +use base::generic_channel::{GenericReceiver, GenericSender}; use base::id::{BrowsingContextId, HistoryStateId, PipelineId, PipelineNamespaceId, WebViewId}; #[cfg(feature = "bluetooth")] use bluetooth_traits::BluetoothRequest; @@ -307,9 +308,9 @@ pub struct InitialScriptState { /// Loading into a Secure Context pub inherited_secure_context: Option, /// A channel with which messages can be sent to us (the script thread). - pub constellation_sender: IpcSender, + pub constellation_sender: GenericSender, /// A port on which messages sent by the constellation to script can be received. - pub constellation_receiver: IpcReceiver, + pub constellation_receiver: GenericReceiver, /// A channel on which messages can be sent to the constellation from script. pub pipeline_to_constellation_sender: ScriptToConstellationChan, /// A handle to register script-(and associated layout-)threads for hang monitoring.