background_hang_monitor_api/
lib.rs1#![deny(unsafe_code)]
6
7use std::time::Duration;
10use std::{fmt, mem};
11
12use serde::{Deserialize, Serialize};
13use servo_base::id::ScriptEventLoopId;
14
15#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
16pub enum ScriptHangAnnotation {
18 SpawnPipeline,
19 ConstellationMsg,
20 DatabaseAccessEvent,
21 DevtoolsMsg,
22 DocumentEvent,
23 FileRead,
24 FontLoading,
25 FormPlannedNavigation,
26 GeolocationEvent,
27 ImageCacheMsg,
28 InputEvent,
29 NavigationAndTraversalEvent,
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 HangAlert {
59 Transient(MonitoredComponentId, HangAnnotation),
61 Permanent(MonitoredComponentId, HangAnnotation, Option<HangProfile>),
63}
64
65impl fmt::Debug for HangAlert {
66 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
67 let (annotation, profile) = match self {
68 HangAlert::Transient(component_id, annotation) => {
69 write!(
70 fmt,
71 "\n The following component is experiencing a transient hang: \n {:?}",
72 component_id
73 )?;
74 (*annotation, None)
75 },
76 HangAlert::Permanent(component_id, annotation, profile) => {
77 write!(
78 fmt,
79 "\n The following component is experiencing a permanent hang: \n {:?}",
80 component_id
81 )?;
82 (*annotation, profile.clone())
83 },
84 };
85
86 write!(fmt, "\n Annotation for the hang:\n{:?}", annotation)?;
87 if let Some(profile) = profile {
88 write!(fmt, "\n {:?}", profile)?;
89 }
90
91 Ok(())
92 }
93}
94
95#[derive(Clone, Deserialize, Serialize)]
96pub struct HangProfileSymbol {
97 pub name: Option<String>,
98 pub filename: Option<String>,
99 pub lineno: Option<u32>,
100}
101
102#[derive(Clone, Deserialize, Serialize)]
103pub struct HangProfile {
105 pub backtrace: Vec<HangProfileSymbol>,
106}
107
108impl fmt::Debug for HangProfile {
109 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
110 let hex_width = mem::size_of::<usize>() * 2 + 2;
111
112 write!(fmt, "HangProfile backtrace:")?;
113
114 if self.backtrace.is_empty() {
115 write!(fmt, "backtrace failed to resolve")?;
116 return Ok(());
117 }
118
119 for symbol in self.backtrace.iter() {
120 write!(fmt, "\n {:1$}", "", hex_width)?;
121
122 if let Some(ref name) = symbol.name {
123 write!(fmt, " - {}", name)?;
124 } else {
125 write!(fmt, " - <unknown>")?;
126 }
127
128 if let (Some(ref file), Some(ref line)) = (symbol.filename.as_ref(), symbol.lineno) {
129 write!(fmt, "\n {:3$}at {}:{}", "", file, line, hex_width)?;
130 }
131 }
132
133 Ok(())
134 }
135}
136
137#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
138pub enum MonitoredComponentType {
139 Script,
140}
141
142#[derive(Clone, Debug, Deserialize, Eq, Hash, PartialEq, Serialize)]
143pub struct MonitoredComponentId(pub ScriptEventLoopId, pub MonitoredComponentType);
144
145pub trait BackgroundHangMonitorRegister: BackgroundHangMonitorClone + Send {
148 fn register_component(
151 &self,
152 component: MonitoredComponentId,
153 transient_hang_timeout: Duration,
154 permanent_hang_timeout: Duration,
155 exit_signal: Box<dyn BackgroundHangMonitorExitSignal>,
156 ) -> Box<dyn BackgroundHangMonitor>;
157}
158
159impl Clone for Box<dyn BackgroundHangMonitorRegister> {
160 fn clone(&self) -> Box<dyn BackgroundHangMonitorRegister> {
161 self.clone_box()
162 }
163}
164
165pub trait BackgroundHangMonitorClone {
166 fn clone_box(&self) -> Box<dyn BackgroundHangMonitorRegister>;
167}
168
169pub trait BackgroundHangMonitor {
171 fn notify_activity(&self, annotation: HangAnnotation);
173 fn notify_wait(&self);
175 fn unregister(&self);
177}
178
179pub trait BackgroundHangMonitorExitSignal: Send {
184 fn signal_to_exit(&self);
186}
187
188#[derive(Clone, Debug, Deserialize, Serialize)]
190pub enum BackgroundHangMonitorControlMsg {
191 Exit,
193}