blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 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 | |
avi | a6a6a68 | 2015-12-27 07:15:14 +0900 | [diff] [blame] | 7 | #include <stddef.h> |
| 8 | |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 9 | #include <utility> |
| 10 | |
Peter Kasting | 88430fa | 2018-02-13 15:22:40 +0900 | [diff] [blame] | 11 | #include "base/bind.h" |
| 12 | #include "base/bind_helpers.h" |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 13 | #include "base/callback_helpers.h" |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 14 | #include "base/location.h" |
| 15 | #include "base/memory/ref_counted.h" |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 16 | #include "base/synchronization/cancellation_flag.h" |
| 17 | #include "base/task_runner.h" |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 18 | #include "base/threading/sequenced_task_runner_handle.h" |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 19 | |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 20 | namespace base { |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 21 | |
| 22 | namespace { |
| 23 | |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 24 | void RunIfNotCanceled(const CancellationFlag* flag, OnceClosure task) { |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 25 | if (!flag->IsSet()) |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 26 | std::move(task).Run(); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 27 | } |
| 28 | |
| 29 | void RunIfNotCanceledThenUntrack(const CancellationFlag* flag, |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 30 | OnceClosure task, |
| 31 | OnceClosure untrack) { |
| 32 | RunIfNotCanceled(flag, std::move(task)); |
| 33 | std::move(untrack).Run(); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 34 | } |
| 35 | |
| 36 | bool IsCanceled(const CancellationFlag* flag, |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 37 | ScopedClosureRunner* cleanup_runner) { |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 38 | return flag->IsSet(); |
| 39 | } |
| 40 | |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 41 | void RunAndDeleteFlag(OnceClosure closure, const CancellationFlag* flag) { |
| 42 | std::move(closure).Run(); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 43 | delete flag; |
| 44 | } |
| 45 | |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 46 | void RunOrPostToTaskRunner(TaskRunner* task_runner, OnceClosure closure) { |
Yeol | 0d4f3eb | 2017-07-26 02:09:10 +0900 | [diff] [blame] | 47 | if (task_runner->RunsTasksInCurrentSequence()) |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 48 | std::move(closure).Run(); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 49 | else |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 50 | task_runner->PostTask(FROM_HERE, std::move(closure)); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 51 | } |
| 52 | |
| 53 | } // namespace |
| 54 | |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 55 | // static |
| 56 | const CancelableTaskTracker::TaskId CancelableTaskTracker::kBadTaskId = 0; |
| 57 | |
| 58 | CancelableTaskTracker::CancelableTaskTracker() |
kulkarni.a | 5df678e | 2014-09-13 17:49:34 +0900 | [diff] [blame] | 59 | : next_id_(1),weak_factory_(this) {} |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 60 | |
| 61 | CancelableTaskTracker::~CancelableTaskTracker() { |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 62 | DCHECK(sequence_checker_.CalledOnValidSequence()); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 63 | |
| 64 | TryCancelAll(); |
| 65 | } |
| 66 | |
| 67 | CancelableTaskTracker::TaskId CancelableTaskTracker::PostTask( |
| 68 | TaskRunner* task_runner, |
Brett Wilson | 89388db | 2017-09-12 14:22:16 +0900 | [diff] [blame] | 69 | const Location& from_here, |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 70 | OnceClosure task) { |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 71 | DCHECK(sequence_checker_.CalledOnValidSequence()); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 72 | |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 73 | return PostTaskAndReply(task_runner, from_here, std::move(task), |
| 74 | BindOnce(&DoNothing)); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 75 | } |
| 76 | |
| 77 | CancelableTaskTracker::TaskId CancelableTaskTracker::PostTaskAndReply( |
| 78 | TaskRunner* task_runner, |
Brett Wilson | 89388db | 2017-09-12 14:22:16 +0900 | [diff] [blame] | 79 | const Location& from_here, |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 80 | OnceClosure task, |
| 81 | OnceClosure reply) { |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 82 | DCHECK(sequence_checker_.CalledOnValidSequence()); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 83 | |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 84 | // We need a SequencedTaskRunnerHandle to run |reply|. |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 85 | DCHECK(SequencedTaskRunnerHandle::IsSet()); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 86 | |
| 87 | // Owned by reply callback below. |
| 88 | CancellationFlag* flag = new CancellationFlag(); |
| 89 | |
| 90 | TaskId id = next_id_; |
avi | a6a6a68 | 2015-12-27 07:15:14 +0900 | [diff] [blame] | 91 | next_id_++; // int64_t is big enough that we ignore the potential overflow. |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 92 | |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 93 | OnceClosure untrack_closure = |
| 94 | BindOnce(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id); |
tzik | ec39442 | 2017-02-08 21:29:47 +0900 | [diff] [blame] | 95 | bool success = task_runner->PostTaskAndReply( |
tzik | 6bdbeb2 | 2017-04-12 00:00:44 +0900 | [diff] [blame] | 96 | from_here, BindOnce(&RunIfNotCanceled, flag, std::move(task)), |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 97 | BindOnce(&RunIfNotCanceledThenUntrack, Owned(flag), std::move(reply), |
| 98 | std::move(untrack_closure))); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 99 | |
| 100 | if (!success) |
| 101 | return kBadTaskId; |
| 102 | |
| 103 | Track(id, flag); |
| 104 | return id; |
| 105 | } |
| 106 | |
| 107 | CancelableTaskTracker::TaskId CancelableTaskTracker::NewTrackedTaskId( |
| 108 | IsCanceledCallback* is_canceled_cb) { |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 109 | DCHECK(sequence_checker_.CalledOnValidSequence()); |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 110 | DCHECK(SequencedTaskRunnerHandle::IsSet()); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 111 | |
| 112 | TaskId id = next_id_; |
avi | a6a6a68 | 2015-12-27 07:15:14 +0900 | [diff] [blame] | 113 | next_id_++; // int64_t is big enough that we ignore the potential overflow. |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 114 | |
| 115 | // Will be deleted by |untrack_and_delete_flag| after Untrack(). |
| 116 | CancellationFlag* flag = new CancellationFlag(); |
| 117 | |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 118 | OnceClosure untrack_and_delete_flag = BindOnce( |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 119 | &RunAndDeleteFlag, |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 120 | BindOnce(&CancelableTaskTracker::Untrack, weak_factory_.GetWeakPtr(), id), |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 121 | flag); |
| 122 | |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 123 | // Will always run |untrack_and_delete_flag| on current sequence. |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 124 | ScopedClosureRunner* untrack_and_delete_flag_runner = |
Claudio DeSouza | 1181b42 | 2018-02-22 02:27:16 +0900 | [diff] [blame^] | 125 | new ScopedClosureRunner(BindOnce( |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 126 | &RunOrPostToTaskRunner, RetainedRef(SequencedTaskRunnerHandle::Get()), |
Claudio DeSouza | 1181b42 | 2018-02-22 02:27:16 +0900 | [diff] [blame^] | 127 | std::move(untrack_and_delete_flag))); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 128 | |
| 129 | *is_canceled_cb = |
tzik | 63997c8 | 2017-04-18 03:58:19 +0900 | [diff] [blame] | 130 | Bind(&IsCanceled, flag, Owned(untrack_and_delete_flag_runner)); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 131 | |
| 132 | Track(id, flag); |
| 133 | return id; |
| 134 | } |
| 135 | |
| 136 | void CancelableTaskTracker::TryCancel(TaskId id) { |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 137 | DCHECK(sequence_checker_.CalledOnValidSequence()); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 138 | |
brettw | 0b7bff3 | 2017-04-28 04:42:32 +0900 | [diff] [blame] | 139 | const auto it = task_flags_.find(id); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 140 | 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 | |
| 152 | void CancelableTaskTracker::TryCancelAll() { |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 153 | DCHECK(sequence_checker_.CalledOnValidSequence()); |
brettw | 0b7bff3 | 2017-04-28 04:42:32 +0900 | [diff] [blame] | 154 | for (const auto& it : task_flags_) |
| 155 | it.second->Set(); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 156 | } |
| 157 | |
| 158 | bool CancelableTaskTracker::HasTrackedTasks() const { |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 159 | DCHECK(sequence_checker_.CalledOnValidSequence()); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 160 | return !task_flags_.empty(); |
| 161 | } |
| 162 | |
| 163 | void CancelableTaskTracker::Track(TaskId id, CancellationFlag* flag) { |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 164 | DCHECK(sequence_checker_.CalledOnValidSequence()); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 165 | bool success = task_flags_.insert(std::make_pair(id, flag)).second; |
| 166 | DCHECK(success); |
| 167 | } |
| 168 | |
| 169 | void CancelableTaskTracker::Untrack(TaskId id) { |
fdoray | c3edd89 | 2016-12-21 22:02:08 +0900 | [diff] [blame] | 170 | DCHECK(sequence_checker_.CalledOnValidSequence()); |
blundell@chromium.org | 00b7598 | 2014-02-06 22:47:13 +0900 | [diff] [blame] | 171 | size_t num = task_flags_.erase(id); |
| 172 | DCHECK_EQ(1u, num); |
| 173 | } |
| 174 | |
| 175 | } // namespace base |