1 // Copyright 2018 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 #ifndef BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_H_
6 #define BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_H_
7 
8 #include <memory>
9 
10 #include "base/macros.h"
11 #include "base/memory/weak_ptr.h"
12 #include "base/optional.h"
13 #include "base/single_thread_task_runner.h"
14 #include "base/task/common/checked_lock.h"
15 #include "base/task/sequence_manager/lazy_now.h"
16 #include "base/task/sequence_manager/tasks.h"
17 #include "base/task/task_observer.h"
18 #include "base/threading/platform_thread.h"
19 #include "base/time/time.h"
20 
21 namespace base {
22 
23 class TaskObserver;
24 
25 namespace trace_event {
26 class BlameContext;
27 }
28 
29 namespace sequence_manager {
30 
31 namespace internal {
32 class AssociatedThreadId;
33 class SequenceManagerImpl;
34 class TaskQueueImpl;
35 }  // namespace internal
36 
37 class TimeDomain;
38 
39 // TODO(kraynov): Make TaskQueue to actually be an interface for TaskQueueImpl
40 // and stop using ref-counting because we're no longer tied to task runner
41 // lifecycle and there's no other need for ref-counting either.
42 // NOTE: When TaskQueue gets automatically deleted on zero ref-count,
43 // TaskQueueImpl gets gracefully shutdown. It means that it doesn't get
44 // unregistered immediately and might accept some last minute tasks until
45 // SequenceManager will unregister it at some point. It's done to ensure that
46 // task queue always gets unregistered on the main thread.
47 class BASE_EXPORT TaskQueue : public RefCountedThreadSafe<TaskQueue> {
48  public:
49   class Observer {
50    public:
51     virtual ~Observer() = default;
52 
53     // Notify observer that the time at which this queue wants to run
54     // the next task has changed. |next_wakeup| can be in the past
55     // (e.g. TimeTicks() can be used to notify about immediate work).
56     // Can be called on any thread
57     // All methods but SetObserver, SetTimeDomain and GetTimeDomain can be
58     // called on |queue|.
59     //
60     // TODO(altimin): Make it Optional<TimeTicks> to tell
61     // observer about cancellations.
62     virtual void OnQueueNextWakeUpChanged(TimeTicks next_wake_up) = 0;
63   };
64 
65   // Shuts down the queue. All tasks currently queued will be discarded.
66   virtual void ShutdownTaskQueue();
67 
68   // Shuts down the queue when there are no more tasks queued.
69   void ShutdownTaskQueueGracefully();
70 
71   // TODO(scheduler-dev): Could we define a more clear list of priorities?
72   // See https://crbug.com/847858.
73   enum QueuePriority : uint8_t {
74     // Queues with control priority will run before any other queue, and will
75     // explicitly starve other queues. Typically this should only be used for
76     // private queues which perform control operations.
77     kControlPriority = 0,
78 
79     // The selector will prioritize highest over high, normal and low; and
80     // high over normal and low; and normal over low. However it will ensure
81     // neither of the lower priority queues can be completely starved by higher
82     // priority tasks. All three of these queues will always take priority over
83     // and can starve the best effort queue.
84     kHighestPriority = 1,
85 
86     kVeryHighPriority = 2,
87 
88     kHighPriority = 3,
89 
90     // Queues with normal priority are the default.
91     kNormalPriority = 4,
92     kLowPriority = 5,
93 
94     // Queues with best effort priority will only be run if all other queues are
95     // empty. They can be starved by the other queues.
96     kBestEffortPriority = 6,
97     // Must be the last entry.
98     kQueuePriorityCount = 7,
99     kFirstQueuePriority = kControlPriority,
100   };
101 
102   // Can be called on any thread.
103   static const char* PriorityToString(QueuePriority priority);
104 
105   // Options for constructing a TaskQueue.
106   struct Spec {
SpecSpec107     explicit Spec(const char* name) : name(name) {}
108 
SetShouldMonitorQuiescenceSpec109     Spec SetShouldMonitorQuiescence(bool should_monitor) {
110       should_monitor_quiescence = should_monitor;
111       return *this;
112     }
113 
SetShouldNotifyObserversSpec114     Spec SetShouldNotifyObservers(bool run_observers) {
115       should_notify_observers = run_observers;
116       return *this;
117     }
118 
119     // Delayed fences require Now() to be sampled when posting immediate tasks
120     // which is not free.
SetDelayedFencesAllowedSpec121     Spec SetDelayedFencesAllowed(bool allow_delayed_fences) {
122       delayed_fence_allowed = allow_delayed_fences;
123       return *this;
124     }
125 
SetTimeDomainSpec126     Spec SetTimeDomain(TimeDomain* domain) {
127       time_domain = domain;
128       return *this;
129     }
130 
131     const char* name;
132     bool should_monitor_quiescence = false;
133     TimeDomain* time_domain = nullptr;
134     bool should_notify_observers = true;
135     bool delayed_fence_allowed = false;
136   };
137 
138   // TODO(altimin): Make this private after TaskQueue/TaskQueueImpl refactoring.
139   TaskQueue(std::unique_ptr<internal::TaskQueueImpl> impl,
140             const TaskQueue::Spec& spec);
141 
142   // Information about task execution.
143   //
144   // Wall-time related methods (start_time, end_time, wall_duration) can be
145   // called only when |has_wall_time()| is true.
146   // Thread-time related mehtods (start_thread_time, end_thread_time,
147   // thread_duration) can be called only when |has_thread_time()| is true.
148   //
149   // start_* should be called after RecordTaskStart.
150   // end_* and *_duration should be called after RecordTaskEnd.
151   class BASE_EXPORT TaskTiming {
152    public:
153     enum class State { NotStarted, Running, Finished };
154     enum class TimeRecordingPolicy { DoRecord, DoNotRecord };
155 
156     TaskTiming(bool has_wall_time, bool has_thread_time);
157 
has_wall_time()158     bool has_wall_time() const { return has_wall_time_; }
has_thread_time()159     bool has_thread_time() const { return has_thread_time_; }
160 
start_time()161     base::TimeTicks start_time() const {
162       DCHECK(has_wall_time());
163       return start_time_;
164     }
end_time()165     base::TimeTicks end_time() const {
166       DCHECK(has_wall_time());
167       return end_time_;
168     }
wall_duration()169     base::TimeDelta wall_duration() const {
170       DCHECK(has_wall_time());
171       return end_time_ - start_time_;
172     }
start_thread_time()173     base::ThreadTicks start_thread_time() const {
174       DCHECK(has_thread_time());
175       return start_thread_time_;
176     }
end_thread_time()177     base::ThreadTicks end_thread_time() const {
178       DCHECK(has_thread_time());
179       return end_thread_time_;
180     }
thread_duration()181     base::TimeDelta thread_duration() const {
182       DCHECK(has_thread_time());
183       return end_thread_time_ - start_thread_time_;
184     }
185 
state()186     State state() const { return state_; }
187 
188     void RecordTaskStart(LazyNow* now);
189     void RecordTaskEnd(LazyNow* now);
190 
191     // Protected for tests.
192    protected:
193     State state_ = State::NotStarted;
194 
195     bool has_wall_time_;
196     bool has_thread_time_;
197 
198     base::TimeTicks start_time_;
199     base::TimeTicks end_time_;
200     base::ThreadTicks start_thread_time_;
201     base::ThreadTicks end_thread_time_;
202   };
203 
204   // An interface that lets the owner vote on whether or not the associated
205   // TaskQueue should be enabled.
206   class BASE_EXPORT QueueEnabledVoter {
207    public:
208     ~QueueEnabledVoter();
209 
210     QueueEnabledVoter(const QueueEnabledVoter&) = delete;
211     const QueueEnabledVoter& operator=(const QueueEnabledVoter&) = delete;
212 
213     // Votes to enable or disable the associated TaskQueue. The TaskQueue will
214     // only be enabled if all the voters agree it should be enabled, or if there
215     // are no voters.
216     // NOTE this must be called on the thread the associated TaskQueue was
217     // created on.
218     void SetVoteToEnable(bool enabled);
219 
IsVotingToEnable()220     bool IsVotingToEnable() const { return enabled_; }
221 
222    private:
223     friend class TaskQueue;
224     explicit QueueEnabledVoter(scoped_refptr<TaskQueue> task_queue);
225 
226     scoped_refptr<TaskQueue> const task_queue_;
227     bool enabled_;
228   };
229 
230   // Returns an interface that allows the caller to vote on whether or not this
231   // TaskQueue is enabled. The TaskQueue will be enabled if there are no voters
232   // or if all agree it should be enabled.
233   // NOTE this must be called on the thread this TaskQueue was created by.
234   std::unique_ptr<QueueEnabledVoter> CreateQueueEnabledVoter();
235 
236   // NOTE this must be called on the thread this TaskQueue was created by.
237   bool IsQueueEnabled() const;
238 
239   // Returns true if the queue is completely empty.
240   bool IsEmpty() const;
241 
242   // Returns the number of pending tasks in the queue.
243   size_t GetNumberOfPendingTasks() const;
244 
245   // Returns true if the queue has work that's ready to execute now.
246   // NOTE: this must be called on the thread this TaskQueue was created by.
247   bool HasTaskToRunImmediately() const;
248 
249   // Returns requested run time of next scheduled wake-up for a delayed task
250   // which is not ready to run. If there are no such tasks (immediate tasks
251   // don't count) or the queue is disabled it returns nullopt.
252   // NOTE: this must be called on the thread this TaskQueue was created by.
253   Optional<TimeTicks> GetNextScheduledWakeUp();
254 
255   // Can be called on any thread.
256   virtual const char* GetName() const;
257 
258   // Set the priority of the queue to |priority|. NOTE this must be called on
259   // the thread this TaskQueue was created by.
260   void SetQueuePriority(QueuePriority priority);
261 
262   // Returns the current queue priority.
263   QueuePriority GetQueuePriority() const;
264 
265   // These functions can only be called on the same thread that the task queue
266   // manager executes its tasks on.
267   void AddTaskObserver(TaskObserver* task_observer);
268   void RemoveTaskObserver(TaskObserver* task_observer);
269 
270   // Set the blame context which is entered and left while executing tasks from
271   // this task queue. |blame_context| must be null or outlive this task queue.
272   // Must be called on the thread this TaskQueue was created by.
273   void SetBlameContext(trace_event::BlameContext* blame_context);
274 
275   // Removes the task queue from the previous TimeDomain and adds it to
276   // |domain|.  This is a moderately expensive operation.
277   void SetTimeDomain(TimeDomain* domain);
278 
279   // Returns the queue's current TimeDomain.  Can be called from any thread.
280   TimeDomain* GetTimeDomain() const;
281 
282   enum class InsertFencePosition {
283     kNow,  // Tasks posted on the queue up till this point further may run.
284            // All further tasks are blocked.
285     kBeginningOfTime,  // No tasks posted on this queue may run.
286   };
287 
288   // Inserts a barrier into the task queue which prevents tasks with an enqueue
289   // order greater than the fence from running until either the fence has been
290   // removed or a subsequent fence has unblocked some tasks within the queue.
291   // Note: delayed tasks get their enqueue order set once their delay has
292   // expired, and non-delayed tasks get their enqueue order set when posted.
293   //
294   // Fences come in three flavours:
295   // - Regular (InsertFence(NOW)) - all tasks posted after this moment
296   //   are blocked.
297   // - Fully blocking (InsertFence(kBeginningOfTime)) - all tasks including
298   //   already posted are blocked.
299   // - Delayed (InsertFenceAt(timestamp)) - blocks all tasks posted after given
300   //   point in time (must be in the future).
301   //
302   // Only one fence can be scheduled at a time. Inserting a new fence
303   // will automatically remove the previous one, regardless of fence type.
304   void InsertFence(InsertFencePosition position);
305 
306   // Delayed fences are only allowed for queues created with
307   // SetDelayedFencesAllowed(true) because this feature implies sampling Now()
308   // (which isn't free) for every PostTask, even those with zero delay.
309   void InsertFenceAt(TimeTicks time);
310 
311   // Removes any previously added fence and unblocks execution of any tasks
312   // blocked by it.
313   void RemoveFence();
314 
315   // Returns true if the queue has a fence but it isn't necessarily blocking
316   // execution of tasks (it may be the case if tasks enqueue order hasn't
317   // reached the number set for a fence).
318   bool HasActiveFence();
319 
320   // Returns true if the queue has a fence which is blocking execution of tasks.
321   bool BlockedByFence() const;
322 
323   // Returns an EnqueueOrder generated at the last transition to unblocked. A
324   // queue is unblocked when it is enabled and no fence prevents the front task
325   // from running. If the EnqueueOrder of a task is greater than this when it
326   // starts running, it means that is was never blocked.
327   EnqueueOrder GetEnqueueOrderAtWhichWeBecameUnblocked() const;
328 
329   void SetObserver(Observer* observer);
330 
331   // Controls whether or not the queue will emit traces events when tasks are
332   // posted to it while disabled. This only applies for the current or next
333   // period during which the queue is disabled. When the queue is re-enabled
334   // this will revert back to the default value of false.
335   void SetShouldReportPostedTasksWhenDisabled(bool should_report);
336 
337   // Create a task runner for this TaskQueue which will annotate all
338   // posted tasks with the given task type.
339   // May be called on any thread.
340   // NOTE: Task runners don't hold a reference to a TaskQueue, hence,
341   // it's required to retain that reference to prevent automatic graceful
342   // shutdown. Unique ownership of task queues will fix this issue soon.
343   scoped_refptr<SingleThreadTaskRunner> CreateTaskRunner(TaskType task_type);
344 
345   // Default task runner which doesn't annotate tasks with a task type.
task_runner()346   scoped_refptr<SingleThreadTaskRunner> task_runner() const {
347     return default_task_runner_;
348   }
349 
350  protected:
351   virtual ~TaskQueue();
352 
GetTaskQueueImpl()353   internal::TaskQueueImpl* GetTaskQueueImpl() const { return impl_.get(); }
354 
355  private:
356   friend class RefCountedThreadSafe<TaskQueue>;
357   friend class internal::SequenceManagerImpl;
358   friend class internal::TaskQueueImpl;
359 
360   void AddQueueEnabledVoter(bool voter_is_enabled);
361   void RemoveQueueEnabledVoter(bool voter_is_enabled);
362   bool AreAllQueueEnabledVotersEnabled() const;
363   void OnQueueEnabledVoteChanged(bool enabled);
364 
365   bool IsOnMainThread() const;
366 
367   // TaskQueue has ownership of an underlying implementation but in certain
368   // cases (e.g. detached frames) their lifetime may diverge.
369   // This method should be used to take away the impl for graceful shutdown.
370   // TaskQueue will disregard any calls or posting tasks thereafter.
371   std::unique_ptr<internal::TaskQueueImpl> TakeTaskQueueImpl();
372 
373   // |impl_| can be written to on the main thread but can be read from
374   // any thread.
375   // |impl_lock_| must be acquired when writing to |impl_| or when accessing
376   // it from non-main thread. Reading from the main thread does not require
377   // a lock.
378   mutable base::internal::CheckedLock impl_lock_{
379       base::internal::UniversalPredecessor{}};
380   std::unique_ptr<internal::TaskQueueImpl> impl_;
381 
382   const WeakPtr<internal::SequenceManagerImpl> sequence_manager_;
383 
384   scoped_refptr<internal::AssociatedThreadId> associated_thread_;
385   scoped_refptr<SingleThreadTaskRunner> default_task_runner_;
386 
387   int enabled_voter_count_ = 0;
388   int voter_count_ = 0;
389   const char* name_;
390 
391   DISALLOW_COPY_AND_ASSIGN(TaskQueue);
392 };
393 
394 }  // namespace sequence_manager
395 }  // namespace base
396 
397 #endif  // BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_H_
398