• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
5 // CancelableTaskTracker posts tasks (in the form of a Closure) 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 Closure). After
11 // the task is run on the TaskRunner, |reply| will be posted back to
12 // originating TaskRunner.
13 //
14 // NOTE:
15 //
16 // CancelableCallback (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 inputed 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 <utility>
42 
43 #include "base/base_export.h"
44 #include "base/bind.h"
45 #include "base/callback.h"
46 #include "base/containers/small_map.h"
47 #include "base/macros.h"
48 #include "base/memory/weak_ptr.h"
49 #include "base/post_task_and_reply_with_result_internal.h"
50 #include "base/sequence_checker.h"
51 
52 namespace base {
53 
54 class CancellationFlag;
55 class Location;
56 class TaskRunner;
57 
58 class BASE_EXPORT CancelableTaskTracker {
59  public:
60   // All values except kBadTaskId are valid.
61   typedef int64_t TaskId;
62   static const TaskId kBadTaskId;
63 
64   typedef Callback<bool()> IsCanceledCallback;
65 
66   CancelableTaskTracker();
67 
68   // Cancels all tracked tasks.
69   ~CancelableTaskTracker();
70 
71   TaskId PostTask(TaskRunner* task_runner,
72                   const Location& from_here,
73                   OnceClosure task);
74 
75   TaskId PostTaskAndReply(TaskRunner* task_runner,
76                           const Location& from_here,
77                           OnceClosure task,
78                           OnceClosure reply);
79 
80   template <typename TaskReturnType, typename ReplyArgType>
PostTaskAndReplyWithResult(TaskRunner * task_runner,const Location & from_here,OnceCallback<TaskReturnType ()> task,OnceCallback<void (ReplyArgType)> reply)81   TaskId PostTaskAndReplyWithResult(TaskRunner* task_runner,
82                                     const Location& from_here,
83                                     OnceCallback<TaskReturnType()> task,
84                                     OnceCallback<void(ReplyArgType)> reply) {
85     TaskReturnType* result = new TaskReturnType();
86     return PostTaskAndReply(
87         task_runner, from_here,
88         BindOnce(&internal::ReturnAsParamAdapter<TaskReturnType>,
89                  std::move(task), Unretained(result)),
90         BindOnce(&internal::ReplyAdapter<TaskReturnType, ReplyArgType>,
91                  std::move(reply), Owned(result)));
92   }
93 
94   // Callback version of PostTaskWithTraitsAndReplyWithResult above.
95   // Though RepeatingCallback is convertible to OnceCallback, we need this since
96   // we can not use template deduction and object conversion at once on the
97   // overload resolution.
98   // TODO(tzik): Update all callers of the Callback version to use OnceCallback.
99   template <typename TaskReturnType, typename ReplyArgType>
PostTaskAndReplyWithResult(TaskRunner * task_runner,const Location & from_here,Callback<TaskReturnType ()> task,Callback<void (ReplyArgType)> reply)100   TaskId PostTaskAndReplyWithResult(TaskRunner* task_runner,
101                                     const Location& from_here,
102                                     Callback<TaskReturnType()> task,
103                                     Callback<void(ReplyArgType)> reply) {
104     return PostTaskAndReplyWithResult(
105         task_runner, from_here,
106         static_cast<OnceCallback<TaskReturnType()>>(std::move(task)),
107         static_cast<OnceCallback<void(ReplyArgType)>>(std::move(reply)));
108   }
109 
110   // Creates a tracked TaskId and an associated IsCanceledCallback. Client can
111   // later call TryCancel() with the returned TaskId, and run |is_canceled_cb|
112   // from any thread to check whether the TaskId is canceled.
113   //
114   // The returned task ID is tracked until the last copy of
115   // |is_canceled_cb| is destroyed.
116   //
117   // Note. This function is used to address some special cancelation requirement
118   // in existing code. You SHOULD NOT need this function in new code.
119   TaskId NewTrackedTaskId(IsCanceledCallback* is_canceled_cb);
120 
121   // After calling this function, |task| and |reply| will not run. If the
122   // cancelation happens when |task| is running or has finished running, |reply|
123   // will not run. If |reply| is running or has finished running, cancellation
124   // is a noop.
125   //
126   // Note. It's OK to cancel a |task| for more than once. The later calls are
127   // noops.
128   void TryCancel(TaskId id);
129 
130   // It's OK to call this function for more than once. The later calls are
131   // noops.
132   void TryCancelAll();
133 
134   // Returns true iff there are in-flight tasks that are still being
135   // tracked.
136   bool HasTrackedTasks() const;
137 
138  private:
139   void Track(TaskId id, CancellationFlag* flag);
140   void Untrack(TaskId id);
141 
142   // Typically the number of tasks are 0-2 and occationally 3-4. But since
143   // this is a general API that could be used in unexpected ways, use a
144   // small_map instead of a flat_map to avoid falling over if there are many
145   // tasks.
146   small_map<std::map<TaskId, CancellationFlag*>, 4> task_flags_;
147 
148   TaskId next_id_;
149   SequenceChecker sequence_checker_;
150 
151   WeakPtrFactory<CancelableTaskTracker> weak_factory_;
152 
153   DISALLOW_COPY_AND_ASSIGN(CancelableTaskTracker);
154 };
155 
156 }  // namespace base
157 
158 #endif  // BASE_TASK_CANCELABLE_TASK_TRACKER_H_
159