1 // Copyright 2017 The Chromium Authors
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/lazy_thread_pool_task_runner.h"
6
7 #include <atomic>
8 #include <utility>
9
10 #include "base/check_op.h"
11 #include "base/lazy_instance_helpers.h"
12 #include "base/task/thread_pool.h"
13 #include "build/build_config.h"
14
15 namespace base {
16 namespace internal {
17
18 namespace {
19 ScopedLazyTaskRunnerListForTesting* g_scoped_lazy_task_runner_list_for_testing =
20 nullptr;
21 } // namespace
22
23 template <typename TaskRunnerType, bool com_sta>
Reset()24 void LazyThreadPoolTaskRunner<TaskRunnerType, com_sta>::Reset() {
25 uintptr_t state = state_.load(std::memory_order_acquire);
26
27 DCHECK_NE(state, kLazyInstanceStateCreating) << "Race: all threads should be "
28 "unwound in unittests before "
29 "resetting TaskRunners.";
30
31 // Return if no reference is held by this instance.
32 if (!state)
33 return;
34
35 // Release the reference acquired in Get().
36 SequencedTaskRunner* task_runner = reinterpret_cast<TaskRunnerType*>(state);
37 task_runner->Release();
38
39 // Clear the state.
40 state_.store(0, std::memory_order_relaxed);
41 }
42
43 template <>
44 scoped_refptr<SequencedTaskRunner>
Create()45 LazyThreadPoolTaskRunner<SequencedTaskRunner, false>::Create() {
46 // It is invalid to specify a SingleThreadTaskRunnerThreadMode with a
47 // LazyThreadPoolSequencedTaskRunner.
48 DCHECK_EQ(thread_mode_, SingleThreadTaskRunnerThreadMode::SHARED);
49
50 return ThreadPool::CreateSequencedTaskRunner(traits_);
51 }
52
53 template <>
54 scoped_refptr<SingleThreadTaskRunner>
Create()55 LazyThreadPoolTaskRunner<SingleThreadTaskRunner, false>::Create() {
56 return ThreadPool::CreateSingleThreadTaskRunner(traits_, thread_mode_);
57 }
58
59 #if BUILDFLAG(IS_WIN)
60 template <>
61 scoped_refptr<SingleThreadTaskRunner>
Create()62 LazyThreadPoolTaskRunner<SingleThreadTaskRunner, true>::Create() {
63 return ThreadPool::CreateCOMSTATaskRunner(traits_, thread_mode_);
64 }
65 #endif
66
67 // static
68 template <typename TaskRunnerType, bool com_sta>
CreateRaw(void * void_self)69 TaskRunnerType* LazyThreadPoolTaskRunner<TaskRunnerType, com_sta>::CreateRaw(
70 void* void_self) {
71 auto self =
72 reinterpret_cast<LazyThreadPoolTaskRunner<TaskRunnerType, com_sta>*>(
73 void_self);
74
75 scoped_refptr<TaskRunnerType> task_runner = self->Create();
76
77 // Acquire a reference to the TaskRunner. The reference will either
78 // never be released or be released in Reset(). The reference is not
79 // managed by a scoped_refptr because adding a scoped_refptr member to
80 // LazyThreadPoolTaskRunner would prevent its static initialization.
81 task_runner->AddRef();
82
83 // Reset this instance when the current
84 // ScopedLazyTaskRunnerListForTesting is destroyed, if any.
85 if (g_scoped_lazy_task_runner_list_for_testing) {
86 g_scoped_lazy_task_runner_list_for_testing->AddCallback(
87 BindOnce(&LazyThreadPoolTaskRunner<TaskRunnerType, com_sta>::Reset,
88 Unretained(self)));
89 }
90
91 return task_runner.get();
92 }
93
94 template <typename TaskRunnerType, bool com_sta>
95 scoped_refptr<TaskRunnerType>
Get()96 LazyThreadPoolTaskRunner<TaskRunnerType, com_sta>::Get() {
97 return WrapRefCounted(subtle::GetOrCreateLazyPointer(
98 state_, &LazyThreadPoolTaskRunner<TaskRunnerType, com_sta>::CreateRaw,
99 reinterpret_cast<void*>(this), nullptr, nullptr));
100 }
101
102 template class LazyThreadPoolTaskRunner<SequencedTaskRunner, false>;
103 template class LazyThreadPoolTaskRunner<SingleThreadTaskRunner, false>;
104
105 #if BUILDFLAG(IS_WIN)
106 template class LazyThreadPoolTaskRunner<SingleThreadTaskRunner, true>;
107 #endif
108
ScopedLazyTaskRunnerListForTesting()109 ScopedLazyTaskRunnerListForTesting::ScopedLazyTaskRunnerListForTesting() {
110 DCHECK(!g_scoped_lazy_task_runner_list_for_testing);
111 g_scoped_lazy_task_runner_list_for_testing = this;
112 }
113
~ScopedLazyTaskRunnerListForTesting()114 ScopedLazyTaskRunnerListForTesting::~ScopedLazyTaskRunnerListForTesting() {
115 internal::CheckedAutoLock auto_lock(lock_);
116 for (auto& callback : callbacks_)
117 std::move(callback).Run();
118 g_scoped_lazy_task_runner_list_for_testing = nullptr;
119 }
120
AddCallback(OnceClosure callback)121 void ScopedLazyTaskRunnerListForTesting::AddCallback(OnceClosure callback) {
122 internal::CheckedAutoLock auto_lock(lock_);
123 callbacks_.push_back(std::move(callback));
124 }
125
126 } // namespace internal
127 } // namespace base
128