Home | History | Annotate | Download | only in sequence_manager
      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 "base/macros.h"
      9 #include "base/memory/weak_ptr.h"
     10 #include "base/message_loop/message_loop.h"
     11 #include "base/optional.h"
     12 #include "base/single_thread_task_runner.h"
     13 #include "base/synchronization/lock.h"
     14 #include "base/task/sequence_manager/lazy_now.h"
     15 #include "base/task/sequence_manager/moveable_auto_lock.h"
     16 #include "base/threading/platform_thread.h"
     17 #include "base/time/time.h"
     18 
     19 namespace base {
     20 
     21 namespace trace_event {
     22 class BlameContext;
     23 }
     24 
     25 namespace sequence_manager {
     26 
     27 namespace internal {
     28 class GracefulQueueShutdownHelper;
     29 class SequenceManagerImpl;
     30 class TaskQueueImpl;
     31 }  // namespace internal
     32 
     33 class TimeDomain;
     34 
     35 class BASE_EXPORT TaskQueue : public SingleThreadTaskRunner {
     36  public:
     37   class Observer {
     38    public:
     39     virtual ~Observer() = default;
     40 
     41     // Notify observer that the time at which this queue wants to run
     42     // the next task has changed. |next_wakeup| can be in the past
     43     // (e.g. TimeTicks() can be used to notify about immediate work).
     44     // Can be called on any thread
     45     // All methods but SetObserver, SetTimeDomain and GetTimeDomain can be
     46     // called on |queue|.
     47     //
     48     // TODO(altimin): Make it Optional<TimeTicks> to tell
     49     // observer about cancellations.
     50     virtual void OnQueueNextWakeUpChanged(TaskQueue* queue,
     51                                           TimeTicks next_wake_up) = 0;
     52   };
     53 
     54   // A wrapper around OnceClosure with additional metadata to be passed
     55   // to PostTask and plumbed until PendingTask is created.
     56   struct BASE_EXPORT PostedTask {
     57     PostedTask(OnceClosure callback,
     58                Location posted_from,
     59                TimeDelta delay = TimeDelta(),
     60                Nestable nestable = Nestable::kNestable,
     61                int task_type = 0);
     62     PostedTask(PostedTask&& move_from);
     63     PostedTask(const PostedTask& copy_from) = delete;
     64     ~PostedTask();
     65 
     66     OnceClosure callback;
     67     Location posted_from;
     68     TimeDelta delay;
     69     Nestable nestable;
     70     int task_type;
     71   };
     72 
     73   // Prepare the task queue to get released.
     74   // All tasks posted after this call will be discarded.
     75   virtual void ShutdownTaskQueue();
     76 
     77   // TODO(scheduler-dev): Could we define a more clear list of priorities?
     78   // See https://crbug.com/847858.
     79   enum QueuePriority {
     80     // Queues with control priority will run before any other queue, and will
     81     // explicitly starve other queues. Typically this should only be used for
     82     // private queues which perform control operations.
     83     kControlPriority,
     84 
     85     // The selector will prioritize highest over high, normal and low; and
     86     // high over normal and low; and normal over low. However it will ensure
     87     // neither of the lower priority queues can be completely starved by higher
     88     // priority tasks. All three of these queues will always take priority over
     89     // and can starve the best effort queue.
     90     kHighestPriority,
     91 
     92     kHighPriority,
     93 
     94     // Queues with normal priority are the default.
     95     kNormalPriority,
     96     kLowPriority,
     97 
     98     // Queues with best effort priority will only be run if all other queues are
     99     // empty. They can be starved by the other queues.
    100     kBestEffortPriority,
    101     // Must be the last entry.
    102     kQueuePriorityCount,
    103     kFirstQueuePriority = kControlPriority,
    104   };
    105 
    106   // Can be called on any thread.
    107   static const char* PriorityToString(QueuePriority priority);
    108 
    109   // Options for constructing a TaskQueue.
    110   struct Spec {
    111     explicit Spec(const char* name)
    112         : name(name),
    113           should_monitor_quiescence(false),
    114           time_domain(nullptr),
    115           should_notify_observers(true) {}
    116 
    117     Spec SetShouldMonitorQuiescence(bool should_monitor) {
    118       should_monitor_quiescence = should_monitor;
    119       return *this;
    120     }
    121 
    122     Spec SetShouldNotifyObservers(bool run_observers) {
    123       should_notify_observers = run_observers;
    124       return *this;
    125     }
    126 
    127     Spec SetTimeDomain(TimeDomain* domain) {
    128       time_domain = domain;
    129       return *this;
    130     }
    131 
    132     const char* name;
    133     bool should_monitor_quiescence;
    134     TimeDomain* time_domain;
    135     bool should_notify_observers;
    136   };
    137 
    138   // Interface to pass per-task metadata to RendererScheduler.
    139   class BASE_EXPORT Task : public PendingTask {
    140    public:
    141     Task(PostedTask posted_task, TimeTicks desired_run_time);
    142 
    143     int task_type() const { return task_type_; }
    144 
    145    private:
    146     int task_type_;
    147   };
    148 
    149   // Information about task execution.
    150   //
    151   // Wall-time related methods (start_time, end_time, wall_duration) can be
    152   // called only when |has_wall_time()| is true.
    153   // Thread-time related mehtods (start_thread_time, end_thread_time,
    154   // thread_duration) can be called only when |has_thread_time()| is true.
    155   //
    156   // start_* should be called after RecordTaskStart.
    157   // end_* and *_duration should be called after RecordTaskEnd.
    158   class BASE_EXPORT TaskTiming {
    159    public:
    160     TaskTiming(bool has_wall_time, bool has_thread_time);
    161 
    162     bool has_wall_time() const { return has_wall_time_; }
    163     bool has_thread_time() const { return has_thread_time_; }
    164 
    165     base::TimeTicks start_time() const {
    166       DCHECK(has_wall_time());
    167       return start_time_;
    168     }
    169     base::TimeTicks end_time() const {
    170       DCHECK(has_wall_time());
    171       return end_time_;
    172     }
    173     base::TimeDelta wall_duration() const {
    174       DCHECK(has_wall_time());
    175       return end_time_ - start_time_;
    176     }
    177     base::ThreadTicks start_thread_time() const {
    178       DCHECK(has_thread_time());
    179       return start_thread_time_;
    180     }
    181     base::ThreadTicks end_thread_time() const {
    182       DCHECK(has_thread_time());
    183       return end_thread_time_;
    184     }
    185     base::TimeDelta thread_duration() const {
    186       DCHECK(has_thread_time());
    187       return end_thread_time_ - start_thread_time_;
    188     }
    189 
    190     void RecordTaskStart(LazyNow* now);
    191     void RecordTaskEnd(LazyNow* now);
    192 
    193     // Protected for tests.
    194    protected:
    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 QueueEnabledVoter {
    207    public:
    208     QueueEnabledVoter() = default;
    209     virtual ~QueueEnabledVoter() = default;
    210 
    211     // Votes to enable or disable the associated TaskQueue. The TaskQueue will
    212     // only be enabled if all the voters agree it should be enabled, or if there
    213     // are no voters.
    214     // NOTE this must be called on the thread the associated TaskQueue was
    215     // created on.
    216     virtual void SetQueueEnabled(bool enabled) = 0;
    217 
    218    private:
    219     DISALLOW_COPY_AND_ASSIGN(QueueEnabledVoter);
    220   };
    221 
    222   // Returns an interface that allows the caller to vote on whether or not this
    223   // TaskQueue is enabled. The TaskQueue will be enabled if there are no voters
    224   // or if all agree it should be enabled.
    225   // NOTE this must be called on the thread this TaskQueue was created by.
    226   std::unique_ptr<QueueEnabledVoter> CreateQueueEnabledVoter();
    227 
    228   // NOTE this must be called on the thread this TaskQueue was created by.
    229   bool IsQueueEnabled() const;
    230 
    231   // Returns true if the queue is completely empty.
    232   bool IsEmpty() const;
    233 
    234   // Returns the number of pending tasks in the queue.
    235   size_t GetNumberOfPendingTasks() const;
    236 
    237   // Returns true if the queue has work that's ready to execute now.
    238   // NOTE: this must be called on the thread this TaskQueue was created by.
    239   bool HasTaskToRunImmediately() const;
    240 
    241   // Returns requested run time of next scheduled wake-up for a delayed task
    242   // which is not ready to run. If there are no such tasks (immediate tasks
    243   // don't count) or the queue is disabled it returns nullopt.
    244   // NOTE: this must be called on the thread this TaskQueue was created by.
    245   Optional<TimeTicks> GetNextScheduledWakeUp();
    246 
    247   // Can be called on any thread.
    248   virtual const char* GetName() const;
    249 
    250   // Set the priority of the queue to |priority|. NOTE this must be called on
    251   // the thread this TaskQueue was created by.
    252   void SetQueuePriority(QueuePriority priority);
    253 
    254   // Returns the current queue priority.
    255   QueuePriority GetQueuePriority() const;
    256 
    257   // These functions can only be called on the same thread that the task queue
    258   // manager executes its tasks on.
    259   void AddTaskObserver(MessageLoop::TaskObserver* task_observer);
    260   void RemoveTaskObserver(MessageLoop::TaskObserver* task_observer);
    261 
    262   // Set the blame context which is entered and left while executing tasks from
    263   // this task queue. |blame_context| must be null or outlive this task queue.
    264   // Must be called on the thread this TaskQueue was created by.
    265   void SetBlameContext(trace_event::BlameContext* blame_context);
    266 
    267   // Removes the task queue from the previous TimeDomain and adds it to
    268   // |domain|.  This is a moderately expensive operation.
    269   void SetTimeDomain(TimeDomain* domain);
    270 
    271   // Returns the queue's current TimeDomain.  Can be called from any thread.
    272   TimeDomain* GetTimeDomain() const;
    273 
    274   enum class InsertFencePosition {
    275     kNow,  // Tasks posted on the queue up till this point further may run.
    276            // All further tasks are blocked.
    277     kBeginningOfTime,  // No tasks posted on this queue may run.
    278   };
    279 
    280   // Inserts a barrier into the task queue which prevents tasks with an enqueue
    281   // order greater than the fence from running until either the fence has been
    282   // removed or a subsequent fence has unblocked some tasks within the queue.
    283   // Note: delayed tasks get their enqueue order set once their delay has
    284   // expired, and non-delayed tasks get their enqueue order set when posted.
    285   //
    286   // Fences come in three flavours:
    287   // - Regular (InsertFence(NOW)) - all tasks posted after this moment
    288   //   are blocked.
    289   // - Fully blocking (InsertFence(kBeginningOfTime)) - all tasks including
    290   //   already posted are blocked.
    291   // - Delayed (InsertFenceAt(timestamp)) - blocks all tasks posted after given
    292   //   point in time (must be in the future).
    293   //
    294   // Only one fence can be scheduled at a time. Inserting a new fence
    295   // will automatically remove the previous one, regardless of fence type.
    296   void InsertFence(InsertFencePosition position);
    297   void InsertFenceAt(TimeTicks time);
    298 
    299   // Removes any previously added fence and unblocks execution of any tasks
    300   // blocked by it.
    301   void RemoveFence();
    302 
    303   // Returns true if the queue has a fence but it isn't necessarily blocking
    304   // execution of tasks (it may be the case if tasks enqueue order hasn't
    305   // reached the number set for a fence).
    306   bool HasActiveFence();
    307 
    308   // Returns true if the queue has a fence which is blocking execution of tasks.
    309   bool BlockedByFence() const;
    310 
    311   void SetObserver(Observer* observer);
    312 
    313   // SingleThreadTaskRunner implementation
    314   bool RunsTasksInCurrentSequence() const override;
    315   bool PostDelayedTask(const Location& from_here,
    316                        OnceClosure task,
    317                        TimeDelta delay) override;
    318   bool PostNonNestableDelayedTask(const Location& from_here,
    319                                   OnceClosure task,
    320                                   TimeDelta delay) override;
    321 
    322   bool PostTaskWithMetadata(PostedTask task);
    323 
    324  protected:
    325   TaskQueue(std::unique_ptr<internal::TaskQueueImpl> impl,
    326             const TaskQueue::Spec& spec);
    327   ~TaskQueue() override;
    328 
    329   internal::TaskQueueImpl* GetTaskQueueImpl() const { return impl_.get(); }
    330 
    331  private:
    332   friend class internal::SequenceManagerImpl;
    333   friend class internal::TaskQueueImpl;
    334 
    335   bool IsOnMainThread() const;
    336 
    337   Optional<MoveableAutoLock> AcquireImplReadLockIfNeeded() const;
    338 
    339   // TaskQueue has ownership of an underlying implementation but in certain
    340   // cases (e.g. detached frames) their lifetime may diverge.
    341   // This method should be used to take away the impl for graceful shutdown.
    342   // TaskQueue will disregard any calls or posting tasks thereafter.
    343   std::unique_ptr<internal::TaskQueueImpl> TakeTaskQueueImpl();
    344 
    345   // |impl_| can be written to on the main thread but can be read from
    346   // any thread.
    347   // |impl_lock_| must be acquired when writing to |impl_| or when accessing
    348   // it from non-main thread. Reading from the main thread does not require
    349   // a lock.
    350   mutable Lock impl_lock_;
    351   std::unique_ptr<internal::TaskQueueImpl> impl_;
    352 
    353   const PlatformThreadId thread_id_;
    354 
    355   const WeakPtr<internal::SequenceManagerImpl> sequence_manager_;
    356 
    357   const scoped_refptr<internal::GracefulQueueShutdownHelper>
    358       graceful_queue_shutdown_helper_;
    359 
    360   THREAD_CHECKER(main_thread_checker_);
    361 
    362   DISALLOW_COPY_AND_ASSIGN(TaskQueue);
    363 };
    364 
    365 }  // namespace sequence_manager
    366 }  // namespace base
    367 
    368 #endif  // BASE_TASK_SEQUENCE_MANAGER_TASK_QUEUE_H_
    369