// Copyright 2017 The Chromium Authors // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/task/lazy_thread_pool_task_runner.h" #include #include #include "base/check_op.h" #include "base/lazy_instance_helpers.h" #include "base/task/thread_pool.h" #include "build/build_config.h" namespace base { namespace internal { namespace { ScopedLazyTaskRunnerListForTesting* g_scoped_lazy_task_runner_list_for_testing = nullptr; } // namespace template void LazyThreadPoolTaskRunner::Reset() { uintptr_t state = state_.load(std::memory_order_acquire); 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. state_.store(0, std::memory_order_relaxed); } template <> scoped_refptr LazyThreadPoolTaskRunner::Create() { // It is invalid to specify a SingleThreadTaskRunnerThreadMode with a // LazyThreadPoolSequencedTaskRunner. DCHECK_EQ(thread_mode_, SingleThreadTaskRunnerThreadMode::SHARED); return ThreadPool::CreateSequencedTaskRunner(traits_); } template <> scoped_refptr LazyThreadPoolTaskRunner::Create() { return ThreadPool::CreateSingleThreadTaskRunner(traits_, thread_mode_); } #if BUILDFLAG(IS_WIN) template <> scoped_refptr LazyThreadPoolTaskRunner::Create() { return ThreadPool::CreateCOMSTATaskRunner(traits_, thread_mode_); } #endif // static template TaskRunnerType* LazyThreadPoolTaskRunner::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 // LazyThreadPoolTaskRunner 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(&LazyThreadPoolTaskRunner::Reset, Unretained(self))); } return task_runner.get(); } template scoped_refptr LazyThreadPoolTaskRunner::Get() { return WrapRefCounted(subtle::GetOrCreateLazyPointer( state_, &LazyThreadPoolTaskRunner::CreateRaw, reinterpret_cast(this), nullptr, nullptr)); } template class LazyThreadPoolTaskRunner; template class LazyThreadPoolTaskRunner; #if BUILDFLAG(IS_WIN) template class LazyThreadPoolTaskRunner; #endif ScopedLazyTaskRunnerListForTesting::ScopedLazyTaskRunnerListForTesting() { DCHECK(!g_scoped_lazy_task_runner_list_for_testing); g_scoped_lazy_task_runner_list_for_testing = this; } ScopedLazyTaskRunnerListForTesting::~ScopedLazyTaskRunnerListForTesting() { internal::CheckedAutoLock 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::CheckedAutoLock auto_lock(lock_); callbacks_.push_back(std::move(callback)); } } // namespace internal } // namespace base