Add direct script to embedder channel (#39039)

This PR **removes** `ScriptToConstellationMessage::ForwardToEmbedder`,
and replaces it with an explicit `ScriptToEmbedderChannel`. This new
channel is based on `GenericCallback` and in single-process mode will
directly send the message the to the embedder and wake it. In
multi-process mode, the message is routed via the ROUTER, since waking
is only possible from the same process currently. This means in
multi-process mode there are likely no direct perf benefits, since we
still need to hop the message over the ROUTER (instead of over the
constellation).
In single-process mode we can directly send the message to the embedder,
which should provide a noticable latency improvement in all cases where
script is blocked waiting on the embedder to reply.

This does not change the way the embedder receives messages - the
receiving end is unchanged.

## How was sending messages to the embedder working before?

1. Script wraps it's message to the embedder in
`ScriptToConstellationMessage::ForwardToEmbedder` and sends it to
constellation.
2. The [constellation event loop] receives the message in
[handle_request]
3. If deserialization fails, [an error is logged and the message is
ignored]
4. Since our message came from script, it is handle in
[handle_request_from_script]
5. The message is logged with trace log level
6. If the pipeline is closed, [a warning is logged and the message
ignored]
7. The wrapped `EmbedderMsg` [is forwarded to the embedder]. Sending the
message also invokes `wake()` on the embedder eventloop waker.

[constellation event loop]:
2e1b2e7260/components/constellation/constellation.rs (L755)

[handle request]:
2e1b2e7260/components/constellation/constellation.rs (L1182)

[an error is logged and the message is ignored]:
2e1b2e7260/components/constellation/constellation.rs (L1252)

[handle_request_from_script]:
https://github.com/servo/servo/blob/main/components/constellation/constellation.rs#L1590
 
[a warning is logged and the message ignored]:
2e1b2e7260/components/constellation/constellation.rs (L1599)

[is forwarded to the embedder]:
2e1b2e7260/components/constellation/constellation.rs (L1701)

Testing: Communication between Script and Embedder is extensive, so this
should be covered by existing tests.

Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This commit is contained in:
Jonathan Schwender 2025-09-02 08:33:44 +02:00 committed by GitHub
parent 97c8c83cbb
commit f4dd2960b8
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 120 additions and 113 deletions

View file

@ -27,7 +27,9 @@ use constellation_traits::{LoadData, SWManagerMsg, ScriptToConstellationChan};
use crossbeam_channel::{Sender, unbounded};
use devtools_traits::{DevtoolsControlMsg, ScriptToDevtoolsControlMsg};
use embedder_traits::user_content_manager::UserContentManager;
use embedder_traits::{AnimationState, FocusSequenceNumber, Theme, ViewportDetails};
use embedder_traits::{
AnimationState, FocusSequenceNumber, ScriptToEmbedderChan, Theme, ViewportDetails,
};
use fonts::{SystemFontServiceProxy, SystemFontServiceProxySender};
use ipc_channel::Error;
use ipc_channel::ipc::{self, IpcReceiver, IpcSender};
@ -131,6 +133,9 @@ pub struct InitialPipelineState {
/// A channel to the associated constellation.
pub script_to_constellation_chan: ScriptToConstellationChan,
/// A channel to the embedder.
pub script_to_embedder_chan: ScriptToEmbedderChan,
/// A sender to request pipeline namespace ids.
pub namespace_request_sender: GenericSender<PipelineNamespaceRequest>,
@ -277,6 +282,7 @@ impl Pipeline {
parent_pipeline_id: state.parent_pipeline_id,
opener: state.opener,
script_to_constellation_chan: state.script_to_constellation_chan.clone(),
script_to_embedder_chan: state.script_to_embedder_chan,
namespace_request_sender: state.namespace_request_sender,
background_hang_monitor_to_constellation_chan: state
.background_hang_monitor_to_constellation_chan
@ -476,6 +482,7 @@ pub struct UnprivilegedPipelineContent {
opener: Option<BrowsingContextId>,
namespace_request_sender: GenericSender<PipelineNamespaceRequest>,
script_to_constellation_chan: ScriptToConstellationChan,
script_to_embedder_chan: ScriptToEmbedderChan,
background_hang_monitor_to_constellation_chan: IpcSender<HangMonitorAlert>,
bhm_control_port: Option<IpcReceiver<BackgroundHangMonitorControlMsg>>,
devtools_ipc_sender: Option<IpcSender<ScriptToDevtoolsControlMsg>>,
@ -530,6 +537,7 @@ impl UnprivilegedPipelineContent {
constellation_sender: self.script_chan.clone(),
constellation_receiver: self.script_port,
pipeline_to_constellation_sender: self.script_to_constellation_chan.clone(),
pipeline_to_embedder_sender: self.script_to_embedder_chan,
background_hang_monitor_register: background_hang_monitor_register.clone(),
#[cfg(feature = "bluetooth")]
bluetooth_sender: self.bluetooth_thread,