cancelable_task_tracker.h 6.2 KB

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