generic_channel: Preserve IPC errors (#38854)

We should not be using `route_ipc_receiver_to_new_crossbeam_receiver` or
similar methods, that `unwrap()` on the ROUTER thread if they encounter
IPC errors. Instead, we now propagate the error to the crossbeam
receiver.
In the GenericChannel::Crossbeam case this means, that we need to use a
`Result<T>` as the data type, even though the Result variant is always
okay, so that the receiver type is the same regardless of `IPC` or not.
This is required, so we have the same channel type, and can pass the
inner crossbeam channel into e.g. `select!`, without having to wrap or
re-implement select.

This also means, that as we switch towards GenericChannel, we will
gradually improve our error handling and eventually remove the existing
panics on IPC errors.

These changes were extracted out of
https://github.com/servo/servo/pull/38782

Testing: Covered by existing tests. No new panics were introduced.

Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This commit is contained in:
Jonathan Schwender 2025-08-25 06:19:41 +02:00 committed by GitHub
parent 2b7186893f
commit ea5d786506
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 131 additions and 26 deletions

View file

@ -8,7 +8,7 @@ use std::cell::RefCell;
use std::option::Option;
use std::result::Result;
use base::generic_channel::GenericSender;
use base::generic_channel::{GenericSender, RoutedReceiver};
use base::id::PipelineId;
#[cfg(feature = "bluetooth")]
use bluetooth_traits::BluetoothRequest;
@ -371,7 +371,7 @@ pub(crate) struct ScriptThreadSenders {
pub(crate) struct ScriptThreadReceivers {
/// A [`Receiver`] that receives messages from the constellation.
#[no_trace]
pub(crate) constellation_receiver: Receiver<ScriptThreadMessage>,
pub(crate) constellation_receiver: RoutedReceiver<ScriptThreadMessage>,
/// The [`Receiver`] which receives incoming messages from the `ImageCache`.
#[no_trace]
@ -405,7 +405,7 @@ impl ScriptThreadReceivers {
.expect("Spurious wake-up of the event-loop, task-queue has no tasks available");
MixedMessage::FromScript(event)
},
recv(self.constellation_receiver) -> msg => MixedMessage::FromConstellation(msg.unwrap()),
recv(self.constellation_receiver) -> msg => MixedMessage::FromConstellation(msg.unwrap().unwrap()),
recv(self.devtools_server_receiver) -> msg => MixedMessage::FromDevtools(msg.unwrap()),
recv(self.image_cache_receiver) -> msg => MixedMessage::FromImageCache(msg.unwrap()),
recv(timer_scheduler.wait_channel()) -> _ => MixedMessage::TimerFired,
@ -438,6 +438,14 @@ impl ScriptThreadReceivers {
task_queue: &TaskQueue<MainThreadScriptMsg>,
) -> Option<MixedMessage> {
if let Ok(message) = self.constellation_receiver.try_recv() {
let message = message
.inspect_err(|e| {
log::warn!(
"ScriptThreadReceivers IPC error on constellation_receiver: {:?}",
e
);
})
.ok()?;
return MixedMessage::FromConstellation(message).into();
}
if let Ok(message) = task_queue.take_tasks_and_recv() {

View file

@ -870,7 +870,7 @@ impl ScriptThread {
JS_AddInterruptCallback(cx, Some(interrupt_callback));
}
let constellation_receiver = state.constellation_receiver.into_inner();
let constellation_receiver = state.constellation_receiver.route_preserving_errors();
// Ask the router to proxy IPC messages from the devtools to us.
let devtools_server_sender = state.devtools_server_sender;