background_hang_monitor_api/
lib.rs1#![deny(unsafe_code)]
6
7use std::time::Duration;
10use std::{fmt, mem};
11
12use base::id::PipelineId;
13use serde::{Deserialize, Serialize};
14
15#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
16pub enum ScriptHangAnnotation {
18 AttachLayout,
19 ConstellationMsg,
20 DatabaseAccessEvent,
21 DevtoolsMsg,
22 DocumentEvent,
23 FileRead,
24 FontLoading,
25 FormPlannedNavigation,
26 ImageCacheMsg,
27 InputEvent,
28 HistoryEvent,
29 NetworkEvent,
30 Rendering,
31 Resize,
32 ScriptEvent,
33 SetScrollState,
34 SetViewport,
35 StylesheetLoad,
36 TimerEvent,
37 UpdateReplacedElement,
38 WebSocketEvent,
39 WorkerEvent,
40 WorkletEvent,
41 ServiceWorkerEvent,
42 EnterFullscreen,
43 ExitFullscreen,
44 WebVREvent,
45 PerformanceTimelineTask,
46 PortMessage,
47 WebGPUMsg,
48}
49
50#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
51pub enum HangAnnotation {
52 Script(ScriptHangAnnotation),
53}
54
55#[derive(Deserialize, Serialize)]
57pub enum HangMonitorAlert {
58 Hang(HangAlert),
60 Profile(Vec<u8>),
62}
63
64impl fmt::Debug for HangMonitorAlert {
65 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
66 match *self {
67 HangMonitorAlert::Hang(..) => write!(fmt, "Hang"),
68 HangMonitorAlert::Profile(..) => write!(fmt, "Profile"),
69 }
70 }
71}
72
73#[derive(Deserialize, Serialize)]
75pub enum HangAlert {
76 Transient(MonitoredComponentId, HangAnnotation),
78 Permanent(MonitoredComponentId, HangAnnotation, Option<HangProfile>),
80}
81
82impl fmt::Debug for HangAlert {
83 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
84 let (annotation, profile) = match self {
85 HangAlert::Transient(component_id, annotation) => {
86 write!(
87 fmt,
88 "\n The following component is experiencing a transient hang: \n {:?}",
89 component_id
90 )?;
91 (*annotation, None)
92 },
93 HangAlert::Permanent(component_id, annotation, profile) => {
94 write!(
95 fmt,
96 "\n The following component is experiencing a permanent hang: \n {:?}",
97 component_id
98 )?;
99 (*annotation, profile.clone())
100 },
101 };
102
103 write!(fmt, "\n Annotation for the hang:\n{:?}", annotation)?;
104 if let Some(profile) = profile {
105 write!(fmt, "\n {:?}", profile)?;
106 }
107
108 Ok(())
109 }
110}
111
112#[derive(Clone, Deserialize, Serialize)]
113pub struct HangProfileSymbol {
114 pub name: Option<String>,
115 pub filename: Option<String>,
116 pub lineno: Option<u32>,
117}
118
119#[derive(Clone, Deserialize, Serialize)]
120pub struct HangProfile {
122 pub backtrace: Vec<HangProfileSymbol>,
123}
124
125impl fmt::Debug for HangProfile {
126 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
127 let hex_width = mem::size_of::<usize>() * 2 + 2;
128
129 write!(fmt, "HangProfile backtrace:")?;
130
131 if self.backtrace.is_empty() {
132 write!(fmt, "backtrace failed to resolve")?;
133 return Ok(());
134 }
135
136 for symbol in self.backtrace.iter() {
137 write!(fmt, "\n {:1$}", "", hex_width)?;
138
139 if let Some(ref name) = symbol.name {
140 write!(fmt, " - {}", name)?;
141 } else {
142 write!(fmt, " - <unknown>")?;
143 }
144
145 if let (Some(ref file), Some(ref line)) = (symbol.filename.as_ref(), symbol.lineno) {
146 write!(fmt, "\n {:3$}at {}:{}", "", file, line, hex_width)?;
147 }
148 }
149
150 Ok(())
151 }
152}
153
154#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
155pub enum MonitoredComponentType {
156 Script,
157}
158
159#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
160pub struct MonitoredComponentId(pub PipelineId, pub MonitoredComponentType);
161
162pub trait BackgroundHangMonitorRegister: BackgroundHangMonitorClone + Send {
165 fn register_component(
168 &self,
169 component: MonitoredComponentId,
170 transient_hang_timeout: Duration,
171 permanent_hang_timeout: Duration,
172 exit_signal: Box<dyn BackgroundHangMonitorExitSignal>,
173 ) -> Box<dyn BackgroundHangMonitor>;
174}
175
176impl Clone for Box<dyn BackgroundHangMonitorRegister> {
177 fn clone(&self) -> Box<dyn BackgroundHangMonitorRegister> {
178 self.clone_box()
179 }
180}
181
182pub trait BackgroundHangMonitorClone {
183 fn clone_box(&self) -> Box<dyn BackgroundHangMonitorRegister>;
184}
185
186pub trait BackgroundHangMonitor {
188 fn notify_activity(&self, annotation: HangAnnotation);
190 fn notify_wait(&self);
192 fn unregister(&self);
194}
195
196pub trait BackgroundHangMonitorExitSignal: Send {
201 fn signal_to_exit(&self);
203}
204
205#[derive(Deserialize, Serialize)]
207pub enum BackgroundHangMonitorControlMsg {
208 ToggleSampler(Duration, Duration),
210 Exit,
212}