blob: 39a7a1104f7e9b6ab321cac38323aac54f410560 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/task/sequence_manager/test/lazy_thread_controller_for_test.h"
#include "base/message_loop/message_loop.h"
#include "base/time/default_tick_clock.h"
namespace base {
namespace sequence_manager {
LazyThreadControllerForTest::LazyThreadControllerForTest()
: ThreadControllerImpl(MessageLoop::current(),
nullptr,
DefaultTickClock::GetInstance()),
thread_ref_(PlatformThread::CurrentRef()) {
if (message_loop_)
task_runner_ = message_loop_->task_runner();
}
LazyThreadControllerForTest::~LazyThreadControllerForTest() = default;
void LazyThreadControllerForTest::EnsureMessageLoop() {
if (message_loop_)
return;
DCHECK(RunsTasksInCurrentSequence());
message_loop_ = MessageLoop::current();
DCHECK(message_loop_);
task_runner_ = message_loop_->task_runner();
if (pending_observer_) {
RunLoop::AddNestingObserverOnCurrentThread(this);
pending_observer_ = false;
}
if (pending_default_task_runner_) {
ThreadControllerImpl::SetDefaultTaskRunner(pending_default_task_runner_);
pending_default_task_runner_ = nullptr;
}
}
bool LazyThreadControllerForTest::HasMessageLoop() {
return !!message_loop_;
}
void LazyThreadControllerForTest::AddNestingObserver(
RunLoop::NestingObserver* observer) {
// While |observer| _could_ be associated with the current thread regardless
// of the presence of a MessageLoop, the association is delayed until
// EnsureMessageLoop() is invoked. This works around a state issue where
// otherwise many tests fail because of the following sequence:
// 1) blink::scheduler::CreateRendererSchedulerForTests()
// -> SequenceManager::SequenceManager()
// -> LazySchedulerMessageLoopDelegateForTests::AddNestingObserver()
// 2) Any test framework with a MessageLoop member (and not caring
// about the blink scheduler) does:
// blink::scheduler::GetSingleThreadTaskRunnerForTesting()->PostTask(
// FROM_HERE, an_init_task_with_a_nested_loop);
// RunLoop.RunUntilIdle();
// 3) |a_task_with_a_nested_loop| triggers
// SequenceManager::OnBeginNestedLoop() which:
// a) flags any_thread().is_nested = true;
// b) posts a task to self, which triggers:
// LazySchedulerMessageLoopDelegateForTests::PostDelayedTask()
// 4) This self-task in turn triggers SequenceManager::DoWork()
// which expects to be the only one to trigger nested loops (doesn't
// support SequenceManager::OnBeginNestedLoop() being invoked before
// it kicks in), resulting in it hitting:
// DCHECK_EQ(any_thread().is_nested, delegate_->IsNested()); (1 vs 0).
// TODO(skyostil): fix this convolution as part of http://crbug.com/495659.
ThreadControllerImpl::nesting_observer_ = observer;
if (!HasMessageLoop()) {
DCHECK(!pending_observer_);
pending_observer_ = true;
return;
}
RunLoop::AddNestingObserverOnCurrentThread(this);
}
void LazyThreadControllerForTest::RemoveNestingObserver(
RunLoop::NestingObserver* observer) {
ThreadControllerImpl::nesting_observer_ = nullptr;
if (!HasMessageLoop()) {
DCHECK(pending_observer_);
pending_observer_ = false;
return;
}
if (MessageLoop::current() != message_loop_)
return;
RunLoop::RemoveNestingObserverOnCurrentThread(this);
}
bool LazyThreadControllerForTest::RunsTasksInCurrentSequence() {
return thread_ref_ == PlatformThread::CurrentRef();
}
void LazyThreadControllerForTest::ScheduleWork() {
EnsureMessageLoop();
ThreadControllerImpl::ScheduleWork();
}
void LazyThreadControllerForTest::SetNextDelayedDoWork(LazyNow* lazy_now,
TimeTicks run_time) {
EnsureMessageLoop();
ThreadControllerImpl::SetNextDelayedDoWork(lazy_now, run_time);
}
void LazyThreadControllerForTest::SetDefaultTaskRunner(
scoped_refptr<SingleThreadTaskRunner> task_runner) {
if (!HasMessageLoop()) {
pending_default_task_runner_ = task_runner;
return;
}
ThreadControllerImpl::SetDefaultTaskRunner(task_runner);
}
void LazyThreadControllerForTest::RestoreDefaultTaskRunner() {
pending_default_task_runner_ = nullptr;
if (HasMessageLoop() && MessageLoop::current() == message_loop_)
ThreadControllerImpl::RestoreDefaultTaskRunner();
}
} // namespace sequence_manager
} // namespace base