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 GeolocationEvent,
27 ImageCacheMsg,
28 InputEvent,
29 HistoryEvent,
30 NetworkEvent,
31 Rendering,
32 Resize,
33 ScriptEvent,
34 SetScrollState,
35 SetViewport,
36 StylesheetLoad,
37 TimerEvent,
38 UpdateReplacedElement,
39 WebSocketEvent,
40 WorkerEvent,
41 WorkletEvent,
42 ServiceWorkerEvent,
43 EnterFullscreen,
44 ExitFullscreen,
45 WebVREvent,
46 PerformanceTimelineTask,
47 PortMessage,
48 WebGPUMsg,
49}
50
51#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
52pub enum HangAnnotation {
53 Script(ScriptHangAnnotation),
54}
55
56#[derive(Deserialize, Serialize)]
58pub enum HangMonitorAlert {
59 Hang(HangAlert),
61 Profile(Vec<u8>),
63}
64
65impl fmt::Debug for HangMonitorAlert {
66 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
67 match *self {
68 HangMonitorAlert::Hang(..) => write!(fmt, "Hang"),
69 HangMonitorAlert::Profile(..) => write!(fmt, "Profile"),
70 }
71 }
72}
73
74#[derive(Deserialize, Serialize)]
76pub enum HangAlert {
77 Transient(MonitoredComponentId, HangAnnotation),
79 Permanent(MonitoredComponentId, HangAnnotation, Option<HangProfile>),
81}
82
83impl fmt::Debug for HangAlert {
84 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
85 let (annotation, profile) = match self {
86 HangAlert::Transient(component_id, annotation) => {
87 write!(
88 fmt,
89 "\n The following component is experiencing a transient hang: \n {:?}",
90 component_id
91 )?;
92 (*annotation, None)
93 },
94 HangAlert::Permanent(component_id, annotation, profile) => {
95 write!(
96 fmt,
97 "\n The following component is experiencing a permanent hang: \n {:?}",
98 component_id
99 )?;
100 (*annotation, profile.clone())
101 },
102 };
103
104 write!(fmt, "\n Annotation for the hang:\n{:?}", annotation)?;
105 if let Some(profile) = profile {
106 write!(fmt, "\n {:?}", profile)?;
107 }
108
109 Ok(())
110 }
111}
112
113#[derive(Clone, Deserialize, Serialize)]
114pub struct HangProfileSymbol {
115 pub name: Option<String>,
116 pub filename: Option<String>,
117 pub lineno: Option<u32>,
118}
119
120#[derive(Clone, Deserialize, Serialize)]
121pub struct HangProfile {
123 pub backtrace: Vec<HangProfileSymbol>,
124}
125
126impl fmt::Debug for HangProfile {
127 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
128 let hex_width = mem::size_of::<usize>() * 2 + 2;
129
130 write!(fmt, "HangProfile backtrace:")?;
131
132 if self.backtrace.is_empty() {
133 write!(fmt, "backtrace failed to resolve")?;
134 return Ok(());
135 }
136
137 for symbol in self.backtrace.iter() {
138 write!(fmt, "\n {:1$}", "", hex_width)?;
139
140 if let Some(ref name) = symbol.name {
141 write!(fmt, " - {}", name)?;
142 } else {
143 write!(fmt, " - <unknown>")?;
144 }
145
146 if let (Some(ref file), Some(ref line)) = (symbol.filename.as_ref(), symbol.lineno) {
147 write!(fmt, "\n {:3$}at {}:{}", "", file, line, hex_width)?;
148 }
149 }
150
151 Ok(())
152 }
153}
154
155#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
156pub enum MonitoredComponentType {
157 Script,
158}
159
160#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
161pub struct MonitoredComponentId(pub PipelineId, pub MonitoredComponentType);
162
163pub trait BackgroundHangMonitorRegister: BackgroundHangMonitorClone + Send {
166 fn register_component(
169 &self,
170 component: MonitoredComponentId,
171 transient_hang_timeout: Duration,
172 permanent_hang_timeout: Duration,
173 exit_signal: Box<dyn BackgroundHangMonitorExitSignal>,
174 ) -> Box<dyn BackgroundHangMonitor>;
175}
176
177impl Clone for Box<dyn BackgroundHangMonitorRegister> {
178 fn clone(&self) -> Box<dyn BackgroundHangMonitorRegister> {
179 self.clone_box()
180 }
181}
182
183pub trait BackgroundHangMonitorClone {
184 fn clone_box(&self) -> Box<dyn BackgroundHangMonitorRegister>;
185}
186
187pub trait BackgroundHangMonitor {
189 fn notify_activity(&self, annotation: HangAnnotation);
191 fn notify_wait(&self);
193 fn unregister(&self);
195}
196
197pub trait BackgroundHangMonitorExitSignal: Send {
202 fn signal_to_exit(&self);
204}
205
206#[derive(Deserialize, Serialize)]
208pub enum BackgroundHangMonitorControlMsg {
209 ToggleSampler(Duration, Duration),
211 Exit,
213}