blob: ddc997e6dc08745a1fe6bc1d957ae41a3128ad12 [file] [log] [blame]
blundell@chromium.org00b75982014-02-06 22:47:13 +09001// 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
avia6a6a682015-12-27 07:15:14 +09007#include <stddef.h>
8
blundell@chromium.org00b75982014-02-06 22:47:13 +09009#include <utility>
10
Peter Kasting88430fa2018-02-13 15:22:40 +090011#include "base/bind.h"
12#include "base/bind_helpers.h"
blundell@chromium.org00b75982014-02-06 22:47:13 +090013#include "base/callback_helpers.h"
blundell@chromium.org00b75982014-02-06 22:47:13 +090014#include "base/location.h"
15#include "base/memory/ref_counted.h"
blundell@chromium.org00b75982014-02-06 22:47:13 +090016#include "base/synchronization/cancellation_flag.h"
17#include "base/task_runner.h"
fdorayc3edd892016-12-21 22:02:08 +090018#include "base/threading/sequenced_task_runner_handle.h"
blundell@chromium.org00b75982014-02-06 22:47:13 +090019
fdorayc3edd892016-12-21 22:02:08 +090020namespace base {
blundell@chromium.org00b75982014-02-06 22:47:13 +090021
22namespace {
23
tzik63997c82017-04-18 03:58:19 +090024void RunIfNotCanceled(const CancellationFlag* flag, OnceClosure task) {
blundell@chromium.org00b75982014-02-06 22:47:13 +090025 if (!flag->IsSet())
tzik63997c82017-04-18 03:58:19 +090026 std::move(task).Run();
blundell@chromium.org00b75982014-02-06 22:47:13 +090027}
28
29void RunIfNotCanceledThenUntrack(const CancellationFlag* flag,
tzik63997c82017-04-18 03:58:19 +090030 OnceClosure task,
31 OnceClosure untrack) {
32 RunIfNotCanceled(flag, std::move(task));
33 std::move(untrack).Run();
blundell@chromium.org00b75982014-02-06 22:47:13 +090034}
35
36bool IsCanceled(const CancellationFlag* flag,
tzik63997c82017-04-18 03:58:19 +090037 ScopedClosureRunner* cleanup_runner) {
blundell@chromium.org00b75982014-02-06 22:47:13 +090038 return flag->IsSet();
39}
40
tzik63997c82017-04-18 03:58:19 +090041void RunAndDeleteFlag(OnceClosure closure, const CancellationFlag* flag) {
42 std::move(closure).Run();
blundell@chromium.org00b75982014-02-06 22:47:13 +090043 delete flag;
44}
45
tzik63997c82017-04-18 03:58:19 +090046void RunOrPostToTaskRunner(TaskRunner* task_runner, OnceClosure closure) {
Yeol0d4f3eb2017-07-26 02:09:10 +090047 if (task_runner->RunsTasksInCurrentSequence())
tzik63997c82017-04-18 03:58:19 +090048 std::move(closure).Run();
blundell@chromium.org00b75982014-02-06 22:47:13 +090049 else
tzik63997c82017-04-18 03:58:19 +090050 task_runner->PostTask(FROM_HERE, std::move(closure));
blundell@chromium.org00b75982014-02-06 22:47:13 +090051}
52
53} // namespace
54
blundell@chromium.org00b75982014-02-06 22:47:13 +090055// static
56const CancelableTaskTracker::TaskId CancelableTaskTracker::kBadTaskId = 0;
57
58CancelableTaskTracker::CancelableTaskTracker()
kulkarni.a5df678e2014-09-13 17:49:34 +090059 : next_id_(1),weak_factory_(this) {}
blundell@chromium.org00b75982014-02-06 22:47:13 +090060
61CancelableTaskTracker::~CancelableTaskTracker() {
fdorayc3edd892016-12-21 22:02:08 +090062 DCHECK(sequence_checker_.CalledOnValidSequence());
blundell@chromium.org00b75982014-02-06 22:47:13 +090063
64 TryCancelAll();
65}
66
67CancelableTaskTracker::TaskId CancelableTaskTracker::PostTask(
68 TaskRunner* task_runner,
Brett Wilson89388db2017-09-12 14:22:16 +090069 const Location& from_here,
tzik63997c82017-04-18 03:58:19 +090070 OnceClosure task) {
fdorayc3edd892016-12-21 22:02:08 +090071 DCHECK(sequence_checker_.CalledOnValidSequence());
blundell@chromium.org00b75982014-02-06 22:47:13 +090072
tzik63997c82017-04-18 03:58:19 +090073 return PostTaskAndReply(task_runner, from_here, std::move(task),
74 BindOnce(&DoNothing));
blundell@chromium.org00b75982014-02-06 22:47:13 +090075}
76
77CancelableTaskTracker::TaskId CancelableTaskTracker::PostTaskAndReply(
78 TaskRunner* task_runner,
Brett Wilson89388db2017-09-12 14:22:16 +090079 const Location& from_here,
tzik63997c82017-04-18 03:58:19 +090080 OnceClosure task,
81 OnceClosure reply) {
fdorayc3edd892016-12-21 22:02:08 +090082 DCHECK(sequence_checker_.CalledOnValidSequence());
blundell@chromium.org00b75982014-02-06 22:47:13 +090083
fdorayc3edd892016-12-21 22:02:08 +090084 // We need a SequencedTaskRunnerHandle to run |reply|.
tzik63997c82017-04-18 03:58:19 +090085 DCHECK(SequencedTaskRunnerHandle::IsSet());
blundell@chromium.org00b75982014-02-06 22:47:13 +090086
87 // Owned by reply callback below.
88 CancellationFlag* flag = new CancellationFlag();
89
90 TaskId id = next_id_;
avia6a6a682015-12-27 07:15:14 +090091 next_id_++; // int64_t is big enough that we ignore the potential overflow.
blundell@chromium.org00b75982014-02-06 22:47:13 +090092
tzik63997c82017-04-18 03:58:19 +090093 OnceClosure untrack_closure =
94 BindOnce(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id);
tzikec394422017-02-08 21:29:47 +090095 bool success = task_runner->PostTaskAndReply(
tzik6bdbeb22017-04-12 00:00:44 +090096 from_here, BindOnce(&RunIfNotCanceled, flag, std::move(task)),
tzik63997c82017-04-18 03:58:19 +090097 BindOnce(&RunIfNotCanceledThenUntrack, Owned(flag), std::move(reply),
98 std::move(untrack_closure)));
blundell@chromium.org00b75982014-02-06 22:47:13 +090099
100 if (!success)
101 return kBadTaskId;
102
103 Track(id, flag);
104 return id;
105}
106
107CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId(
108 IsCanceledCallback* is_canceled_cb) {
fdorayc3edd892016-12-21 22:02:08 +0900109 DCHECK(sequence_checker_.CalledOnValidSequence());
tzik63997c82017-04-18 03:58:19 +0900110 DCHECK(SequencedTaskRunnerHandle::IsSet());
blundell@chromium.org00b75982014-02-06 22:47:13 +0900111
112 TaskId id = next_id_;
avia6a6a682015-12-27 07:15:14 +0900113 next_id_++; // int64_t is big enough that we ignore the potential overflow.
blundell@chromium.org00b75982014-02-06 22:47:13 +0900114
115 // Will be deleted by |untrack_and_delete_flag| after Untrack().
116 CancellationFlag* flag = new CancellationFlag();
117
tzik63997c82017-04-18 03:58:19 +0900118 OnceClosure untrack_and_delete_flag = BindOnce(
blundell@chromium.org00b75982014-02-06 22:47:13 +0900119 &RunAndDeleteFlag,
tzik63997c82017-04-18 03:58:19 +0900120 BindOnce(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id),
blundell@chromium.org00b75982014-02-06 22:47:13 +0900121 flag);
122
fdorayc3edd892016-12-21 22:02:08 +0900123 // Will always run |untrack_and_delete_flag| on current sequence.
tzik63997c82017-04-18 03:58:19 +0900124 ScopedClosureRunner* untrack_and_delete_flag_runner =
Claudio DeSouza1181b422018-02-22 02:27:16 +0900125 new ScopedClosureRunner(BindOnce(
tzik63997c82017-04-18 03:58:19 +0900126 &RunOrPostToTaskRunner, RetainedRef(SequencedTaskRunnerHandle::Get()),
Claudio DeSouza1181b422018-02-22 02:27:16 +0900127 std::move(untrack_and_delete_flag)));
blundell@chromium.org00b75982014-02-06 22:47:13 +0900128
129 *is_canceled_cb =
tzik63997c82017-04-18 03:58:19 +0900130 Bind(&IsCanceled, flag, Owned(untrack_and_delete_flag_runner));
blundell@chromium.org00b75982014-02-06 22:47:13 +0900131
132 Track(id, flag);
133 return id;
134}
135
136void CancelableTaskTracker::TryCancel(TaskId id) {
fdorayc3edd892016-12-21 22:02:08 +0900137 DCHECK(sequence_checker_.CalledOnValidSequence());
blundell@chromium.org00b75982014-02-06 22:47:13 +0900138
brettw0b7bff32017-04-28 04:42:32 +0900139 const auto it = task_flags_.find(id);
blundell@chromium.org00b75982014-02-06 22:47:13 +0900140 if (it == task_flags_.end()) {
141 // Two possibilities:
142 //
143 // 1. The task has already been untracked.
144 // 2. The TaskId is bad or unknown.
145 //
146 // Since this function is best-effort, it's OK to ignore these.
147 return;
148 }
149 it->second->Set();
150}
151
152void CancelableTaskTracker::TryCancelAll() {
fdorayc3edd892016-12-21 22:02:08 +0900153 DCHECK(sequence_checker_.CalledOnValidSequence());
brettw0b7bff32017-04-28 04:42:32 +0900154 for (const auto& it : task_flags_)
155 it.second->Set();
blundell@chromium.org00b75982014-02-06 22:47:13 +0900156}
157
158bool CancelableTaskTracker::HasTrackedTasks() const {
fdorayc3edd892016-12-21 22:02:08 +0900159 DCHECK(sequence_checker_.CalledOnValidSequence());
blundell@chromium.org00b75982014-02-06 22:47:13 +0900160 return !task_flags_.empty();
161}
162
163void CancelableTaskTracker::Track(TaskId id, CancellationFlag* flag) {
fdorayc3edd892016-12-21 22:02:08 +0900164 DCHECK(sequence_checker_.CalledOnValidSequence());
blundell@chromium.org00b75982014-02-06 22:47:13 +0900165 bool success = task_flags_.insert(std::make_pair(id, flag)).second;
166 DCHECK(success);
167}
168
169void CancelableTaskTracker::Untrack(TaskId id) {
fdorayc3edd892016-12-21 22:02:08 +0900170 DCHECK(sequence_checker_.CalledOnValidSequence());
blundell@chromium.org00b75982014-02-06 22:47:13 +0900171 size_t num = task_flags_.erase(id);
172 DCHECK_EQ(1u, num);
173}
174
175} // namespace base