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