|  | // Copyright 2014 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | // CancelableTaskTracker posts tasks (in the form of a Closure) to a | 
|  | // TaskRunner, and is able to cancel the task later if it's not needed | 
|  | // anymore.  On destruction, CancelableTaskTracker will cancel all | 
|  | // tracked tasks. | 
|  | // | 
|  | // Each cancelable task can be associated with a reply (also a Closure). After | 
|  | // the task is run on the TaskRunner, |reply| will be posted back to | 
|  | // originating TaskRunner. | 
|  | // | 
|  | // NOTE: | 
|  | // | 
|  | // CancelableCallback (base/cancelable_callback.h) and WeakPtr binding are | 
|  | // preferred solutions for canceling a task. However, they don't support | 
|  | // cancelation from another sequence. This is sometimes a performance critical | 
|  | // requirement. E.g. We need to cancel database lookup task on DB thread when | 
|  | // user changes inputed text. If it is performance critical to do a best effort | 
|  | // cancelation of a task, then CancelableTaskTracker is appropriate, otherwise | 
|  | // use one of the other mechanisms. | 
|  | // | 
|  | // THREAD-SAFETY: | 
|  | // | 
|  | // 1. A CancelableTaskTracker object must be created, used, and destroyed on a | 
|  | //    single sequence. | 
|  | // | 
|  | // 2. It's safe to destroy a CancelableTaskTracker while there are outstanding | 
|  | //    tasks. This is commonly used to cancel all outstanding tasks. | 
|  | // | 
|  | // 3. The task is deleted on the target sequence, and the reply are deleted on | 
|  | //    the originating sequence. | 
|  | // | 
|  | // 4. IsCanceledCallback can be run or deleted on any sequence. | 
|  | #ifndef BASE_TASK_CANCELABLE_TASK_TRACKER_H_ | 
|  | #define BASE_TASK_CANCELABLE_TASK_TRACKER_H_ | 
|  |  | 
|  | #include <stdint.h> | 
|  |  | 
|  | #include <utility> | 
|  |  | 
|  | #include "base/base_export.h" | 
|  | #include "base/bind.h" | 
|  | #include "base/callback.h" | 
|  | #include "base/containers/small_map.h" | 
|  | #include "base/macros.h" | 
|  | #include "base/memory/weak_ptr.h" | 
|  | #include "base/post_task_and_reply_with_result_internal.h" | 
|  | #include "base/sequence_checker.h" | 
|  |  | 
|  | namespace base { | 
|  |  | 
|  | class CancellationFlag; | 
|  | class Location; | 
|  | class TaskRunner; | 
|  |  | 
|  | class BASE_EXPORT CancelableTaskTracker { | 
|  | public: | 
|  | // All values except kBadTaskId are valid. | 
|  | typedef int64_t TaskId; | 
|  | static const TaskId kBadTaskId; | 
|  |  | 
|  | typedef Callback<bool()> IsCanceledCallback; | 
|  |  | 
|  | CancelableTaskTracker(); | 
|  |  | 
|  | // Cancels all tracked tasks. | 
|  | ~CancelableTaskTracker(); | 
|  |  | 
|  | TaskId PostTask(TaskRunner* task_runner, | 
|  | const Location& from_here, | 
|  | OnceClosure task); | 
|  |  | 
|  | TaskId PostTaskAndReply(TaskRunner* task_runner, | 
|  | const Location& from_here, | 
|  | OnceClosure task, | 
|  | OnceClosure reply); | 
|  |  | 
|  | template <typename TaskReturnType, typename ReplyArgType> | 
|  | TaskId PostTaskAndReplyWithResult(TaskRunner* task_runner, | 
|  | const Location& from_here, | 
|  | OnceCallback<TaskReturnType()> task, | 
|  | OnceCallback<void(ReplyArgType)> reply) { | 
|  | TaskReturnType* result = new TaskReturnType(); | 
|  | return PostTaskAndReply( | 
|  | task_runner, from_here, | 
|  | BindOnce(&internal::ReturnAsParamAdapter<TaskReturnType>, | 
|  | std::move(task), Unretained(result)), | 
|  | BindOnce(&internal::ReplyAdapter<TaskReturnType, ReplyArgType>, | 
|  | std::move(reply), Owned(result))); | 
|  | } | 
|  |  | 
|  | // Callback version of PostTaskWithTraitsAndReplyWithResult above. | 
|  | // Though RepeatingCallback is convertible to OnceCallback, we need this since | 
|  | // we can not use template deduction and object conversion at once on the | 
|  | // overload resolution. | 
|  | // TODO(tzik): Update all callers of the Callback version to use OnceCallback. | 
|  | template <typename TaskReturnType, typename ReplyArgType> | 
|  | TaskId PostTaskAndReplyWithResult(TaskRunner* task_runner, | 
|  | const Location& from_here, | 
|  | Callback<TaskReturnType()> task, | 
|  | Callback<void(ReplyArgType)> reply) { | 
|  | return PostTaskAndReplyWithResult( | 
|  | task_runner, from_here, | 
|  | static_cast<OnceCallback<TaskReturnType()>>(std::move(task)), | 
|  | static_cast<OnceCallback<void(ReplyArgType)>>(std::move(reply))); | 
|  | } | 
|  |  | 
|  | // Creates a tracked TaskId and an associated IsCanceledCallback. Client can | 
|  | // later call TryCancel() with the returned TaskId, and run |is_canceled_cb| | 
|  | // from any thread to check whether the TaskId is canceled. | 
|  | // | 
|  | // The returned task ID is tracked until the last copy of | 
|  | // |is_canceled_cb| is destroyed. | 
|  | // | 
|  | // Note. This function is used to address some special cancelation requirement | 
|  | // in existing code. You SHOULD NOT need this function in new code. | 
|  | TaskId NewTrackedTaskId(IsCanceledCallback* is_canceled_cb); | 
|  |  | 
|  | // After calling this function, |task| and |reply| will not run. If the | 
|  | // cancelation happens when |task| is running or has finished running, |reply| | 
|  | // will not run. If |reply| is running or has finished running, cancellation | 
|  | // is a noop. | 
|  | // | 
|  | // Note. It's OK to cancel a |task| for more than once. The later calls are | 
|  | // noops. | 
|  | void TryCancel(TaskId id); | 
|  |  | 
|  | // It's OK to call this function for more than once. The later calls are | 
|  | // noops. | 
|  | void TryCancelAll(); | 
|  |  | 
|  | // Returns true iff there are in-flight tasks that are still being | 
|  | // tracked. | 
|  | bool HasTrackedTasks() const; | 
|  |  | 
|  | private: | 
|  | void Track(TaskId id, CancellationFlag* flag); | 
|  | void Untrack(TaskId id); | 
|  |  | 
|  | // Typically the number of tasks are 0-2 and occationally 3-4. But since | 
|  | // this is a general API that could be used in unexpected ways, use a | 
|  | // small_map instead of a flat_map to avoid falling over if there are many | 
|  | // tasks. | 
|  | small_map<std::map<TaskId, CancellationFlag*>, 4> task_flags_; | 
|  |  | 
|  | TaskId next_id_; | 
|  | SequenceChecker sequence_checker_; | 
|  |  | 
|  | WeakPtrFactory<CancelableTaskTracker> weak_factory_; | 
|  |  | 
|  | DISALLOW_COPY_AND_ASSIGN(CancelableTaskTracker); | 
|  | }; | 
|  |  | 
|  | }  // namespace base | 
|  |  | 
|  | #endif  // BASE_TASK_CANCELABLE_TASK_TRACKER_H_ |