1b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Copyright 2014 The Chromium Authors. All rights reserved. 2b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Use of this source code is governed by a BSD-style license that can be 3b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// found in the LICENSE file. 4b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 5b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// CancelableTaskTracker posts tasks (in the form of a Closure) to a 6b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// TaskRunner, and is able to cancel the task later if it's not needed 7b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// anymore. On destruction, CancelableTaskTracker will cancel all 8b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// tracked tasks. 9b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// 10b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// Each cancelable task can be associated with a reply (also a Closure). After 11b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// the task is run on the TaskRunner, |reply| will be posted back to 12b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// originating TaskRunner. 13b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// 14b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// NOTE: 15b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// 16b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// CancelableCallback (base/cancelable_callback.h) and WeakPtr binding are 17b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// preferred solutions for canceling a task. However, they don't support 18b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// cancelation from another thread. This is sometimes a performance critical 19b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// requirement. E.g. We need to cancel database lookup task on DB thread when 20b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// user changes inputed text. If it is performance critical to do a best effort 21b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// cancelation of a task, then CancelableTaskTracker is appropriate, 22b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// otherwise use one of the other mechanisms. 23b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// 24b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// THREAD-SAFETY: 25b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// 26b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// 1. CancelableTaskTracker objects are not thread safe. They must 27b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// be created, used, and destroyed on the originating thread that posts the 28b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// task. It's safe to destroy a CancelableTaskTracker while there 29b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// are outstanding tasks. This is commonly used to cancel all outstanding 30b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// tasks. 31b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// 32b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// 2. Both task and reply are deleted on the originating thread. 33b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// 34b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// 3. IsCanceledCallback is thread safe and can be run or deleted on any 35b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat// thread. 36b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#ifndef BASE_TASK_CANCELABLE_TASK_TRACKER_H_ 37b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#define BASE_TASK_CANCELABLE_TASK_TRACKER_H_ 38b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 39cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include <stdint.h> 40cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko 41b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/base_export.h" 42b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/callback.h" 43b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/containers/hash_tables.h" 44cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko#include "base/macros.h" 45b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/memory/weak_ptr.h" 46b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/task_runner_util.h" 47b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#include "base/threading/thread_checker.h" 48b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 49b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace tracked_objects { 50b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass Location; 51b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace tracked_objects 52b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 53b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratnamespace base { 54b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 55b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass CancellationFlag; 56b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass TaskRunner; 57b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 58b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Eratclass BASE_EXPORT CancelableTaskTracker { 59b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat public: 60b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // All values except kBadTaskId are valid. 61cce46a0c214b37e8da48c522c83037e8ffa4f9fdAlex Vakulenko typedef int64_t TaskId; 62b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat static const TaskId kBadTaskId; 63b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 64b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat typedef base::Callback<bool()> IsCanceledCallback; 65b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 66b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat CancelableTaskTracker(); 67b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 68b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Cancels all tracked tasks. 69b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat ~CancelableTaskTracker(); 70b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 71b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat TaskId PostTask(base::TaskRunner* task_runner, 72b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const tracked_objects::Location& from_here, 73b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const base::Closure& task); 74b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 75b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat TaskId PostTaskAndReply(base::TaskRunner* task_runner, 76b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const tracked_objects::Location& from_here, 77b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const base::Closure& task, 78b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const base::Closure& reply); 79b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 80b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat template <typename TaskReturnType, typename ReplyArgType> 81b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat TaskId PostTaskAndReplyWithResult( 82b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::TaskRunner* task_runner, 83b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const tracked_objects::Location& from_here, 84b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const base::Callback<TaskReturnType(void)>& task, 85b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat const base::Callback<void(ReplyArgType)>& reply) { 86b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat TaskReturnType* result = new TaskReturnType(); 87b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat return PostTaskAndReply( 88b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat task_runner, 89b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat from_here, 90b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::Bind(&base::internal::ReturnAsParamAdapter<TaskReturnType>, 91b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat task, 92b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::Unretained(result)), 93b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::Bind(&base::internal::ReplyAdapter<TaskReturnType, ReplyArgType>, 94b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat reply, 95b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::Owned(result))); 96b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat } 97b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 98b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Creates a tracked TaskId and an associated IsCanceledCallback. Client can 99b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // later call TryCancel() with the returned TaskId, and run |is_canceled_cb| 100b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // from any thread to check whether the TaskId is canceled. 101b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // 102b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // The returned task ID is tracked until the last copy of 103b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // |is_canceled_cb| is destroyed. 104b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // 105b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Note. This function is used to address some special cancelation requirement 106b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // in existing code. You SHOULD NOT need this function in new code. 107b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat TaskId NewTrackedTaskId(IsCanceledCallback* is_canceled_cb); 108b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 109b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // After calling this function, |task| and |reply| will not run. If the 110b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // cancelation happens when |task| is running or has finished running, |reply| 111b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // will not run. If |reply| is running or has finished running, cancellation 112b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // is a noop. 113b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // 114b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Note. It's OK to cancel a |task| for more than once. The later calls are 115b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // noops. 116b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void TryCancel(TaskId id); 117b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 118b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // It's OK to call this function for more than once. The later calls are 119b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // noops. 120b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void TryCancelAll(); 121b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 122b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // Returns true iff there are in-flight tasks that are still being 123b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat // tracked. 124b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat bool HasTrackedTasks() const; 125b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 126b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat private: 127b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void Track(TaskId id, base::CancellationFlag* flag); 128b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat void Untrack(TaskId id); 129b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 130b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::hash_map<TaskId, base::CancellationFlag*> task_flags_; 131b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 132b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat TaskId next_id_; 133b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::ThreadChecker thread_checker_; 134b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 135b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat base::WeakPtrFactory<CancelableTaskTracker> weak_factory_; 136b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 137b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat DISALLOW_COPY_AND_ASSIGN(CancelableTaskTracker); 138b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat}; 139b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 140b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat} // namespace base 141b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat 142b8cf94937c52feb53b55c39e3f82094d27de464cDaniel Erat#endif // BASE_TASK_CANCELABLE_TASK_TRACKER_H_ 143