blob: 218d02b64a2cbff34d122550e2144facde553c3e [file] [log] [blame]
Francois Doray1eb7c8c2017-06-12 20:20:311// 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
13namespace base {
14namespace internal {
15
16namespace {
17ScopedLazyTaskRunnerListForTesting* g_scoped_lazy_task_runner_list_for_testing =
18 nullptr;
19} // namespace
20
21template <typename TaskRunnerType, bool com_sta>
22void 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
41template <>
42scoped_refptr<SequencedTaskRunner>
43LazyTaskRunner<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
51template <>
52scoped_refptr<SingleThreadTaskRunner>
53LazyTaskRunner<SingleThreadTaskRunner, false>::Create() {
54 return CreateSingleThreadTaskRunnerWithTraits(traits_, thread_mode_);
55}
56
57#if defined(OS_WIN)
58template <>
59scoped_refptr<SingleThreadTaskRunner>
60LazyTaskRunner<SingleThreadTaskRunner, true>::Create() {
61 return CreateCOMSTATaskRunnerWithTraits(traits_, thread_mode_);
62}
63#endif
64
Gabriel Charetted55aad502018-01-26 18:07:5165// static
66template <typename TaskRunnerType, bool com_sta>
67TaskRunnerType* 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
Francois Doray1eb7c8c2017-06-12 20:20:3190template <typename TaskRunnerType, bool com_sta>
91scoped_refptr<TaskRunnerType> LazyTaskRunner<TaskRunnerType, com_sta>::Get() {
Gabriel Charetted55aad502018-01-26 18:07:5192 return WrapRefCounted(subtle::GetOrCreateLazyPointer(
93 &state_, &LazyTaskRunner<TaskRunnerType, com_sta>::CreateRaw,
94 reinterpret_cast<void*>(this), nullptr, nullptr));
Francois Doray1eb7c8c2017-06-12 20:20:3195}
96
97template class LazyTaskRunner<SequencedTaskRunner, false>;
98template class LazyTaskRunner<SingleThreadTaskRunner, false>;
99
100#if defined(OS_WIN)
101template class LazyTaskRunner<SingleThreadTaskRunner, true>;
102#endif
103
104ScopedLazyTaskRunnerListForTesting::ScopedLazyTaskRunnerListForTesting() {
105 DCHECK(!g_scoped_lazy_task_runner_list_for_testing);
106 g_scoped_lazy_task_runner_list_for_testing = this;
107}
108
109ScopedLazyTaskRunnerListForTesting::~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
116void 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