1 // Copyright 2014 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/cancelable_task_tracker.h"
6
7 #include <stddef.h>
8
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/bind_helpers.h"
13 #include "base/callback_helpers.h"
14 #include "base/location.h"
15 #include "base/memory/ref_counted.h"
16 #include "base/synchronization/cancellation_flag.h"
17 #include "base/task_runner.h"
18 #include "base/threading/sequenced_task_runner_handle.h"
19
20 namespace base {
21
22 namespace {
23
RunIfNotCanceled(const CancellationFlag * flag,OnceClosure task)24 void RunIfNotCanceled(const CancellationFlag* flag, OnceClosure task) {
25 if (!flag->IsSet())
26 std::move(task).Run();
27 }
28
RunIfNotCanceledThenUntrack(const CancellationFlag * flag,OnceClosure task,OnceClosure untrack)29 void RunIfNotCanceledThenUntrack(const CancellationFlag* flag,
30 OnceClosure task,
31 OnceClosure untrack) {
32 RunIfNotCanceled(flag, std::move(task));
33 std::move(untrack).Run();
34 }
35
IsCanceled(const CancellationFlag * flag,ScopedClosureRunner * cleanup_runner)36 bool IsCanceled(const CancellationFlag* flag,
37 ScopedClosureRunner* cleanup_runner) {
38 return flag->IsSet();
39 }
40
RunAndDeleteFlag(OnceClosure closure,const CancellationFlag * flag)41 void RunAndDeleteFlag(OnceClosure closure, const CancellationFlag* flag) {
42 std::move(closure).Run();
43 delete flag;
44 }
45
RunOrPostToTaskRunner(TaskRunner * task_runner,OnceClosure closure)46 void RunOrPostToTaskRunner(TaskRunner* task_runner, OnceClosure closure) {
47 if (task_runner->RunsTasksInCurrentSequence())
48 std::move(closure).Run();
49 else
50 task_runner->PostTask(FROM_HERE, std::move(closure));
51 }
52
53 } // namespace
54
55 // static
56 const CancelableTaskTracker::TaskId CancelableTaskTracker::kBadTaskId = 0;
57
CancelableTaskTracker()58 CancelableTaskTracker::CancelableTaskTracker()
59 : next_id_(1),weak_factory_(this) {}
60
~CancelableTaskTracker()61 CancelableTaskTracker::~CancelableTaskTracker() {
62 DCHECK(sequence_checker_.CalledOnValidSequence());
63
64 TryCancelAll();
65 }
66
PostTask(TaskRunner * task_runner,const Location & from_here,OnceClosure task)67 CancelableTaskTracker::TaskId CancelableTaskTracker::PostTask(
68 TaskRunner* task_runner,
69 const Location& from_here,
70 OnceClosure task) {
71 DCHECK(sequence_checker_.CalledOnValidSequence());
72
73 return PostTaskAndReply(task_runner, from_here, std::move(task), DoNothing());
74 }
75
PostTaskAndReply(TaskRunner * task_runner,const Location & from_here,OnceClosure task,OnceClosure reply)76 CancelableTaskTracker::TaskId CancelableTaskTracker::PostTaskAndReply(
77 TaskRunner* task_runner,
78 const Location& from_here,
79 OnceClosure task,
80 OnceClosure reply) {
81 DCHECK(sequence_checker_.CalledOnValidSequence());
82
83 // We need a SequencedTaskRunnerHandle to run |reply|.
84 DCHECK(SequencedTaskRunnerHandle::IsSet());
85
86 // Owned by reply callback below.
87 CancellationFlag* flag = new CancellationFlag();
88
89 TaskId id = next_id_;
90 next_id_++; // int64_t is big enough that we ignore the potential overflow.
91
92 OnceClosure untrack_closure =
93 BindOnce(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id);
94 bool success = task_runner->PostTaskAndReply(
95 from_here, BindOnce(&RunIfNotCanceled, flag, std::move(task)),
96 BindOnce(&RunIfNotCanceledThenUntrack, Owned(flag), std::move(reply),
97 std::move(untrack_closure)));
98
99 if (!success)
100 return kBadTaskId;
101
102 Track(id, flag);
103 return id;
104 }
105
NewTrackedTaskId(IsCanceledCallback * is_canceled_cb)106 CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId(
107 IsCanceledCallback* is_canceled_cb) {
108 DCHECK(sequence_checker_.CalledOnValidSequence());
109 DCHECK(SequencedTaskRunnerHandle::IsSet());
110
111 TaskId id = next_id_;
112 next_id_++; // int64_t is big enough that we ignore the potential overflow.
113
114 // Will be deleted by |untrack_and_delete_flag| after Untrack().
115 CancellationFlag* flag = new CancellationFlag();
116
117 OnceClosure untrack_and_delete_flag = BindOnce(
118 &RunAndDeleteFlag,
119 BindOnce(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id),
120 flag);
121
122 // Will always run |untrack_and_delete_flag| on current sequence.
123 ScopedClosureRunner* untrack_and_delete_flag_runner =
124 new ScopedClosureRunner(BindOnce(
125 &RunOrPostToTaskRunner, RetainedRef(SequencedTaskRunnerHandle::Get()),
126 std::move(untrack_and_delete_flag)));
127
128 *is_canceled_cb =
129 Bind(&IsCanceled, flag, Owned(untrack_and_delete_flag_runner));
130
131 Track(id, flag);
132 return id;
133 }
134
TryCancel(TaskId id)135 void CancelableTaskTracker::TryCancel(TaskId id) {
136 DCHECK(sequence_checker_.CalledOnValidSequence());
137
138 const auto it = task_flags_.find(id);
139 if (it == task_flags_.end()) {
140 // Two possibilities:
141 //
142 // 1. The task has already been untracked.
143 // 2. The TaskId is bad or unknown.
144 //
145 // Since this function is best-effort, it's OK to ignore these.
146 return;
147 }
148 it->second->Set();
149 }
150
TryCancelAll()151 void CancelableTaskTracker::TryCancelAll() {
152 DCHECK(sequence_checker_.CalledOnValidSequence());
153 for (const auto& it : task_flags_)
154 it.second->Set();
155 weak_factory_.InvalidateWeakPtrs();
156 task_flags_.clear();
157 }
158
HasTrackedTasks() const159 bool CancelableTaskTracker::HasTrackedTasks() const {
160 DCHECK(sequence_checker_.CalledOnValidSequence());
161 return !task_flags_.empty();
162 }
163
Track(TaskId id,CancellationFlag * flag)164 void CancelableTaskTracker::Track(TaskId id, CancellationFlag* flag) {
165 DCHECK(sequence_checker_.CalledOnValidSequence());
166 bool success = task_flags_.insert(std::make_pair(id, flag)).second;
167 DCHECK(success);
168 }
169
Untrack(TaskId id)170 void CancelableTaskTracker::Untrack(TaskId id) {
171 DCHECK(sequence_checker_.CalledOnValidSequence());
172 size_t num = task_flags_.erase(id);
173 DCHECK_EQ(1u, num);
174 }
175
176 } // namespace base
177