| Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2014 The Chromium Authors |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| kylechar | 01598d7 | 2019-05-21 18:35:31 | [diff] [blame] | 5 | // CancelableTaskTracker posts tasks (in the form of a OnceClosure) to a |
| [email protected] | e95b717f | 2014-02-06 13:47:13 | [diff] [blame] | 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. |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 9 | // |
| kylechar | 01598d7 | 2019-05-21 18:35:31 | [diff] [blame] | 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 |
| [email protected] | e95b717f | 2014-02-06 13:47:13 | [diff] [blame] | 12 | // originating TaskRunner. |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 13 | // |
| 14 | // NOTE: |
| 15 | // |
| Colin Blundell | ea615d42 | 2021-05-12 09:35:41 | [diff] [blame] | 16 | // CancelableOnceCallback (base/cancelable_callback.h) and WeakPtr binding are |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 17 | // preferred solutions for canceling a task. However, they don't support |
| fdoray | 6661c52 | 2016-12-21 13:02:08 | [diff] [blame] | 18 | // cancelation from another sequence. This is sometimes a performance critical |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 19 | // requirement. E.g. We need to cancel database lookup task on DB thread when |
| Colin Blundell | ea615d42 | 2021-05-12 09:35:41 | [diff] [blame] | 20 | // user changes inputted text. If it is performance critical to do a best effort |
| fdoray | 6661c52 | 2016-12-21 13:02:08 | [diff] [blame] | 21 | // cancelation of a task, then CancelableTaskTracker is appropriate, otherwise |
| 22 | // use one of the other mechanisms. |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 23 | // |
| 24 | // THREAD-SAFETY: |
| 25 | // |
| fdoray | 6661c52 | 2016-12-21 13:02:08 | [diff] [blame] | 26 | // 1. A CancelableTaskTracker object must be created, used, and destroyed on a |
| 27 | // single sequence. |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 28 | // |
| fdoray | 6661c52 | 2016-12-21 13:02:08 | [diff] [blame] | 29 | // 2. It's safe to destroy a CancelableTaskTracker while there are outstanding |
| 30 | // tasks. This is commonly used to cancel all outstanding tasks. |
| [email protected] | 4f1935e | 2012-11-16 23:10:07 | [diff] [blame] | 31 | // |
| tzik | d773cb47 | 2017-04-17 18:58:19 | [diff] [blame] | 32 | // 3. The task is deleted on the target sequence, and the reply are deleted on |
| 33 | // the originating sequence. |
| fdoray | 6661c52 | 2016-12-21 13:02:08 | [diff] [blame] | 34 | // |
| 35 | // 4. IsCanceledCallback can be run or deleted on any sequence. |
| [email protected] | e95b717f | 2014-02-06 13:47:13 | [diff] [blame] | 36 | #ifndef BASE_TASK_CANCELABLE_TASK_TRACKER_H_ |
| 37 | #define BASE_TASK_CANCELABLE_TASK_TRACKER_H_ |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 38 | |
| avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 39 | #include <stdint.h> |
| 40 | |
| Mikel Astiz | c076a97 | 2018-07-25 13:49:25 | [diff] [blame] | 41 | #include <memory> |
| tzik | 0352751 | 2017-02-08 12:29:47 | [diff] [blame] | 42 | #include <utility> |
| 43 | |
| [email protected] | e95b717f | 2014-02-06 13:47:13 | [diff] [blame] | 44 | #include "base/base_export.h" |
| brettw | 1ce49f6 | 2017-04-27 19:42:32 | [diff] [blame] | 45 | #include "base/containers/small_map.h" |
| Avi Drissman | 63e1f99 | 2023-01-13 18:54:43 | [diff] [blame] | 46 | #include "base/functional/bind.h" |
| 47 | #include "base/functional/callback.h" |
| 48 | #include "base/functional/callback_helpers.h" |
| Wez | 77d9d10 | 2019-01-10 00:20:21 | [diff] [blame] | 49 | #include "base/memory/ref_counted.h" |
| Wez | 50cbb92 | 2019-12-05 20:40:41 | [diff] [blame] | 50 | #include "base/memory/weak_ptr.h" |
| fdoray | 6661c52 | 2016-12-21 13:02:08 | [diff] [blame] | 51 | #include "base/sequence_checker.h" |
| Wez | 77d9d10 | 2019-01-10 00:20:21 | [diff] [blame] | 52 | #include "base/synchronization/atomic_flag.h" |
| Patrick Monette | 643cdf6 | 2021-10-15 19:13:42 | [diff] [blame] | 53 | #include "base/task/post_task_and_reply_with_result_internal.h" |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 54 | |
| [email protected] | e95b717f | 2014-02-06 13:47:13 | [diff] [blame] | 55 | namespace base { |
| 56 | |
| Brett Wilson | abbb960 | 2017-09-11 23:26:39 | [diff] [blame] | 57 | class Location; |
| Wez | 77d9d10 | 2019-01-10 00:20:21 | [diff] [blame] | 58 | class ScopedClosureRunner; |
| [email protected] | e95b717f | 2014-02-06 13:47:13 | [diff] [blame] | 59 | class TaskRunner; |
| 60 | |
| 61 | class BASE_EXPORT CancelableTaskTracker { |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 62 | public: |
| 63 | // All values except kBadTaskId are valid. |
| avi | 9b6f4293 | 2015-12-26 22:15:14 | [diff] [blame] | 64 | typedef int64_t TaskId; |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 65 | static const TaskId kBadTaskId; |
| 66 | |
| kylechar | 01598d7 | 2019-05-21 18:35:31 | [diff] [blame] | 67 | using IsCanceledCallback = RepeatingCallback<bool()>; |
| [email protected] | 4f1935e | 2012-11-16 23:10:07 | [diff] [blame] | 68 | |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 69 | CancelableTaskTracker(); |
| 70 | |
| Peter Boström | 7319bbd | 2021-09-15 22:59:38 | [diff] [blame] | 71 | CancelableTaskTracker(const CancelableTaskTracker&) = delete; |
| 72 | CancelableTaskTracker& operator=(const CancelableTaskTracker&) = delete; |
| 73 | |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 74 | // Cancels all tracked tasks. |
| 75 | ~CancelableTaskTracker(); |
| 76 | |
| tzik | d773cb47 | 2017-04-17 18:58:19 | [diff] [blame] | 77 | TaskId PostTask(TaskRunner* task_runner, |
| Brett Wilson | abbb960 | 2017-09-11 23:26:39 | [diff] [blame] | 78 | const Location& from_here, |
| tzik | d773cb47 | 2017-04-17 18:58:19 | [diff] [blame] | 79 | OnceClosure task); |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 80 | |
| tzik | d773cb47 | 2017-04-17 18:58:19 | [diff] [blame] | 81 | TaskId PostTaskAndReply(TaskRunner* task_runner, |
| Brett Wilson | abbb960 | 2017-09-11 23:26:39 | [diff] [blame] | 82 | const Location& from_here, |
| tzik | d773cb47 | 2017-04-17 18:58:19 | [diff] [blame] | 83 | OnceClosure task, |
| 84 | OnceClosure reply); |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 85 | |
| Jan Wilken Dörrie | 2e1d2d9a | 2020-01-24 17:14:18 | [diff] [blame] | 86 | template <typename TaskReturnType, typename ReplyArgType> |
| tzik | d773cb47 | 2017-04-17 18:58:19 | [diff] [blame] | 87 | TaskId PostTaskAndReplyWithResult(TaskRunner* task_runner, |
| Brett Wilson | abbb960 | 2017-09-11 23:26:39 | [diff] [blame] | 88 | const Location& from_here, |
| Jan Wilken Dörrie | 2e1d2d9a | 2020-01-24 17:14:18 | [diff] [blame] | 89 | OnceCallback<TaskReturnType()> task, |
| 90 | OnceCallback<void(ReplyArgType)> reply) { |
| Mikel Astiz | c076a97 | 2018-07-25 13:49:25 | [diff] [blame] | 91 | auto* result = new std::unique_ptr<TaskReturnType>(); |
| [email protected] | f5449ac | 2014-07-04 11:19:50 | [diff] [blame] | 92 | return PostTaskAndReply( |
| tzik | 0352751 | 2017-02-08 12:29:47 | [diff] [blame] | 93 | task_runner, from_here, |
| tzik | d773cb47 | 2017-04-17 18:58:19 | [diff] [blame] | 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 | |
| [email protected] | 4f1935e | 2012-11-16 23:10:07 | [diff] [blame] | 100 | // Creates a tracked TaskId and an associated IsCanceledCallback. Client can |
| 101 | // later call TryCancel() with the returned TaskId, and run |is_canceled_cb| |
| [email protected] | d5dd90d | 2012-11-26 21:13:35 | [diff] [blame] | 102 | // from any thread to check whether the TaskId is canceled. |
| [email protected] | 4f1935e | 2012-11-16 23:10:07 | [diff] [blame] | 103 | // |
| [email protected] | 3d5b88a | 2012-11-28 23:28:45 | [diff] [blame] | 104 | // The returned task ID is tracked until the last copy of |
| 105 | // |is_canceled_cb| is destroyed. |
| 106 | // |
| [email protected] | 4f1935e | 2012-11-16 23:10:07 | [diff] [blame] | 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 | |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 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 | |
| [email protected] | 3d5b88a | 2012-11-28 23:28:45 | [diff] [blame] | 124 | // Returns true iff there are in-flight tasks that are still being |
| 125 | // tracked. |
| 126 | bool HasTrackedTasks() const; |
| 127 | |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 128 | private: |
| Wez | 77d9d10 | 2019-01-10 00:20:21 | [diff] [blame] | 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 | |
| Wez | d6a5f0f2 | 2023-04-14 14:28:48 | [diff] [blame] | 135 | static void RunIfNotCanceled(const scoped_refptr<TaskCancellationFlag>& flag, |
| 136 | OnceClosure task); |
| Wez | c9bba14 | 2019-11-15 07:36:46 | [diff] [blame] | 137 | static void RunThenUntrackIfNotCanceled( |
| 138 | const scoped_refptr<TaskCancellationFlag>& flag, |
| 139 | OnceClosure task, |
| 140 | OnceClosure untrack); |
| Wez | d6a5f0f2 | 2023-04-14 14:28:48 | [diff] [blame] | 141 | static bool IsCanceled(const scoped_refptr<TaskCancellationFlag>& flag, |
| 142 | const ScopedClosureRunner& cleanup_runner); |
| Wez | 77d9d10 | 2019-01-10 00:20:21 | [diff] [blame] | 143 | |
| 144 | void Track(TaskId id, scoped_refptr<TaskCancellationFlag> flag); |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 145 | void Untrack(TaskId id); |
| 146 | |
| brettw | 1ce49f6 | 2017-04-27 19:42:32 | [diff] [blame] | 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. |
| Wez | 77d9d10 | 2019-01-10 00:20:21 | [diff] [blame] | 151 | small_map<std::map<TaskId, scoped_refptr<TaskCancellationFlag>>, 4> |
| 152 | task_flags_; |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 153 | |
| Wez | 77d9d10 | 2019-01-10 00:20:21 | [diff] [blame] | 154 | TaskId next_id_ = 1; |
| Christian Flach | 3eee770 | 2022-09-09 14:25:43 | [diff] [blame] | 155 | SEQUENCE_CHECKER(sequence_checker_); |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 156 | |
| Alison Gale | 59c007a | 2024-04-20 03:05:40 | [diff] [blame] | 157 | // TODO(crbug.com/40050290): Remove once crasher is resolved. |
| Wez | 50cbb92 | 2019-12-05 20:40:41 | [diff] [blame] | 158 | base::WeakPtr<CancelableTaskTracker> weak_this_; |
| 159 | base::WeakPtrFactory<CancelableTaskTracker> weak_factory_{this}; |
| [email protected] | 62867b0 | 2012-11-03 07:21:03 | [diff] [blame] | 160 | }; |
| 161 | |
| [email protected] | e95b717f | 2014-02-06 13:47:13 | [diff] [blame] | 162 | } // namespace base |
| 163 | |
| 164 | #endif // BASE_TASK_CANCELABLE_TASK_TRACKER_H_ |