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