From 666b17a9a141529842d9cfeb647bd0634e0e0cbc Mon Sep 17 00:00:00 2001 From: Jonathan Schwender <55576758+jschwe@users.noreply.github.com> Date: Thu, 18 Sep 2025 08:06:08 +0800 Subject: [PATCH] canvas: Port CanvasMsg channel to generic channel (#39348) Additionally also improve the warning message if the routed receiver disconnects and exit the thread. If the routed receiver disconnects, we can't receive any canvas messages anymore, and any control messages can't remedy that, so we might as well exit. Testing: Channel changes are covered by existing tests. Exiting the canvas thread if the routed thread disconnects is not tested, and needs reviewer attention. Part of https://github.com/servo/servo/issues/38912 Signed-off-by: Jonathan Schwender --- components/canvas/canvas_paint_thread.rs | 25 +++++++++++-------- components/constellation/constellation.rs | 8 +++--- .../script/dom/canvas/2d/canvas_state.rs | 6 ++--- .../constellation/from_script_message.rs | 2 +- 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/components/canvas/canvas_paint_thread.rs b/components/canvas/canvas_paint_thread.rs index 517ddf01351..290708ee716 100644 --- a/components/canvas/canvas_paint_thread.rs +++ b/components/canvas/canvas_paint_thread.rs @@ -5,14 +5,13 @@ use std::borrow::ToOwned; use std::{f32, thread}; -use base::Epoch; +use base::generic_channel::GenericSender; +use base::{Epoch, generic_channel}; use canvas_traits::ConstellationCanvasMsg; use canvas_traits::canvas::*; use compositing_traits::CrossProcessCompositorApi; use crossbeam_channel::{Sender, select, unbounded}; use euclid::default::{Rect, Size2D, Transform2D}; -use ipc_channel::ipc::{self, IpcSender}; -use ipc_channel::router::ROUTER; use log::warn; use pixels::Snapshot; use rustc_hash::FxHashMap; @@ -39,9 +38,9 @@ impl CanvasPaintThread { /// communicate with it. pub fn start( compositor_api: CrossProcessCompositorApi, - ) -> (Sender, IpcSender) { - let (ipc_sender, ipc_receiver) = ipc::channel::().unwrap(); - let msg_receiver = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(ipc_receiver); + ) -> (Sender, GenericSender) { + let (ipc_sender, ipc_receiver) = generic_channel::channel::().unwrap(); + let msg_receiver = ipc_receiver.route_preserving_errors(); let (create_sender, create_receiver) = unbounded(); thread::Builder::new() .name("Canvas".to_owned()) @@ -52,17 +51,21 @@ impl CanvasPaintThread { select! { recv(msg_receiver) -> msg => { match msg { - Ok(CanvasMsg::Canvas2d(message, canvas_id)) => { + Ok(Ok(CanvasMsg::Canvas2d(message, canvas_id))) => { canvas_paint_thread.process_canvas_2d_message(message, canvas_id); }, - Ok(CanvasMsg::Close(canvas_id)) => { + Ok(Ok(CanvasMsg::Close(canvas_id))) => { canvas_paint_thread.canvases.remove(&canvas_id); }, - Ok(CanvasMsg::Recreate(size, canvas_id)) => { + Ok(Ok(CanvasMsg::Recreate(size, canvas_id))) => { canvas_paint_thread.canvas(canvas_id).recreate(size); }, - Err(e) => { - warn!("Error on CanvasPaintThread receive ({})", e); + Ok(Err(e)) => { + warn!("CanvasPaintThread message deserialization error: {e:?}"); + } + Err(_disconnected) => { + warn!("CanvasMsg receiver disconnected"); + break; }, } } diff --git a/components/constellation/constellation.rs b/components/constellation/constellation.rs index c988dfa24e3..815a4583131 100644 --- a/components/constellation/constellation.rs +++ b/components/constellation/constellation.rs @@ -451,7 +451,7 @@ pub struct Constellation { webxr_registry: Option, /// Lazily initialized channels for canvas paint thread. - canvas: OnceCell<(Sender, IpcSender)>, + canvas: OnceCell<(Sender, GenericSender)>, /// Navigation requests from script awaiting approval from the embedder. pending_approval_navigations: PendingApprovalNavigations, @@ -4495,7 +4495,7 @@ where fn handle_create_canvas_paint_thread_msg( &mut self, size: UntypedSize2D, - response_sender: IpcSender, CanvasId, ImageKey)>>, + response_sender: IpcSender, CanvasId, ImageKey)>>, ) { let (canvas_data_sender, canvas_data_receiver) = unbounded(); let (canvas_sender, canvas_ipc_sender) = self @@ -5648,7 +5648,9 @@ where } } - fn create_canvas_paint_thread(&self) -> (Sender, IpcSender) { + fn create_canvas_paint_thread( + &self, + ) -> (Sender, GenericSender) { CanvasPaintThread::start(self.compositor_proxy.cross_process_compositor_api.clone()) } } diff --git a/components/script/dom/canvas/2d/canvas_state.rs b/components/script/dom/canvas/2d/canvas_state.rs index 3d61ca0c918..a8f3e5f0354 100644 --- a/components/script/dom/canvas/2d/canvas_state.rs +++ b/components/script/dom/canvas/2d/canvas_state.rs @@ -9,6 +9,7 @@ use std::sync::Arc; use app_units::Au; use base::Epoch; +use base::generic_channel::GenericSender; use canvas_traits::canvas::{ Canvas2dMsg, CanvasFont, CanvasId, CanvasMsg, CompositionOptions, CompositionOrBlending, FillOrStrokeStyle, FillRule, GlyphAndPosition, LineCapStyle, LineJoinStyle, LineOptions, @@ -23,7 +24,7 @@ use fonts::{ ByteIndex, FontBaseline, FontContext, FontGroup, FontIdentifier, FontMetrics, FontRef, LAST_RESORT_GLYPH_ADVANCE, ShapingFlags, ShapingOptions, }; -use ipc_channel::ipc::{self, IpcSender}; +use ipc_channel::ipc; use net_traits::image_cache::{ImageCache, ImageResponse}; use net_traits::request::CorsSettings; use pixels::{PixelFormat, Snapshot, SnapshotAlphaMode, SnapshotPixelFormat}; @@ -193,9 +194,8 @@ impl CanvasContextState { #[cfg_attr(crown, crown::unrooted_must_root_lint::must_root)] #[derive(JSTraceable, MallocSizeOf)] pub(super) struct CanvasState { - #[ignore_malloc_size_of = "Defined in ipc-channel"] #[no_trace] - ipc_renderer: IpcSender, + ipc_renderer: GenericSender, #[no_trace] canvas_id: CanvasId, #[no_trace] diff --git a/components/shared/constellation/from_script_message.rs b/components/shared/constellation/from_script_message.rs index 353dd22bc35..02b3a913505 100644 --- a/components/shared/constellation/from_script_message.rs +++ b/components/shared/constellation/from_script_message.rs @@ -542,7 +542,7 @@ pub enum ScriptToConstellationMessage { /// 2D canvases may use the GPU and we don't want to give untrusted content access to the GPU.) CreateCanvasPaintThread( UntypedSize2D, - IpcSender, CanvasId, ImageKey)>>, + IpcSender, CanvasId, ImageKey)>>, ), /// Notifies the constellation that this pipeline is requesting focus. ///