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