| // Copyright 2015 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef BASE_TASK_SEQUENCE_MANAGER_WORK_QUEUE_H_ |
| #define BASE_TASK_SEQUENCE_MANAGER_WORK_QUEUE_H_ |
| |
| #include "base/base_export.h" |
| #include "base/task/common/intrusive_heap.h" |
| #include "base/task/sequence_manager/enqueue_order.h" |
| #include "base/task/sequence_manager/sequenced_task_source.h" |
| #include "base/task/sequence_manager/task_queue_impl.h" |
| #include "base/trace_event/trace_event.h" |
| #include "base/trace_event/traced_value.h" |
| |
| namespace base { |
| namespace sequence_manager { |
| namespace internal { |
| |
| class WorkQueueSets; |
| |
| // This class keeps track of immediate and delayed tasks which are due to run |
| // now. It interfaces deeply with WorkQueueSets which keeps track of which queue |
| // (with a given priority) contains the oldest task. |
| // |
| // If a fence is inserted, WorkQueue behaves normally up until |
| // TakeTaskFromWorkQueue reaches or exceeds the fence. At that point it the |
| // API subset used by WorkQueueSets pretends the WorkQueue is empty until the |
| // fence is removed. This functionality is a primitive intended for use by |
| // throttling mechanisms. |
| class BASE_EXPORT WorkQueue { |
| public: |
| using QueueType = internal::TaskQueueImpl::WorkQueueType; |
| |
| // Note |task_queue| can be null if queue_type is kNonNestable. |
| WorkQueue(TaskQueueImpl* task_queue, const char* name, QueueType queue_type); |
| ~WorkQueue(); |
| |
| // Associates this work queue with the given work queue sets. This must be |
| // called before any tasks can be inserted into this work queue. |
| void AssignToWorkQueueSets(WorkQueueSets* work_queue_sets); |
| |
| // Assigns the current set index. |
| void AssignSetIndex(size_t work_queue_set_index); |
| |
| void AsValueInto(TimeTicks now, trace_event::TracedValue* state) const; |
| |
| // Returns true if the |tasks_| is empty. This method ignores any fences. |
| bool Empty() const { return tasks_.empty(); } |
| |
| // If the |tasks_| isn't empty and a fence hasn't been reached, |
| // |enqueue_order| gets set to the enqueue order of the front task and the |
| // function returns true. Otherwise the function returns false. |
| bool GetFrontTaskEnqueueOrder(EnqueueOrder* enqueue_order) const; |
| |
| // Returns the first task in this queue or null if the queue is empty. This |
| // method ignores any fences. |
| const Task* GetFrontTask() const; |
| |
| // Returns the last task in this queue or null if the queue is empty. This |
| // method ignores any fences. |
| const Task* GetBackTask() const; |
| |
| // Pushes the task onto the |tasks_| and if a fence hasn't been reached |
| // it informs the WorkQueueSets if the head changed. |
| void Push(Task task); |
| |
| // RAII helper that helps efficiently push N Tasks to a WorkQueue. |
| class BASE_EXPORT TaskPusher { |
| public: |
| TaskPusher(const TaskPusher&) = delete; |
| TaskPusher(TaskPusher&& other); |
| ~TaskPusher(); |
| |
| void Push(Task* task); |
| |
| private: |
| friend class WorkQueue; |
| |
| explicit TaskPusher(WorkQueue* work_queue); |
| |
| WorkQueue* work_queue_; |
| const bool was_empty_; |
| }; |
| |
| // Returns an RAII helper to efficiently push multiple tasks. |
| TaskPusher CreateTaskPusher(); |
| |
| // Pushes the task onto the front of the |tasks_| and if it's before any |
| // fence it informs the WorkQueueSets the head changed. Use with caution this |
| // API can easily lead to task starvation if misused. |
| void PushNonNestableTaskToFront(Task task); |
| |
| // Reloads the empty |tasks_| with |
| // |task_queue_->TakeImmediateIncomingQueue| and if a fence hasn't been |
| // reached it informs the WorkQueueSets if the head changed. |
| void TakeImmediateIncomingQueueTasks(); |
| |
| size_t Size() const { return tasks_.size(); } |
| |
| size_t Capacity() const { return tasks_.capacity(); } |
| |
| // Pulls a task off the |tasks_| and informs the WorkQueueSets. If the |
| // task removed had an enqueue order >= the current fence then WorkQueue |
| // pretends to be empty as far as the WorkQueueSets is concerned. |
| Task TakeTaskFromWorkQueue(); |
| |
| // Removes all canceled tasks from the head of the list. Returns true if any |
| // tasks were removed. |
| bool RemoveAllCanceledTasksFromFront(); |
| |
| const char* name() const { return name_; } |
| |
| TaskQueueImpl* task_queue() const { return task_queue_; } |
| |
| WorkQueueSets* work_queue_sets() const { return work_queue_sets_; } |
| |
| size_t work_queue_set_index() const { return work_queue_set_index_; } |
| |
| base::internal::HeapHandle heap_handle() const { return heap_handle_; } |
| |
| void set_heap_handle(base::internal::HeapHandle handle) { |
| heap_handle_ = handle; |
| } |
| |
| QueueType queue_type() const { return queue_type_; } |
| |
| // Returns true if the front task in this queue has an older enqueue order |
| // than the front task of |other_queue|. Both queue are assumed to be |
| // non-empty. This method ignores any fences. |
| bool ShouldRunBefore(const WorkQueue* other_queue) const; |
| |
| // Submit a fence. When TakeTaskFromWorkQueue encounters a task whose |
| // enqueue_order is >= |fence| then the WorkQueue will start pretending to be. |
| // empty. |
| // Inserting a fence may supersede a previous one and unblock some tasks. |
| // Returns true if any tasks where unblocked, returns false otherwise. |
| bool InsertFence(EnqueueOrder fence); |
| |
| // Submit a fence without triggering a WorkQueueSets notification. |
| // Caller must ensure that WorkQueueSets are properly updated. |
| // This method should not be called when a fence is already present. |
| void InsertFenceSilently(EnqueueOrder fence); |
| |
| // Removes any fences that where added and if WorkQueue was pretending to be |
| // empty, then the real value is reported to WorkQueueSets. Returns true if |
| // any tasks where unblocked. |
| bool RemoveFence(); |
| |
| // Returns true if any tasks are blocked by the fence. Returns true if the |
| // queue is empty and fence has been set (i.e. future tasks would be blocked). |
| // Otherwise returns false. |
| bool BlockedByFence() const; |
| |
| // Shrinks |tasks_| if it's wasting memory. |
| void MaybeShrinkQueue(); |
| |
| // Delete all tasks within this WorkQueue. |
| void DeletePendingTasks(); |
| |
| // Test support function. This should not be used in production code. |
| void PopTaskForTesting(); |
| |
| private: |
| bool InsertFenceImpl(EnqueueOrder fence); |
| |
| TaskQueueImpl::TaskDeque tasks_; |
| WorkQueueSets* work_queue_sets_ = nullptr; // NOT OWNED. |
| TaskQueueImpl* const task_queue_; // NOT OWNED. |
| size_t work_queue_set_index_ = 0; |
| |
| // Iff the queue isn't empty (or appearing to be empty due to a fence) then |
| // |heap_handle_| will be valid and correspond to this queue's location within |
| // an IntrusiveHeap inside the WorkQueueSet. |
| base::internal::HeapHandle heap_handle_; |
| const char* const name_; |
| EnqueueOrder fence_; |
| const QueueType queue_type_; |
| |
| DISALLOW_COPY_AND_ASSIGN(WorkQueue); |
| }; |
| |
| } // namespace internal |
| } // namespace sequence_manager |
| } // namespace base |
| |
| #endif // BASE_TASK_SEQUENCE_MANAGER_WORK_QUEUE_H_ |