From c75995ec87b3e60729ed42883d882df110ab1e5f Mon Sep 17 00:00:00 2001 From: Mukilan Thiyagarajan Date: Tue, 26 Aug 2025 19:46:58 +0530 Subject: [PATCH] Revert "GenericChannel: Migrate compositor channels to GenericChannel (#38782)" (#38940) This reverts commit fb1c0a4c48dee5791b8785e5d5d4906b935bdb76. Previously in `create_compositor_channel`, the [routing callback][1] was setup so that a message received on the Compositor's IPC receiver will be forwarded to the local receiver using the `CompositorProxy` which also takes care of waking up the event loop. In #38782, this was changed so that the routing callbacks simply forwards the message directly without going via the `CompositorProxy`. This breaks behaviours that rely on the event loop being woken up on message sending, e.g. updating image frames for animated gifs. Since the GenericChannel API doesn't allow custom routing callbacks, revert this change until we figure out a better solution. [1]: https://github.com/servo/servo/blob/d2ccce6052a6cff7ddee67f4e8d2823a04366058/components/servo/lib.rs#L1114 Signed-off-by: Mukilan Thiyagarajan Signed-off-by: Mukilan Thiyagarajan --- components/compositing/compositor.rs | 8 ++-- components/compositing/lib.rs | 5 +-- components/constellation/constellation.rs | 13 +++--- components/script/dom/workletglobalscope.rs | 3 +- components/script/messaging.rs | 2 +- components/servo/lib.rs | 31 ++++++++------ components/shared/base/generic_channel.rs | 40 ------------------- components/shared/compositing/lib.rs | 30 +++----------- .../constellation/from_script_message.rs | 6 +-- 9 files changed, 42 insertions(+), 96 deletions(-) diff --git a/components/compositing/compositor.rs b/components/compositing/compositor.rs index 40f74b8c20e..5d7724725c2 100644 --- a/components/compositing/compositor.rs +++ b/components/compositing/compositor.rs @@ -11,9 +11,9 @@ use std::rc::Rc; use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; +use base::Epoch; use base::cross_process_instant::CrossProcessInstant; use base::id::{PipelineId, WebViewId}; -use base::{Epoch, generic_channel}; use bitflags::bitflags; use compositing_traits::display_list::{CompositorDisplayListInfo, ScrollTree, ScrollType}; use compositing_traits::rendering_context::RenderingContext; @@ -22,7 +22,7 @@ use compositing_traits::{ WebViewTrait, }; use constellation_traits::{EmbedderToConstellationMessage, PaintMetricEvent}; -use crossbeam_channel::Sender; +use crossbeam_channel::{Receiver, Sender}; use dpi::PhysicalSize; use embedder_traits::{CompositorHitTestResult, InputEvent, ShutdownState, ViewportDetails}; use euclid::{Point2D, Rect, Scale, Size2D, Transform3D}; @@ -92,7 +92,7 @@ pub struct ServoRenderer { shutdown_state: Rc>, /// The port on which we receive messages. - compositor_receiver: generic_channel::RoutedReceiver, + compositor_receiver: Receiver, /// The channel on which messages can be sent to the constellation. pub(crate) constellation_sender: Sender, @@ -1388,7 +1388,7 @@ impl IOCompositor { } /// Get the message receiver for this [`IOCompositor`]. - pub fn receiver(&self) -> Ref<'_, generic_channel::RoutedReceiver> { + pub fn receiver(&self) -> Ref<'_, Receiver> { Ref::map(self.global.borrow(), |global| &global.compositor_receiver) } diff --git a/components/compositing/lib.rs b/components/compositing/lib.rs index c2bfd8eb9d7..4faeadf5ba6 100644 --- a/components/compositing/lib.rs +++ b/components/compositing/lib.rs @@ -7,11 +7,10 @@ use std::cell::Cell; use std::rc::Rc; -use base::generic_channel; use compositing_traits::rendering_context::RenderingContext; use compositing_traits::{CompositorMsg, CompositorProxy}; use constellation_traits::EmbedderToConstellationMessage; -use crossbeam_channel::Sender; +use crossbeam_channel::{Receiver, Sender}; use embedder_traits::{EventLoopWaker, ShutdownState}; use profile_traits::{mem, time}; use webrender::RenderApi; @@ -33,7 +32,7 @@ pub struct InitialCompositorState { /// A channel to the compositor. pub sender: CompositorProxy, /// A port on which messages inbound to the compositor can be received. - pub receiver: generic_channel::RoutedReceiver, + pub receiver: Receiver, /// A channel to the constellation. pub constellation_chan: Sender, /// A channel to the time profiler thread. diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index 4c0d244ac5e..cec20412a29 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -290,11 +290,11 @@ pub struct Constellation { /// An IPC channel for script threads to send messages to the constellation. /// This is the script threads' view of `script_receiver`. - script_sender: GenericSender<(PipelineId, ScriptToConstellationMessage)>, + script_sender: IpcSender<(PipelineId, ScriptToConstellationMessage)>, /// A channel for the constellation to receive messages from script threads. /// This is the constellation's view of `script_sender`. - script_receiver: RoutedReceiver<(PipelineId, ScriptToConstellationMessage)>, + script_receiver: Receiver>, /// A handle to register components for hang monitoring. /// None when in multiprocess mode. @@ -607,8 +607,11 @@ where .name("Constellation".to_owned()) .spawn(move || { let (script_ipc_sender, script_ipc_receiver) = - generic_channel::channel().expect("ipc channel failure"); - let script_receiver = script_ipc_receiver.route_preserving_errors(); + ipc::channel().expect("ipc channel failure"); + let script_receiver = + route_ipc_receiver_to_new_crossbeam_receiver_preserving_errors( + script_ipc_receiver, + ); let (namespace_ipc_sender, namespace_ipc_receiver) = generic_channel::channel().expect("ipc channel failure"); @@ -1243,7 +1246,7 @@ where let request = match request { Ok(request) => request, - Err(err) => return error!("Deserialization failed ({err:?})."), + Err(err) => return error!("Deserialization failed ({}).", err), }; match request { diff --git a/components/script/dom/workletglobalscope.rs b/components/script/dom/workletglobalscope.rs index 117fbf56302..a083a38f1da 100644 --- a/components/script/dom/workletglobalscope.rs +++ b/components/script/dom/workletglobalscope.rs @@ -4,7 +4,6 @@ use std::sync::Arc; -use base::generic_channel::GenericSender; use base::id::PipelineId; use constellation_traits::{ScriptToConstellationChan, ScriptToConstellationMessage}; use crossbeam_channel::Sender; @@ -196,7 +195,7 @@ pub(crate) struct WorkletGlobalScopeInit { /// Channel to devtools pub(crate) devtools_chan: Option>, /// Messages to send to constellation - pub(crate) to_constellation_sender: GenericSender<(PipelineId, ScriptToConstellationMessage)>, + pub(crate) to_constellation_sender: IpcSender<(PipelineId, ScriptToConstellationMessage)>, /// The image cache pub(crate) image_cache: Arc, /// Identity manager for WebGPU resources diff --git a/components/script/messaging.rs b/components/script/messaging.rs index 6104cdfaecc..fb295a0f0d3 100644 --- a/components/script/messaging.rs +++ b/components/script/messaging.rs @@ -340,7 +340,7 @@ pub(crate) struct ScriptThreadSenders { /// particular pipelines. #[no_trace] pub(crate) pipeline_to_constellation_sender: - GenericSender<(PipelineId, ScriptToConstellationMessage)>, + IpcSender<(PipelineId, ScriptToConstellationMessage)>, /// The shared [`IpcSender`] which is sent to the `ImageCache` when requesting an image. The /// messages on this channel are routed to crossbeam [`Sender`] on the router thread, which diff --git a/components/servo/lib.rs b/components/servo/lib.rs index 6d62e07eed7..075493d79b0 100644 --- a/components/servo/lib.rs +++ b/components/servo/lib.rs @@ -33,7 +33,6 @@ use std::rc::{Rc, Weak}; use std::sync::{Arc, Mutex}; use std::thread; -use base::generic_channel; pub use base::id::WebViewId; use base::id::{PipelineNamespace, PipelineNamespaceId}; #[cfg(feature = "bluetooth")] @@ -83,6 +82,7 @@ use gaol::sandbox::{ChildSandbox, ChildSandboxMethods}; pub use gleam::gl; use gleam::gl::RENDERER; use ipc_channel::ipc::{self, IpcSender}; +use ipc_channel::router::ROUTER; use javascript_evaluator::JavaScriptEvaluator; pub use keyboard_types::{ Code, CompositionEvent, CompositionState, Key, KeyState, Location, Modifiers, NamedKey, @@ -544,7 +544,7 @@ impl Servo { let mut compositor = self.compositor.borrow_mut(); let mut messages = Vec::new(); while let Ok(message) = compositor.receiver().try_recv() { - messages.push(message.expect("IPC serialization error")); + messages.push(message); } compositor.handle_messages(messages); } @@ -1095,23 +1095,28 @@ fn create_embedder_channel( fn create_compositor_channel( event_loop_waker: Box, -) -> ( - CompositorProxy, - generic_channel::RoutedReceiver, -) { - let routed_channel = - generic_channel::routed_channel_with_local_sender().expect("Create channel failure"); +) -> (CompositorProxy, Receiver) { + let (sender, receiver) = unbounded(); - let cross_process_compositor_api = - CrossProcessCompositorApi(routed_channel.generic_sender.clone()); + let (compositor_ipc_sender, compositor_ipc_receiver) = + ipc::channel().expect("ipc channel failure"); - let compositor_proxy = CompositorProxy::new( - routed_channel.local_sender, + let cross_process_compositor_api = CrossProcessCompositorApi(compositor_ipc_sender); + let compositor_proxy = CompositorProxy { + sender, cross_process_compositor_api, event_loop_waker, + }; + + let compositor_proxy_clone = compositor_proxy.clone(); + ROUTER.add_typed_route( + compositor_ipc_receiver, + Box::new(move |message| { + compositor_proxy_clone.send(message.expect("Could not convert Compositor message")); + }), ); - (compositor_proxy, routed_channel.local_receiver) + (compositor_proxy, receiver) } #[allow(clippy::too_many_arguments)] diff --git a/components/shared/base/generic_channel.rs b/components/shared/base/generic_channel.rs index 2dd0c2a5b7c..ce336f0d174 100644 --- a/components/shared/base/generic_channel.rs +++ b/components/shared/base/generic_channel.rs @@ -395,18 +395,6 @@ where } } -/// A GenericChannel, which was routed via the Router. -pub struct GenericRoutedChannel Deserialize<'de>> { - /// A GenericSender of the channel, i.e. it may be sent to other processes in multiprocess mode. - /// Connected to `local_receiver` via the [ROUTER]. - pub generic_sender: GenericSender, - /// A sender that directly sends to the local_receiver. Can only be used in the same process - /// as the `local_receiver`. - pub local_sender: crossbeam_channel::Sender>, - /// The receiving end of the channel. Only usable in the current process. - pub local_receiver: RoutedReceiver, -} - /// Private helper function to create a crossbeam based channel. /// /// Do NOT make this function public! @@ -447,34 +435,6 @@ where } } -/// Returns a [GenericRoutedChannel], where the receiver is usable in the current process, -/// and sending is possible both in remote and local process, via the generic_sender and the -/// local_sender. -pub fn routed_channel_with_local_sender() -> Option> -where - T: for<'de> Deserialize<'de> + Serialize + Send + 'static, -{ - let (crossbeam_sender, crossbeam_receiver) = crossbeam_channel::unbounded(); - let generic_sender = if opts::get().multiprocess || opts::get().force_ipc { - let (ipc_sender, ipc_receiver) = ipc_channel::ipc::channel().ok()?; - let crossbeam_sender_clone = crossbeam_sender.clone(); - ROUTER.add_typed_route( - ipc_receiver, - Box::new(move |message| { - let _ = crossbeam_sender_clone.send(message); - }), - ); - GenericSender(GenericSenderVariants::Ipc(ipc_sender)) - } else { - GenericSender(GenericSenderVariants::Crossbeam(crossbeam_sender.clone())) - }; - Some(GenericRoutedChannel { - generic_sender, - local_sender: crossbeam_sender, - local_receiver: crossbeam_receiver, - }) -} - #[cfg(test)] mod single_process_channel_tests { //! These unit-tests test that ipc_channel and crossbeam_channel Senders and Receivers diff --git a/components/shared/compositing/lib.rs b/components/shared/compositing/lib.rs index 8345b0b9e83..f61dbbb6711 100644 --- a/components/shared/compositing/lib.rs +++ b/components/shared/compositing/lib.rs @@ -23,7 +23,6 @@ pub mod viewport_description; use std::collections::HashMap; use std::sync::{Arc, Mutex}; -use base::generic_channel::GenericSender; use bitflags::bitflags; use display_list::CompositorDisplayListInfo; use embedder_traits::ScreenGeometry; @@ -45,12 +44,7 @@ use crate::viewport_description::ViewportDescription; /// Sends messages to the compositor. #[derive(Clone)] pub struct CompositorProxy { - /// A sender optimised for sending in the local process. - /// The type is a Result to match the API of ipc_channel after routing, - /// which contains a Result to propagate deserialization errors to the - /// recipient. - /// The field is private to hide the inner `Result` type. - sender: Sender>, + pub sender: Sender, /// Access to [`Self::sender`] that is possible to send across an IPC /// channel. These messages are routed via the router thread to /// [`Self::sender`]. @@ -58,20 +52,6 @@ pub struct CompositorProxy { pub event_loop_waker: Box, } -impl CompositorProxy { - pub fn new( - local_process_sender: Sender>, - cross_process_compositor_api: CrossProcessCompositorApi, - event_loop_waker: Box, - ) -> Self { - Self { - sender: local_process_sender, - cross_process_compositor_api, - event_loop_waker, - } - } -} - impl OpaqueSender for CompositorProxy { fn send(&self, message: CompositorMsg) { CompositorProxy::send(self, message) @@ -80,7 +60,7 @@ impl OpaqueSender for CompositorProxy { impl CompositorProxy { pub fn send(&self, msg: CompositorMsg) { - if let Err(err) = self.sender.send(Ok(msg)) { + if let Err(err) = self.sender.send(msg) { warn!("Failed to send response ({:?}).", err); } self.event_loop_waker.wake(); @@ -190,18 +170,18 @@ pub struct CompositionPipeline { /// A mechanism to send messages from ScriptThread to the parent process' WebRender instance. #[derive(Clone, Deserialize, MallocSizeOf, Serialize)] -pub struct CrossProcessCompositorApi(pub GenericSender); +pub struct CrossProcessCompositorApi(pub IpcSender); impl CrossProcessCompositorApi { /// Create a new [`CrossProcessCompositorApi`] struct that does not have a listener on the other /// end to use for unit testing. pub fn dummy() -> Self { - let (sender, _) = base::generic_channel::channel().unwrap(); + let (sender, _) = ipc::channel().unwrap(); Self(sender) } /// Get the sender for this proxy. - pub fn sender(&self) -> &GenericSender { + pub fn sender(&self) -> &IpcSender { &self.0 } diff --git a/components/shared/constellation/from_script_message.rs b/components/shared/constellation/from_script_message.rs index c55e08826e1..1f96d933a93 100644 --- a/components/shared/constellation/from_script_message.rs +++ b/components/shared/constellation/from_script_message.rs @@ -8,7 +8,6 @@ use std::collections::HashMap; use std::fmt; use base::Epoch; -use base::generic_channel::{GenericSender, SendResult}; use base::id::{ BroadcastChannelRouterId, BrowsingContextId, HistoryStateId, MessagePortId, MessagePortRouterId, PipelineId, ServiceWorkerId, ServiceWorkerRegistrationId, WebViewId, @@ -22,6 +21,7 @@ use embedder_traits::{ }; use euclid::default::Size2D as UntypedSize2D; use http::{HeaderMap, Method}; +use ipc_channel::Error as IpcError; use ipc_channel::ipc::{IpcReceiver, IpcSender}; use malloc_size_of_derive::MallocSizeOf; use net_traits::policy_container::PolicyContainer; @@ -46,14 +46,14 @@ use crate::{ #[derive(Clone, Debug, Deserialize, MallocSizeOf, Serialize)] pub struct ScriptToConstellationChan { /// Sender for communicating with constellation thread. - pub sender: GenericSender<(PipelineId, ScriptToConstellationMessage)>, + pub sender: IpcSender<(PipelineId, ScriptToConstellationMessage)>, /// Used to identify the origin of the message. pub pipeline_id: PipelineId, } impl ScriptToConstellationChan { /// Send ScriptMsg and attach the pipeline_id to the message. - pub fn send(&self, msg: ScriptToConstellationMessage) -> SendResult { + pub fn send(&self, msg: ScriptToConstellationMessage) -> Result<(), IpcError> { self.sender.send((self.pipeline_id, msg)) } }