work_queue.h 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. // Copyright 2015 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. #ifndef BASE_TASK_SEQUENCE_MANAGER_WORK_QUEUE_H_
  5. #define BASE_TASK_SEQUENCE_MANAGER_WORK_QUEUE_H_
  6. #include "base/base_export.h"
  7. #include "base/task/common/intrusive_heap.h"
  8. #include "base/task/sequence_manager/enqueue_order.h"
  9. #include "base/task/sequence_manager/sequenced_task_source.h"
  10. #include "base/task/sequence_manager/task_queue_impl.h"
  11. #include "base/values.h"
  12. namespace base {
  13. namespace sequence_manager {
  14. namespace internal {
  15. class WorkQueueSets;
  16. // This class keeps track of immediate and delayed tasks which are due to run
  17. // now. It interfaces deeply with WorkQueueSets which keeps track of which queue
  18. // (with a given priority) contains the oldest task.
  19. //
  20. // If a fence is inserted, WorkQueue behaves normally up until
  21. // TakeTaskFromWorkQueue reaches or exceeds the fence. At that point it the
  22. // API subset used by WorkQueueSets pretends the WorkQueue is empty until the
  23. // fence is removed. This functionality is a primitive intended for use by
  24. // throttling mechanisms.
  25. class BASE_EXPORT WorkQueue {
  26. public:
  27. using QueueType = internal::TaskQueueImpl::WorkQueueType;
  28. // Note |task_queue| can be null if queue_type is kNonNestable.
  29. WorkQueue(TaskQueueImpl* task_queue, const char* name, QueueType queue_type);
  30. WorkQueue(const WorkQueue&) = delete;
  31. WorkQueue& operator=(const WorkQueue&) = delete;
  32. ~WorkQueue();
  33. // Associates this work queue with the given work queue sets. This must be
  34. // called before any tasks can be inserted into this work queue.
  35. void AssignToWorkQueueSets(WorkQueueSets* work_queue_sets);
  36. // Assigns the current set index.
  37. void AssignSetIndex(size_t work_queue_set_index);
  38. Value AsValue(TimeTicks now) const;
  39. // Returns true if the |tasks_| is empty. This method ignores any fences.
  40. bool Empty() const { return tasks_.empty(); }
  41. // If the |tasks_| isn't empty and a fence hasn't been reached,
  42. // |enqueue_order| gets set to the enqueue order of the front task and the
  43. // function returns true. Otherwise the function returns false.
  44. bool GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const;
  45. // Returns the first task in this queue or null if the queue is empty. This
  46. // method ignores any fences.
  47. const Task* GetFrontTask() const;
  48. // Returns the last task in this queue or null if the queue is empty. This
  49. // method ignores any fences.
  50. const Task* GetBackTask() const;
  51. // Pushes the task onto the |tasks_| and if a fence hasn't been reached
  52. // it informs the WorkQueueSets if the head changed.
  53. void Push(Task task);
  54. // RAII helper that helps efficiently push N Tasks to a WorkQueue.
  55. class BASE_EXPORT TaskPusher {
  56. public:
  57. TaskPusher(const TaskPusher&) = delete;
  58. TaskPusher(TaskPusher&& other);
  59. ~TaskPusher();
  60. void Push(Task* task);
  61. private:
  62. friend class WorkQueue;
  63. explicit TaskPusher(WorkQueue* work_queue);
  64. WorkQueue* work_queue_;
  65. const bool was_empty_;
  66. };
  67. // Returns an RAII helper to efficiently push multiple tasks.
  68. TaskPusher CreateTaskPusher();
  69. // Pushes the task onto the front of the |tasks_| and if it's before any
  70. // fence it informs the WorkQueueSets the head changed. Use with caution this
  71. // API can easily lead to task starvation if misused.
  72. void PushNonNestableTaskToFront(Task task);
  73. // Reloads the empty |tasks_| with
  74. // |task_queue_->TakeImmediateIncomingQueue| and if a fence hasn't been
  75. // reached it informs the WorkQueueSets if the head changed.
  76. void TakeImmediateIncomingQueueTasks();
  77. size_t Size() const { return tasks_.size(); }
  78. size_t Capacity() const { return tasks_.capacity(); }
  79. // Pulls a task off the |tasks_| and informs the WorkQueueSets. If the
  80. // task removed had an enqueue order >= the current fence then WorkQueue
  81. // pretends to be empty as far as the WorkQueueSets is concerned.
  82. Task TakeTaskFromWorkQueue();
  83. // Removes all canceled tasks from the head of the list. Returns true if any
  84. // tasks were removed.
  85. bool RemoveAllCanceledTasksFromFront();
  86. const char* name() const { return name_; }
  87. TaskQueueImpl* task_queue() const { return task_queue_; }
  88. WorkQueueSets* work_queue_sets() const { return work_queue_sets_; }
  89. size_t work_queue_set_index() const { return work_queue_set_index_; }
  90. base::internal::HeapHandle heap_handle() const { return heap_handle_; }
  91. void set_heap_handle(base::internal::HeapHandle handle) {
  92. heap_handle_ = handle;
  93. }
  94. QueueType queue_type() const { return queue_type_; }
  95. // Returns true if the front task in this queue has an older enqueue order
  96. // than the front task of |other_queue|. Both queue are assumed to be
  97. // non-empty. This method ignores any fences.
  98. bool ShouldRunBefore(const WorkQueue* other_queue) const;
  99. // Submit a fence. When TakeTaskFromWorkQueue encounters a task whose
  100. // enqueue_order is >= |fence| then the WorkQueue will start pretending to be.
  101. // empty.
  102. // Inserting a fence may supersede a previous one and unblock some tasks.
  103. // Returns true if any tasks where unblocked, returns false otherwise.
  104. bool InsertFence(EnqueueOrder fence);
  105. // Submit a fence without triggering a WorkQueueSets notification.
  106. // Caller must ensure that WorkQueueSets are properly updated.
  107. // This method should not be called when a fence is already present.
  108. void InsertFenceSilently(EnqueueOrder fence);
  109. // Removes any fences that where added and if WorkQueue was pretending to be
  110. // empty, then the real value is reported to WorkQueueSets. Returns true if
  111. // any tasks where unblocked.
  112. bool RemoveFence();
  113. // Returns true if any tasks are blocked by the fence. Returns true if the
  114. // queue is empty and fence has been set (i.e. future tasks would be blocked).
  115. // Otherwise returns false.
  116. bool BlockedByFence() const;
  117. // Shrinks |tasks_| if it's wasting memory.
  118. void MaybeShrinkQueue();
  119. // Delete all tasks within this WorkQueue.
  120. void DeletePendingTasks();
  121. // Test support function. This should not be used in production code.
  122. void PopTaskForTesting();
  123. // Iterates through |tasks_| adding any that are older than |reference| to
  124. // |result|.
  125. void CollectTasksOlderThan(EnqueueOrder reference,
  126. std::vector<const Task*>* result) const;
  127. private:
  128. bool InsertFenceImpl(EnqueueOrder fence);
  129. TaskQueueImpl::TaskDeque tasks_;
  130. WorkQueueSets* work_queue_sets_ = nullptr; // NOT OWNED.
  131. TaskQueueImpl* const task_queue_; // NOT OWNED.
  132. size_t work_queue_set_index_ = 0;
  133. // Iff the queue isn't empty (or appearing to be empty due to a fence) then
  134. // |heap_handle_| will be valid and correspond to this queue's location within
  135. // an IntrusiveHeap inside the WorkQueueSet.
  136. base::internal::HeapHandle heap_handle_;
  137. const char* const name_;
  138. EnqueueOrder fence_;
  139. const QueueType queue_type_;
  140. };
  141. } // namespace internal
  142. } // namespace sequence_manager
  143. } // namespace base
  144. #endif // BASE_TASK_SEQUENCE_MANAGER_WORK_QUEUE_H_