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