1*6777b538SAndroid Build Coastguard Worker // Copyright 2020 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker
5*6777b538SAndroid Build Coastguard Worker #include "base/threading/hang_watcher.h"
6*6777b538SAndroid Build Coastguard Worker
7*6777b538SAndroid Build Coastguard Worker #include <atomic>
8*6777b538SAndroid Build Coastguard Worker #include <utility>
9*6777b538SAndroid Build Coastguard Worker
10*6777b538SAndroid Build Coastguard Worker #include "base/containers/flat_map.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/debug/alias.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/debug/crash_logging.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/debug/dump_without_crashing.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/debug/leak_annotations.h"
15*6777b538SAndroid Build Coastguard Worker #include "base/feature_list.h"
16*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
17*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h"
18*6777b538SAndroid Build Coastguard Worker #include "base/metrics/field_trial_params.h"
19*6777b538SAndroid Build Coastguard Worker #include "base/metrics/histogram_macros.h"
20*6777b538SAndroid Build Coastguard Worker #include "base/power_monitor/power_monitor.h"
21*6777b538SAndroid Build Coastguard Worker #include "base/ranges/algorithm.h"
22*6777b538SAndroid Build Coastguard Worker #include "base/strings/string_number_conversions.h"
23*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
24*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/waitable_event.h"
25*6777b538SAndroid Build Coastguard Worker #include "base/threading/platform_thread.h"
26*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_checker.h"
27*6777b538SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
28*6777b538SAndroid Build Coastguard Worker #include "base/threading/threading_features.h"
29*6777b538SAndroid Build Coastguard Worker #include "base/time/default_tick_clock.h"
30*6777b538SAndroid Build Coastguard Worker #include "base/time/time.h"
31*6777b538SAndroid Build Coastguard Worker #include "base/trace_event/base_tracing.h"
32*6777b538SAndroid Build Coastguard Worker #include "build/build_config.h"
33*6777b538SAndroid Build Coastguard Worker #include "third_party/abseil-cpp/absl/base/attributes.h"
34*6777b538SAndroid Build Coastguard Worker
35*6777b538SAndroid Build Coastguard Worker namespace base {
36*6777b538SAndroid Build Coastguard Worker
37*6777b538SAndroid Build Coastguard Worker namespace {
38*6777b538SAndroid Build Coastguard Worker
39*6777b538SAndroid Build Coastguard Worker // Defines how much logging happens when the HangWatcher monitors the threads.
40*6777b538SAndroid Build Coastguard Worker // Logging levels are set per thread type through Finch. It's important that
41*6777b538SAndroid Build Coastguard Worker // the order of the enum members stay the same and that their numerical
42*6777b538SAndroid Build Coastguard Worker // values be in increasing order. The implementation of
43*6777b538SAndroid Build Coastguard Worker // ThreadTypeLoggingLevelGreaterOrEqual() depends on it.
44*6777b538SAndroid Build Coastguard Worker enum class LoggingLevel { kNone = 0, kUmaOnly = 1, kUmaAndCrash = 2 };
45*6777b538SAndroid Build Coastguard Worker
46*6777b538SAndroid Build Coastguard Worker HangWatcher* g_instance = nullptr;
47*6777b538SAndroid Build Coastguard Worker ABSL_CONST_INIT thread_local internal::HangWatchState* hang_watch_state =
48*6777b538SAndroid Build Coastguard Worker nullptr;
49*6777b538SAndroid Build Coastguard Worker std::atomic<bool> g_use_hang_watcher{false};
50*6777b538SAndroid Build Coastguard Worker std::atomic<HangWatcher::ProcessType> g_hang_watcher_process_type{
51*6777b538SAndroid Build Coastguard Worker HangWatcher::ProcessType::kBrowserProcess};
52*6777b538SAndroid Build Coastguard Worker
53*6777b538SAndroid Build Coastguard Worker std::atomic<LoggingLevel> g_threadpool_log_level{LoggingLevel::kNone};
54*6777b538SAndroid Build Coastguard Worker std::atomic<LoggingLevel> g_io_thread_log_level{LoggingLevel::kNone};
55*6777b538SAndroid Build Coastguard Worker std::atomic<LoggingLevel> g_main_thread_log_level{LoggingLevel::kNone};
56*6777b538SAndroid Build Coastguard Worker
57*6777b538SAndroid Build Coastguard Worker // Indicates whether HangWatcher::Run() should return after the next monitoring.
58*6777b538SAndroid Build Coastguard Worker std::atomic<bool> g_keep_monitoring{true};
59*6777b538SAndroid Build Coastguard Worker
60*6777b538SAndroid Build Coastguard Worker // Emits the hung thread count histogram. |count| is the number of threads
61*6777b538SAndroid Build Coastguard Worker // of type |thread_type| that were hung or became hung during the last
62*6777b538SAndroid Build Coastguard Worker // monitoring window. This function should be invoked for each thread type
63*6777b538SAndroid Build Coastguard Worker // encountered on each call to Monitor().
LogHungThreadCountHistogram(HangWatcher::ThreadType thread_type,int count)64*6777b538SAndroid Build Coastguard Worker void LogHungThreadCountHistogram(HangWatcher::ThreadType thread_type,
65*6777b538SAndroid Build Coastguard Worker int count) {
66*6777b538SAndroid Build Coastguard Worker // In the case of unique threads like the IO or UI/Main thread a count does
67*6777b538SAndroid Build Coastguard Worker // not make sense.
68*6777b538SAndroid Build Coastguard Worker const bool any_thread_hung = count >= 1;
69*6777b538SAndroid Build Coastguard Worker
70*6777b538SAndroid Build Coastguard Worker const HangWatcher::ProcessType process_type =
71*6777b538SAndroid Build Coastguard Worker g_hang_watcher_process_type.load(std::memory_order_relaxed);
72*6777b538SAndroid Build Coastguard Worker switch (process_type) {
73*6777b538SAndroid Build Coastguard Worker case HangWatcher::ProcessType::kUnknownProcess:
74*6777b538SAndroid Build Coastguard Worker break;
75*6777b538SAndroid Build Coastguard Worker
76*6777b538SAndroid Build Coastguard Worker case HangWatcher::ProcessType::kBrowserProcess:
77*6777b538SAndroid Build Coastguard Worker switch (thread_type) {
78*6777b538SAndroid Build Coastguard Worker case HangWatcher::ThreadType::kIOThread:
79*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_BOOLEAN(
80*6777b538SAndroid Build Coastguard Worker "HangWatcher.IsThreadHung.BrowserProcess."
81*6777b538SAndroid Build Coastguard Worker "IOThread",
82*6777b538SAndroid Build Coastguard Worker any_thread_hung);
83*6777b538SAndroid Build Coastguard Worker break;
84*6777b538SAndroid Build Coastguard Worker case HangWatcher::ThreadType::kMainThread:
85*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_BOOLEAN(
86*6777b538SAndroid Build Coastguard Worker "HangWatcher.IsThreadHung.BrowserProcess."
87*6777b538SAndroid Build Coastguard Worker "UIThread",
88*6777b538SAndroid Build Coastguard Worker any_thread_hung);
89*6777b538SAndroid Build Coastguard Worker break;
90*6777b538SAndroid Build Coastguard Worker case HangWatcher::ThreadType::kThreadPoolThread:
91*6777b538SAndroid Build Coastguard Worker // Not recorded for now.
92*6777b538SAndroid Build Coastguard Worker break;
93*6777b538SAndroid Build Coastguard Worker }
94*6777b538SAndroid Build Coastguard Worker break;
95*6777b538SAndroid Build Coastguard Worker
96*6777b538SAndroid Build Coastguard Worker case HangWatcher::ProcessType::kGPUProcess:
97*6777b538SAndroid Build Coastguard Worker // Not recorded for now.
98*6777b538SAndroid Build Coastguard Worker break;
99*6777b538SAndroid Build Coastguard Worker
100*6777b538SAndroid Build Coastguard Worker case HangWatcher::ProcessType::kRendererProcess:
101*6777b538SAndroid Build Coastguard Worker switch (thread_type) {
102*6777b538SAndroid Build Coastguard Worker case HangWatcher::ThreadType::kIOThread:
103*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_BOOLEAN(
104*6777b538SAndroid Build Coastguard Worker "HangWatcher.IsThreadHung.RendererProcess."
105*6777b538SAndroid Build Coastguard Worker "IOThread",
106*6777b538SAndroid Build Coastguard Worker any_thread_hung);
107*6777b538SAndroid Build Coastguard Worker break;
108*6777b538SAndroid Build Coastguard Worker case HangWatcher::ThreadType::kMainThread:
109*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_BOOLEAN(
110*6777b538SAndroid Build Coastguard Worker "HangWatcher.IsThreadHung.RendererProcess."
111*6777b538SAndroid Build Coastguard Worker "MainThread",
112*6777b538SAndroid Build Coastguard Worker any_thread_hung);
113*6777b538SAndroid Build Coastguard Worker break;
114*6777b538SAndroid Build Coastguard Worker case HangWatcher::ThreadType::kThreadPoolThread:
115*6777b538SAndroid Build Coastguard Worker // Not recorded for now.
116*6777b538SAndroid Build Coastguard Worker break;
117*6777b538SAndroid Build Coastguard Worker }
118*6777b538SAndroid Build Coastguard Worker break;
119*6777b538SAndroid Build Coastguard Worker
120*6777b538SAndroid Build Coastguard Worker case HangWatcher::ProcessType::kUtilityProcess:
121*6777b538SAndroid Build Coastguard Worker switch (thread_type) {
122*6777b538SAndroid Build Coastguard Worker case HangWatcher::ThreadType::kIOThread:
123*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_BOOLEAN(
124*6777b538SAndroid Build Coastguard Worker "HangWatcher.IsThreadHung.UtilityProcess."
125*6777b538SAndroid Build Coastguard Worker "IOThread",
126*6777b538SAndroid Build Coastguard Worker any_thread_hung);
127*6777b538SAndroid Build Coastguard Worker break;
128*6777b538SAndroid Build Coastguard Worker case HangWatcher::ThreadType::kMainThread:
129*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_BOOLEAN(
130*6777b538SAndroid Build Coastguard Worker "HangWatcher.IsThreadHung.UtilityProcess."
131*6777b538SAndroid Build Coastguard Worker "MainThread",
132*6777b538SAndroid Build Coastguard Worker any_thread_hung);
133*6777b538SAndroid Build Coastguard Worker break;
134*6777b538SAndroid Build Coastguard Worker case HangWatcher::ThreadType::kThreadPoolThread:
135*6777b538SAndroid Build Coastguard Worker // Not recorded for now.
136*6777b538SAndroid Build Coastguard Worker break;
137*6777b538SAndroid Build Coastguard Worker }
138*6777b538SAndroid Build Coastguard Worker break;
139*6777b538SAndroid Build Coastguard Worker }
140*6777b538SAndroid Build Coastguard Worker }
141*6777b538SAndroid Build Coastguard Worker
142*6777b538SAndroid Build Coastguard Worker // Returns true if |thread_type| was configured through Finch to have a logging
143*6777b538SAndroid Build Coastguard Worker // level that is equal to or exceeds |logging_level|.
ThreadTypeLoggingLevelGreaterOrEqual(HangWatcher::ThreadType thread_type,LoggingLevel logging_level)144*6777b538SAndroid Build Coastguard Worker bool ThreadTypeLoggingLevelGreaterOrEqual(HangWatcher::ThreadType thread_type,
145*6777b538SAndroid Build Coastguard Worker LoggingLevel logging_level) {
146*6777b538SAndroid Build Coastguard Worker switch (thread_type) {
147*6777b538SAndroid Build Coastguard Worker case HangWatcher::ThreadType::kIOThread:
148*6777b538SAndroid Build Coastguard Worker return g_io_thread_log_level.load(std::memory_order_relaxed) >=
149*6777b538SAndroid Build Coastguard Worker logging_level;
150*6777b538SAndroid Build Coastguard Worker case HangWatcher::ThreadType::kMainThread:
151*6777b538SAndroid Build Coastguard Worker return g_main_thread_log_level.load(std::memory_order_relaxed) >=
152*6777b538SAndroid Build Coastguard Worker logging_level;
153*6777b538SAndroid Build Coastguard Worker case HangWatcher::ThreadType::kThreadPoolThread:
154*6777b538SAndroid Build Coastguard Worker return g_threadpool_log_level.load(std::memory_order_relaxed) >=
155*6777b538SAndroid Build Coastguard Worker logging_level;
156*6777b538SAndroid Build Coastguard Worker }
157*6777b538SAndroid Build Coastguard Worker }
158*6777b538SAndroid Build Coastguard Worker
159*6777b538SAndroid Build Coastguard Worker } // namespace
160*6777b538SAndroid Build Coastguard Worker
161*6777b538SAndroid Build Coastguard Worker // Determines if the HangWatcher is activated. When false the HangWatcher
162*6777b538SAndroid Build Coastguard Worker // thread never started.
163*6777b538SAndroid Build Coastguard Worker BASE_FEATURE(kEnableHangWatcher,
164*6777b538SAndroid Build Coastguard Worker "EnableHangWatcher",
165*6777b538SAndroid Build Coastguard Worker FEATURE_ENABLED_BY_DEFAULT);
166*6777b538SAndroid Build Coastguard Worker
167*6777b538SAndroid Build Coastguard Worker BASE_FEATURE(kEnableHangWatcherInZygoteChildren,
168*6777b538SAndroid Build Coastguard Worker "EnableHangWatcherInZygoteChildren",
169*6777b538SAndroid Build Coastguard Worker FEATURE_ENABLED_BY_DEFAULT);
170*6777b538SAndroid Build Coastguard Worker
171*6777b538SAndroid Build Coastguard Worker // Browser process.
172*6777b538SAndroid Build Coastguard Worker constexpr base::FeatureParam<int> kIOThreadLogLevel{
173*6777b538SAndroid Build Coastguard Worker &kEnableHangWatcher, "io_thread_log_level",
174*6777b538SAndroid Build Coastguard Worker static_cast<int>(LoggingLevel::kUmaOnly)};
175*6777b538SAndroid Build Coastguard Worker constexpr base::FeatureParam<int> kUIThreadLogLevel{
176*6777b538SAndroid Build Coastguard Worker &kEnableHangWatcher, "ui_thread_log_level",
177*6777b538SAndroid Build Coastguard Worker static_cast<int>(LoggingLevel::kUmaOnly)};
178*6777b538SAndroid Build Coastguard Worker constexpr base::FeatureParam<int> kThreadPoolLogLevel{
179*6777b538SAndroid Build Coastguard Worker &kEnableHangWatcher, "threadpool_log_level",
180*6777b538SAndroid Build Coastguard Worker static_cast<int>(LoggingLevel::kUmaOnly)};
181*6777b538SAndroid Build Coastguard Worker
182*6777b538SAndroid Build Coastguard Worker // GPU process.
183*6777b538SAndroid Build Coastguard Worker constexpr base::FeatureParam<int> kGPUProcessIOThreadLogLevel{
184*6777b538SAndroid Build Coastguard Worker &kEnableHangWatcher, "gpu_process_io_thread_log_level",
185*6777b538SAndroid Build Coastguard Worker static_cast<int>(LoggingLevel::kNone)};
186*6777b538SAndroid Build Coastguard Worker constexpr base::FeatureParam<int> kGPUProcessMainThreadLogLevel{
187*6777b538SAndroid Build Coastguard Worker &kEnableHangWatcher, "gpu_process_main_thread_log_level",
188*6777b538SAndroid Build Coastguard Worker static_cast<int>(LoggingLevel::kNone)};
189*6777b538SAndroid Build Coastguard Worker constexpr base::FeatureParam<int> kGPUProcessThreadPoolLogLevel{
190*6777b538SAndroid Build Coastguard Worker &kEnableHangWatcher, "gpu_process_threadpool_log_level",
191*6777b538SAndroid Build Coastguard Worker static_cast<int>(LoggingLevel::kNone)};
192*6777b538SAndroid Build Coastguard Worker
193*6777b538SAndroid Build Coastguard Worker // Renderer process.
194*6777b538SAndroid Build Coastguard Worker constexpr base::FeatureParam<int> kRendererProcessIOThreadLogLevel{
195*6777b538SAndroid Build Coastguard Worker &kEnableHangWatcher, "renderer_process_io_thread_log_level",
196*6777b538SAndroid Build Coastguard Worker static_cast<int>(LoggingLevel::kUmaOnly)};
197*6777b538SAndroid Build Coastguard Worker constexpr base::FeatureParam<int> kRendererProcessMainThreadLogLevel{
198*6777b538SAndroid Build Coastguard Worker &kEnableHangWatcher, "renderer_process_main_thread_log_level",
199*6777b538SAndroid Build Coastguard Worker static_cast<int>(LoggingLevel::kUmaOnly)};
200*6777b538SAndroid Build Coastguard Worker constexpr base::FeatureParam<int> kRendererProcessThreadPoolLogLevel{
201*6777b538SAndroid Build Coastguard Worker &kEnableHangWatcher, "renderer_process_threadpool_log_level",
202*6777b538SAndroid Build Coastguard Worker static_cast<int>(LoggingLevel::kUmaOnly)};
203*6777b538SAndroid Build Coastguard Worker
204*6777b538SAndroid Build Coastguard Worker // Utility process.
205*6777b538SAndroid Build Coastguard Worker constexpr base::FeatureParam<int> kUtilityProcessIOThreadLogLevel{
206*6777b538SAndroid Build Coastguard Worker &kEnableHangWatcher, "utility_process_io_thread_log_level",
207*6777b538SAndroid Build Coastguard Worker static_cast<int>(LoggingLevel::kUmaOnly)};
208*6777b538SAndroid Build Coastguard Worker constexpr base::FeatureParam<int> kUtilityProcessMainThreadLogLevel{
209*6777b538SAndroid Build Coastguard Worker &kEnableHangWatcher, "utility_process_main_thread_log_level",
210*6777b538SAndroid Build Coastguard Worker static_cast<int>(LoggingLevel::kUmaOnly)};
211*6777b538SAndroid Build Coastguard Worker constexpr base::FeatureParam<int> kUtilityProcessThreadPoolLogLevel{
212*6777b538SAndroid Build Coastguard Worker &kEnableHangWatcher, "utility_process_threadpool_log_level",
213*6777b538SAndroid Build Coastguard Worker static_cast<int>(LoggingLevel::kUmaOnly)};
214*6777b538SAndroid Build Coastguard Worker
215*6777b538SAndroid Build Coastguard Worker constexpr const char* kThreadName = "HangWatcher";
216*6777b538SAndroid Build Coastguard Worker
217*6777b538SAndroid Build Coastguard Worker // The time that the HangWatcher thread will sleep for between calls to
218*6777b538SAndroid Build Coastguard Worker // Monitor(). Increasing or decreasing this does not modify the type of hangs
219*6777b538SAndroid Build Coastguard Worker // that can be detected. It instead increases the probability that a call to
220*6777b538SAndroid Build Coastguard Worker // Monitor() will happen at the right time to catch a hang. This has to be
221*6777b538SAndroid Build Coastguard Worker // balanced with power/cpu use concerns as busy looping would catch amost all
222*6777b538SAndroid Build Coastguard Worker // hangs but present unacceptable overhead. NOTE: If this period is ever changed
223*6777b538SAndroid Build Coastguard Worker // then all metrics that depend on it like
224*6777b538SAndroid Build Coastguard Worker // HangWatcher.IsThreadHung need to be updated.
225*6777b538SAndroid Build Coastguard Worker constexpr auto kMonitoringPeriod = base::Seconds(10);
226*6777b538SAndroid Build Coastguard Worker
WatchHangsInScope(TimeDelta timeout)227*6777b538SAndroid Build Coastguard Worker WatchHangsInScope::WatchHangsInScope(TimeDelta timeout) {
228*6777b538SAndroid Build Coastguard Worker internal::HangWatchState* current_hang_watch_state =
229*6777b538SAndroid Build Coastguard Worker HangWatcher::IsEnabled()
230*6777b538SAndroid Build Coastguard Worker ? internal::HangWatchState::GetHangWatchStateForCurrentThread()
231*6777b538SAndroid Build Coastguard Worker : nullptr;
232*6777b538SAndroid Build Coastguard Worker
233*6777b538SAndroid Build Coastguard Worker DCHECK(timeout >= base::TimeDelta()) << "Negative timeouts are invalid.";
234*6777b538SAndroid Build Coastguard Worker
235*6777b538SAndroid Build Coastguard Worker // Thread is not monitored, noop.
236*6777b538SAndroid Build Coastguard Worker if (!current_hang_watch_state) {
237*6777b538SAndroid Build Coastguard Worker took_effect_ = false;
238*6777b538SAndroid Build Coastguard Worker return;
239*6777b538SAndroid Build Coastguard Worker }
240*6777b538SAndroid Build Coastguard Worker
241*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
242*6777b538SAndroid Build Coastguard Worker previous_watch_hangs_in_scope_ =
243*6777b538SAndroid Build Coastguard Worker current_hang_watch_state->GetCurrentWatchHangsInScope();
244*6777b538SAndroid Build Coastguard Worker current_hang_watch_state->SetCurrentWatchHangsInScope(this);
245*6777b538SAndroid Build Coastguard Worker #endif
246*6777b538SAndroid Build Coastguard Worker
247*6777b538SAndroid Build Coastguard Worker auto [old_flags, old_deadline] =
248*6777b538SAndroid Build Coastguard Worker current_hang_watch_state->GetFlagsAndDeadline();
249*6777b538SAndroid Build Coastguard Worker
250*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1034046): Check whether we are over deadline already for the
251*6777b538SAndroid Build Coastguard Worker // previous WatchHangsInScope here by issuing only one TimeTicks::Now()
252*6777b538SAndroid Build Coastguard Worker // and resuing the value.
253*6777b538SAndroid Build Coastguard Worker
254*6777b538SAndroid Build Coastguard Worker previous_deadline_ = old_deadline;
255*6777b538SAndroid Build Coastguard Worker TimeTicks deadline = TimeTicks::Now() + timeout;
256*6777b538SAndroid Build Coastguard Worker current_hang_watch_state->SetDeadline(deadline);
257*6777b538SAndroid Build Coastguard Worker current_hang_watch_state->IncrementNestingLevel();
258*6777b538SAndroid Build Coastguard Worker
259*6777b538SAndroid Build Coastguard Worker const bool hangs_ignored_for_current_scope =
260*6777b538SAndroid Build Coastguard Worker internal::HangWatchDeadline::IsFlagSet(
261*6777b538SAndroid Build Coastguard Worker internal::HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope,
262*6777b538SAndroid Build Coastguard Worker old_flags);
263*6777b538SAndroid Build Coastguard Worker
264*6777b538SAndroid Build Coastguard Worker // If the current WatchHangsInScope is ignored, temporarily reactivate hang
265*6777b538SAndroid Build Coastguard Worker // watching for newly created WatchHangsInScopes. On exiting hang watching
266*6777b538SAndroid Build Coastguard Worker // is suspended again to return to the original state.
267*6777b538SAndroid Build Coastguard Worker if (hangs_ignored_for_current_scope) {
268*6777b538SAndroid Build Coastguard Worker current_hang_watch_state->UnsetIgnoreCurrentWatchHangsInScope();
269*6777b538SAndroid Build Coastguard Worker set_hangs_ignored_on_exit_ = true;
270*6777b538SAndroid Build Coastguard Worker }
271*6777b538SAndroid Build Coastguard Worker }
272*6777b538SAndroid Build Coastguard Worker
~WatchHangsInScope()273*6777b538SAndroid Build Coastguard Worker WatchHangsInScope::~WatchHangsInScope() {
274*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
275*6777b538SAndroid Build Coastguard Worker
276*6777b538SAndroid Build Coastguard Worker // If hang watching was not enabled at construction time there is nothing to
277*6777b538SAndroid Build Coastguard Worker // validate or undo.
278*6777b538SAndroid Build Coastguard Worker if (!took_effect_) {
279*6777b538SAndroid Build Coastguard Worker return;
280*6777b538SAndroid Build Coastguard Worker }
281*6777b538SAndroid Build Coastguard Worker
282*6777b538SAndroid Build Coastguard Worker // If the thread was unregistered since construction there is also nothing to
283*6777b538SAndroid Build Coastguard Worker // do.
284*6777b538SAndroid Build Coastguard Worker auto* const state =
285*6777b538SAndroid Build Coastguard Worker internal::HangWatchState::GetHangWatchStateForCurrentThread();
286*6777b538SAndroid Build Coastguard Worker if (!state) {
287*6777b538SAndroid Build Coastguard Worker return;
288*6777b538SAndroid Build Coastguard Worker }
289*6777b538SAndroid Build Coastguard Worker
290*6777b538SAndroid Build Coastguard Worker // If a hang is currently being captured we should block here so execution
291*6777b538SAndroid Build Coastguard Worker // stops and we avoid recording unrelated stack frames in the crash.
292*6777b538SAndroid Build Coastguard Worker if (state->IsFlagSet(internal::HangWatchDeadline::Flag::kShouldBlockOnHang)) {
293*6777b538SAndroid Build Coastguard Worker base::HangWatcher::GetInstance()->BlockIfCaptureInProgress();
294*6777b538SAndroid Build Coastguard Worker }
295*6777b538SAndroid Build Coastguard Worker
296*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
297*6777b538SAndroid Build Coastguard Worker // Verify that no Scope was destructed out of order.
298*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(this, state->GetCurrentWatchHangsInScope());
299*6777b538SAndroid Build Coastguard Worker state->SetCurrentWatchHangsInScope(previous_watch_hangs_in_scope_);
300*6777b538SAndroid Build Coastguard Worker #endif
301*6777b538SAndroid Build Coastguard Worker
302*6777b538SAndroid Build Coastguard Worker if (state->nesting_level() == 1) {
303*6777b538SAndroid Build Coastguard Worker // If a call to InvalidateActiveExpectations() suspended hang watching
304*6777b538SAndroid Build Coastguard Worker // during the lifetime of this or any nested WatchHangsInScope it can now
305*6777b538SAndroid Build Coastguard Worker // safely be reactivated by clearing the ignore bit since this is the
306*6777b538SAndroid Build Coastguard Worker // outer-most scope.
307*6777b538SAndroid Build Coastguard Worker state->UnsetIgnoreCurrentWatchHangsInScope();
308*6777b538SAndroid Build Coastguard Worker } else if (set_hangs_ignored_on_exit_) {
309*6777b538SAndroid Build Coastguard Worker // Return to ignoring hangs since this was the previous state before hang
310*6777b538SAndroid Build Coastguard Worker // watching was temporarily enabled for this WatchHangsInScope only in the
311*6777b538SAndroid Build Coastguard Worker // constructor.
312*6777b538SAndroid Build Coastguard Worker state->SetIgnoreCurrentWatchHangsInScope();
313*6777b538SAndroid Build Coastguard Worker }
314*6777b538SAndroid Build Coastguard Worker
315*6777b538SAndroid Build Coastguard Worker // Reset the deadline to the value it had before entering this
316*6777b538SAndroid Build Coastguard Worker // WatchHangsInScope.
317*6777b538SAndroid Build Coastguard Worker state->SetDeadline(previous_deadline_);
318*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1034046): Log when a WatchHangsInScope exits after its
319*6777b538SAndroid Build Coastguard Worker // deadline and that went undetected by the HangWatcher.
320*6777b538SAndroid Build Coastguard Worker
321*6777b538SAndroid Build Coastguard Worker state->DecrementNestingLevel();
322*6777b538SAndroid Build Coastguard Worker }
323*6777b538SAndroid Build Coastguard Worker
324*6777b538SAndroid Build Coastguard Worker // static
InitializeOnMainThread(ProcessType process_type,bool is_zygote_child,bool emit_crashes)325*6777b538SAndroid Build Coastguard Worker void HangWatcher::InitializeOnMainThread(ProcessType process_type,
326*6777b538SAndroid Build Coastguard Worker bool is_zygote_child,
327*6777b538SAndroid Build Coastguard Worker bool emit_crashes) {
328*6777b538SAndroid Build Coastguard Worker DCHECK(!g_use_hang_watcher);
329*6777b538SAndroid Build Coastguard Worker DCHECK(g_io_thread_log_level == LoggingLevel::kNone);
330*6777b538SAndroid Build Coastguard Worker DCHECK(g_main_thread_log_level == LoggingLevel::kNone);
331*6777b538SAndroid Build Coastguard Worker DCHECK(g_threadpool_log_level == LoggingLevel::kNone);
332*6777b538SAndroid Build Coastguard Worker
333*6777b538SAndroid Build Coastguard Worker bool enable_hang_watcher = base::FeatureList::IsEnabled(kEnableHangWatcher);
334*6777b538SAndroid Build Coastguard Worker
335*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
336*6777b538SAndroid Build Coastguard Worker if (is_zygote_child) {
337*6777b538SAndroid Build Coastguard Worker enable_hang_watcher =
338*6777b538SAndroid Build Coastguard Worker enable_hang_watcher &&
339*6777b538SAndroid Build Coastguard Worker base::FeatureList::IsEnabled(kEnableHangWatcherInZygoteChildren);
340*6777b538SAndroid Build Coastguard Worker }
341*6777b538SAndroid Build Coastguard Worker #endif
342*6777b538SAndroid Build Coastguard Worker
343*6777b538SAndroid Build Coastguard Worker // Do not start HangWatcher in the GPU process until the issue related to
344*6777b538SAndroid Build Coastguard Worker // invalid magic signature in the GPU WatchDog is fixed
345*6777b538SAndroid Build Coastguard Worker // (https://crbug.com/1297760).
346*6777b538SAndroid Build Coastguard Worker if (process_type == ProcessType::kGPUProcess)
347*6777b538SAndroid Build Coastguard Worker enable_hang_watcher = false;
348*6777b538SAndroid Build Coastguard Worker
349*6777b538SAndroid Build Coastguard Worker g_use_hang_watcher.store(enable_hang_watcher, std::memory_order_relaxed);
350*6777b538SAndroid Build Coastguard Worker
351*6777b538SAndroid Build Coastguard Worker // Keep the process type.
352*6777b538SAndroid Build Coastguard Worker g_hang_watcher_process_type.store(process_type, std::memory_order_relaxed);
353*6777b538SAndroid Build Coastguard Worker
354*6777b538SAndroid Build Coastguard Worker // If hang watching is disabled as a whole there is no need to read the
355*6777b538SAndroid Build Coastguard Worker // params.
356*6777b538SAndroid Build Coastguard Worker if (!enable_hang_watcher)
357*6777b538SAndroid Build Coastguard Worker return;
358*6777b538SAndroid Build Coastguard Worker
359*6777b538SAndroid Build Coastguard Worker // Retrieve thread-specific config for hang watching.
360*6777b538SAndroid Build Coastguard Worker if (process_type == HangWatcher::ProcessType::kBrowserProcess) {
361*6777b538SAndroid Build Coastguard Worker // Crashes are set to always emit. Override any feature flags.
362*6777b538SAndroid Build Coastguard Worker if (emit_crashes) {
363*6777b538SAndroid Build Coastguard Worker g_io_thread_log_level.store(
364*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(LoggingLevel::kUmaAndCrash),
365*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
366*6777b538SAndroid Build Coastguard Worker g_main_thread_log_level.store(
367*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(LoggingLevel::kUmaAndCrash),
368*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
369*6777b538SAndroid Build Coastguard Worker } else {
370*6777b538SAndroid Build Coastguard Worker g_io_thread_log_level.store(
371*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(kIOThreadLogLevel.Get()),
372*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
373*6777b538SAndroid Build Coastguard Worker g_main_thread_log_level.store(
374*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(kUIThreadLogLevel.Get()),
375*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
376*6777b538SAndroid Build Coastguard Worker }
377*6777b538SAndroid Build Coastguard Worker
378*6777b538SAndroid Build Coastguard Worker g_threadpool_log_level.store(
379*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(kThreadPoolLogLevel.Get()),
380*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
381*6777b538SAndroid Build Coastguard Worker } else if (process_type == HangWatcher::ProcessType::kGPUProcess) {
382*6777b538SAndroid Build Coastguard Worker g_threadpool_log_level.store(
383*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(kGPUProcessThreadPoolLogLevel.Get()),
384*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
385*6777b538SAndroid Build Coastguard Worker g_io_thread_log_level.store(
386*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(kGPUProcessIOThreadLogLevel.Get()),
387*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
388*6777b538SAndroid Build Coastguard Worker g_main_thread_log_level.store(
389*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(kGPUProcessMainThreadLogLevel.Get()),
390*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
391*6777b538SAndroid Build Coastguard Worker } else if (process_type == HangWatcher::ProcessType::kRendererProcess) {
392*6777b538SAndroid Build Coastguard Worker g_threadpool_log_level.store(
393*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(kRendererProcessThreadPoolLogLevel.Get()),
394*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
395*6777b538SAndroid Build Coastguard Worker g_io_thread_log_level.store(
396*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(kRendererProcessIOThreadLogLevel.Get()),
397*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
398*6777b538SAndroid Build Coastguard Worker g_main_thread_log_level.store(
399*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(kRendererProcessMainThreadLogLevel.Get()),
400*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
401*6777b538SAndroid Build Coastguard Worker } else if (process_type == HangWatcher::ProcessType::kUtilityProcess) {
402*6777b538SAndroid Build Coastguard Worker g_threadpool_log_level.store(
403*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(kUtilityProcessThreadPoolLogLevel.Get()),
404*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
405*6777b538SAndroid Build Coastguard Worker g_io_thread_log_level.store(
406*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(kUtilityProcessIOThreadLogLevel.Get()),
407*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
408*6777b538SAndroid Build Coastguard Worker g_main_thread_log_level.store(
409*6777b538SAndroid Build Coastguard Worker static_cast<LoggingLevel>(kUtilityProcessMainThreadLogLevel.Get()),
410*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
411*6777b538SAndroid Build Coastguard Worker }
412*6777b538SAndroid Build Coastguard Worker }
413*6777b538SAndroid Build Coastguard Worker
UnitializeOnMainThreadForTesting()414*6777b538SAndroid Build Coastguard Worker void HangWatcher::UnitializeOnMainThreadForTesting() {
415*6777b538SAndroid Build Coastguard Worker g_use_hang_watcher.store(false, std::memory_order_relaxed);
416*6777b538SAndroid Build Coastguard Worker g_threadpool_log_level.store(LoggingLevel::kNone, std::memory_order_relaxed);
417*6777b538SAndroid Build Coastguard Worker g_io_thread_log_level.store(LoggingLevel::kNone, std::memory_order_relaxed);
418*6777b538SAndroid Build Coastguard Worker g_main_thread_log_level.store(LoggingLevel::kNone, std::memory_order_relaxed);
419*6777b538SAndroid Build Coastguard Worker }
420*6777b538SAndroid Build Coastguard Worker
421*6777b538SAndroid Build Coastguard Worker // static
IsEnabled()422*6777b538SAndroid Build Coastguard Worker bool HangWatcher::IsEnabled() {
423*6777b538SAndroid Build Coastguard Worker return g_use_hang_watcher.load(std::memory_order_relaxed);
424*6777b538SAndroid Build Coastguard Worker }
425*6777b538SAndroid Build Coastguard Worker
426*6777b538SAndroid Build Coastguard Worker // static
IsThreadPoolHangWatchingEnabled()427*6777b538SAndroid Build Coastguard Worker bool HangWatcher::IsThreadPoolHangWatchingEnabled() {
428*6777b538SAndroid Build Coastguard Worker return g_threadpool_log_level.load(std::memory_order_relaxed) !=
429*6777b538SAndroid Build Coastguard Worker LoggingLevel::kNone;
430*6777b538SAndroid Build Coastguard Worker }
431*6777b538SAndroid Build Coastguard Worker
432*6777b538SAndroid Build Coastguard Worker // static
IsIOThreadHangWatchingEnabled()433*6777b538SAndroid Build Coastguard Worker bool HangWatcher::IsIOThreadHangWatchingEnabled() {
434*6777b538SAndroid Build Coastguard Worker return g_io_thread_log_level.load(std::memory_order_relaxed) !=
435*6777b538SAndroid Build Coastguard Worker LoggingLevel::kNone;
436*6777b538SAndroid Build Coastguard Worker }
437*6777b538SAndroid Build Coastguard Worker
438*6777b538SAndroid Build Coastguard Worker // static
IsCrashReportingEnabled()439*6777b538SAndroid Build Coastguard Worker bool HangWatcher::IsCrashReportingEnabled() {
440*6777b538SAndroid Build Coastguard Worker if (g_main_thread_log_level.load(std::memory_order_relaxed) ==
441*6777b538SAndroid Build Coastguard Worker LoggingLevel::kUmaAndCrash) {
442*6777b538SAndroid Build Coastguard Worker return true;
443*6777b538SAndroid Build Coastguard Worker }
444*6777b538SAndroid Build Coastguard Worker if (g_io_thread_log_level.load(std::memory_order_relaxed) ==
445*6777b538SAndroid Build Coastguard Worker LoggingLevel::kUmaAndCrash) {
446*6777b538SAndroid Build Coastguard Worker return true;
447*6777b538SAndroid Build Coastguard Worker }
448*6777b538SAndroid Build Coastguard Worker if (g_threadpool_log_level.load(std::memory_order_relaxed) ==
449*6777b538SAndroid Build Coastguard Worker LoggingLevel::kUmaAndCrash) {
450*6777b538SAndroid Build Coastguard Worker return true;
451*6777b538SAndroid Build Coastguard Worker }
452*6777b538SAndroid Build Coastguard Worker return false;
453*6777b538SAndroid Build Coastguard Worker }
454*6777b538SAndroid Build Coastguard Worker
455*6777b538SAndroid Build Coastguard Worker // static
InvalidateActiveExpectations()456*6777b538SAndroid Build Coastguard Worker void HangWatcher::InvalidateActiveExpectations() {
457*6777b538SAndroid Build Coastguard Worker auto* const state =
458*6777b538SAndroid Build Coastguard Worker internal::HangWatchState::GetHangWatchStateForCurrentThread();
459*6777b538SAndroid Build Coastguard Worker if (!state) {
460*6777b538SAndroid Build Coastguard Worker // If the current thread is not under watch there is nothing to invalidate.
461*6777b538SAndroid Build Coastguard Worker return;
462*6777b538SAndroid Build Coastguard Worker }
463*6777b538SAndroid Build Coastguard Worker state->SetIgnoreCurrentWatchHangsInScope();
464*6777b538SAndroid Build Coastguard Worker }
465*6777b538SAndroid Build Coastguard Worker
HangWatcher()466*6777b538SAndroid Build Coastguard Worker HangWatcher::HangWatcher()
467*6777b538SAndroid Build Coastguard Worker : monitor_period_(kMonitoringPeriod),
468*6777b538SAndroid Build Coastguard Worker should_monitor_(WaitableEvent::ResetPolicy::AUTOMATIC),
469*6777b538SAndroid Build Coastguard Worker thread_(this, kThreadName),
470*6777b538SAndroid Build Coastguard Worker tick_clock_(base::DefaultTickClock::GetInstance()),
471*6777b538SAndroid Build Coastguard Worker memory_pressure_listener_(
472*6777b538SAndroid Build Coastguard Worker FROM_HERE,
473*6777b538SAndroid Build Coastguard Worker base::BindRepeating(&HangWatcher::OnMemoryPressure,
474*6777b538SAndroid Build Coastguard Worker base::Unretained(this))) {
475*6777b538SAndroid Build Coastguard Worker // |thread_checker_| should not be bound to the constructing thread.
476*6777b538SAndroid Build Coastguard Worker DETACH_FROM_THREAD(hang_watcher_thread_checker_);
477*6777b538SAndroid Build Coastguard Worker
478*6777b538SAndroid Build Coastguard Worker should_monitor_.declare_only_used_while_idle();
479*6777b538SAndroid Build Coastguard Worker
480*6777b538SAndroid Build Coastguard Worker DCHECK(!g_instance);
481*6777b538SAndroid Build Coastguard Worker g_instance = this;
482*6777b538SAndroid Build Coastguard Worker }
483*6777b538SAndroid Build Coastguard Worker
484*6777b538SAndroid Build Coastguard Worker // static
CreateHangWatcherInstance()485*6777b538SAndroid Build Coastguard Worker void HangWatcher::CreateHangWatcherInstance() {
486*6777b538SAndroid Build Coastguard Worker DCHECK(!g_instance);
487*6777b538SAndroid Build Coastguard Worker g_instance = new base::HangWatcher();
488*6777b538SAndroid Build Coastguard Worker // The hang watcher is leaked to make sure it survives all watched threads.
489*6777b538SAndroid Build Coastguard Worker ANNOTATE_LEAKING_OBJECT_PTR(g_instance);
490*6777b538SAndroid Build Coastguard Worker }
491*6777b538SAndroid Build Coastguard Worker
492*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_NACL)
493*6777b538SAndroid Build Coastguard Worker debug::ScopedCrashKeyString
GetTimeSinceLastCriticalMemoryPressureCrashKey()494*6777b538SAndroid Build Coastguard Worker HangWatcher::GetTimeSinceLastCriticalMemoryPressureCrashKey() {
495*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(hang_watcher_thread_checker_);
496*6777b538SAndroid Build Coastguard Worker
497*6777b538SAndroid Build Coastguard Worker // The crash key size is large enough to hold the biggest possible return
498*6777b538SAndroid Build Coastguard Worker // value from base::TimeDelta::InSeconds().
499*6777b538SAndroid Build Coastguard Worker constexpr debug::CrashKeySize kCrashKeyContentSize =
500*6777b538SAndroid Build Coastguard Worker debug::CrashKeySize::Size32;
501*6777b538SAndroid Build Coastguard Worker DCHECK_GE(static_cast<uint64_t>(kCrashKeyContentSize),
502*6777b538SAndroid Build Coastguard Worker base::NumberToString(std::numeric_limits<int64_t>::max()).size());
503*6777b538SAndroid Build Coastguard Worker
504*6777b538SAndroid Build Coastguard Worker static debug::CrashKeyString* crash_key = AllocateCrashKeyString(
505*6777b538SAndroid Build Coastguard Worker "seconds-since-last-memory-pressure", kCrashKeyContentSize);
506*6777b538SAndroid Build Coastguard Worker
507*6777b538SAndroid Build Coastguard Worker const base::TimeTicks last_critical_memory_pressure_time =
508*6777b538SAndroid Build Coastguard Worker last_critical_memory_pressure_.load(std::memory_order_relaxed);
509*6777b538SAndroid Build Coastguard Worker if (last_critical_memory_pressure_time.is_null()) {
510*6777b538SAndroid Build Coastguard Worker constexpr char kNoMemoryPressureMsg[] = "No critical memory pressure";
511*6777b538SAndroid Build Coastguard Worker static_assert(
512*6777b538SAndroid Build Coastguard Worker std::size(kNoMemoryPressureMsg) <=
513*6777b538SAndroid Build Coastguard Worker static_cast<uint64_t>(kCrashKeyContentSize),
514*6777b538SAndroid Build Coastguard Worker "The crash key is too small to hold \"No critical memory pressure\".");
515*6777b538SAndroid Build Coastguard Worker return debug::ScopedCrashKeyString(crash_key, kNoMemoryPressureMsg);
516*6777b538SAndroid Build Coastguard Worker } else {
517*6777b538SAndroid Build Coastguard Worker base::TimeDelta time_since_last_critical_memory_pressure =
518*6777b538SAndroid Build Coastguard Worker base::TimeTicks::Now() - last_critical_memory_pressure_time;
519*6777b538SAndroid Build Coastguard Worker return debug::ScopedCrashKeyString(
520*6777b538SAndroid Build Coastguard Worker crash_key, base::NumberToString(
521*6777b538SAndroid Build Coastguard Worker time_since_last_critical_memory_pressure.InSeconds()));
522*6777b538SAndroid Build Coastguard Worker }
523*6777b538SAndroid Build Coastguard Worker }
524*6777b538SAndroid Build Coastguard Worker #endif
525*6777b538SAndroid Build Coastguard Worker
GetTimeSinceLastSystemPowerResumeCrashKeyValue() const526*6777b538SAndroid Build Coastguard Worker std::string HangWatcher::GetTimeSinceLastSystemPowerResumeCrashKeyValue()
527*6777b538SAndroid Build Coastguard Worker const {
528*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(hang_watcher_thread_checker_);
529*6777b538SAndroid Build Coastguard Worker
530*6777b538SAndroid Build Coastguard Worker const TimeTicks last_system_power_resume_time =
531*6777b538SAndroid Build Coastguard Worker PowerMonitor::GetLastSystemResumeTime();
532*6777b538SAndroid Build Coastguard Worker if (last_system_power_resume_time.is_null())
533*6777b538SAndroid Build Coastguard Worker return "Never suspended";
534*6777b538SAndroid Build Coastguard Worker if (last_system_power_resume_time == TimeTicks::Max())
535*6777b538SAndroid Build Coastguard Worker return "Power suspended";
536*6777b538SAndroid Build Coastguard Worker
537*6777b538SAndroid Build Coastguard Worker const TimeDelta time_since_last_system_resume =
538*6777b538SAndroid Build Coastguard Worker TimeTicks::Now() - last_system_power_resume_time;
539*6777b538SAndroid Build Coastguard Worker return NumberToString(time_since_last_system_resume.InSeconds());
540*6777b538SAndroid Build Coastguard Worker }
541*6777b538SAndroid Build Coastguard Worker
OnMemoryPressure(base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level)542*6777b538SAndroid Build Coastguard Worker void HangWatcher::OnMemoryPressure(
543*6777b538SAndroid Build Coastguard Worker base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
544*6777b538SAndroid Build Coastguard Worker if (memory_pressure_level ==
545*6777b538SAndroid Build Coastguard Worker base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL) {
546*6777b538SAndroid Build Coastguard Worker last_critical_memory_pressure_.store(base::TimeTicks::Now(),
547*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
548*6777b538SAndroid Build Coastguard Worker }
549*6777b538SAndroid Build Coastguard Worker }
550*6777b538SAndroid Build Coastguard Worker
~HangWatcher()551*6777b538SAndroid Build Coastguard Worker HangWatcher::~HangWatcher() {
552*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(constructing_thread_checker_);
553*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(g_instance, this);
554*6777b538SAndroid Build Coastguard Worker DCHECK(watch_states_.empty());
555*6777b538SAndroid Build Coastguard Worker g_instance = nullptr;
556*6777b538SAndroid Build Coastguard Worker Stop();
557*6777b538SAndroid Build Coastguard Worker }
558*6777b538SAndroid Build Coastguard Worker
Start()559*6777b538SAndroid Build Coastguard Worker void HangWatcher::Start() {
560*6777b538SAndroid Build Coastguard Worker thread_.Start();
561*6777b538SAndroid Build Coastguard Worker thread_started_ = true;
562*6777b538SAndroid Build Coastguard Worker }
563*6777b538SAndroid Build Coastguard Worker
Stop()564*6777b538SAndroid Build Coastguard Worker void HangWatcher::Stop() {
565*6777b538SAndroid Build Coastguard Worker g_keep_monitoring.store(false, std::memory_order_relaxed);
566*6777b538SAndroid Build Coastguard Worker should_monitor_.Signal();
567*6777b538SAndroid Build Coastguard Worker thread_.Join();
568*6777b538SAndroid Build Coastguard Worker thread_started_ = false;
569*6777b538SAndroid Build Coastguard Worker
570*6777b538SAndroid Build Coastguard Worker // In production HangWatcher is always leaked but during testing it's possibly
571*6777b538SAndroid Build Coastguard Worker // stopped and restarted using a new instance. This makes sure the next call
572*6777b538SAndroid Build Coastguard Worker // to Start() will actually monitor in that case.
573*6777b538SAndroid Build Coastguard Worker g_keep_monitoring.store(true, std::memory_order_relaxed);
574*6777b538SAndroid Build Coastguard Worker }
575*6777b538SAndroid Build Coastguard Worker
IsWatchListEmpty()576*6777b538SAndroid Build Coastguard Worker bool HangWatcher::IsWatchListEmpty() {
577*6777b538SAndroid Build Coastguard Worker AutoLock auto_lock(watch_state_lock_);
578*6777b538SAndroid Build Coastguard Worker return watch_states_.empty();
579*6777b538SAndroid Build Coastguard Worker }
580*6777b538SAndroid Build Coastguard Worker
Wait()581*6777b538SAndroid Build Coastguard Worker void HangWatcher::Wait() {
582*6777b538SAndroid Build Coastguard Worker while (true) {
583*6777b538SAndroid Build Coastguard Worker // Amount by which the actual time spent sleeping can deviate from
584*6777b538SAndroid Build Coastguard Worker // the target time and still be considered timely.
585*6777b538SAndroid Build Coastguard Worker constexpr base::TimeDelta kWaitDriftTolerance = base::Milliseconds(100);
586*6777b538SAndroid Build Coastguard Worker
587*6777b538SAndroid Build Coastguard Worker const base::TimeTicks time_before_wait = tick_clock_->NowTicks();
588*6777b538SAndroid Build Coastguard Worker
589*6777b538SAndroid Build Coastguard Worker // Sleep until next scheduled monitoring or until signaled.
590*6777b538SAndroid Build Coastguard Worker const bool was_signaled = should_monitor_.TimedWait(monitor_period_);
591*6777b538SAndroid Build Coastguard Worker
592*6777b538SAndroid Build Coastguard Worker if (after_wait_callback_)
593*6777b538SAndroid Build Coastguard Worker after_wait_callback_.Run(time_before_wait);
594*6777b538SAndroid Build Coastguard Worker
595*6777b538SAndroid Build Coastguard Worker const base::TimeTicks time_after_wait = tick_clock_->NowTicks();
596*6777b538SAndroid Build Coastguard Worker const base::TimeDelta wait_time = time_after_wait - time_before_wait;
597*6777b538SAndroid Build Coastguard Worker const bool wait_was_normal =
598*6777b538SAndroid Build Coastguard Worker wait_time <= (monitor_period_ + kWaitDriftTolerance);
599*6777b538SAndroid Build Coastguard Worker
600*6777b538SAndroid Build Coastguard Worker UMA_HISTOGRAM_TIMES("HangWatcher.SleepDrift.BrowserProcess",
601*6777b538SAndroid Build Coastguard Worker wait_time - monitor_period_);
602*6777b538SAndroid Build Coastguard Worker
603*6777b538SAndroid Build Coastguard Worker if (!wait_was_normal) {
604*6777b538SAndroid Build Coastguard Worker // If the time spent waiting was too high it might indicate the machine is
605*6777b538SAndroid Build Coastguard Worker // very slow or that that it went to sleep. In any case we can't trust the
606*6777b538SAndroid Build Coastguard Worker // WatchHangsInScopes that are currently live. Update the ignore
607*6777b538SAndroid Build Coastguard Worker // threshold to make sure they don't trigger a hang on subsequent monitors
608*6777b538SAndroid Build Coastguard Worker // then keep waiting.
609*6777b538SAndroid Build Coastguard Worker
610*6777b538SAndroid Build Coastguard Worker base::AutoLock auto_lock(watch_state_lock_);
611*6777b538SAndroid Build Coastguard Worker
612*6777b538SAndroid Build Coastguard Worker // Find the latest deadline among the live watch states. They might change
613*6777b538SAndroid Build Coastguard Worker // atomically while iterating but that's fine because if they do that
614*6777b538SAndroid Build Coastguard Worker // means the new WatchHangsInScope was constructed very soon after the
615*6777b538SAndroid Build Coastguard Worker // abnormal sleep happened and might be affected by the root cause still.
616*6777b538SAndroid Build Coastguard Worker // Ignoring it is cautious and harmless.
617*6777b538SAndroid Build Coastguard Worker base::TimeTicks latest_deadline;
618*6777b538SAndroid Build Coastguard Worker for (const auto& state : watch_states_) {
619*6777b538SAndroid Build Coastguard Worker base::TimeTicks deadline = state->GetDeadline();
620*6777b538SAndroid Build Coastguard Worker if (deadline > latest_deadline) {
621*6777b538SAndroid Build Coastguard Worker latest_deadline = deadline;
622*6777b538SAndroid Build Coastguard Worker }
623*6777b538SAndroid Build Coastguard Worker }
624*6777b538SAndroid Build Coastguard Worker
625*6777b538SAndroid Build Coastguard Worker deadline_ignore_threshold_ = latest_deadline;
626*6777b538SAndroid Build Coastguard Worker }
627*6777b538SAndroid Build Coastguard Worker
628*6777b538SAndroid Build Coastguard Worker // Stop waiting.
629*6777b538SAndroid Build Coastguard Worker if (wait_was_normal || was_signaled)
630*6777b538SAndroid Build Coastguard Worker return;
631*6777b538SAndroid Build Coastguard Worker }
632*6777b538SAndroid Build Coastguard Worker }
633*6777b538SAndroid Build Coastguard Worker
Run()634*6777b538SAndroid Build Coastguard Worker void HangWatcher::Run() {
635*6777b538SAndroid Build Coastguard Worker // Monitor() should only run on |thread_|. Bind |thread_checker_| here to make
636*6777b538SAndroid Build Coastguard Worker // sure of that.
637*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(hang_watcher_thread_checker_);
638*6777b538SAndroid Build Coastguard Worker
639*6777b538SAndroid Build Coastguard Worker while (g_keep_monitoring.load(std::memory_order_relaxed)) {
640*6777b538SAndroid Build Coastguard Worker Wait();
641*6777b538SAndroid Build Coastguard Worker
642*6777b538SAndroid Build Coastguard Worker if (!IsWatchListEmpty() &&
643*6777b538SAndroid Build Coastguard Worker g_keep_monitoring.load(std::memory_order_relaxed)) {
644*6777b538SAndroid Build Coastguard Worker Monitor();
645*6777b538SAndroid Build Coastguard Worker if (after_monitor_closure_for_testing_) {
646*6777b538SAndroid Build Coastguard Worker after_monitor_closure_for_testing_.Run();
647*6777b538SAndroid Build Coastguard Worker }
648*6777b538SAndroid Build Coastguard Worker }
649*6777b538SAndroid Build Coastguard Worker }
650*6777b538SAndroid Build Coastguard Worker }
651*6777b538SAndroid Build Coastguard Worker
652*6777b538SAndroid Build Coastguard Worker // static
GetInstance()653*6777b538SAndroid Build Coastguard Worker HangWatcher* HangWatcher::GetInstance() {
654*6777b538SAndroid Build Coastguard Worker return g_instance;
655*6777b538SAndroid Build Coastguard Worker }
656*6777b538SAndroid Build Coastguard Worker
657*6777b538SAndroid Build Coastguard Worker // static
RecordHang()658*6777b538SAndroid Build Coastguard Worker void HangWatcher::RecordHang() {
659*6777b538SAndroid Build Coastguard Worker base::debug::DumpWithoutCrashing();
660*6777b538SAndroid Build Coastguard Worker NO_CODE_FOLDING();
661*6777b538SAndroid Build Coastguard Worker }
662*6777b538SAndroid Build Coastguard Worker
RegisterThreadInternal(ThreadType thread_type)663*6777b538SAndroid Build Coastguard Worker ScopedClosureRunner HangWatcher::RegisterThreadInternal(
664*6777b538SAndroid Build Coastguard Worker ThreadType thread_type) {
665*6777b538SAndroid Build Coastguard Worker AutoLock auto_lock(watch_state_lock_);
666*6777b538SAndroid Build Coastguard Worker CHECK(base::FeatureList::GetInstance());
667*6777b538SAndroid Build Coastguard Worker
668*6777b538SAndroid Build Coastguard Worker // Do not install a WatchState if the results would never be observable.
669*6777b538SAndroid Build Coastguard Worker if (!ThreadTypeLoggingLevelGreaterOrEqual(thread_type,
670*6777b538SAndroid Build Coastguard Worker LoggingLevel::kUmaOnly)) {
671*6777b538SAndroid Build Coastguard Worker return ScopedClosureRunner(base::DoNothing());
672*6777b538SAndroid Build Coastguard Worker }
673*6777b538SAndroid Build Coastguard Worker
674*6777b538SAndroid Build Coastguard Worker watch_states_.push_back(
675*6777b538SAndroid Build Coastguard Worker internal::HangWatchState::CreateHangWatchStateForCurrentThread(
676*6777b538SAndroid Build Coastguard Worker thread_type));
677*6777b538SAndroid Build Coastguard Worker return ScopedClosureRunner(BindOnce(&HangWatcher::UnregisterThread,
678*6777b538SAndroid Build Coastguard Worker Unretained(HangWatcher::GetInstance())));
679*6777b538SAndroid Build Coastguard Worker }
680*6777b538SAndroid Build Coastguard Worker
681*6777b538SAndroid Build Coastguard Worker // static
RegisterThread(ThreadType thread_type)682*6777b538SAndroid Build Coastguard Worker ScopedClosureRunner HangWatcher::RegisterThread(ThreadType thread_type) {
683*6777b538SAndroid Build Coastguard Worker if (!GetInstance()) {
684*6777b538SAndroid Build Coastguard Worker return ScopedClosureRunner();
685*6777b538SAndroid Build Coastguard Worker }
686*6777b538SAndroid Build Coastguard Worker
687*6777b538SAndroid Build Coastguard Worker return GetInstance()->RegisterThreadInternal(thread_type);
688*6777b538SAndroid Build Coastguard Worker }
689*6777b538SAndroid Build Coastguard Worker
GetHighestDeadline() const690*6777b538SAndroid Build Coastguard Worker base::TimeTicks HangWatcher::WatchStateSnapShot::GetHighestDeadline() const {
691*6777b538SAndroid Build Coastguard Worker DCHECK(IsActionable());
692*6777b538SAndroid Build Coastguard Worker
693*6777b538SAndroid Build Coastguard Worker // Since entries are sorted in increasing order the last entry is the largest
694*6777b538SAndroid Build Coastguard Worker // one.
695*6777b538SAndroid Build Coastguard Worker return hung_watch_state_copies_.back().deadline;
696*6777b538SAndroid Build Coastguard Worker }
697*6777b538SAndroid Build Coastguard Worker
698*6777b538SAndroid Build Coastguard Worker HangWatcher::WatchStateSnapShot::WatchStateSnapShot() = default;
699*6777b538SAndroid Build Coastguard Worker
Init(const HangWatchStates & watch_states,base::TimeTicks deadline_ignore_threshold)700*6777b538SAndroid Build Coastguard Worker void HangWatcher::WatchStateSnapShot::Init(
701*6777b538SAndroid Build Coastguard Worker const HangWatchStates& watch_states,
702*6777b538SAndroid Build Coastguard Worker base::TimeTicks deadline_ignore_threshold) {
703*6777b538SAndroid Build Coastguard Worker DCHECK(!initialized_);
704*6777b538SAndroid Build Coastguard Worker
705*6777b538SAndroid Build Coastguard Worker // No matter if the snapshot is actionable or not after this function
706*6777b538SAndroid Build Coastguard Worker // it will have been initialized.
707*6777b538SAndroid Build Coastguard Worker initialized_ = true;
708*6777b538SAndroid Build Coastguard Worker
709*6777b538SAndroid Build Coastguard Worker const base::TimeTicks now = base::TimeTicks::Now();
710*6777b538SAndroid Build Coastguard Worker bool all_threads_marked = true;
711*6777b538SAndroid Build Coastguard Worker bool found_deadline_before_ignore_threshold = false;
712*6777b538SAndroid Build Coastguard Worker
713*6777b538SAndroid Build Coastguard Worker // Use an std::array to store the hang counts to avoid allocations. The
714*6777b538SAndroid Build Coastguard Worker // numerical values of the HangWatcher::ThreadType enum is used to index into
715*6777b538SAndroid Build Coastguard Worker // the array. A |kInvalidHangCount| is used to signify there were no threads
716*6777b538SAndroid Build Coastguard Worker // of the type found.
717*6777b538SAndroid Build Coastguard Worker constexpr size_t kHangCountArraySize =
718*6777b538SAndroid Build Coastguard Worker static_cast<std::size_t>(base::HangWatcher::ThreadType::kMax) + 1;
719*6777b538SAndroid Build Coastguard Worker std::array<int, kHangCountArraySize> hung_counts_per_thread_type;
720*6777b538SAndroid Build Coastguard Worker
721*6777b538SAndroid Build Coastguard Worker constexpr int kInvalidHangCount = -1;
722*6777b538SAndroid Build Coastguard Worker hung_counts_per_thread_type.fill(kInvalidHangCount);
723*6777b538SAndroid Build Coastguard Worker
724*6777b538SAndroid Build Coastguard Worker // Will be true if any of the hung threads has a logging level high enough,
725*6777b538SAndroid Build Coastguard Worker // as defined through finch params, to warant dumping a crash.
726*6777b538SAndroid Build Coastguard Worker bool any_hung_thread_has_dumping_enabled = false;
727*6777b538SAndroid Build Coastguard Worker
728*6777b538SAndroid Build Coastguard Worker // Copy hung thread information.
729*6777b538SAndroid Build Coastguard Worker for (const auto& watch_state : watch_states) {
730*6777b538SAndroid Build Coastguard Worker uint64_t flags;
731*6777b538SAndroid Build Coastguard Worker TimeTicks deadline;
732*6777b538SAndroid Build Coastguard Worker std::tie(flags, deadline) = watch_state->GetFlagsAndDeadline();
733*6777b538SAndroid Build Coastguard Worker
734*6777b538SAndroid Build Coastguard Worker if (deadline <= deadline_ignore_threshold) {
735*6777b538SAndroid Build Coastguard Worker found_deadline_before_ignore_threshold = true;
736*6777b538SAndroid Build Coastguard Worker }
737*6777b538SAndroid Build Coastguard Worker
738*6777b538SAndroid Build Coastguard Worker if (internal::HangWatchDeadline::IsFlagSet(
739*6777b538SAndroid Build Coastguard Worker internal::HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope,
740*6777b538SAndroid Build Coastguard Worker flags)) {
741*6777b538SAndroid Build Coastguard Worker continue;
742*6777b538SAndroid Build Coastguard Worker }
743*6777b538SAndroid Build Coastguard Worker
744*6777b538SAndroid Build Coastguard Worker // If a thread type is monitored and did not hang it still needs to be
745*6777b538SAndroid Build Coastguard Worker // logged as a zero count;
746*6777b538SAndroid Build Coastguard Worker const size_t hang_count_index =
747*6777b538SAndroid Build Coastguard Worker static_cast<size_t>(watch_state.get()->thread_type());
748*6777b538SAndroid Build Coastguard Worker if (hung_counts_per_thread_type[hang_count_index] == kInvalidHangCount) {
749*6777b538SAndroid Build Coastguard Worker hung_counts_per_thread_type[hang_count_index] = 0;
750*6777b538SAndroid Build Coastguard Worker }
751*6777b538SAndroid Build Coastguard Worker
752*6777b538SAndroid Build Coastguard Worker // Only copy hung threads.
753*6777b538SAndroid Build Coastguard Worker if (deadline <= now) {
754*6777b538SAndroid Build Coastguard Worker ++hung_counts_per_thread_type[hang_count_index];
755*6777b538SAndroid Build Coastguard Worker
756*6777b538SAndroid Build Coastguard Worker if (ThreadTypeLoggingLevelGreaterOrEqual(watch_state.get()->thread_type(),
757*6777b538SAndroid Build Coastguard Worker LoggingLevel::kUmaAndCrash)) {
758*6777b538SAndroid Build Coastguard Worker any_hung_thread_has_dumping_enabled = true;
759*6777b538SAndroid Build Coastguard Worker }
760*6777b538SAndroid Build Coastguard Worker
761*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(ENABLE_BASE_TRACING)
762*6777b538SAndroid Build Coastguard Worker // Emit trace events for monitored threads.
763*6777b538SAndroid Build Coastguard Worker if (ThreadTypeLoggingLevelGreaterOrEqual(watch_state.get()->thread_type(),
764*6777b538SAndroid Build Coastguard Worker LoggingLevel::kUmaOnly)) {
765*6777b538SAndroid Build Coastguard Worker const PlatformThreadId thread_id = watch_state.get()->GetThreadID();
766*6777b538SAndroid Build Coastguard Worker const auto track = perfetto::Track::FromPointer(
767*6777b538SAndroid Build Coastguard Worker this, perfetto::ThreadTrack::ForThread(thread_id));
768*6777b538SAndroid Build Coastguard Worker TRACE_EVENT_BEGIN("base", "HangWatcher::ThreadHung", track, deadline);
769*6777b538SAndroid Build Coastguard Worker TRACE_EVENT_END("base", track, now);
770*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1021571): Remove this once fixed.
771*6777b538SAndroid Build Coastguard Worker PERFETTO_INTERNAL_ADD_EMPTY_EVENT();
772*6777b538SAndroid Build Coastguard Worker }
773*6777b538SAndroid Build Coastguard Worker #endif
774*6777b538SAndroid Build Coastguard Worker
775*6777b538SAndroid Build Coastguard Worker // Attempt to mark the thread as needing to stay within its current
776*6777b538SAndroid Build Coastguard Worker // WatchHangsInScope until capture is complete.
777*6777b538SAndroid Build Coastguard Worker bool thread_marked = watch_state->SetShouldBlockOnHang(flags, deadline);
778*6777b538SAndroid Build Coastguard Worker
779*6777b538SAndroid Build Coastguard Worker // If marking some threads already failed the snapshot won't be kept so
780*6777b538SAndroid Build Coastguard Worker // there is no need to keep adding to it. The loop doesn't abort though
781*6777b538SAndroid Build Coastguard Worker // to keep marking the other threads. If these threads remain hung until
782*6777b538SAndroid Build Coastguard Worker // the next capture then they'll already be marked and will be included
783*6777b538SAndroid Build Coastguard Worker // in the capture at that time.
784*6777b538SAndroid Build Coastguard Worker if (thread_marked && all_threads_marked) {
785*6777b538SAndroid Build Coastguard Worker hung_watch_state_copies_.push_back(
786*6777b538SAndroid Build Coastguard Worker WatchStateCopy{deadline, watch_state.get()->GetThreadID()});
787*6777b538SAndroid Build Coastguard Worker } else {
788*6777b538SAndroid Build Coastguard Worker all_threads_marked = false;
789*6777b538SAndroid Build Coastguard Worker }
790*6777b538SAndroid Build Coastguard Worker }
791*6777b538SAndroid Build Coastguard Worker }
792*6777b538SAndroid Build Coastguard Worker
793*6777b538SAndroid Build Coastguard Worker // Log the hung thread counts to histograms for each thread type if any thread
794*6777b538SAndroid Build Coastguard Worker // of the type were found.
795*6777b538SAndroid Build Coastguard Worker for (size_t i = 0; i < kHangCountArraySize; ++i) {
796*6777b538SAndroid Build Coastguard Worker const int hang_count = hung_counts_per_thread_type[i];
797*6777b538SAndroid Build Coastguard Worker const HangWatcher::ThreadType thread_type =
798*6777b538SAndroid Build Coastguard Worker static_cast<HangWatcher::ThreadType>(i);
799*6777b538SAndroid Build Coastguard Worker if (hang_count != kInvalidHangCount &&
800*6777b538SAndroid Build Coastguard Worker ThreadTypeLoggingLevelGreaterOrEqual(thread_type,
801*6777b538SAndroid Build Coastguard Worker LoggingLevel::kUmaOnly)) {
802*6777b538SAndroid Build Coastguard Worker LogHungThreadCountHistogram(thread_type, hang_count);
803*6777b538SAndroid Build Coastguard Worker }
804*6777b538SAndroid Build Coastguard Worker }
805*6777b538SAndroid Build Coastguard Worker
806*6777b538SAndroid Build Coastguard Worker // Three cases can invalidate this snapshot and prevent the capture of the
807*6777b538SAndroid Build Coastguard Worker // hang.
808*6777b538SAndroid Build Coastguard Worker //
809*6777b538SAndroid Build Coastguard Worker // 1. Some threads could not be marked for blocking so this snapshot isn't
810*6777b538SAndroid Build Coastguard Worker // actionable since marked threads could be hung because of unmarked ones.
811*6777b538SAndroid Build Coastguard Worker // If only the marked threads were captured the information would be
812*6777b538SAndroid Build Coastguard Worker // incomplete.
813*6777b538SAndroid Build Coastguard Worker //
814*6777b538SAndroid Build Coastguard Worker // 2. Any of the threads have a deadline before |deadline_ignore_threshold|.
815*6777b538SAndroid Build Coastguard Worker // If any thread is ignored it reduces the confidence in the whole state and
816*6777b538SAndroid Build Coastguard Worker // it's better to avoid capturing misleading data.
817*6777b538SAndroid Build Coastguard Worker //
818*6777b538SAndroid Build Coastguard Worker // 3. The hung threads found were all of types that are not configured through
819*6777b538SAndroid Build Coastguard Worker // Finch to trigger a crash dump.
820*6777b538SAndroid Build Coastguard Worker //
821*6777b538SAndroid Build Coastguard Worker if (!all_threads_marked || found_deadline_before_ignore_threshold ||
822*6777b538SAndroid Build Coastguard Worker !any_hung_thread_has_dumping_enabled) {
823*6777b538SAndroid Build Coastguard Worker hung_watch_state_copies_.clear();
824*6777b538SAndroid Build Coastguard Worker return;
825*6777b538SAndroid Build Coastguard Worker }
826*6777b538SAndroid Build Coastguard Worker
827*6777b538SAndroid Build Coastguard Worker // Sort |hung_watch_state_copies_| by order of decreasing hang severity so the
828*6777b538SAndroid Build Coastguard Worker // most severe hang is first in the list.
829*6777b538SAndroid Build Coastguard Worker ranges::sort(hung_watch_state_copies_,
830*6777b538SAndroid Build Coastguard Worker [](const WatchStateCopy& lhs, const WatchStateCopy& rhs) {
831*6777b538SAndroid Build Coastguard Worker return lhs.deadline < rhs.deadline;
832*6777b538SAndroid Build Coastguard Worker });
833*6777b538SAndroid Build Coastguard Worker }
834*6777b538SAndroid Build Coastguard Worker
Clear()835*6777b538SAndroid Build Coastguard Worker void HangWatcher::WatchStateSnapShot::Clear() {
836*6777b538SAndroid Build Coastguard Worker hung_watch_state_copies_.clear();
837*6777b538SAndroid Build Coastguard Worker initialized_ = false;
838*6777b538SAndroid Build Coastguard Worker }
839*6777b538SAndroid Build Coastguard Worker
840*6777b538SAndroid Build Coastguard Worker HangWatcher::WatchStateSnapShot::WatchStateSnapShot(
841*6777b538SAndroid Build Coastguard Worker const WatchStateSnapShot& other) = default;
842*6777b538SAndroid Build Coastguard Worker
843*6777b538SAndroid Build Coastguard Worker HangWatcher::WatchStateSnapShot::~WatchStateSnapShot() = default;
844*6777b538SAndroid Build Coastguard Worker
PrepareHungThreadListCrashKey() const845*6777b538SAndroid Build Coastguard Worker std::string HangWatcher::WatchStateSnapShot::PrepareHungThreadListCrashKey()
846*6777b538SAndroid Build Coastguard Worker const {
847*6777b538SAndroid Build Coastguard Worker DCHECK(IsActionable());
848*6777b538SAndroid Build Coastguard Worker
849*6777b538SAndroid Build Coastguard Worker // Build a crash key string that contains the ids of the hung threads.
850*6777b538SAndroid Build Coastguard Worker constexpr char kSeparator{'|'};
851*6777b538SAndroid Build Coastguard Worker std::string list_of_hung_thread_ids;
852*6777b538SAndroid Build Coastguard Worker
853*6777b538SAndroid Build Coastguard Worker // Add as many thread ids to the crash key as possible.
854*6777b538SAndroid Build Coastguard Worker for (const WatchStateCopy& copy : hung_watch_state_copies_) {
855*6777b538SAndroid Build Coastguard Worker std::string fragment = base::NumberToString(copy.thread_id) + kSeparator;
856*6777b538SAndroid Build Coastguard Worker if (list_of_hung_thread_ids.size() + fragment.size() <
857*6777b538SAndroid Build Coastguard Worker static_cast<std::size_t>(debug::CrashKeySize::Size256)) {
858*6777b538SAndroid Build Coastguard Worker list_of_hung_thread_ids += fragment;
859*6777b538SAndroid Build Coastguard Worker } else {
860*6777b538SAndroid Build Coastguard Worker // Respect the by priority ordering of thread ids in the crash key by
861*6777b538SAndroid Build Coastguard Worker // stopping the construction as soon as one does not fit. This avoids
862*6777b538SAndroid Build Coastguard Worker // including lesser priority ids while omitting more important ones.
863*6777b538SAndroid Build Coastguard Worker break;
864*6777b538SAndroid Build Coastguard Worker }
865*6777b538SAndroid Build Coastguard Worker }
866*6777b538SAndroid Build Coastguard Worker
867*6777b538SAndroid Build Coastguard Worker return list_of_hung_thread_ids;
868*6777b538SAndroid Build Coastguard Worker }
869*6777b538SAndroid Build Coastguard Worker
IsActionable() const870*6777b538SAndroid Build Coastguard Worker bool HangWatcher::WatchStateSnapShot::IsActionable() const {
871*6777b538SAndroid Build Coastguard Worker DCHECK(initialized_);
872*6777b538SAndroid Build Coastguard Worker return !hung_watch_state_copies_.empty();
873*6777b538SAndroid Build Coastguard Worker }
874*6777b538SAndroid Build Coastguard Worker
GrabWatchStateSnapshotForTesting() const875*6777b538SAndroid Build Coastguard Worker HangWatcher::WatchStateSnapShot HangWatcher::GrabWatchStateSnapshotForTesting()
876*6777b538SAndroid Build Coastguard Worker const {
877*6777b538SAndroid Build Coastguard Worker WatchStateSnapShot snapshot;
878*6777b538SAndroid Build Coastguard Worker snapshot.Init(watch_states_, deadline_ignore_threshold_);
879*6777b538SAndroid Build Coastguard Worker return snapshot;
880*6777b538SAndroid Build Coastguard Worker }
881*6777b538SAndroid Build Coastguard Worker
Monitor()882*6777b538SAndroid Build Coastguard Worker void HangWatcher::Monitor() {
883*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(hang_watcher_thread_checker_);
884*6777b538SAndroid Build Coastguard Worker AutoLock auto_lock(watch_state_lock_);
885*6777b538SAndroid Build Coastguard Worker
886*6777b538SAndroid Build Coastguard Worker // If all threads unregistered since this function was invoked there's
887*6777b538SAndroid Build Coastguard Worker // nothing to do anymore.
888*6777b538SAndroid Build Coastguard Worker if (watch_states_.empty())
889*6777b538SAndroid Build Coastguard Worker return;
890*6777b538SAndroid Build Coastguard Worker
891*6777b538SAndroid Build Coastguard Worker watch_state_snapshot_.Init(watch_states_, deadline_ignore_threshold_);
892*6777b538SAndroid Build Coastguard Worker
893*6777b538SAndroid Build Coastguard Worker if (watch_state_snapshot_.IsActionable()) {
894*6777b538SAndroid Build Coastguard Worker DoDumpWithoutCrashing(watch_state_snapshot_);
895*6777b538SAndroid Build Coastguard Worker }
896*6777b538SAndroid Build Coastguard Worker
897*6777b538SAndroid Build Coastguard Worker watch_state_snapshot_.Clear();
898*6777b538SAndroid Build Coastguard Worker }
899*6777b538SAndroid Build Coastguard Worker
DoDumpWithoutCrashing(const WatchStateSnapShot & watch_state_snapshot)900*6777b538SAndroid Build Coastguard Worker void HangWatcher::DoDumpWithoutCrashing(
901*6777b538SAndroid Build Coastguard Worker const WatchStateSnapShot& watch_state_snapshot) {
902*6777b538SAndroid Build Coastguard Worker TRACE_EVENT("base", "HangWatcher::DoDumpWithoutCrashing");
903*6777b538SAndroid Build Coastguard Worker
904*6777b538SAndroid Build Coastguard Worker capture_in_progress_.store(true, std::memory_order_relaxed);
905*6777b538SAndroid Build Coastguard Worker base::AutoLock scope_lock(capture_lock_);
906*6777b538SAndroid Build Coastguard Worker
907*6777b538SAndroid Build Coastguard Worker #if !BUILDFLAG(IS_NACL)
908*6777b538SAndroid Build Coastguard Worker const std::string list_of_hung_thread_ids =
909*6777b538SAndroid Build Coastguard Worker watch_state_snapshot.PrepareHungThreadListCrashKey();
910*6777b538SAndroid Build Coastguard Worker
911*6777b538SAndroid Build Coastguard Worker static debug::CrashKeyString* crash_key = AllocateCrashKeyString(
912*6777b538SAndroid Build Coastguard Worker "list-of-hung-threads", debug::CrashKeySize::Size256);
913*6777b538SAndroid Build Coastguard Worker
914*6777b538SAndroid Build Coastguard Worker const debug::ScopedCrashKeyString list_of_hung_threads_crash_key_string(
915*6777b538SAndroid Build Coastguard Worker crash_key, list_of_hung_thread_ids);
916*6777b538SAndroid Build Coastguard Worker
917*6777b538SAndroid Build Coastguard Worker const debug::ScopedCrashKeyString
918*6777b538SAndroid Build Coastguard Worker time_since_last_critical_memory_pressure_crash_key_string =
919*6777b538SAndroid Build Coastguard Worker GetTimeSinceLastCriticalMemoryPressureCrashKey();
920*6777b538SAndroid Build Coastguard Worker
921*6777b538SAndroid Build Coastguard Worker SCOPED_CRASH_KEY_STRING32("HangWatcher", "seconds-since-last-resume",
922*6777b538SAndroid Build Coastguard Worker GetTimeSinceLastSystemPowerResumeCrashKeyValue());
923*6777b538SAndroid Build Coastguard Worker #endif
924*6777b538SAndroid Build Coastguard Worker
925*6777b538SAndroid Build Coastguard Worker // To avoid capturing more than one hang that blames a subset of the same
926*6777b538SAndroid Build Coastguard Worker // threads it's necessary to keep track of what is the furthest deadline
927*6777b538SAndroid Build Coastguard Worker // that contributed to declaring a hang. Only once
928*6777b538SAndroid Build Coastguard Worker // all threads have deadlines past this point can we be sure that a newly
929*6777b538SAndroid Build Coastguard Worker // discovered hang is not directly related.
930*6777b538SAndroid Build Coastguard Worker // Example:
931*6777b538SAndroid Build Coastguard Worker // **********************************************************************
932*6777b538SAndroid Build Coastguard Worker // Timeline A : L------1-------2----------3-------4----------N-----------
933*6777b538SAndroid Build Coastguard Worker // Timeline B : -------2----------3-------4----------L----5------N-------
934*6777b538SAndroid Build Coastguard Worker // Timeline C : L----------------------------5------6----7---8------9---N
935*6777b538SAndroid Build Coastguard Worker // **********************************************************************
936*6777b538SAndroid Build Coastguard Worker // In the example when a Monitor() happens during timeline A
937*6777b538SAndroid Build Coastguard Worker // |deadline_ignore_threshold_| (L) is at time zero and deadlines (1-4)
938*6777b538SAndroid Build Coastguard Worker // are before Now() (N) . A hang is captured and L is updated. During
939*6777b538SAndroid Build Coastguard Worker // the next Monitor() (timeline B) a new deadline is over but we can't
940*6777b538SAndroid Build Coastguard Worker // capture a hang because deadlines 2-4 are still live and already counted
941*6777b538SAndroid Build Coastguard Worker // toward a hang. During a third monitor (timeline C) all live deadlines
942*6777b538SAndroid Build Coastguard Worker // are now after L and a second hang can be recorded.
943*6777b538SAndroid Build Coastguard Worker base::TimeTicks latest_expired_deadline =
944*6777b538SAndroid Build Coastguard Worker watch_state_snapshot.GetHighestDeadline();
945*6777b538SAndroid Build Coastguard Worker
946*6777b538SAndroid Build Coastguard Worker if (on_hang_closure_for_testing_)
947*6777b538SAndroid Build Coastguard Worker on_hang_closure_for_testing_.Run();
948*6777b538SAndroid Build Coastguard Worker else
949*6777b538SAndroid Build Coastguard Worker RecordHang();
950*6777b538SAndroid Build Coastguard Worker
951*6777b538SAndroid Build Coastguard Worker // Update after running the actual capture.
952*6777b538SAndroid Build Coastguard Worker deadline_ignore_threshold_ = latest_expired_deadline;
953*6777b538SAndroid Build Coastguard Worker
954*6777b538SAndroid Build Coastguard Worker capture_in_progress_.store(false, std::memory_order_relaxed);
955*6777b538SAndroid Build Coastguard Worker }
956*6777b538SAndroid Build Coastguard Worker
SetAfterMonitorClosureForTesting(base::RepeatingClosure closure)957*6777b538SAndroid Build Coastguard Worker void HangWatcher::SetAfterMonitorClosureForTesting(
958*6777b538SAndroid Build Coastguard Worker base::RepeatingClosure closure) {
959*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(constructing_thread_checker_);
960*6777b538SAndroid Build Coastguard Worker after_monitor_closure_for_testing_ = std::move(closure);
961*6777b538SAndroid Build Coastguard Worker }
962*6777b538SAndroid Build Coastguard Worker
SetOnHangClosureForTesting(base::RepeatingClosure closure)963*6777b538SAndroid Build Coastguard Worker void HangWatcher::SetOnHangClosureForTesting(base::RepeatingClosure closure) {
964*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(constructing_thread_checker_);
965*6777b538SAndroid Build Coastguard Worker on_hang_closure_for_testing_ = std::move(closure);
966*6777b538SAndroid Build Coastguard Worker }
967*6777b538SAndroid Build Coastguard Worker
SetMonitoringPeriodForTesting(base::TimeDelta period)968*6777b538SAndroid Build Coastguard Worker void HangWatcher::SetMonitoringPeriodForTesting(base::TimeDelta period) {
969*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(constructing_thread_checker_);
970*6777b538SAndroid Build Coastguard Worker monitor_period_ = period;
971*6777b538SAndroid Build Coastguard Worker }
972*6777b538SAndroid Build Coastguard Worker
SetAfterWaitCallbackForTesting(RepeatingCallback<void (TimeTicks)> callback)973*6777b538SAndroid Build Coastguard Worker void HangWatcher::SetAfterWaitCallbackForTesting(
974*6777b538SAndroid Build Coastguard Worker RepeatingCallback<void(TimeTicks)> callback) {
975*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(constructing_thread_checker_);
976*6777b538SAndroid Build Coastguard Worker after_wait_callback_ = callback;
977*6777b538SAndroid Build Coastguard Worker }
978*6777b538SAndroid Build Coastguard Worker
SignalMonitorEventForTesting()979*6777b538SAndroid Build Coastguard Worker void HangWatcher::SignalMonitorEventForTesting() {
980*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(constructing_thread_checker_);
981*6777b538SAndroid Build Coastguard Worker should_monitor_.Signal();
982*6777b538SAndroid Build Coastguard Worker }
983*6777b538SAndroid Build Coastguard Worker
984*6777b538SAndroid Build Coastguard Worker // static
StopMonitoringForTesting()985*6777b538SAndroid Build Coastguard Worker void HangWatcher::StopMonitoringForTesting() {
986*6777b538SAndroid Build Coastguard Worker g_keep_monitoring.store(false, std::memory_order_relaxed);
987*6777b538SAndroid Build Coastguard Worker }
988*6777b538SAndroid Build Coastguard Worker
SetTickClockForTesting(const base::TickClock * tick_clock)989*6777b538SAndroid Build Coastguard Worker void HangWatcher::SetTickClockForTesting(const base::TickClock* tick_clock) {
990*6777b538SAndroid Build Coastguard Worker tick_clock_ = tick_clock;
991*6777b538SAndroid Build Coastguard Worker }
992*6777b538SAndroid Build Coastguard Worker
BlockIfCaptureInProgress()993*6777b538SAndroid Build Coastguard Worker void HangWatcher::BlockIfCaptureInProgress() {
994*6777b538SAndroid Build Coastguard Worker // Makes a best-effort attempt to block execution if a hang is currently being
995*6777b538SAndroid Build Coastguard Worker // captured. Only block on |capture_lock| if |capture_in_progress_| hints that
996*6777b538SAndroid Build Coastguard Worker // it's already held to avoid serializing all threads on this function when no
997*6777b538SAndroid Build Coastguard Worker // hang capture is in-progress.
998*6777b538SAndroid Build Coastguard Worker if (capture_in_progress_.load(std::memory_order_relaxed))
999*6777b538SAndroid Build Coastguard Worker base::AutoLock hang_lock(capture_lock_);
1000*6777b538SAndroid Build Coastguard Worker }
1001*6777b538SAndroid Build Coastguard Worker
UnregisterThread()1002*6777b538SAndroid Build Coastguard Worker void HangWatcher::UnregisterThread() {
1003*6777b538SAndroid Build Coastguard Worker AutoLock auto_lock(watch_state_lock_);
1004*6777b538SAndroid Build Coastguard Worker
1005*6777b538SAndroid Build Coastguard Worker auto it = ranges::find(
1006*6777b538SAndroid Build Coastguard Worker watch_states_,
1007*6777b538SAndroid Build Coastguard Worker internal::HangWatchState::GetHangWatchStateForCurrentThread(),
1008*6777b538SAndroid Build Coastguard Worker &std::unique_ptr<internal::HangWatchState>::get);
1009*6777b538SAndroid Build Coastguard Worker
1010*6777b538SAndroid Build Coastguard Worker // Thread should be registered to get unregistered.
1011*6777b538SAndroid Build Coastguard Worker CHECK(it != watch_states_.end(), base::NotFatalUntil::M125);
1012*6777b538SAndroid Build Coastguard Worker
1013*6777b538SAndroid Build Coastguard Worker watch_states_.erase(it);
1014*6777b538SAndroid Build Coastguard Worker }
1015*6777b538SAndroid Build Coastguard Worker
1016*6777b538SAndroid Build Coastguard Worker namespace internal {
1017*6777b538SAndroid Build Coastguard Worker namespace {
1018*6777b538SAndroid Build Coastguard Worker
1019*6777b538SAndroid Build Coastguard Worker constexpr uint64_t kOnlyDeadlineMask = 0x00FF'FFFF'FFFF'FFFFu;
1020*6777b538SAndroid Build Coastguard Worker constexpr uint64_t kOnlyFlagsMask = ~kOnlyDeadlineMask;
1021*6777b538SAndroid Build Coastguard Worker constexpr uint64_t kMaximumFlag = 0x8000'0000'0000'0000u;
1022*6777b538SAndroid Build Coastguard Worker
1023*6777b538SAndroid Build Coastguard Worker // Use as a mask to keep persistent flags and the deadline.
1024*6777b538SAndroid Build Coastguard Worker constexpr uint64_t kPersistentFlagsAndDeadlineMask =
1025*6777b538SAndroid Build Coastguard Worker kOnlyDeadlineMask |
1026*6777b538SAndroid Build Coastguard Worker static_cast<uint64_t>(
1027*6777b538SAndroid Build Coastguard Worker HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope);
1028*6777b538SAndroid Build Coastguard Worker } // namespace
1029*6777b538SAndroid Build Coastguard Worker
1030*6777b538SAndroid Build Coastguard Worker // Flag binary representation assertions.
1031*6777b538SAndroid Build Coastguard Worker static_assert(
1032*6777b538SAndroid Build Coastguard Worker static_cast<uint64_t>(HangWatchDeadline::Flag::kMinValue) >
1033*6777b538SAndroid Build Coastguard Worker kOnlyDeadlineMask,
1034*6777b538SAndroid Build Coastguard Worker "Invalid numerical value for flag. Would interfere with bits of data.");
1035*6777b538SAndroid Build Coastguard Worker static_assert(static_cast<uint64_t>(HangWatchDeadline::Flag::kMaxValue) <=
1036*6777b538SAndroid Build Coastguard Worker kMaximumFlag,
1037*6777b538SAndroid Build Coastguard Worker "A flag can only set a single bit.");
1038*6777b538SAndroid Build Coastguard Worker
1039*6777b538SAndroid Build Coastguard Worker HangWatchDeadline::HangWatchDeadline() = default;
1040*6777b538SAndroid Build Coastguard Worker HangWatchDeadline::~HangWatchDeadline() = default;
1041*6777b538SAndroid Build Coastguard Worker
GetFlagsAndDeadline() const1042*6777b538SAndroid Build Coastguard Worker std::pair<uint64_t, TimeTicks> HangWatchDeadline::GetFlagsAndDeadline() const {
1043*6777b538SAndroid Build Coastguard Worker uint64_t bits = bits_.load(std::memory_order_relaxed);
1044*6777b538SAndroid Build Coastguard Worker return std::make_pair(ExtractFlags(bits),
1045*6777b538SAndroid Build Coastguard Worker DeadlineFromBits(ExtractDeadline((bits))));
1046*6777b538SAndroid Build Coastguard Worker }
1047*6777b538SAndroid Build Coastguard Worker
GetDeadline() const1048*6777b538SAndroid Build Coastguard Worker TimeTicks HangWatchDeadline::GetDeadline() const {
1049*6777b538SAndroid Build Coastguard Worker return DeadlineFromBits(
1050*6777b538SAndroid Build Coastguard Worker ExtractDeadline(bits_.load(std::memory_order_relaxed)));
1051*6777b538SAndroid Build Coastguard Worker }
1052*6777b538SAndroid Build Coastguard Worker
1053*6777b538SAndroid Build Coastguard Worker // static
Max()1054*6777b538SAndroid Build Coastguard Worker TimeTicks HangWatchDeadline::Max() {
1055*6777b538SAndroid Build Coastguard Worker // |kOnlyDeadlineMask| has all the bits reserved for the TimeTicks value
1056*6777b538SAndroid Build Coastguard Worker // set. This means it also represents the highest representable value.
1057*6777b538SAndroid Build Coastguard Worker return DeadlineFromBits(kOnlyDeadlineMask);
1058*6777b538SAndroid Build Coastguard Worker }
1059*6777b538SAndroid Build Coastguard Worker
1060*6777b538SAndroid Build Coastguard Worker // static
IsFlagSet(Flag flag,uint64_t flags)1061*6777b538SAndroid Build Coastguard Worker bool HangWatchDeadline::IsFlagSet(Flag flag, uint64_t flags) {
1062*6777b538SAndroid Build Coastguard Worker return static_cast<uint64_t>(flag) & flags;
1063*6777b538SAndroid Build Coastguard Worker }
1064*6777b538SAndroid Build Coastguard Worker
SetDeadline(TimeTicks new_deadline)1065*6777b538SAndroid Build Coastguard Worker void HangWatchDeadline::SetDeadline(TimeTicks new_deadline) {
1066*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1067*6777b538SAndroid Build Coastguard Worker DCHECK(new_deadline <= Max()) << "Value too high to be represented.";
1068*6777b538SAndroid Build Coastguard Worker DCHECK(new_deadline >= TimeTicks{}) << "Value cannot be negative.";
1069*6777b538SAndroid Build Coastguard Worker
1070*6777b538SAndroid Build Coastguard Worker if (switch_bits_callback_for_testing_) {
1071*6777b538SAndroid Build Coastguard Worker const uint64_t switched_in_bits = SwitchBitsForTesting();
1072*6777b538SAndroid Build Coastguard Worker // If a concurrent deadline change is tested it cannot have a deadline or
1073*6777b538SAndroid Build Coastguard Worker // persistent flag change since those always happen on the same thread.
1074*6777b538SAndroid Build Coastguard Worker DCHECK((switched_in_bits & kPersistentFlagsAndDeadlineMask) == 0u);
1075*6777b538SAndroid Build Coastguard Worker }
1076*6777b538SAndroid Build Coastguard Worker
1077*6777b538SAndroid Build Coastguard Worker // Discard all non-persistent flags and apply deadline change.
1078*6777b538SAndroid Build Coastguard Worker const uint64_t old_bits = bits_.load(std::memory_order_relaxed);
1079*6777b538SAndroid Build Coastguard Worker const uint64_t new_flags =
1080*6777b538SAndroid Build Coastguard Worker ExtractFlags(old_bits & kPersistentFlagsAndDeadlineMask);
1081*6777b538SAndroid Build Coastguard Worker bits_.store(new_flags | ExtractDeadline(static_cast<uint64_t>(
1082*6777b538SAndroid Build Coastguard Worker new_deadline.ToInternalValue())),
1083*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
1084*6777b538SAndroid Build Coastguard Worker }
1085*6777b538SAndroid Build Coastguard Worker
1086*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1087026): Add flag DCHECKs here.
SetShouldBlockOnHang(uint64_t old_flags,TimeTicks old_deadline)1087*6777b538SAndroid Build Coastguard Worker bool HangWatchDeadline::SetShouldBlockOnHang(uint64_t old_flags,
1088*6777b538SAndroid Build Coastguard Worker TimeTicks old_deadline) {
1089*6777b538SAndroid Build Coastguard Worker DCHECK(old_deadline <= Max()) << "Value too high to be represented.";
1090*6777b538SAndroid Build Coastguard Worker DCHECK(old_deadline >= TimeTicks{}) << "Value cannot be negative.";
1091*6777b538SAndroid Build Coastguard Worker
1092*6777b538SAndroid Build Coastguard Worker // Set the kShouldBlockOnHang flag only if |bits_| did not change since it was
1093*6777b538SAndroid Build Coastguard Worker // read. kShouldBlockOnHang is the only non-persistent flag and should never
1094*6777b538SAndroid Build Coastguard Worker // be set twice. Persistent flags and deadline changes are done from the same
1095*6777b538SAndroid Build Coastguard Worker // thread so there is no risk of losing concurrently added information.
1096*6777b538SAndroid Build Coastguard Worker uint64_t old_bits =
1097*6777b538SAndroid Build Coastguard Worker old_flags | static_cast<uint64_t>(old_deadline.ToInternalValue());
1098*6777b538SAndroid Build Coastguard Worker const uint64_t desired_bits =
1099*6777b538SAndroid Build Coastguard Worker old_bits | static_cast<uint64_t>(Flag::kShouldBlockOnHang);
1100*6777b538SAndroid Build Coastguard Worker
1101*6777b538SAndroid Build Coastguard Worker // If a test needs to simulate |bits_| changing since calling this function
1102*6777b538SAndroid Build Coastguard Worker // this happens now.
1103*6777b538SAndroid Build Coastguard Worker if (switch_bits_callback_for_testing_) {
1104*6777b538SAndroid Build Coastguard Worker const uint64_t switched_in_bits = SwitchBitsForTesting();
1105*6777b538SAndroid Build Coastguard Worker
1106*6777b538SAndroid Build Coastguard Worker // Injecting the flag being tested is invalid.
1107*6777b538SAndroid Build Coastguard Worker DCHECK(!IsFlagSet(Flag::kShouldBlockOnHang, switched_in_bits));
1108*6777b538SAndroid Build Coastguard Worker }
1109*6777b538SAndroid Build Coastguard Worker
1110*6777b538SAndroid Build Coastguard Worker return bits_.compare_exchange_weak(old_bits, desired_bits,
1111*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed,
1112*6777b538SAndroid Build Coastguard Worker std::memory_order_relaxed);
1113*6777b538SAndroid Build Coastguard Worker }
1114*6777b538SAndroid Build Coastguard Worker
SetIgnoreCurrentWatchHangsInScope()1115*6777b538SAndroid Build Coastguard Worker void HangWatchDeadline::SetIgnoreCurrentWatchHangsInScope() {
1116*6777b538SAndroid Build Coastguard Worker SetPersistentFlag(Flag::kIgnoreCurrentWatchHangsInScope);
1117*6777b538SAndroid Build Coastguard Worker }
1118*6777b538SAndroid Build Coastguard Worker
UnsetIgnoreCurrentWatchHangsInScope()1119*6777b538SAndroid Build Coastguard Worker void HangWatchDeadline::UnsetIgnoreCurrentWatchHangsInScope() {
1120*6777b538SAndroid Build Coastguard Worker ClearPersistentFlag(Flag::kIgnoreCurrentWatchHangsInScope);
1121*6777b538SAndroid Build Coastguard Worker }
1122*6777b538SAndroid Build Coastguard Worker
SetPersistentFlag(Flag flag)1123*6777b538SAndroid Build Coastguard Worker void HangWatchDeadline::SetPersistentFlag(Flag flag) {
1124*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1125*6777b538SAndroid Build Coastguard Worker if (switch_bits_callback_for_testing_)
1126*6777b538SAndroid Build Coastguard Worker SwitchBitsForTesting();
1127*6777b538SAndroid Build Coastguard Worker bits_.fetch_or(static_cast<uint64_t>(flag), std::memory_order_relaxed);
1128*6777b538SAndroid Build Coastguard Worker }
1129*6777b538SAndroid Build Coastguard Worker
ClearPersistentFlag(Flag flag)1130*6777b538SAndroid Build Coastguard Worker void HangWatchDeadline::ClearPersistentFlag(Flag flag) {
1131*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1132*6777b538SAndroid Build Coastguard Worker if (switch_bits_callback_for_testing_)
1133*6777b538SAndroid Build Coastguard Worker SwitchBitsForTesting();
1134*6777b538SAndroid Build Coastguard Worker bits_.fetch_and(~(static_cast<uint64_t>(flag)), std::memory_order_relaxed);
1135*6777b538SAndroid Build Coastguard Worker }
1136*6777b538SAndroid Build Coastguard Worker
1137*6777b538SAndroid Build Coastguard Worker // static
ExtractFlags(uint64_t bits)1138*6777b538SAndroid Build Coastguard Worker uint64_t HangWatchDeadline::ExtractFlags(uint64_t bits) {
1139*6777b538SAndroid Build Coastguard Worker return bits & kOnlyFlagsMask;
1140*6777b538SAndroid Build Coastguard Worker }
1141*6777b538SAndroid Build Coastguard Worker
1142*6777b538SAndroid Build Coastguard Worker // static
ExtractDeadline(uint64_t bits)1143*6777b538SAndroid Build Coastguard Worker uint64_t HangWatchDeadline::ExtractDeadline(uint64_t bits) {
1144*6777b538SAndroid Build Coastguard Worker return bits & kOnlyDeadlineMask;
1145*6777b538SAndroid Build Coastguard Worker }
1146*6777b538SAndroid Build Coastguard Worker
1147*6777b538SAndroid Build Coastguard Worker // static
DeadlineFromBits(uint64_t bits)1148*6777b538SAndroid Build Coastguard Worker TimeTicks HangWatchDeadline::DeadlineFromBits(uint64_t bits) {
1149*6777b538SAndroid Build Coastguard Worker // |kOnlyDeadlineMask| has all the deadline bits set to 1 so is the largest
1150*6777b538SAndroid Build Coastguard Worker // representable value.
1151*6777b538SAndroid Build Coastguard Worker DCHECK(bits <= kOnlyDeadlineMask)
1152*6777b538SAndroid Build Coastguard Worker << "Flags bits are set. Remove them before returning deadline.";
1153*6777b538SAndroid Build Coastguard Worker static_assert(kOnlyDeadlineMask <= std::numeric_limits<int64_t>::max());
1154*6777b538SAndroid Build Coastguard Worker return TimeTicks::FromInternalValue(static_cast<int64_t>(bits));
1155*6777b538SAndroid Build Coastguard Worker }
1156*6777b538SAndroid Build Coastguard Worker
IsFlagSet(Flag flag) const1157*6777b538SAndroid Build Coastguard Worker bool HangWatchDeadline::IsFlagSet(Flag flag) const {
1158*6777b538SAndroid Build Coastguard Worker return bits_.load(std::memory_order_relaxed) & static_cast<uint64_t>(flag);
1159*6777b538SAndroid Build Coastguard Worker }
1160*6777b538SAndroid Build Coastguard Worker
SetSwitchBitsClosureForTesting(RepeatingCallback<uint64_t (void)> closure)1161*6777b538SAndroid Build Coastguard Worker void HangWatchDeadline::SetSwitchBitsClosureForTesting(
1162*6777b538SAndroid Build Coastguard Worker RepeatingCallback<uint64_t(void)> closure) {
1163*6777b538SAndroid Build Coastguard Worker switch_bits_callback_for_testing_ = closure;
1164*6777b538SAndroid Build Coastguard Worker }
1165*6777b538SAndroid Build Coastguard Worker
ResetSwitchBitsClosureForTesting()1166*6777b538SAndroid Build Coastguard Worker void HangWatchDeadline::ResetSwitchBitsClosureForTesting() {
1167*6777b538SAndroid Build Coastguard Worker DCHECK(switch_bits_callback_for_testing_);
1168*6777b538SAndroid Build Coastguard Worker switch_bits_callback_for_testing_.Reset();
1169*6777b538SAndroid Build Coastguard Worker }
1170*6777b538SAndroid Build Coastguard Worker
SwitchBitsForTesting()1171*6777b538SAndroid Build Coastguard Worker uint64_t HangWatchDeadline::SwitchBitsForTesting() {
1172*6777b538SAndroid Build Coastguard Worker DCHECK(switch_bits_callback_for_testing_);
1173*6777b538SAndroid Build Coastguard Worker
1174*6777b538SAndroid Build Coastguard Worker const uint64_t old_bits = bits_.load(std::memory_order_relaxed);
1175*6777b538SAndroid Build Coastguard Worker const uint64_t new_bits = switch_bits_callback_for_testing_.Run();
1176*6777b538SAndroid Build Coastguard Worker const uint64_t old_flags = ExtractFlags(old_bits);
1177*6777b538SAndroid Build Coastguard Worker
1178*6777b538SAndroid Build Coastguard Worker const uint64_t switched_in_bits = old_flags | new_bits;
1179*6777b538SAndroid Build Coastguard Worker bits_.store(switched_in_bits, std::memory_order_relaxed);
1180*6777b538SAndroid Build Coastguard Worker return switched_in_bits;
1181*6777b538SAndroid Build Coastguard Worker }
1182*6777b538SAndroid Build Coastguard Worker
HangWatchState(HangWatcher::ThreadType thread_type)1183*6777b538SAndroid Build Coastguard Worker HangWatchState::HangWatchState(HangWatcher::ThreadType thread_type)
1184*6777b538SAndroid Build Coastguard Worker : resetter_(&hang_watch_state, this, nullptr), thread_type_(thread_type) {
1185*6777b538SAndroid Build Coastguard Worker // TODO(crbug.com/1223033): Remove this once macOS uses system-wide ids.
1186*6777b538SAndroid Build Coastguard Worker // On macOS the thread ids used by CrashPad are not the same as the ones
1187*6777b538SAndroid Build Coastguard Worker // provided by PlatformThread. Make sure to use the same for correct
1188*6777b538SAndroid Build Coastguard Worker // attribution.
1189*6777b538SAndroid Build Coastguard Worker #if BUILDFLAG(IS_MAC)
1190*6777b538SAndroid Build Coastguard Worker uint64_t thread_id;
1191*6777b538SAndroid Build Coastguard Worker pthread_threadid_np(pthread_self(), &thread_id);
1192*6777b538SAndroid Build Coastguard Worker thread_id_ = checked_cast<PlatformThreadId>(thread_id);
1193*6777b538SAndroid Build Coastguard Worker #else
1194*6777b538SAndroid Build Coastguard Worker thread_id_ = PlatformThread::CurrentId();
1195*6777b538SAndroid Build Coastguard Worker #endif
1196*6777b538SAndroid Build Coastguard Worker }
1197*6777b538SAndroid Build Coastguard Worker
~HangWatchState()1198*6777b538SAndroid Build Coastguard Worker HangWatchState::~HangWatchState() {
1199*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1200*6777b538SAndroid Build Coastguard Worker
1201*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(GetHangWatchStateForCurrentThread(), this);
1202*6777b538SAndroid Build Coastguard Worker
1203*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
1204*6777b538SAndroid Build Coastguard Worker // Destroying the HangWatchState should not be done if there are live
1205*6777b538SAndroid Build Coastguard Worker // WatchHangsInScopes.
1206*6777b538SAndroid Build Coastguard Worker DCHECK(!current_watch_hangs_in_scope_);
1207*6777b538SAndroid Build Coastguard Worker #endif
1208*6777b538SAndroid Build Coastguard Worker }
1209*6777b538SAndroid Build Coastguard Worker
1210*6777b538SAndroid Build Coastguard Worker // static
1211*6777b538SAndroid Build Coastguard Worker std::unique_ptr<HangWatchState>
CreateHangWatchStateForCurrentThread(HangWatcher::ThreadType thread_type)1212*6777b538SAndroid Build Coastguard Worker HangWatchState::CreateHangWatchStateForCurrentThread(
1213*6777b538SAndroid Build Coastguard Worker HangWatcher::ThreadType thread_type) {
1214*6777b538SAndroid Build Coastguard Worker // Allocate a watch state object for this thread.
1215*6777b538SAndroid Build Coastguard Worker std::unique_ptr<HangWatchState> hang_state =
1216*6777b538SAndroid Build Coastguard Worker std::make_unique<HangWatchState>(thread_type);
1217*6777b538SAndroid Build Coastguard Worker
1218*6777b538SAndroid Build Coastguard Worker // Setting the thread local worked.
1219*6777b538SAndroid Build Coastguard Worker DCHECK_EQ(GetHangWatchStateForCurrentThread(), hang_state.get());
1220*6777b538SAndroid Build Coastguard Worker
1221*6777b538SAndroid Build Coastguard Worker // Transfer ownership to caller.
1222*6777b538SAndroid Build Coastguard Worker return hang_state;
1223*6777b538SAndroid Build Coastguard Worker }
1224*6777b538SAndroid Build Coastguard Worker
GetDeadline() const1225*6777b538SAndroid Build Coastguard Worker TimeTicks HangWatchState::GetDeadline() const {
1226*6777b538SAndroid Build Coastguard Worker return deadline_.GetDeadline();
1227*6777b538SAndroid Build Coastguard Worker }
1228*6777b538SAndroid Build Coastguard Worker
GetFlagsAndDeadline() const1229*6777b538SAndroid Build Coastguard Worker std::pair<uint64_t, TimeTicks> HangWatchState::GetFlagsAndDeadline() const {
1230*6777b538SAndroid Build Coastguard Worker return deadline_.GetFlagsAndDeadline();
1231*6777b538SAndroid Build Coastguard Worker }
1232*6777b538SAndroid Build Coastguard Worker
SetDeadline(TimeTicks deadline)1233*6777b538SAndroid Build Coastguard Worker void HangWatchState::SetDeadline(TimeTicks deadline) {
1234*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1235*6777b538SAndroid Build Coastguard Worker deadline_.SetDeadline(deadline);
1236*6777b538SAndroid Build Coastguard Worker }
1237*6777b538SAndroid Build Coastguard Worker
IsOverDeadline() const1238*6777b538SAndroid Build Coastguard Worker bool HangWatchState::IsOverDeadline() const {
1239*6777b538SAndroid Build Coastguard Worker return TimeTicks::Now() > deadline_.GetDeadline();
1240*6777b538SAndroid Build Coastguard Worker }
1241*6777b538SAndroid Build Coastguard Worker
SetIgnoreCurrentWatchHangsInScope()1242*6777b538SAndroid Build Coastguard Worker void HangWatchState::SetIgnoreCurrentWatchHangsInScope() {
1243*6777b538SAndroid Build Coastguard Worker deadline_.SetIgnoreCurrentWatchHangsInScope();
1244*6777b538SAndroid Build Coastguard Worker }
1245*6777b538SAndroid Build Coastguard Worker
UnsetIgnoreCurrentWatchHangsInScope()1246*6777b538SAndroid Build Coastguard Worker void HangWatchState::UnsetIgnoreCurrentWatchHangsInScope() {
1247*6777b538SAndroid Build Coastguard Worker deadline_.UnsetIgnoreCurrentWatchHangsInScope();
1248*6777b538SAndroid Build Coastguard Worker }
1249*6777b538SAndroid Build Coastguard Worker
SetShouldBlockOnHang(uint64_t old_flags,TimeTicks old_deadline)1250*6777b538SAndroid Build Coastguard Worker bool HangWatchState::SetShouldBlockOnHang(uint64_t old_flags,
1251*6777b538SAndroid Build Coastguard Worker TimeTicks old_deadline) {
1252*6777b538SAndroid Build Coastguard Worker return deadline_.SetShouldBlockOnHang(old_flags, old_deadline);
1253*6777b538SAndroid Build Coastguard Worker }
1254*6777b538SAndroid Build Coastguard Worker
IsFlagSet(HangWatchDeadline::Flag flag)1255*6777b538SAndroid Build Coastguard Worker bool HangWatchState::IsFlagSet(HangWatchDeadline::Flag flag) {
1256*6777b538SAndroid Build Coastguard Worker return deadline_.IsFlagSet(flag);
1257*6777b538SAndroid Build Coastguard Worker }
1258*6777b538SAndroid Build Coastguard Worker
1259*6777b538SAndroid Build Coastguard Worker #if DCHECK_IS_ON()
SetCurrentWatchHangsInScope(WatchHangsInScope * current_hang_watch_scope_enable)1260*6777b538SAndroid Build Coastguard Worker void HangWatchState::SetCurrentWatchHangsInScope(
1261*6777b538SAndroid Build Coastguard Worker WatchHangsInScope* current_hang_watch_scope_enable) {
1262*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1263*6777b538SAndroid Build Coastguard Worker current_watch_hangs_in_scope_ = current_hang_watch_scope_enable;
1264*6777b538SAndroid Build Coastguard Worker }
1265*6777b538SAndroid Build Coastguard Worker
GetCurrentWatchHangsInScope()1266*6777b538SAndroid Build Coastguard Worker WatchHangsInScope* HangWatchState::GetCurrentWatchHangsInScope() {
1267*6777b538SAndroid Build Coastguard Worker DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
1268*6777b538SAndroid Build Coastguard Worker return current_watch_hangs_in_scope_;
1269*6777b538SAndroid Build Coastguard Worker }
1270*6777b538SAndroid Build Coastguard Worker #endif
1271*6777b538SAndroid Build Coastguard Worker
GetHangWatchDeadlineForTesting()1272*6777b538SAndroid Build Coastguard Worker HangWatchDeadline* HangWatchState::GetHangWatchDeadlineForTesting() {
1273*6777b538SAndroid Build Coastguard Worker return &deadline_;
1274*6777b538SAndroid Build Coastguard Worker }
1275*6777b538SAndroid Build Coastguard Worker
IncrementNestingLevel()1276*6777b538SAndroid Build Coastguard Worker void HangWatchState::IncrementNestingLevel() {
1277*6777b538SAndroid Build Coastguard Worker ++nesting_level_;
1278*6777b538SAndroid Build Coastguard Worker }
1279*6777b538SAndroid Build Coastguard Worker
DecrementNestingLevel()1280*6777b538SAndroid Build Coastguard Worker void HangWatchState::DecrementNestingLevel() {
1281*6777b538SAndroid Build Coastguard Worker --nesting_level_;
1282*6777b538SAndroid Build Coastguard Worker }
1283*6777b538SAndroid Build Coastguard Worker
1284*6777b538SAndroid Build Coastguard Worker // static
GetHangWatchStateForCurrentThread()1285*6777b538SAndroid Build Coastguard Worker HangWatchState* HangWatchState::GetHangWatchStateForCurrentThread() {
1286*6777b538SAndroid Build Coastguard Worker // Workaround false-positive MSAN use-of-uninitialized-value on
1287*6777b538SAndroid Build Coastguard Worker // thread_local storage for loaded libraries:
1288*6777b538SAndroid Build Coastguard Worker // https://github.com/google/sanitizers/issues/1265
1289*6777b538SAndroid Build Coastguard Worker MSAN_UNPOISON(&hang_watch_state, sizeof(internal::HangWatchState*));
1290*6777b538SAndroid Build Coastguard Worker
1291*6777b538SAndroid Build Coastguard Worker return hang_watch_state;
1292*6777b538SAndroid Build Coastguard Worker }
1293*6777b538SAndroid Build Coastguard Worker
GetThreadID() const1294*6777b538SAndroid Build Coastguard Worker PlatformThreadId HangWatchState::GetThreadID() const {
1295*6777b538SAndroid Build Coastguard Worker return thread_id_;
1296*6777b538SAndroid Build Coastguard Worker }
1297*6777b538SAndroid Build Coastguard Worker
1298*6777b538SAndroid Build Coastguard Worker } // namespace internal
1299*6777b538SAndroid Build Coastguard Worker
1300*6777b538SAndroid Build Coastguard Worker } // namespace base
1301