• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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