1 // Copyright 2017 The Chromium Authors. All rights reserved.
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/task/sequence_manager/test/lazy_thread_controller_for_test.h"
6
7 #include "base/message_loop/message_loop.h"
8 #include "base/time/default_tick_clock.h"
9
10 namespace base {
11 namespace sequence_manager {
12
LazyThreadControllerForTest()13 LazyThreadControllerForTest::LazyThreadControllerForTest()
14 : ThreadControllerImpl(MessageLoop::current(),
15 nullptr,
16 DefaultTickClock::GetInstance()),
17 thread_ref_(PlatformThread::CurrentRef()) {
18 if (message_loop_)
19 task_runner_ = message_loop_->task_runner();
20 }
21
22 LazyThreadControllerForTest::~LazyThreadControllerForTest() = default;
23
EnsureMessageLoop()24 void LazyThreadControllerForTest::EnsureMessageLoop() {
25 if (message_loop_)
26 return;
27 DCHECK(RunsTasksInCurrentSequence());
28 message_loop_ = MessageLoop::current();
29 DCHECK(message_loop_);
30 task_runner_ = message_loop_->task_runner();
31 if (pending_observer_) {
32 RunLoop::AddNestingObserverOnCurrentThread(this);
33 pending_observer_ = false;
34 }
35 if (pending_default_task_runner_) {
36 ThreadControllerImpl::SetDefaultTaskRunner(pending_default_task_runner_);
37 pending_default_task_runner_ = nullptr;
38 }
39 }
40
HasMessageLoop()41 bool LazyThreadControllerForTest::HasMessageLoop() {
42 return !!message_loop_;
43 }
44
AddNestingObserver(RunLoop::NestingObserver * observer)45 void LazyThreadControllerForTest::AddNestingObserver(
46 RunLoop::NestingObserver* observer) {
47 // While |observer| _could_ be associated with the current thread regardless
48 // of the presence of a MessageLoop, the association is delayed until
49 // EnsureMessageLoop() is invoked. This works around a state issue where
50 // otherwise many tests fail because of the following sequence:
51 // 1) blink::scheduler::CreateRendererSchedulerForTests()
52 // -> SequenceManager::SequenceManager()
53 // -> LazySchedulerMessageLoopDelegateForTests::AddNestingObserver()
54 // 2) Any test framework with a MessageLoop member (and not caring
55 // about the blink scheduler) does:
56 // blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
57 // FROM_HERE, an_init_task_with_a_nested_loop);
58 // RunLoop.RunUntilIdle();
59 // 3) |a_task_with_a_nested_loop| triggers
60 // SequenceManager::OnBeginNestedLoop() which:
61 // a) flags any_thread().is_nested = true;
62 // b) posts a task to self, which triggers:
63 // LazySchedulerMessageLoopDelegateForTests::PostDelayedTask()
64 // 4) This self-task in turn triggers SequenceManager::DoWork()
65 // which expects to be the only one to trigger nested loops (doesn't
66 // support SequenceManager::OnBeginNestedLoop() being invoked before
67 // it kicks in), resulting in it hitting:
68 // DCHECK_EQ(any_thread().is_nested, delegate_->IsNested()); (1 vs 0).
69 // TODO(skyostil): fix this convolution as part of http://crbug.com/495659.
70 ThreadControllerImpl::nesting_observer_ = observer;
71 if (!HasMessageLoop()) {
72 DCHECK(!pending_observer_);
73 pending_observer_ = true;
74 return;
75 }
76 RunLoop::AddNestingObserverOnCurrentThread(this);
77 }
78
RemoveNestingObserver(RunLoop::NestingObserver * observer)79 void LazyThreadControllerForTest::RemoveNestingObserver(
80 RunLoop::NestingObserver* observer) {
81 ThreadControllerImpl::nesting_observer_ = nullptr;
82 if (!HasMessageLoop()) {
83 DCHECK(pending_observer_);
84 pending_observer_ = false;
85 return;
86 }
87 if (MessageLoop::current() != message_loop_)
88 return;
89 RunLoop::RemoveNestingObserverOnCurrentThread(this);
90 }
91
RunsTasksInCurrentSequence()92 bool LazyThreadControllerForTest::RunsTasksInCurrentSequence() {
93 return thread_ref_ == PlatformThread::CurrentRef();
94 }
95
ScheduleWork()96 void LazyThreadControllerForTest::ScheduleWork() {
97 EnsureMessageLoop();
98 ThreadControllerImpl::ScheduleWork();
99 }
100
SetNextDelayedDoWork(LazyNow * lazy_now,TimeTicks run_time)101 void LazyThreadControllerForTest::SetNextDelayedDoWork(LazyNow* lazy_now,
102 TimeTicks run_time) {
103 EnsureMessageLoop();
104 ThreadControllerImpl::SetNextDelayedDoWork(lazy_now, run_time);
105 }
106
SetDefaultTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner)107 void LazyThreadControllerForTest::SetDefaultTaskRunner(
108 scoped_refptr<SingleThreadTaskRunner> task_runner) {
109 if (!HasMessageLoop()) {
110 pending_default_task_runner_ = task_runner;
111 return;
112 }
113 ThreadControllerImpl::SetDefaultTaskRunner(task_runner);
114 }
115
RestoreDefaultTaskRunner()116 void LazyThreadControllerForTest::RestoreDefaultTaskRunner() {
117 pending_default_task_runner_ = nullptr;
118 if (HasMessageLoop() && MessageLoop::current() == message_loop_)
119 ThreadControllerImpl::RestoreDefaultTaskRunner();
120 }
121
122 } // namespace sequence_manager
123 } // namespace base
124