1 // Copyright 2020 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/threading/hang_watcher.h"
6
7 #include <atomic>
8 #include <memory>
9 #include <optional>
10
11 #include "base/barrier_closure.h"
12 #include "base/functional/bind.h"
13 #include "base/functional/callback.h"
14 #include "base/functional/callback_helpers.h"
15 #include "base/memory/raw_ptr.h"
16 #include "base/metrics/field_trial_params.h"
17 #include "base/run_loop.h"
18 #include "base/strings/string_number_conversions.h"
19 #include "base/synchronization/lock.h"
20 #include "base/synchronization/waitable_event.h"
21 #include "base/test/bind.h"
22 #include "base/test/metrics/histogram_tester.h"
23 #include "base/test/power_monitor_test.h"
24 #include "base/test/scoped_feature_list.h"
25 #include "base/test/simple_test_tick_clock.h"
26 #include "base/test/task_environment.h"
27 #include "base/test/test_timeouts.h"
28 #include "base/threading/platform_thread.h"
29 #include "base/threading/thread_checker.h"
30 #include "base/threading/threading_features.h"
31 #include "base/time/tick_clock.h"
32 #include "base/time/time.h"
33 #include "build/build_config.h"
34 #include "testing/gmock/include/gmock/gmock.h"
35 #include "testing/gtest/include/gtest/gtest.h"
36
37 using testing::ElementsAre;
38 using testing::IsEmpty;
39
40 namespace base {
41 namespace {
42
43 // Use with a FeatureList to activate crash dumping for threads marked as
44 // threadpool threads.
45 const std::vector<base::test::FeatureRefAndParams> kFeatureAndParams{
46 {base::kEnableHangWatcher, {{"ui_thread_log_level", "2"}}}};
47
48 // Use this value to mark things very far off in the future. Adding this
49 // to TimeTicks::Now() gives a point that will never be reached during the
50 // normal execution of a test.
51 constexpr TimeDelta kVeryLongDelta{base::Days(365)};
52
53 // A relatively small time delta to ensure ordering of hung threads list.
54 constexpr TimeDelta kSmallCPUQuantum{base::Milliseconds(1)};
55
56 constexpr uint64_t kArbitraryDeadline = 0x0000C0FFEEC0FFEEu;
57 constexpr uint64_t kAllOnes = 0xFFFFFFFFFFFFFFFFu;
58 constexpr uint64_t kAllZeros = 0x0000000000000000u;
59 constexpr uint64_t kOnesThenZeroes = 0xAAAAAAAAAAAAAAAAu;
60 constexpr uint64_t kZeroesThenOnes = 0x5555555555555555u;
61
62 #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
63 class HangWatcherEnabledInZygoteChildTest : public testing::Test {
64 public:
HangWatcherEnabledInZygoteChildTest()65 HangWatcherEnabledInZygoteChildTest() {
66 std::vector<base::test::FeatureRefAndParams> enabled_features =
67 kFeatureAndParams;
68 feature_list_.InitWithFeaturesAndParameters(enabled_features, {});
69 HangWatcher::InitializeOnMainThread(
70 HangWatcher::ProcessType::kUtilityProcess,
71 /*emit_crashes=*/true);
72 }
73
TearDown()74 void TearDown() override { HangWatcher::UnitializeOnMainThreadForTesting(); }
75
76 HangWatcherEnabledInZygoteChildTest(
77 const HangWatcherEnabledInZygoteChildTest& other) = delete;
78 HangWatcherEnabledInZygoteChildTest& operator=(
79 const HangWatcherEnabledInZygoteChildTest& other) = delete;
80
81 protected:
82 base::test::ScopedFeatureList feature_list_;
83 };
84
TEST_F(HangWatcherEnabledInZygoteChildTest,IsEnabled)85 TEST_F(HangWatcherEnabledInZygoteChildTest, IsEnabled) {
86 ASSERT_TRUE(HangWatcher::IsEnabled());
87 }
88
89 #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
90
91 // Waits on provided WaitableEvent before executing and signals when done.
92 class BlockingThread : public DelegateSimpleThread::Delegate {
93 public:
BlockingThread(base::WaitableEvent * unblock_thread,base::TimeDelta timeout)94 explicit BlockingThread(base::WaitableEvent* unblock_thread,
95 base::TimeDelta timeout)
96 : thread_(this, "BlockingThread"),
97 unblock_thread_(unblock_thread),
98 timeout_(timeout) {}
99
100 ~BlockingThread() override = default;
101
Run()102 void Run() override {
103 // (Un)Register the thread here instead of in ctor/dtor so that the action
104 // happens on the right thread.
105 base::ScopedClosureRunner unregister_closure =
106 base::HangWatcher::RegisterThread(
107 base::HangWatcher::ThreadType::kMainThread);
108
109 WatchHangsInScope scope(timeout_);
110 wait_until_entered_scope_.Signal();
111
112 unblock_thread_->Wait();
113 run_event_.Signal();
114 }
115
IsDone()116 bool IsDone() { return run_event_.IsSignaled(); }
117
StartAndWaitForScopeEntered()118 void StartAndWaitForScopeEntered() {
119 thread_.Start();
120 // Block until this thread registered itself for hang watching and has
121 // entered a WatchHangsInScope.
122 wait_until_entered_scope_.Wait();
123 }
124
Join()125 void Join() { thread_.Join(); }
126
GetId()127 PlatformThreadId GetId() { return thread_.tid(); }
128
129 private:
130 base::DelegateSimpleThread thread_;
131
132 // Will be signaled once the thread is properly registered for watching and
133 // the WatchHangsInScope has been entered.
134 WaitableEvent wait_until_entered_scope_;
135
136 // Will be signaled once ThreadMain has run.
137 WaitableEvent run_event_;
138
139 const raw_ptr<base::WaitableEvent> unblock_thread_;
140
141 base::TimeDelta timeout_;
142 };
143
144 class HangWatcherTest : public testing::Test {
145 public:
146 const base::TimeDelta kTimeout = base::Seconds(10);
147 const base::TimeDelta kHangTime = kTimeout + base::Seconds(1);
148
HangWatcherTest()149 HangWatcherTest() {
150 feature_list_.InitWithFeaturesAndParameters(kFeatureAndParams, {});
151 HangWatcher::InitializeOnMainThread(
152 HangWatcher::ProcessType::kBrowserProcess, /*emit_crashes=*/true);
153
154 hang_watcher_.SetAfterMonitorClosureForTesting(base::BindRepeating(
155 &WaitableEvent::Signal, base::Unretained(&monitor_event_)));
156
157 hang_watcher_.SetOnHangClosureForTesting(base::BindRepeating(
158 &WaitableEvent::Signal, base::Unretained(&hang_event_)));
159
160 // We're not testing the monitoring loop behavior in this test so we want to
161 // trigger monitoring manually.
162 hang_watcher_.SetMonitoringPeriodForTesting(kVeryLongDelta);
163
164 // Start the monitoring loop.
165 hang_watcher_.Start();
166 }
167
TearDown()168 void TearDown() override { HangWatcher::UnitializeOnMainThreadForTesting(); }
169
170 HangWatcherTest(const HangWatcherTest& other) = delete;
171 HangWatcherTest& operator=(const HangWatcherTest& other) = delete;
172
173 protected:
174 // Used to wait for monitoring. Will be signaled by the HangWatcher thread and
175 // so needs to outlive it.
176 WaitableEvent monitor_event_;
177
178 // Signaled from the HangWatcher thread when a hang is detected. Needs to
179 // outlive the HangWatcher thread.
180 WaitableEvent hang_event_;
181
182 base::test::ScopedFeatureList feature_list_;
183
184 // Used exclusively for MOCK_TIME. No tasks will be run on the environment.
185 // Single threaded to avoid ThreadPool WorkerThreads registering.
186 test::SingleThreadTaskEnvironment task_environment_{
187 test::TaskEnvironment::TimeSource::MOCK_TIME};
188
189 // This must be declared last (after task_environment_, for example) so that
190 // the watcher thread is joined before objects like the mock timer are
191 // destroyed, causing racy crashes.
192 HangWatcher hang_watcher_;
193 };
194
195 class HangWatcherBlockingThreadTest : public HangWatcherTest {
196 public:
HangWatcherBlockingThreadTest()197 HangWatcherBlockingThreadTest() : thread_(&unblock_thread_, kTimeout) {}
198
199 HangWatcherBlockingThreadTest(const HangWatcherBlockingThreadTest& other) =
200 delete;
201 HangWatcherBlockingThreadTest& operator=(
202 const HangWatcherBlockingThreadTest& other) = delete;
203
204 protected:
JoinThread()205 void JoinThread() {
206 unblock_thread_.Signal();
207
208 // Thread is joinable since we signaled |unblock_thread_|.
209 thread_.Join();
210
211 // If thread is done then it signaled.
212 ASSERT_TRUE(thread_.IsDone());
213 }
214
StartBlockedThread()215 void StartBlockedThread() {
216 // Thread has not run yet.
217 ASSERT_FALSE(thread_.IsDone());
218
219 // Start the thread. It will block since |unblock_thread_| was not
220 // signaled yet.
221 thread_.StartAndWaitForScopeEntered();
222
223 // Thread registration triggered a call to HangWatcher::Monitor() which
224 // signaled |monitor_event_|. Reset it so it's ready for waiting later on.
225 monitor_event_.Reset();
226 }
227
MonitorHangs()228 void MonitorHangs() {
229 // HangWatcher::Monitor() should not be set which would mean a call to
230 // HangWatcher::Monitor() happened and was unacounted for.
231 // ASSERT_FALSE(monitor_event_.IsSignaled());
232
233 // Trigger a monitoring on HangWatcher thread and verify results.
234 hang_watcher_.SignalMonitorEventForTesting();
235 monitor_event_.Wait();
236 }
237
238 // Used to unblock the monitored thread. Signaled from the test main thread.
239 WaitableEvent unblock_thread_;
240
241 BlockingThread thread_;
242 };
243 } // namespace
244
TEST_F(HangWatcherTest,InvalidatingExpectationsPreventsCapture)245 TEST_F(HangWatcherTest, InvalidatingExpectationsPreventsCapture) {
246 // Register the main test thread for hang watching.
247 auto unregister_thread_closure =
248 HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
249
250 // Create a hang.
251 WatchHangsInScope expires_instantly(base::TimeDelta{});
252 task_environment_.FastForwardBy(kHangTime);
253
254 // de-activate hang watching,
255 base::HangWatcher::InvalidateActiveExpectations();
256
257 // Trigger a monitoring on HangWatcher thread and verify results.
258 // Hang is not detected.
259 hang_watcher_.SignalMonitorEventForTesting();
260 monitor_event_.Wait();
261 ASSERT_FALSE(hang_event_.IsSignaled());
262 }
263
TEST_F(HangWatcherTest,MultipleInvalidateExpectationsDoNotCancelOut)264 TEST_F(HangWatcherTest, MultipleInvalidateExpectationsDoNotCancelOut) {
265 // Register the main test thread for hang watching.
266 auto unregister_thread_closure =
267 HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
268
269 // Create a hang.
270 WatchHangsInScope expires_instantly(base::TimeDelta{});
271 task_environment_.FastForwardBy(kHangTime);
272
273 // de-activate hang watching,
274 base::HangWatcher::InvalidateActiveExpectations();
275
276 // Redundently de-activate hang watching.
277 base::HangWatcher::InvalidateActiveExpectations();
278
279 // Trigger a monitoring on HangWatcher thread and verify results.
280 // Hang is not detected.
281 hang_watcher_.SignalMonitorEventForTesting();
282 monitor_event_.Wait();
283 ASSERT_FALSE(hang_event_.IsSignaled());
284 }
285
TEST_F(HangWatcherTest,NewInnerWatchHangsInScopeAfterInvalidationDetectsHang)286 TEST_F(HangWatcherTest, NewInnerWatchHangsInScopeAfterInvalidationDetectsHang) {
287 // Register the main test thread for hang watching.
288 auto unregister_thread_closure =
289 HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
290
291 WatchHangsInScope expires_instantly(base::TimeDelta{});
292 task_environment_.FastForwardBy(kHangTime);
293
294 // De-activate hang watching.
295 base::HangWatcher::InvalidateActiveExpectations();
296
297 {
298 WatchHangsInScope also_expires_instantly(base::TimeDelta{});
299 task_environment_.FastForwardBy(kHangTime);
300
301 // Trigger a monitoring on HangWatcher thread and verify results.
302 hang_watcher_.SignalMonitorEventForTesting();
303 monitor_event_.Wait();
304
305 // Hang is detected since the new WatchHangsInScope temporarily
306 // re-activated hang_watching.
307 monitor_event_.Wait();
308 ASSERT_TRUE(hang_event_.IsSignaled());
309 }
310
311 // Reset to attempt capture again.
312 monitor_event_.Reset();
313 hang_event_.Reset();
314
315 // Trigger a monitoring on HangWatcher thread and verify results.
316 hang_watcher_.SignalMonitorEventForTesting();
317 monitor_event_.Wait();
318
319 // Hang is not detected since execution is back to being covered by
320 // |expires_instantly| for which expectations were invalidated.
321 monitor_event_.Wait();
322 ASSERT_FALSE(hang_event_.IsSignaled());
323 }
324
TEST_F(HangWatcherTest,NewSeparateWatchHangsInScopeAfterInvalidationDetectsHang)325 TEST_F(HangWatcherTest,
326 NewSeparateWatchHangsInScopeAfterInvalidationDetectsHang) {
327 // Register the main test thread for hang watching.
328 auto unregister_thread_closure =
329 HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
330
331 {
332 WatchHangsInScope expires_instantly(base::TimeDelta{});
333 task_environment_.FastForwardBy(kHangTime);
334
335 // De-activate hang watching.
336 base::HangWatcher::InvalidateActiveExpectations();
337 }
338
339 WatchHangsInScope also_expires_instantly(base::TimeDelta{});
340 task_environment_.FastForwardBy(kHangTime);
341
342 // Trigger a monitoring on HangWatcher thread and verify results.
343 hang_watcher_.SignalMonitorEventForTesting();
344 monitor_event_.Wait();
345
346 // Hang is detected since the new WatchHangsInScope did not have its
347 // expectations invalidated.
348 monitor_event_.Wait();
349 ASSERT_TRUE(hang_event_.IsSignaled());
350 }
351
352 // Test that invalidating expectations from inner WatchHangsInScope will also
353 // prevent hang detection in outer scopes.
TEST_F(HangWatcherTest,ScopeDisabledObjectInnerScope)354 TEST_F(HangWatcherTest, ScopeDisabledObjectInnerScope) {
355 // Register the main test thread for hang watching.
356 auto unregister_thread_closure =
357 HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
358
359 // Start a WatchHangsInScope that expires right away. Then advance
360 // time to make sure no hang is detected.
361 WatchHangsInScope expires_instantly(base::TimeDelta{});
362 task_environment_.FastForwardBy(kHangTime);
363 {
364 WatchHangsInScope also_expires_instantly(base::TimeDelta{});
365
366 // De-activate hang watching.
367 base::HangWatcher::InvalidateActiveExpectations();
368 task_environment_.FastForwardBy(kHangTime);
369 }
370
371 // Trigger a monitoring on HangWatcher thread and verify results.
372 hang_watcher_.SignalMonitorEventForTesting();
373 monitor_event_.Wait();
374
375 // Hang is ignored since it concerns a scope for which one of the inner scope
376 // was ignored.
377 ASSERT_FALSE(hang_event_.IsSignaled());
378 }
379
TEST_F(HangWatcherTest,NewScopeAfterDisabling)380 TEST_F(HangWatcherTest, NewScopeAfterDisabling) {
381 // Register the main test thread for hang watching.
382 auto unregister_thread_closure =
383 HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
384
385 // Start a WatchHangsInScope that expires right away. Then advance
386 // time to make sure no hang is detected.
387 WatchHangsInScope expires_instantly(base::TimeDelta{});
388 task_environment_.FastForwardBy(kHangTime);
389 {
390 WatchHangsInScope also_expires_instantly(base::TimeDelta{});
391
392 // De-activate hang watching.
393 base::HangWatcher::InvalidateActiveExpectations();
394 task_environment_.FastForwardBy(kHangTime);
395 }
396
397 // New scope for which expecations are never invalidated.
398 WatchHangsInScope also_expires_instantly(base::TimeDelta{});
399 task_environment_.FastForwardBy(kHangTime);
400
401 // Trigger a monitoring on HangWatcher thread and verify results.
402 hang_watcher_.SignalMonitorEventForTesting();
403 monitor_event_.Wait();
404
405 // Hang is detected because it's unrelated to the hangs that were disabled.
406 ASSERT_TRUE(hang_event_.IsSignaled());
407 }
408
TEST_F(HangWatcherTest,NestedScopes)409 TEST_F(HangWatcherTest, NestedScopes) {
410 // Create a state object for the test thread since this test is single
411 // threaded.
412 auto current_hang_watch_state =
413 base::internal::HangWatchState::CreateHangWatchStateForCurrentThread(
414 HangWatcher::ThreadType::kMainThread);
415
416 ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
417 base::TimeTicks original_deadline = current_hang_watch_state->GetDeadline();
418
419 constexpr base::TimeDelta kFirstTimeout(base::Milliseconds(500));
420 base::TimeTicks first_deadline = base::TimeTicks::Now() + kFirstTimeout;
421
422 constexpr base::TimeDelta kSecondTimeout(base::Milliseconds(250));
423 base::TimeTicks second_deadline = base::TimeTicks::Now() + kSecondTimeout;
424
425 // At this point we have not set any timeouts.
426 {
427 // Create a first timeout which is more restrictive than the default.
428 WatchHangsInScope first_scope(kFirstTimeout);
429
430 // We are on mock time. There is no time advancement and as such no hangs.
431 ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
432 ASSERT_EQ(current_hang_watch_state->GetDeadline(), first_deadline);
433 {
434 // Set a yet more restrictive deadline. Still no hang.
435 WatchHangsInScope second_scope(kSecondTimeout);
436 ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
437 ASSERT_EQ(current_hang_watch_state->GetDeadline(), second_deadline);
438 }
439 // First deadline we set should be restored.
440 ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
441 ASSERT_EQ(current_hang_watch_state->GetDeadline(), first_deadline);
442 }
443
444 // Original deadline should now be restored.
445 ASSERT_FALSE(current_hang_watch_state->IsOverDeadline());
446 ASSERT_EQ(current_hang_watch_state->GetDeadline(), original_deadline);
447 }
448
TEST_F(HangWatcherBlockingThreadTest,HistogramsLoggedOnHang)449 TEST_F(HangWatcherBlockingThreadTest, HistogramsLoggedOnHang) {
450 base::HistogramTester histogram_tester;
451 StartBlockedThread();
452
453 // Simulate hang.
454 task_environment_.FastForwardBy(kHangTime);
455
456 // First monitoring catches the hang and emits the histogram.
457 MonitorHangs();
458 EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
459 "BrowserProcess.UIThread.Normal"),
460 ElementsAre(base::Bucket(true, /*count=*/1)));
461
462 // Reset to attempt capture again.
463 hang_event_.Reset();
464 monitor_event_.Reset();
465
466 // Hang is logged again even if it would not trigger a crash dump.
467 MonitorHangs();
468 EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
469 "BrowserProcess.UIThread.Normal"),
470 ElementsAre(base::Bucket(true, /*count=*/2)));
471
472 // Thread types that are not monitored should not get any samples.
473 EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
474 "BrowserProcess.IOThread.Normal"),
475 IsEmpty());
476
477 // No shutdown hangs, either.
478 EXPECT_THAT(histogram_tester.GetAllSamples(
479 "HangWatcher.IsThreadHung.BrowserProcess.UIThread.Shutdown"),
480 IsEmpty());
481 EXPECT_THAT(histogram_tester.GetAllSamples(
482 "HangWatcher.IsThreadHung.BrowserProcess.IOThread.Shutdown"),
483 IsEmpty());
484
485 JoinThread();
486 }
487
TEST_F(HangWatcherBlockingThreadTest,HistogramsLoggedWithoutHangs)488 TEST_F(HangWatcherBlockingThreadTest, HistogramsLoggedWithoutHangs) {
489 base::HistogramTester histogram_tester;
490 StartBlockedThread();
491
492 // No hang to catch so nothing is recorded.
493 MonitorHangs();
494 ASSERT_FALSE(hang_event_.IsSignaled());
495
496 // A thread of type ThreadForTesting was monitored but didn't hang. This is
497 // logged.
498 EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
499 "BrowserProcess.UIThread.Normal"),
500 ElementsAre(base::Bucket(false, /*count=*/1)));
501
502 // Thread types that are not monitored should not get any samples.
503 EXPECT_THAT(histogram_tester.GetAllSamples("HangWatcher.IsThreadHung."
504 "BrowserProcess.IOThread.Normal"),
505 IsEmpty());
506 JoinThread();
507 }
508
TEST_F(HangWatcherBlockingThreadTest,HistogramsLoggedWithShutdownFlag)509 TEST_F(HangWatcherBlockingThreadTest, HistogramsLoggedWithShutdownFlag) {
510 base::HistogramTester histogram_tester;
511 StartBlockedThread();
512
513 // Simulate hang.
514 task_environment_.FastForwardBy(kHangTime);
515
516 // Make this process emit *.Shutdown instead of *.Normal histograms.
517 base::HangWatcher::SetShuttingDown();
518
519 // First monitoring catches the hang and emits the histogram.
520 MonitorHangs();
521 EXPECT_THAT(histogram_tester.GetAllSamples(
522 "HangWatcher.IsThreadHung.BrowserProcess.UIThread.Shutdown"),
523 ElementsAre(base::Bucket(true, /*count=*/1)));
524
525 // Reset to attempt capture again.
526 hang_event_.Reset();
527 monitor_event_.Reset();
528
529 // Hang is logged again even if it would not trigger a crash dump.
530 MonitorHangs();
531 EXPECT_THAT(histogram_tester.GetAllSamples(
532 "HangWatcher.IsThreadHung.BrowserProcess.UIThread.Shutdown"),
533 ElementsAre(base::Bucket(true, /*count=*/2)));
534
535 // Thread types that are not monitored should not get any samples.
536 EXPECT_THAT(histogram_tester.GetAllSamples(
537 "HangWatcher.IsThreadHung.BrowserProcess.IOThread.Shutdown"),
538 IsEmpty());
539
540 // No normal hangs.
541 EXPECT_THAT(histogram_tester.GetAllSamples(
542 "HangWatcher.IsThreadHung.BrowserProcess.UIThread.Normal"),
543 IsEmpty());
544 EXPECT_THAT(histogram_tester.GetAllSamples(
545 "HangWatcher.IsThreadHung.BrowserProcess.IOThread.Normal"),
546 IsEmpty());
547
548 JoinThread();
549 }
550
TEST_F(HangWatcherBlockingThreadTest,Hang)551 TEST_F(HangWatcherBlockingThreadTest, Hang) {
552 StartBlockedThread();
553
554 // Simulate hang.
555 task_environment_.FastForwardBy(kHangTime);
556
557 // First monitoring catches and records the hang.
558 MonitorHangs();
559 ASSERT_TRUE(hang_event_.IsSignaled());
560
561 JoinThread();
562 }
563
TEST_F(HangWatcherBlockingThreadTest,HangAlreadyRecorded)564 TEST_F(HangWatcherBlockingThreadTest, HangAlreadyRecorded) {
565 StartBlockedThread();
566
567 // Simulate hang.
568 task_environment_.FastForwardBy(kHangTime);
569
570 // First monitoring catches and records the hang.
571 MonitorHangs();
572 ASSERT_TRUE(hang_event_.IsSignaled());
573
574 // Reset to attempt capture again.
575 hang_event_.Reset();
576 monitor_event_.Reset();
577
578 // Second monitoring does not record because a hang that was already recorded
579 // is still live.
580 MonitorHangs();
581 ASSERT_FALSE(hang_event_.IsSignaled());
582
583 JoinThread();
584 }
585
TEST_F(HangWatcherBlockingThreadTest,NoHang)586 TEST_F(HangWatcherBlockingThreadTest, NoHang) {
587 StartBlockedThread();
588
589 // No hang to catch so nothing is recorded.
590 MonitorHangs();
591 ASSERT_FALSE(hang_event_.IsSignaled());
592
593 JoinThread();
594 }
595
596 namespace {
597 class HangWatcherSnapshotTest : public testing::Test {
598 public:
SetUp()599 void SetUp() override {
600 feature_list_.InitWithFeaturesAndParameters(kFeatureAndParams, {});
601 HangWatcher::InitializeOnMainThread(
602 HangWatcher::ProcessType::kBrowserProcess, /*emit_crashes=*/true);
603
604 // The monitoring loop behavior is not verified in this test so we want to
605 // trigger monitoring manually.
606 hang_watcher_.SetMonitoringPeriodForTesting(kVeryLongDelta);
607 }
608
TearDown()609 void TearDown() override { HangWatcher::UnitializeOnMainThreadForTesting(); }
610
611 HangWatcherSnapshotTest() = default;
612 HangWatcherSnapshotTest(const HangWatcherSnapshotTest& other) = delete;
613 HangWatcherSnapshotTest& operator=(const HangWatcherSnapshotTest& other) =
614 delete;
615
616 protected:
TriggerMonitorAndWaitForCompletion()617 void TriggerMonitorAndWaitForCompletion() {
618 monitor_event_.Reset();
619 hang_watcher_.SignalMonitorEventForTesting();
620 monitor_event_.Wait();
621 }
622
623 // Verify that a capture takes place and that at the time of the capture the
624 // list of hung thread ids is correct.
TestIDList(const std::string & id_list)625 void TestIDList(const std::string& id_list) {
626 list_of_hung_thread_ids_during_capture_ = id_list;
627 task_environment_.AdvanceClock(kSmallCPUQuantum);
628 TriggerMonitorAndWaitForCompletion();
629 ASSERT_EQ(++reference_capture_count_, hang_capture_count_);
630 }
631
632 // Verify that even if hang monitoring takes place no hangs are detected.
ExpectNoCapture()633 void ExpectNoCapture() {
634 int old_capture_count = hang_capture_count_;
635 task_environment_.AdvanceClock(kSmallCPUQuantum);
636 TriggerMonitorAndWaitForCompletion();
637 ASSERT_EQ(old_capture_count, hang_capture_count_);
638 }
639
ConcatenateThreadIds(const std::vector<base::PlatformThreadId> & ids) const640 std::string ConcatenateThreadIds(
641 const std::vector<base::PlatformThreadId>& ids) const {
642 std::string result;
643 constexpr char kSeparator{'|'};
644
645 for (PlatformThreadId id : ids) {
646 result += base::NumberToString(id) + kSeparator;
647 }
648
649 return result;
650 }
651
652 // Will be signaled once monitoring took place. Marks the end of the test.
653 WaitableEvent monitor_event_;
654
655 const PlatformThreadId test_thread_id_ = PlatformThread::CurrentId();
656
657 // This is written to by the test main thread and read from the hang watching
658 // thread. It does not need to be protected because access to it is
659 // synchronized by always setting before triggering the execution of the
660 // reading code through HangWatcher::SignalMonitorEventForTesting().
661 std::string list_of_hung_thread_ids_during_capture_;
662
663 // This is written to by from the hang watching thread and read the test main
664 // thread. It does not need to be protected because access to it is
665 // synchronized by always reading after monitor_event_ has been signaled.
666 int hang_capture_count_ = 0;
667
668 // Increases at the same time as |hang_capture_count_| to test that capture
669 // actually took place.
670 int reference_capture_count_ = 0;
671
672 std::string seconds_since_last_power_resume_crash_key_;
673
674 base::test::ScopedFeatureList feature_list_;
675
676 // Used exclusively for MOCK_TIME.
677 test::SingleThreadTaskEnvironment task_environment_{
678 test::TaskEnvironment::TimeSource::MOCK_TIME};
679
680 HangWatcher hang_watcher_;
681 };
682 } // namespace
683
684 // Verify that the hang capture fails when marking a thread for blocking fails.
685 // This simulates a WatchHangsInScope completing between the time the hang
686 // was dected and the time it is recorded which would create a non-actionable
687 // report.
TEST_F(HangWatcherSnapshotTest,NonActionableReport)688 TEST_F(HangWatcherSnapshotTest, NonActionableReport) {
689 hang_watcher_.SetOnHangClosureForTesting(
690 base::BindLambdaForTesting([this] { ++hang_capture_count_; }));
691 hang_watcher_.SetAfterMonitorClosureForTesting(
692 base::BindLambdaForTesting([this] { monitor_event_.Signal(); }));
693
694 hang_watcher_.Start();
695
696 // Register the main test thread for hang watching.
697 auto unregister_thread_closure =
698 HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
699 {
700 // Start a WatchHangsInScope that expires right away. Ensures that
701 // the first monitor will detect a hang.
702 WatchHangsInScope expires_instantly(base::TimeDelta{});
703
704 internal::HangWatchState* current_hang_watch_state =
705 internal::HangWatchState::GetHangWatchStateForCurrentThread();
706
707 // Simulate the deadline changing concurrently during the capture. This
708 // makes the capture fail since marking of the deadline fails.
709 ASSERT_NE(current_hang_watch_state->GetDeadline(),
710 base::TimeTicks::FromInternalValue(kArbitraryDeadline));
711 current_hang_watch_state->GetHangWatchDeadlineForTesting()
712 ->SetSwitchBitsClosureForTesting(
713 base::BindLambdaForTesting([] { return kArbitraryDeadline; }));
714
715 ExpectNoCapture();
716
717 // Marking failed.
718 ASSERT_FALSE(current_hang_watch_state->IsFlagSet(
719 internal::HangWatchDeadline::Flag::kShouldBlockOnHang));
720
721 current_hang_watch_state->GetHangWatchDeadlineForTesting()
722 ->ResetSwitchBitsClosureForTesting();
723 }
724 }
725
726 // TODO(crbug.com/40187449): On MAC, the base::PlatformThread::CurrentId(...)
727 // should return the system wide IDs. The HungThreadIDs test fails because the
728 // reported process ids do not match.
729 #if BUILDFLAG(IS_MAC)
730 #define MAYBE_HungThreadIDs DISABLED_HungThreadIDs
731 #else
732 #define MAYBE_HungThreadIDs HungThreadIDs
733 #endif
734
TEST_F(HangWatcherSnapshotTest,MAYBE_HungThreadIDs)735 TEST_F(HangWatcherSnapshotTest, MAYBE_HungThreadIDs) {
736 // During hang capture the list of hung threads should be populated.
737 hang_watcher_.SetOnHangClosureForTesting(base::BindLambdaForTesting([this] {
738 EXPECT_EQ(hang_watcher_.GrabWatchStateSnapshotForTesting()
739 .PrepareHungThreadListCrashKey(),
740 list_of_hung_thread_ids_during_capture_);
741 ++hang_capture_count_;
742 }));
743
744 // When hang capture is over the list should be empty.
745 hang_watcher_.SetAfterMonitorClosureForTesting(
746 base::BindLambdaForTesting([this] { monitor_event_.Signal(); }));
747
748 hang_watcher_.Start();
749
750 // Register the main test thread for hang watching.
751 auto unregister_thread_closure =
752 HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
753
754 BlockingThread blocking_thread(&monitor_event_, base::TimeDelta{});
755 blocking_thread.StartAndWaitForScopeEntered();
756 {
757 // Ensure the blocking thread entered the scope before the main thread. This
758 // will guarantee an ordering while reporting the list of hung threads.
759 task_environment_.AdvanceClock(kSmallCPUQuantum);
760
761 // Start a WatchHangsInScope that expires right away. Ensures that
762 // the first monitor will detect a hang. This scope will naturally have a
763 // later deadline than the one in |blocking_thread_| since it was created
764 // after.
765 WatchHangsInScope expires_instantly(base::TimeDelta{});
766
767 // Hung thread list should contain the id the blocking thread and then the
768 // id of the test main thread since that is the order of increasing
769 // deadline.
770 TestIDList(
771 ConcatenateThreadIds({blocking_thread.GetId(), test_thread_id_}));
772
773 // |expires_instantly| and the scope from |blocking_thread| are still live
774 // but already recorded so should be ignored.
775 ExpectNoCapture();
776
777 // Thread is joinable since we signaled |monitor_event_|. This closes the
778 // scope in |blocking_thread|.
779 blocking_thread.Join();
780
781 // |expires_instantly| is still live but already recorded so should be
782 // ignored.
783 ExpectNoCapture();
784 }
785
786 // All HangWatchScopeEnables are over. There should be no capture.
787 ExpectNoCapture();
788
789 // Once all recorded scopes are over creating a new one and monitoring will
790 // trigger a hang detection.
791 WatchHangsInScope expires_instantly(base::TimeDelta{});
792 TestIDList(ConcatenateThreadIds({test_thread_id_}));
793 }
794
TEST_F(HangWatcherSnapshotTest,TimeSinceLastSystemPowerResumeCrashKey)795 TEST_F(HangWatcherSnapshotTest, TimeSinceLastSystemPowerResumeCrashKey) {
796 // Override the capture of hangs. Simulate a crash key capture.
797 hang_watcher_.SetOnHangClosureForTesting(base::BindLambdaForTesting([this] {
798 ++hang_capture_count_;
799 seconds_since_last_power_resume_crash_key_ =
800 hang_watcher_.GetTimeSinceLastSystemPowerResumeCrashKeyValue();
801 }));
802
803 // When hang capture is over, unblock the main thread.
804 hang_watcher_.SetAfterMonitorClosureForTesting(
805 base::BindLambdaForTesting([this] { monitor_event_.Signal(); }));
806
807 hang_watcher_.Start();
808
809 // Register the main test thread for hang watching.
810 auto unregister_thread_closure =
811 HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
812
813 {
814 WatchHangsInScope expires_instantly(base::TimeDelta{});
815 task_environment_.AdvanceClock(kSmallCPUQuantum);
816
817 TriggerMonitorAndWaitForCompletion();
818 EXPECT_EQ(1, hang_capture_count_);
819 EXPECT_EQ("Never suspended", seconds_since_last_power_resume_crash_key_);
820 }
821
822 {
823 test::ScopedPowerMonitorTestSource power_monitor_source;
824 power_monitor_source.Suspend();
825 task_environment_.AdvanceClock(kSmallCPUQuantum);
826
827 {
828 WatchHangsInScope expires_instantly(base::TimeDelta{});
829 task_environment_.AdvanceClock(kSmallCPUQuantum);
830 TriggerMonitorAndWaitForCompletion();
831 EXPECT_EQ(2, hang_capture_count_);
832 EXPECT_EQ("Power suspended", seconds_since_last_power_resume_crash_key_);
833 }
834
835 power_monitor_source.Resume();
836 constexpr TimeDelta kAfterResumeTime{base::Seconds(5)};
837 task_environment_.AdvanceClock(kAfterResumeTime);
838
839 {
840 WatchHangsInScope expires_instantly(base::TimeDelta{});
841 TriggerMonitorAndWaitForCompletion();
842 EXPECT_EQ(3, hang_capture_count_);
843 EXPECT_EQ(base::NumberToString(kAfterResumeTime.InSeconds()),
844 seconds_since_last_power_resume_crash_key_);
845 }
846 }
847 }
848
849 namespace {
850
851 // Determines how long the HangWatcher will wait between calls to
852 // Monitor(). Choose a low value so that that successive invocations happens
853 // fast. This makes tests that wait for monitoring run fast and makes tests that
854 // expect no monitoring fail fast.
855 const base::TimeDelta kMonitoringPeriod = base::Milliseconds(1);
856
857 // Test if and how often the HangWatcher periodically monitors for hangs.
858 class HangWatcherPeriodicMonitoringTest : public testing::Test {
859 public:
HangWatcherPeriodicMonitoringTest()860 HangWatcherPeriodicMonitoringTest() {
861 hang_watcher_.InitializeOnMainThread(
862 HangWatcher::ProcessType::kBrowserProcess, /*emit_crashes=*/true);
863
864 hang_watcher_.SetMonitoringPeriodForTesting(kMonitoringPeriod);
865 hang_watcher_.SetOnHangClosureForTesting(base::BindRepeating(
866 &WaitableEvent::Signal, base::Unretained(&hang_event_)));
867
868 // HangWatcher uses a TickClock to detect how long it slept in between calls
869 // to Monitor(). Override that clock to control its subjective passage of
870 // time.
871 hang_watcher_.SetTickClockForTesting(&test_clock_);
872 }
873
874 HangWatcherPeriodicMonitoringTest(
875 const HangWatcherPeriodicMonitoringTest& other) = delete;
876 HangWatcherPeriodicMonitoringTest& operator=(
877 const HangWatcherPeriodicMonitoringTest& other) = delete;
878
TearDown()879 void TearDown() override { hang_watcher_.UnitializeOnMainThreadForTesting(); }
880
881 protected:
882 // Setup the callback invoked after waiting in HangWatcher to advance the
883 // tick clock by the desired time delta.
InstallAfterWaitCallback(base::TimeDelta time_delta)884 void InstallAfterWaitCallback(base::TimeDelta time_delta) {
885 hang_watcher_.SetAfterWaitCallbackForTesting(base::BindLambdaForTesting(
886 [this, time_delta](base::TimeTicks time_before_wait) {
887 test_clock_.Advance(time_delta);
888 }));
889 }
890
891 base::SimpleTestTickClock test_clock_;
892
893 // Single threaded to avoid ThreadPool WorkerThreads registering. Will run
894 // delayed tasks created by the tests.
895 test::SingleThreadTaskEnvironment task_environment_;
896
897 std::unique_ptr<base::TickClock> fake_tick_clock_;
898 HangWatcher hang_watcher_;
899
900 // Signaled when a hang is detected.
901 WaitableEvent hang_event_;
902
903 base::ScopedClosureRunner unregister_thread_closure_;
904 };
905 } // namespace
906
907 // Don't register any threads for hang watching. HangWatcher should not monitor.
TEST_F(HangWatcherPeriodicMonitoringTest,NoPeriodicMonitoringWithoutRegisteredThreads)908 TEST_F(HangWatcherPeriodicMonitoringTest,
909 NoPeriodicMonitoringWithoutRegisteredThreads) {
910 RunLoop run_loop;
911
912 // If a call to HangWatcher::Monitor() takes place the test will instantly
913 // fail.
914 hang_watcher_.SetAfterMonitorClosureForTesting(
915 base::BindLambdaForTesting([&run_loop] {
916 ADD_FAILURE() << "Monitoring took place!";
917 run_loop.Quit();
918 }));
919
920 // Make the HangWatcher tick clock advance by exactly the monitoring period
921 // after waiting so it will never detect oversleeping between attempts to call
922 // Monitor(). This would inhibit monitoring and make the test pass for the
923 // wrong reasons.
924 InstallAfterWaitCallback(kMonitoringPeriod);
925
926 hang_watcher_.Start();
927
928 // Unblock the test thread. No thread ever registered after the HangWatcher
929 // was created in the test's constructor. No monitoring should have taken
930 // place.
931 task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
932 FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
933 run_loop.Run();
934
935 // NOTE:
936 // A lack of calls could technically also be caused by the HangWatcher thread
937 // executing too slowly / being descheduled. This is a known limitation.
938 // It's expected for |TestTimeouts::tiny_timeout()| to be large enough that
939 // this is rare.
940 }
941
942 // During normal execution periodic monitorings should take place.
TEST_F(HangWatcherPeriodicMonitoringTest,PeriodicCallsTakePlace)943 TEST_F(HangWatcherPeriodicMonitoringTest, PeriodicCallsTakePlace) {
944 // HangWatcher::Monitor() will run once right away on thread registration.
945 // We want to make sure it runs at a couple more times from being scheduled.
946 constexpr int kMinimumMonitorCount = 3;
947
948 RunLoop run_loop;
949
950 // Setup the HangWatcher to unblock run_loop when the Monitor() has been
951 // invoked enough times.
952 hang_watcher_.SetAfterMonitorClosureForTesting(BarrierClosure(
953 kMinimumMonitorCount, base::BindLambdaForTesting([&run_loop] {
954 // Test condition are confirmed, stop monitoring.
955 HangWatcher::StopMonitoringForTesting();
956
957 // Unblock the test main thread.
958 run_loop.Quit();
959 })));
960
961 // Make the HangWatcher tick clock advance by exactly the monitoring period
962 // after waiting so it will never detect oversleeping between attempts to call
963 // Monitor(). This would inhibit monitoring.
964 InstallAfterWaitCallback(kMonitoringPeriod);
965
966 hang_watcher_.Start();
967
968 // Register a thread,
969 unregister_thread_closure_ =
970 HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
971
972 run_loop.Run();
973
974 // No monitored scope means no possible hangs.
975 ASSERT_FALSE(hang_event_.IsSignaled());
976 }
977
978 // If the HangWatcher detects it slept for longer than expected it will not
979 // monitor.
TEST_F(HangWatcherPeriodicMonitoringTest,NoMonitorOnOverSleep)980 TEST_F(HangWatcherPeriodicMonitoringTest, NoMonitorOnOverSleep) {
981 RunLoop run_loop;
982
983 // If a call to HangWatcher::Monitor() takes place the test will instantly
984 // fail.
985 hang_watcher_.SetAfterMonitorClosureForTesting(
986 base::BindLambdaForTesting([&run_loop] {
987 ADD_FAILURE() << "Monitoring took place!";
988 run_loop.Quit();
989 }));
990
991 // Make the HangWatcher tick clock advance so much after waiting that it will
992 // detect oversleeping every time. This will keep it from monitoring.
993 InstallAfterWaitCallback(base::Minutes(1));
994
995 hang_watcher_.Start();
996
997 // Register a thread.
998 unregister_thread_closure_ =
999 HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
1000
1001 // Unblock the test thread. All waits were perceived as oversleeping so all
1002 // monitoring was inhibited.
1003 task_environment_.GetMainThreadTaskRunner()->PostDelayedTask(
1004 FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout());
1005 run_loop.Run();
1006
1007 // NOTE: A lack of calls could technically also be caused by the HangWatcher
1008 // thread executing too slowly / being descheduled. This is a known
1009 // limitation. It's expected for |TestTimeouts::tiny_timeout()| to be large
1010 // enough that this happens rarely.
1011 }
1012
1013 namespace {
1014 class WatchHangsInScopeBlockingTest : public testing::Test {
1015 public:
WatchHangsInScopeBlockingTest()1016 WatchHangsInScopeBlockingTest() {
1017 feature_list_.InitWithFeaturesAndParameters(kFeatureAndParams, {});
1018 HangWatcher::InitializeOnMainThread(
1019 HangWatcher::ProcessType::kBrowserProcess, /*emit_crashes=*/true);
1020
1021 hang_watcher_.SetOnHangClosureForTesting(base::BindLambdaForTesting([&] {
1022 capture_started_.Signal();
1023 // Simulate capturing that takes a long time.
1024 PlatformThread::Sleep(base::Milliseconds(500));
1025
1026 continue_capture_.Wait();
1027 completed_capture_ = true;
1028 }));
1029
1030 hang_watcher_.SetAfterMonitorClosureForTesting(
1031 base::BindLambdaForTesting([&] {
1032 // Simulate monitoring that takes a long time.
1033 PlatformThread::Sleep(base::Milliseconds(500));
1034 completed_monitoring_.Signal();
1035 }));
1036
1037 // Make sure no periodic monitoring takes place.
1038 hang_watcher_.SetMonitoringPeriodForTesting(kVeryLongDelta);
1039
1040 hang_watcher_.Start();
1041
1042 // Register the test main thread for hang watching.
1043 unregister_thread_closure_ =
1044 HangWatcher::RegisterThread(base::HangWatcher::ThreadType::kMainThread);
1045 }
1046
TearDown()1047 void TearDown() override { HangWatcher::UnitializeOnMainThreadForTesting(); }
1048
1049 WatchHangsInScopeBlockingTest(const WatchHangsInScopeBlockingTest& other) =
1050 delete;
1051 WatchHangsInScopeBlockingTest& operator=(
1052 const WatchHangsInScopeBlockingTest& other) = delete;
1053
VerifyScopesDontBlock()1054 void VerifyScopesDontBlock() {
1055 // Start a WatchHangsInScope that cannot possibly cause a hang to be
1056 // detected.
1057 {
1058 WatchHangsInScope long_scope(kVeryLongDelta);
1059
1060 // Manually trigger a monitoring.
1061 hang_watcher_.SignalMonitorEventForTesting();
1062
1063 // Execution has to continue freely here as no capture is in progress.
1064 }
1065
1066 // Monitoring should not be over yet because the test code should execute
1067 // faster when not blocked.
1068 EXPECT_FALSE(completed_monitoring_.IsSignaled());
1069
1070 // Wait for the full monitoring process to be complete. This is to prove
1071 // that monitoring truly executed and that we raced the signaling.
1072 completed_monitoring_.Wait();
1073
1074 // No hang means no capture.
1075 EXPECT_FALSE(completed_capture_);
1076 }
1077
1078 protected:
1079 base::WaitableEvent capture_started_;
1080 base::WaitableEvent completed_monitoring_;
1081
1082 // The HangWatcher waits on this event via the "on hang" closure when a hang
1083 // is detected.
1084 base::WaitableEvent continue_capture_;
1085 bool completed_capture_{false};
1086
1087 base::test::ScopedFeatureList feature_list_;
1088 HangWatcher hang_watcher_;
1089 base::ScopedClosureRunner unregister_thread_closure_;
1090 };
1091 } // namespace
1092
1093 // Tests that execution is unimpeded by ~WatchHangsInScope() when no capture
1094 // ever takes place.
TEST_F(WatchHangsInScopeBlockingTest,ScopeDoesNotBlocksWithoutCapture)1095 TEST_F(WatchHangsInScopeBlockingTest, ScopeDoesNotBlocksWithoutCapture) {
1096 // No capture should take place so |continue_capture_| is not signaled to
1097 // create a test hang if one ever does.
1098 VerifyScopesDontBlock();
1099 }
1100
1101 // Test that execution blocks in ~WatchHangsInScope() for a thread under
1102 // watch during the capturing of a hang.
TEST_F(WatchHangsInScopeBlockingTest,ScopeBlocksDuringCapture)1103 TEST_F(WatchHangsInScopeBlockingTest, ScopeBlocksDuringCapture) {
1104 // The capture completing is not dependent on any test event. Signal to make
1105 // sure the test is not blocked.
1106 continue_capture_.Signal();
1107
1108 // Start a WatchHangsInScope that expires in the past already. Ensures
1109 // that the first monitor will detect a hang.
1110 {
1111 // Start a WatchHangsInScope that expires right away. Ensures that the
1112 // first monitor will detect a hang.
1113 WatchHangsInScope expires_right_away(base::TimeDelta{});
1114
1115 // Manually trigger a monitoring.
1116 hang_watcher_.SignalMonitorEventForTesting();
1117
1118 // Ensure that the hang capturing started.
1119 capture_started_.Wait();
1120
1121 // Execution will get stuck in the outer scope because it can't escape
1122 // ~WatchHangsInScope() if a hang capture is under way.
1123 }
1124
1125 // A hang was in progress so execution should have been blocked in
1126 // BlockWhileCaptureInProgress() until capture finishes.
1127 EXPECT_TRUE(completed_capture_);
1128 completed_monitoring_.Wait();
1129
1130 // Reset expectations
1131 completed_monitoring_.Reset();
1132 capture_started_.Reset();
1133 completed_capture_ = false;
1134
1135 // Verify that scopes don't block just because a capture happened in the past.
1136 VerifyScopesDontBlock();
1137 }
1138
1139 #if BUILDFLAG(IS_MAC) && defined(ARCH_CPU_ARM64)
1140 // Flaky hangs on arm64 Macs: https://crbug.com/1140207
1141 #define MAYBE_NewScopeDoesNotBlockDuringCapture \
1142 DISABLED_NewScopeDoesNotBlockDuringCapture
1143 #else
1144 #define MAYBE_NewScopeDoesNotBlockDuringCapture \
1145 NewScopeDoesNotBlockDuringCapture
1146 #endif
1147
1148 // Test that execution does not block in ~WatchHangsInScope() when the scope
1149 // was created after the start of a capture.
TEST_F(WatchHangsInScopeBlockingTest,MAYBE_NewScopeDoesNotBlockDuringCapture)1150 TEST_F(WatchHangsInScopeBlockingTest, MAYBE_NewScopeDoesNotBlockDuringCapture) {
1151 // Start a WatchHangsInScope that expires right away. Ensures that the
1152 // first monitor will detect a hang.
1153 WatchHangsInScope expires_right_away(base::TimeDelta{});
1154
1155 // Manually trigger a monitoring.
1156 hang_watcher_.SignalMonitorEventForTesting();
1157
1158 // Ensure that the hang capturing started.
1159 capture_started_.Wait();
1160
1161 // A scope started once a capture is already under way should not block
1162 // execution.
1163 { WatchHangsInScope also_expires_right_away(base::TimeDelta{}); }
1164
1165 // Wait for the new WatchHangsInScope to be destroyed to let the capture
1166 // finish. If the new scope block waiting for the capture to finish this would
1167 // create a deadlock and the test would hang.
1168 continue_capture_.Signal();
1169 }
1170
1171 namespace internal {
1172 namespace {
1173
1174 constexpr std::array<HangWatchDeadline::Flag, 3> kAllFlags{
1175 {HangWatchDeadline::Flag::kMinValue,
1176 HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope,
1177 HangWatchDeadline::Flag::kShouldBlockOnHang}};
1178 } // namespace
1179
1180 class HangWatchDeadlineTest : public testing::Test {
1181 protected:
AssertNoFlagsSet() const1182 void AssertNoFlagsSet() const {
1183 for (HangWatchDeadline::Flag flag : kAllFlags) {
1184 ASSERT_FALSE(deadline_.IsFlagSet(flag));
1185 }
1186 }
1187
1188 // Return a flag mask without one of the flags for test purposes. Use to
1189 // ignore that effect of setting a flag that was just set.
FlagsMinus(uint64_t flags,HangWatchDeadline::Flag flag)1190 uint64_t FlagsMinus(uint64_t flags, HangWatchDeadline::Flag flag) {
1191 return flags & ~(static_cast<uint64_t>(flag));
1192 }
1193
1194 HangWatchDeadline deadline_;
1195 };
1196
1197 // Verify that the extract functions don't mangle any bits.
TEST_F(HangWatchDeadlineTest,BitsPreservedThroughExtract)1198 TEST_F(HangWatchDeadlineTest, BitsPreservedThroughExtract) {
1199 for (auto bits : {kAllOnes, kAllZeros, kOnesThenZeroes, kZeroesThenOnes}) {
1200 ASSERT_TRUE((HangWatchDeadline::ExtractFlags(bits) |
1201 HangWatchDeadline::ExtractDeadline(bits)) == bits);
1202 }
1203 }
1204
1205 // Verify that setting and clearing a persistent flag works and has no unwanted
1206 // side-effects. Neither the flags nor the deadline change concurrently in this
1207 // test.
TEST_F(HangWatchDeadlineTest,SetAndClearPersistentFlag)1208 TEST_F(HangWatchDeadlineTest, SetAndClearPersistentFlag) {
1209 AssertNoFlagsSet();
1210
1211 // Grab the original values for flags and deadline.
1212 auto [old_flags, old_deadline] = deadline_.GetFlagsAndDeadline();
1213
1214 // Set the flag. Operation cannot fail.
1215 deadline_.SetIgnoreCurrentWatchHangsInScope();
1216
1217 // Get new flags and deadline.
1218 auto [new_flags, new_deadline] = deadline_.GetFlagsAndDeadline();
1219
1220 // Flag was set properly.
1221 ASSERT_TRUE(HangWatchDeadline::IsFlagSet(
1222 HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope, new_flags));
1223
1224 // No side-effect on deadline.
1225 ASSERT_EQ(new_deadline, old_deadline);
1226
1227 // No side-effect on other flags.
1228 ASSERT_EQ(
1229 FlagsMinus(new_flags,
1230 HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope),
1231 old_flags);
1232
1233 // Clear the flag, operation cannot fail.
1234 deadline_.UnsetIgnoreCurrentWatchHangsInScope();
1235
1236 // Update new values.
1237 std::tie(new_flags, new_deadline) = deadline_.GetFlagsAndDeadline();
1238
1239 // All flags back to original state.
1240 ASSERT_EQ(new_flags, old_flags);
1241
1242 // Deadline still unnafected.
1243 ASSERT_EQ(new_deadline, old_deadline);
1244 }
1245
1246 // Verify setting the TimeTicks value works and has no unwanted side-effects.
TEST_F(HangWatchDeadlineTest,SetDeadline)1247 TEST_F(HangWatchDeadlineTest, SetDeadline) {
1248 TimeTicks ticks;
1249
1250 AssertNoFlagsSet();
1251 ASSERT_NE(deadline_.GetDeadline(), ticks);
1252
1253 // Set the deadline and verify it stuck.
1254 deadline_.SetDeadline(ticks);
1255 ASSERT_EQ(deadline_.GetDeadline(), ticks);
1256
1257 // Only the value was modified, no flags should be set.
1258 AssertNoFlagsSet();
1259 }
1260
1261 // Verify that setting a non-persistent flag (kShouldBlockOnHang)
1262 // when the TimeTicks value changed since calling the flag setting
1263 // function fails and has no side-effects.
TEST_F(HangWatchDeadlineTest,SetShouldBlockOnHangDeadlineChanged)1264 TEST_F(HangWatchDeadlineTest, SetShouldBlockOnHangDeadlineChanged) {
1265 AssertNoFlagsSet();
1266
1267 auto [flags, deadline] = deadline_.GetFlagsAndDeadline();
1268
1269 // Simulate value change. Flags are constant.
1270 const base::TimeTicks new_deadline =
1271 base::TimeTicks::FromInternalValue(kArbitraryDeadline);
1272 ASSERT_NE(deadline, new_deadline);
1273 deadline_.SetSwitchBitsClosureForTesting(
1274 base::BindLambdaForTesting([] { return kArbitraryDeadline; }));
1275
1276 // kShouldBlockOnHangs does not persist through value change.
1277 ASSERT_FALSE(deadline_.SetShouldBlockOnHang(flags, deadline));
1278
1279 // Flag was not applied.
1280 ASSERT_FALSE(
1281 deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
1282
1283 // New value that was changed concurrently is preserved.
1284 ASSERT_EQ(deadline_.GetDeadline(), new_deadline);
1285 }
1286
1287 // Verify that clearing a persistent (kIgnoreCurrentWatchHangsInScope) when
1288 // the value changed succeeds and has non side-effects.
TEST_F(HangWatchDeadlineTest,ClearIgnoreHangsDeadlineChanged)1289 TEST_F(HangWatchDeadlineTest, ClearIgnoreHangsDeadlineChanged) {
1290 AssertNoFlagsSet();
1291
1292 auto [flags, deadline] = deadline_.GetFlagsAndDeadline();
1293
1294 deadline_.SetIgnoreCurrentWatchHangsInScope();
1295 std::tie(flags, deadline) = deadline_.GetFlagsAndDeadline();
1296 ASSERT_TRUE(HangWatchDeadline::IsFlagSet(
1297 HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope, flags));
1298
1299 // Simulate deadline change. Flags are constant.
1300 const base::TimeTicks new_deadline =
1301 base::TimeTicks::FromInternalValue(kArbitraryDeadline);
1302 ASSERT_NE(deadline, new_deadline);
1303 deadline_.SetSwitchBitsClosureForTesting(base::BindLambdaForTesting([] {
1304 return static_cast<uint64_t>(HangWatchDeadline::Flag::kShouldBlockOnHang) |
1305 kArbitraryDeadline;
1306 }));
1307
1308 // Clearing kIgnoreHang is unaffected by deadline or flags change.
1309 deadline_.UnsetIgnoreCurrentWatchHangsInScope();
1310 ASSERT_FALSE(deadline_.IsFlagSet(
1311 HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope));
1312
1313 // New deadline that was changed concurrently is preserved.
1314 ASSERT_TRUE(deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
1315 ASSERT_EQ(deadline_.GetDeadline(), new_deadline);
1316 }
1317
1318 // Verify that setting a persistent (kIgnoreCurrentWatchHangsInScope) when
1319 // the deadline or flags changed succeeds and has non side-effects.
TEST_F(HangWatchDeadlineTest,SetIgnoreCurrentHangWatchScopeEnableDeadlineChangedd)1320 TEST_F(HangWatchDeadlineTest,
1321 SetIgnoreCurrentHangWatchScopeEnableDeadlineChangedd) {
1322 AssertNoFlagsSet();
1323
1324 auto [flags, deadline] = deadline_.GetFlagsAndDeadline();
1325
1326 // Simulate deadline change. Flags are constant.
1327 const base::TimeTicks new_deadline =
1328 base::TimeTicks::FromInternalValue(kArbitraryDeadline);
1329
1330 ASSERT_NE(deadline, new_deadline);
1331 deadline_.SetSwitchBitsClosureForTesting(base::BindLambdaForTesting([] {
1332 return static_cast<uint64_t>(HangWatchDeadline::Flag::kShouldBlockOnHang) |
1333 kArbitraryDeadline;
1334 }));
1335
1336 // kIgnoreHang persists through value change.
1337 deadline_.SetIgnoreCurrentWatchHangsInScope();
1338 ASSERT_TRUE(deadline_.IsFlagSet(
1339 HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope));
1340
1341 // New deadline and flags that changed concurrently are preserved.
1342 ASSERT_TRUE(deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
1343 ASSERT_EQ(deadline_.GetDeadline(), new_deadline);
1344 }
1345
1346 // Setting a new deadline should wipe flags that a not persistent.
1347 // Persistent flags should not be disturbed.
TEST_F(HangWatchDeadlineTest,SetDeadlineWipesFlags)1348 TEST_F(HangWatchDeadlineTest, SetDeadlineWipesFlags) {
1349 auto [flags, deadline] = deadline_.GetFlagsAndDeadline();
1350
1351 ASSERT_TRUE(deadline_.SetShouldBlockOnHang(flags, deadline));
1352 ASSERT_TRUE(deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
1353
1354 std::tie(flags, deadline) = deadline_.GetFlagsAndDeadline();
1355
1356 deadline_.SetIgnoreCurrentWatchHangsInScope();
1357 ASSERT_TRUE(deadline_.IsFlagSet(
1358 HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope));
1359
1360 // Change the deadline.
1361 deadline_.SetDeadline(TimeTicks{});
1362 ASSERT_EQ(deadline_.GetDeadline(), TimeTicks{});
1363
1364 // Verify the persistent flag stuck and the non-persistent one was unset.
1365 ASSERT_FALSE(
1366 deadline_.IsFlagSet(HangWatchDeadline::Flag::kShouldBlockOnHang));
1367 ASSERT_TRUE(deadline_.IsFlagSet(
1368 HangWatchDeadline::Flag::kIgnoreCurrentWatchHangsInScope));
1369 }
1370
1371 } // namespace internal
1372
1373 } // namespace base
1374