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