// 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/lazy_task_runner.h" #include #include "base/lazy_instance.h" #include "base/logging.h" #include "base/task/post_task.h" namespace base { namespace internal { namespace { ScopedLazyTaskRunnerListForTesting* g_scoped_lazy_task_runner_list_for_testing = nullptr; } // namespace template void LazyTaskRunner::Reset() { subtle::AtomicWord state = subtle::Acquire_Load(&state_); DCHECK_NE(state, kLazyInstanceStateCreating) << "Race: all threads should be " "unwound in unittests before " "resetting TaskRunners."; // Return if no reference is held by this instance. if (!state) return; // Release the reference acquired in Get(). SequencedTaskRunner* task_runner = reinterpret_cast(state); task_runner->Release(); // Clear the state. subtle::NoBarrier_Store(&state_, 0); } template <> scoped_refptr LazyTaskRunner::Create() { // It is invalid to specify a SingleThreadTaskRunnerThreadMode with a // LazySequencedTaskRunner. DCHECK_EQ(thread_mode_, SingleThreadTaskRunnerThreadMode::SHARED); return CreateSequencedTaskRunnerWithTraits(traits_); } template <> scoped_refptr LazyTaskRunner::Create() { return CreateSingleThreadTaskRunnerWithTraits(traits_, thread_mode_); } #if defined(OS_WIN) template <> scoped_refptr LazyTaskRunner::Create() { return CreateCOMSTATaskRunnerWithTraits(traits_, thread_mode_); } #endif // static template TaskRunnerType* LazyTaskRunner::CreateRaw( void* void_self) { auto self = reinterpret_cast*>(void_self); scoped_refptr task_runner = self->Create(); // Acquire a reference to the TaskRunner. The reference will either // never be released or be released in Reset(). The reference is not // managed by a scoped_refptr because adding a scoped_refptr member to // LazyTaskRunner would prevent its static initialization. task_runner->AddRef(); // Reset this instance when the current // ScopedLazyTaskRunnerListForTesting is destroyed, if any. if (g_scoped_lazy_task_runner_list_for_testing) { g_scoped_lazy_task_runner_list_for_testing->AddCallback(BindOnce( &LazyTaskRunner::Reset, Unretained(self))); } return task_runner.get(); } template scoped_refptr LazyTaskRunner::Get() { return WrapRefCounted(subtle::GetOrCreateLazyPointer( &state_, &LazyTaskRunner::CreateRaw, reinterpret_cast(this), nullptr, nullptr)); } template class LazyTaskRunner; template class LazyTaskRunner; #if defined(OS_WIN) template class LazyTaskRunner; #endif ScopedLazyTaskRunnerListForTesting::ScopedLazyTaskRunnerListForTesting() { DCHECK(!g_scoped_lazy_task_runner_list_for_testing); g_scoped_lazy_task_runner_list_for_testing = this; } ScopedLazyTaskRunnerListForTesting::~ScopedLazyTaskRunnerListForTesting() { internal::AutoSchedulerLock auto_lock(lock_); for (auto& callback : callbacks_) std::move(callback).Run(); g_scoped_lazy_task_runner_list_for_testing = nullptr; } void ScopedLazyTaskRunnerListForTesting::AddCallback(OnceClosure callback) { internal::AutoSchedulerLock auto_lock(lock_); callbacks_.push_back(std::move(callback)); } } // namespace internal } // namespace base