blob: 076a684f18438caa4a9ed9f8641ddf395c5d3c45 [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
Peter Kasting24efe5e2018-02-24 09:03:01 +090073 return PostTaskAndReply(task_runner, from_here, std::move(task), DoNothing());
blundell@chromium.org00b75982014-02-06 22:47:13 +090074}
75
76CancelableTaskTracker::TaskId CancelableTaskTracker::PostTaskAndReply(
77 TaskRunner* task_runner,
Brett Wilson89388db2017-09-12 14:22:16 +090078 const Location& from_here,
tzik63997c82017-04-18 03:58:19 +090079 OnceClosure task,
80 OnceClosure reply) {
fdorayc3edd892016-12-21 22:02:08 +090081 DCHECK(sequence_checker_.CalledOnValidSequence());
blundell@chromium.org00b75982014-02-06 22:47:13 +090082
fdorayc3edd892016-12-21 22:02:08 +090083 // We need a SequencedTaskRunnerHandle to run |reply|.
tzik63997c82017-04-18 03:58:19 +090084 DCHECK(SequencedTaskRunnerHandle::IsSet());
blundell@chromium.org00b75982014-02-06 22:47:13 +090085
86 // Owned by reply callback below.
87 CancellationFlag* flag = new CancellationFlag();
88
89 TaskId id = next_id_;
avia6a6a682015-12-27 07:15:14 +090090 next_id_++; // int64_t is big enough that we ignore the potential overflow.
blundell@chromium.org00b75982014-02-06 22:47:13 +090091
tzik63997c82017-04-18 03:58:19 +090092 OnceClosure untrack_closure =
93 BindOnce(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id);
tzikec394422017-02-08 21:29:47 +090094 bool success = task_runner->PostTaskAndReply(
tzik6bdbeb22017-04-12 00:00:44 +090095 from_here, BindOnce(&RunIfNotCanceled, flag, std::move(task)),
tzik63997c82017-04-18 03:58:19 +090096 BindOnce(&RunIfNotCanceledThenUntrack, Owned(flag), std::move(reply),
97 std::move(untrack_closure)));
blundell@chromium.org00b75982014-02-06 22:47:13 +090098
99 if (!success)
100 return kBadTaskId;
101
102 Track(id, flag);
103 return id;
104}
105
106CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId(
107 IsCanceledCallback* is_canceled_cb) {
fdorayc3edd892016-12-21 22:02:08 +0900108 DCHECK(sequence_checker_.CalledOnValidSequence());
tzik63997c82017-04-18 03:58:19 +0900109 DCHECK(SequencedTaskRunnerHandle::IsSet());
blundell@chromium.org00b75982014-02-06 22:47:13 +0900110
111 TaskId id = next_id_;
avia6a6a682015-12-27 07:15:14 +0900112 next_id_++; // int64_t is big enough that we ignore the potential overflow.
blundell@chromium.org00b75982014-02-06 22:47:13 +0900113
114 // Will be deleted by |untrack_and_delete_flag| after Untrack().
115 CancellationFlag* flag = new CancellationFlag();
116
tzik63997c82017-04-18 03:58:19 +0900117 OnceClosure untrack_and_delete_flag = BindOnce(
blundell@chromium.org00b75982014-02-06 22:47:13 +0900118 &RunAndDeleteFlag,
tzik63997c82017-04-18 03:58:19 +0900119 BindOnce(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id),
blundell@chromium.org00b75982014-02-06 22:47:13 +0900120 flag);
121
fdorayc3edd892016-12-21 22:02:08 +0900122 // Will always run |untrack_and_delete_flag| on current sequence.
tzik63997c82017-04-18 03:58:19 +0900123 ScopedClosureRunner* untrack_and_delete_flag_runner =
Claudio DeSouza1181b422018-02-22 02:27:16 +0900124 new ScopedClosureRunner(BindOnce(
tzik63997c82017-04-18 03:58:19 +0900125 &RunOrPostToTaskRunner, RetainedRef(SequencedTaskRunnerHandle::Get()),
Claudio DeSouza1181b422018-02-22 02:27:16 +0900126 std::move(untrack_and_delete_flag)));
blundell@chromium.org00b75982014-02-06 22:47:13 +0900127
128 *is_canceled_cb =
tzik63997c82017-04-18 03:58:19 +0900129 Bind(&IsCanceled, flag, Owned(untrack_and_delete_flag_runner));
blundell@chromium.org00b75982014-02-06 22:47:13 +0900130
131 Track(id, flag);
132 return id;
133}
134
135void CancelableTaskTracker::TryCancel(TaskId id) {
fdorayc3edd892016-12-21 22:02:08 +0900136 DCHECK(sequence_checker_.CalledOnValidSequence());
blundell@chromium.org00b75982014-02-06 22:47:13 +0900137
brettw0b7bff32017-04-28 04:42:32 +0900138 const auto it = task_flags_.find(id);
blundell@chromium.org00b75982014-02-06 22:47:13 +0900139 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
151void CancelableTaskTracker::TryCancelAll() {
fdorayc3edd892016-12-21 22:02:08 +0900152 DCHECK(sequence_checker_.CalledOnValidSequence());
brettw0b7bff32017-04-28 04:42:32 +0900153 for (const auto& it : task_flags_)
154 it.second->Set();
blundell@chromium.org00b75982014-02-06 22:47:13 +0900155}
156
157bool CancelableTaskTracker::HasTrackedTasks() const {
fdorayc3edd892016-12-21 22:02:08 +0900158 DCHECK(sequence_checker_.CalledOnValidSequence());
blundell@chromium.org00b75982014-02-06 22:47:13 +0900159 return !task_flags_.empty();
160}
161
162void CancelableTaskTracker::Track(TaskId id, CancellationFlag* flag) {
fdorayc3edd892016-12-21 22:02:08 +0900163 DCHECK(sequence_checker_.CalledOnValidSequence());
blundell@chromium.org00b75982014-02-06 22:47:13 +0900164 bool success = task_flags_.insert(std::make_pair(id, flag)).second;
165 DCHECK(success);
166}
167
168void CancelableTaskTracker::Untrack(TaskId id) {
fdorayc3edd892016-12-21 22:02:08 +0900169 DCHECK(sequence_checker_.CalledOnValidSequence());
blundell@chromium.org00b75982014-02-06 22:47:13 +0900170 size_t num = task_flags_.erase(id);
171 DCHECK_EQ(1u, num);
172}
173
174} // namespace base