generic channel: Migrate background hang monitor to GenericChannel (#39345)

Refactor the background hang monitor channels to use GenericChannel. 
Deserialization errors of `BackgroundHangMonitorControlMsg` are now
logged and ignored instead of causing a panic.

Testing: No major functional changes. Covered by BHM tests.
GenericChannel is also already widely used in servo.
Part of #38912

---------

Signed-off-by: Jonathan Schwender <schwenderjonathan@gmail.com>
This commit is contained in:
Jonathan Schwender 2025-09-17 19:11:07 +08:00 committed by GitHub
parent 6cba44e0e3
commit d848bd2759
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 36 additions and 31 deletions

View file

@ -11,9 +11,8 @@ use background_hang_monitor_api::{
BackgroundHangMonitorExitSignal, BackgroundHangMonitorRegister, HangAlert, HangAnnotation,
HangMonitorAlert, MonitoredComponentId,
};
use base::generic_channel::{GenericReceiver, GenericSender, RoutedReceiver};
use crossbeam_channel::{Receiver, Sender, after, never, select, unbounded};
use ipc_channel::ipc::{IpcReceiver, IpcSender};
use ipc_channel::router::ROUTER;
use rustc_hash::FxHashMap;
use crate::sampler::{NativeStack, Sampler};
@ -28,8 +27,8 @@ impl HangMonitorRegister {
/// Start a new hang monitor worker, and return a handle to register components for monitoring,
/// as well as a join handle on the worker thread.
pub fn init(
constellation_chan: IpcSender<HangMonitorAlert>,
control_port: IpcReceiver<BackgroundHangMonitorControlMsg>,
constellation_chan: GenericSender<HangMonitorAlert>,
control_port: GenericReceiver<BackgroundHangMonitorControlMsg>,
monitoring_enabled: bool,
) -> (Box<dyn BackgroundHangMonitorRegister>, JoinHandle<()>) {
let (sender, port) = unbounded();
@ -211,9 +210,9 @@ struct Sample(MonitoredComponentId, Instant, NativeStack);
struct BackgroundHangMonitorWorker {
component_names: FxHashMap<MonitoredComponentId, String>,
monitored_components: FxHashMap<MonitoredComponentId, MonitoredComponent>,
constellation_chan: IpcSender<HangMonitorAlert>,
constellation_chan: GenericSender<HangMonitorAlert>,
port: Receiver<(MonitoredComponentId, MonitoredComponentMsg)>,
control_port: Receiver<BackgroundHangMonitorControlMsg>,
control_port: RoutedReceiver<BackgroundHangMonitorControlMsg>,
sampling_duration: Option<Duration>,
sampling_max_duration: Option<Duration>,
last_sample: Instant,
@ -229,12 +228,12 @@ type MonitoredComponentReceiver = Receiver<(MonitoredComponentId, MonitoredCompo
impl BackgroundHangMonitorWorker {
fn new(
constellation_chan: IpcSender<HangMonitorAlert>,
control_port: IpcReceiver<BackgroundHangMonitorControlMsg>,
constellation_chan: GenericSender<HangMonitorAlert>,
control_port: GenericReceiver<BackgroundHangMonitorControlMsg>,
port: MonitoredComponentReceiver,
monitoring_enabled: bool,
) -> Self {
let control_port = ROUTER.route_ipc_receiver_to_new_crossbeam_receiver(control_port);
let control_port = control_port.route_preserving_errors();
Self {
component_names: Default::default(),
monitored_components: Default::default(),
@ -318,7 +317,7 @@ impl BackgroundHangMonitorWorker {
},
recv(self.control_port) -> event => {
match event {
Ok(BackgroundHangMonitorControlMsg::ToggleSampler(rate, max_duration)) => {
Ok(Ok(BackgroundHangMonitorControlMsg::ToggleSampler(rate, max_duration))) => {
if self.sampling_duration.is_some() {
println!("Enabling profiler.");
self.finish_sampled_profile();
@ -331,7 +330,7 @@ impl BackgroundHangMonitorWorker {
}
None
},
Ok(BackgroundHangMonitorControlMsg::Exit) => {
Ok(Ok(BackgroundHangMonitorControlMsg::Exit)) => {
for component in self.monitored_components.values_mut() {
component.exit_signal.signal_to_exit();
}
@ -347,6 +346,10 @@ impl BackgroundHangMonitorWorker {
// which we know has happened when `self.port` disconnects.
None
},
Ok(Err(e)) => {
log::warn!("BackgroundHangMonitorWorker control message deserialization error: {e:?}");
None
},
Err(_) => return false,
}
}

View file

@ -14,6 +14,7 @@ use background_hang_monitor_api::{
BackgroundHangMonitorControlMsg, BackgroundHangMonitorExitSignal, HangAlert, HangAnnotation,
HangMonitorAlert, MonitoredComponentId, MonitoredComponentType, ScriptHangAnnotation,
};
use base::generic_channel;
use base::id::TEST_PIPELINE_ID;
use ipc_channel::ipc;
@ -24,8 +25,9 @@ fn test_hang_monitoring() {
let _lock = SERIAL.lock().unwrap();
let (background_hang_monitor_ipc_sender, background_hang_monitor_receiver) =
ipc::channel().expect("ipc channel failure");
let (_sampler_sender, sampler_receiver) = ipc::channel().expect("ipc channel failure");
generic_channel::channel().expect("ipc channel failure");
let (_sampler_sender, sampler_receiver) =
generic_channel::channel().expect("ipc channel failure");
let (background_hang_monitor_register, join_handle) = HangMonitorRegister::init(
background_hang_monitor_ipc_sender.clone(),
@ -140,8 +142,9 @@ fn test_hang_monitoring_unregister() {
let _lock = SERIAL.lock().unwrap();
let (background_hang_monitor_ipc_sender, background_hang_monitor_receiver) =
ipc::channel().expect("ipc channel failure");
let (_sampler_sender, sampler_receiver) = ipc::channel().expect("ipc channel failure");
generic_channel::channel().expect("ipc channel failure");
let (_sampler_sender, sampler_receiver) =
generic_channel::channel().expect("ipc channel failure");
let (background_hang_monitor_register, join_handle) = HangMonitorRegister::init(
background_hang_monitor_ipc_sender.clone(),
@ -225,8 +228,9 @@ fn test_hang_monitoring_exit_signal_inner(op_order: fn(&mut dyn FnMut(), &mut dy
let _lock = SERIAL.lock().unwrap();
let (background_hang_monitor_ipc_sender, _background_hang_monitor_receiver) =
ipc::channel().expect("ipc channel failure");
let (control_sender, control_receiver) = ipc::channel().expect("ipc channel failure");
generic_channel::channel().expect("ipc channel failure");
let (control_sender, control_receiver) =
generic_channel::channel().expect("ipc channel failure");
struct BHMExitSignal {
closing: Arc<AtomicBool>,