xref: /aosp_15_r20/external/cronet/base/task/cancelable_task_tracker.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2014 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker // CancelableTaskTracker posts tasks (in the form of a OnceClosure) to a
6*6777b538SAndroid Build Coastguard Worker // TaskRunner, and is able to cancel the task later if it's not needed
7*6777b538SAndroid Build Coastguard Worker // anymore.  On destruction, CancelableTaskTracker will cancel all
8*6777b538SAndroid Build Coastguard Worker // tracked tasks.
9*6777b538SAndroid Build Coastguard Worker //
10*6777b538SAndroid Build Coastguard Worker // Each cancelable task can be associated with a reply (also a OnceClosure).
11*6777b538SAndroid Build Coastguard Worker // After the task is run on the TaskRunner, |reply| will be posted back to
12*6777b538SAndroid Build Coastguard Worker // originating TaskRunner.
13*6777b538SAndroid Build Coastguard Worker //
14*6777b538SAndroid Build Coastguard Worker // NOTE:
15*6777b538SAndroid Build Coastguard Worker //
16*6777b538SAndroid Build Coastguard Worker // CancelableOnceCallback (base/cancelable_callback.h) and WeakPtr binding are
17*6777b538SAndroid Build Coastguard Worker // preferred solutions for canceling a task. However, they don't support
18*6777b538SAndroid Build Coastguard Worker // cancelation from another sequence. This is sometimes a performance critical
19*6777b538SAndroid Build Coastguard Worker // requirement. E.g. We need to cancel database lookup task on DB thread when
20*6777b538SAndroid Build Coastguard Worker // user changes inputted text. If it is performance critical to do a best effort
21*6777b538SAndroid Build Coastguard Worker // cancelation of a task, then CancelableTaskTracker is appropriate, otherwise
22*6777b538SAndroid Build Coastguard Worker // use one of the other mechanisms.
23*6777b538SAndroid Build Coastguard Worker //
24*6777b538SAndroid Build Coastguard Worker // THREAD-SAFETY:
25*6777b538SAndroid Build Coastguard Worker //
26*6777b538SAndroid Build Coastguard Worker // 1. A CancelableTaskTracker object must be created, used, and destroyed on a
27*6777b538SAndroid Build Coastguard Worker //    single sequence.
28*6777b538SAndroid Build Coastguard Worker //
29*6777b538SAndroid Build Coastguard Worker // 2. It's safe to destroy a CancelableTaskTracker while there are outstanding
30*6777b538SAndroid Build Coastguard Worker //    tasks. This is commonly used to cancel all outstanding tasks.
31*6777b538SAndroid Build Coastguard Worker //
32*6777b538SAndroid Build Coastguard Worker // 3. The task is deleted on the target sequence, and the reply are deleted on
33*6777b538SAndroid Build Coastguard Worker //    the originating sequence.
34*6777b538SAndroid Build Coastguard Worker //
35*6777b538SAndroid Build Coastguard Worker // 4. IsCanceledCallback can be run or deleted on any sequence.
36*6777b538SAndroid Build Coastguard Worker #ifndef BASE_TASK_CANCELABLE_TASK_TRACKER_H_
37*6777b538SAndroid Build Coastguard Worker #define BASE_TASK_CANCELABLE_TASK_TRACKER_H_
38*6777b538SAndroid Build Coastguard Worker 
39*6777b538SAndroid Build Coastguard Worker #include <stdint.h>
40*6777b538SAndroid Build Coastguard Worker 
41*6777b538SAndroid Build Coastguard Worker #include <memory>
42*6777b538SAndroid Build Coastguard Worker #include <utility>
43*6777b538SAndroid Build Coastguard Worker 
44*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h"
45*6777b538SAndroid Build Coastguard Worker #include "base/containers/small_map.h"
46*6777b538SAndroid Build Coastguard Worker #include "base/functional/bind.h"
47*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback.h"
48*6777b538SAndroid Build Coastguard Worker #include "base/functional/callback_helpers.h"
49*6777b538SAndroid Build Coastguard Worker #include "base/memory/ref_counted.h"
50*6777b538SAndroid Build Coastguard Worker #include "base/memory/weak_ptr.h"
51*6777b538SAndroid Build Coastguard Worker #include "base/sequence_checker.h"
52*6777b538SAndroid Build Coastguard Worker #include "base/synchronization/atomic_flag.h"
53*6777b538SAndroid Build Coastguard Worker #include "base/task/post_task_and_reply_with_result_internal.h"
54*6777b538SAndroid Build Coastguard Worker 
55*6777b538SAndroid Build Coastguard Worker namespace base {
56*6777b538SAndroid Build Coastguard Worker 
57*6777b538SAndroid Build Coastguard Worker class Location;
58*6777b538SAndroid Build Coastguard Worker class ScopedClosureRunner;
59*6777b538SAndroid Build Coastguard Worker class TaskRunner;
60*6777b538SAndroid Build Coastguard Worker 
61*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT CancelableTaskTracker {
62*6777b538SAndroid Build Coastguard Worker  public:
63*6777b538SAndroid Build Coastguard Worker   // All values except kBadTaskId are valid.
64*6777b538SAndroid Build Coastguard Worker   typedef int64_t TaskId;
65*6777b538SAndroid Build Coastguard Worker   static const TaskId kBadTaskId;
66*6777b538SAndroid Build Coastguard Worker 
67*6777b538SAndroid Build Coastguard Worker   using IsCanceledCallback = RepeatingCallback<bool()>;
68*6777b538SAndroid Build Coastguard Worker 
69*6777b538SAndroid Build Coastguard Worker   CancelableTaskTracker();
70*6777b538SAndroid Build Coastguard Worker 
71*6777b538SAndroid Build Coastguard Worker   CancelableTaskTracker(const CancelableTaskTracker&) = delete;
72*6777b538SAndroid Build Coastguard Worker   CancelableTaskTracker& operator=(const CancelableTaskTracker&) = delete;
73*6777b538SAndroid Build Coastguard Worker 
74*6777b538SAndroid Build Coastguard Worker   // Cancels all tracked tasks.
75*6777b538SAndroid Build Coastguard Worker   ~CancelableTaskTracker();
76*6777b538SAndroid Build Coastguard Worker 
77*6777b538SAndroid Build Coastguard Worker   TaskId PostTask(TaskRunner* task_runner,
78*6777b538SAndroid Build Coastguard Worker                   const Location& from_here,
79*6777b538SAndroid Build Coastguard Worker                   OnceClosure task);
80*6777b538SAndroid Build Coastguard Worker 
81*6777b538SAndroid Build Coastguard Worker   TaskId PostTaskAndReply(TaskRunner* task_runner,
82*6777b538SAndroid Build Coastguard Worker                           const Location& from_here,
83*6777b538SAndroid Build Coastguard Worker                           OnceClosure task,
84*6777b538SAndroid Build Coastguard Worker                           OnceClosure reply);
85*6777b538SAndroid Build Coastguard Worker 
86*6777b538SAndroid Build Coastguard Worker   template <typename TaskReturnType, typename ReplyArgType>
PostTaskAndReplyWithResult(TaskRunner * task_runner,const Location & from_here,OnceCallback<TaskReturnType ()> task,OnceCallback<void (ReplyArgType)> reply)87*6777b538SAndroid Build Coastguard Worker   TaskId PostTaskAndReplyWithResult(TaskRunner* task_runner,
88*6777b538SAndroid Build Coastguard Worker                                     const Location& from_here,
89*6777b538SAndroid Build Coastguard Worker                                     OnceCallback<TaskReturnType()> task,
90*6777b538SAndroid Build Coastguard Worker                                     OnceCallback<void(ReplyArgType)> reply) {
91*6777b538SAndroid Build Coastguard Worker     auto* result = new std::unique_ptr<TaskReturnType>();
92*6777b538SAndroid Build Coastguard Worker     return PostTaskAndReply(
93*6777b538SAndroid Build Coastguard Worker         task_runner, from_here,
94*6777b538SAndroid Build Coastguard Worker         BindOnce(&internal::ReturnAsParamAdapter<TaskReturnType>,
95*6777b538SAndroid Build Coastguard Worker                  std::move(task), Unretained(result)),
96*6777b538SAndroid Build Coastguard Worker         BindOnce(&internal::ReplyAdapter<TaskReturnType, ReplyArgType>,
97*6777b538SAndroid Build Coastguard Worker                  std::move(reply), Owned(result)));
98*6777b538SAndroid Build Coastguard Worker   }
99*6777b538SAndroid Build Coastguard Worker 
100*6777b538SAndroid Build Coastguard Worker   // Creates a tracked TaskId and an associated IsCanceledCallback. Client can
101*6777b538SAndroid Build Coastguard Worker   // later call TryCancel() with the returned TaskId, and run |is_canceled_cb|
102*6777b538SAndroid Build Coastguard Worker   // from any thread to check whether the TaskId is canceled.
103*6777b538SAndroid Build Coastguard Worker   //
104*6777b538SAndroid Build Coastguard Worker   // The returned task ID is tracked until the last copy of
105*6777b538SAndroid Build Coastguard Worker   // |is_canceled_cb| is destroyed.
106*6777b538SAndroid Build Coastguard Worker   //
107*6777b538SAndroid Build Coastguard Worker   // Note. This function is used to address some special cancelation requirement
108*6777b538SAndroid Build Coastguard Worker   // in existing code. You SHOULD NOT need this function in new code.
109*6777b538SAndroid Build Coastguard Worker   TaskId NewTrackedTaskId(IsCanceledCallback* is_canceled_cb);
110*6777b538SAndroid Build Coastguard Worker 
111*6777b538SAndroid Build Coastguard Worker   // After calling this function, |task| and |reply| will not run. If the
112*6777b538SAndroid Build Coastguard Worker   // cancelation happens when |task| is running or has finished running, |reply|
113*6777b538SAndroid Build Coastguard Worker   // will not run. If |reply| is running or has finished running, cancellation
114*6777b538SAndroid Build Coastguard Worker   // is a noop.
115*6777b538SAndroid Build Coastguard Worker   //
116*6777b538SAndroid Build Coastguard Worker   // Note. It's OK to cancel a |task| for more than once. The later calls are
117*6777b538SAndroid Build Coastguard Worker   // noops.
118*6777b538SAndroid Build Coastguard Worker   void TryCancel(TaskId id);
119*6777b538SAndroid Build Coastguard Worker 
120*6777b538SAndroid Build Coastguard Worker   // It's OK to call this function for more than once. The later calls are
121*6777b538SAndroid Build Coastguard Worker   // noops.
122*6777b538SAndroid Build Coastguard Worker   void TryCancelAll();
123*6777b538SAndroid Build Coastguard Worker 
124*6777b538SAndroid Build Coastguard Worker   // Returns true iff there are in-flight tasks that are still being
125*6777b538SAndroid Build Coastguard Worker   // tracked.
126*6777b538SAndroid Build Coastguard Worker   bool HasTrackedTasks() const;
127*6777b538SAndroid Build Coastguard Worker 
128*6777b538SAndroid Build Coastguard Worker  private:
129*6777b538SAndroid Build Coastguard Worker   // Cancellation flags are ref-counted to ensure they remain valid even if the
130*6777b538SAndroid Build Coastguard Worker   // tracker and its calling thread are torn down while there are still
131*6777b538SAndroid Build Coastguard Worker   // cancelable tasks queued to the target TaskRunner.
132*6777b538SAndroid Build Coastguard Worker   // See https://crbug.com/918948.
133*6777b538SAndroid Build Coastguard Worker   using TaskCancellationFlag = RefCountedData<AtomicFlag>;
134*6777b538SAndroid Build Coastguard Worker 
135*6777b538SAndroid Build Coastguard Worker   static void RunIfNotCanceled(const scoped_refptr<TaskCancellationFlag>& flag,
136*6777b538SAndroid Build Coastguard Worker                                OnceClosure task);
137*6777b538SAndroid Build Coastguard Worker   static void RunThenUntrackIfNotCanceled(
138*6777b538SAndroid Build Coastguard Worker       const scoped_refptr<TaskCancellationFlag>& flag,
139*6777b538SAndroid Build Coastguard Worker       OnceClosure task,
140*6777b538SAndroid Build Coastguard Worker       OnceClosure untrack);
141*6777b538SAndroid Build Coastguard Worker   static bool IsCanceled(const scoped_refptr<TaskCancellationFlag>& flag,
142*6777b538SAndroid Build Coastguard Worker                          const ScopedClosureRunner& cleanup_runner);
143*6777b538SAndroid Build Coastguard Worker 
144*6777b538SAndroid Build Coastguard Worker   void Track(TaskId id, scoped_refptr<TaskCancellationFlag> flag);
145*6777b538SAndroid Build Coastguard Worker   void Untrack(TaskId id);
146*6777b538SAndroid Build Coastguard Worker 
147*6777b538SAndroid Build Coastguard Worker   // Typically the number of tasks are 0-2 and occationally 3-4. But since
148*6777b538SAndroid Build Coastguard Worker   // this is a general API that could be used in unexpected ways, use a
149*6777b538SAndroid Build Coastguard Worker   // small_map instead of a flat_map to avoid falling over if there are many
150*6777b538SAndroid Build Coastguard Worker   // tasks.
151*6777b538SAndroid Build Coastguard Worker   small_map<std::map<TaskId, scoped_refptr<TaskCancellationFlag>>, 4>
152*6777b538SAndroid Build Coastguard Worker       task_flags_;
153*6777b538SAndroid Build Coastguard Worker 
154*6777b538SAndroid Build Coastguard Worker   TaskId next_id_ = 1;
155*6777b538SAndroid Build Coastguard Worker   SEQUENCE_CHECKER(sequence_checker_);
156*6777b538SAndroid Build Coastguard Worker 
157*6777b538SAndroid Build Coastguard Worker   // TODO(https://crbug.com/1009795): Remove once crasher is resolved.
158*6777b538SAndroid Build Coastguard Worker   base::WeakPtr<CancelableTaskTracker> weak_this_;
159*6777b538SAndroid Build Coastguard Worker   base::WeakPtrFactory<CancelableTaskTracker> weak_factory_{this};
160*6777b538SAndroid Build Coastguard Worker };
161*6777b538SAndroid Build Coastguard Worker 
162*6777b538SAndroid Build Coastguard Worker }  // namespace base
163*6777b538SAndroid Build Coastguard Worker 
164*6777b538SAndroid Build Coastguard Worker #endif  // BASE_TASK_CANCELABLE_TASK_TRACKER_H_
165