xref: /aosp_15_r20/external/cronet/base/task/lazy_thread_pool_task_runner.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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