xref: /aosp_15_r20/external/libchrome/base/task/cancelable_task_tracker.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
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