1 // Copyright 2021 The Chromium Authors 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_WAKE_UP_QUEUE_H_ 6 #define BASE_TASK_SEQUENCE_MANAGER_WAKE_UP_QUEUE_H_ 7 8 #include <optional> 9 10 #include "base/base_export.h" 11 #include "base/check.h" 12 #include "base/containers/intrusive_heap.h" 13 #include "base/memory/raw_ptr.h" 14 #include "base/memory/raw_ptr_exclusion.h" 15 #include "base/task/common/lazy_now.h" 16 #include "base/task/sequence_manager/task_queue_impl.h" 17 #include "base/time/time.h" 18 #include "base/values.h" 19 20 namespace base { 21 namespace sequence_manager { 22 23 class EnqueueOrder; 24 25 namespace internal { 26 27 class AssociatedThreadId; 28 class SequenceManagerImpl; 29 class TaskQueueImpl; 30 31 // WakeUpQueue is a queue of (wake_up, TaskQueueImpl*) pairs which 32 // aggregates wake-ups from multiple TaskQueueImpl into a single wake-up, and 33 // notifies TaskQueueImpls when wake-up times are reached. 34 class BASE_EXPORT WakeUpQueue { 35 public: 36 WakeUpQueue(const WakeUpQueue&) = delete; 37 WakeUpQueue& operator=(const WakeUpQueue&) = delete; 38 virtual ~WakeUpQueue(); 39 40 // Returns a wake-up for the next pending delayed task (pending delayed tasks 41 // that are ripe may be ignored). If there are no such tasks (immediate tasks 42 // don't count) or queues are disabled it returns nullopt. 43 std::optional<WakeUp> GetNextDelayedWakeUp() const; 44 45 // Debug info. 46 Value::Dict AsValue(TimeTicks now) const; 47 has_pending_high_resolution_tasks()48 bool has_pending_high_resolution_tasks() const { 49 return pending_high_res_wake_up_count_; 50 } 51 52 // Returns true if there are no pending delayed tasks. empty()53 bool empty() const { return wake_up_queue_.empty(); } 54 55 // Moves ready delayed tasks in TaskQueues to delayed WorkQueues, consuming 56 // expired wake-ups in the process. 57 void MoveReadyDelayedTasksToWorkQueues(LazyNow* lazy_now, 58 EnqueueOrder enqueue_order); 59 60 // Schedule `queue` to wake up at certain time. Repeating calls with the same 61 // `queue` invalidate previous requests. Nullopt `wake_up` cancels a 62 // previously set wake up for `queue`. 63 void SetNextWakeUpForQueue(internal::TaskQueueImpl* queue, 64 LazyNow* lazy_now, 65 std::optional<WakeUp> wake_up); 66 67 // Remove the TaskQueue from any internal data structures. 68 virtual void UnregisterQueue(internal::TaskQueueImpl* queue) = 0; 69 70 // Removes all canceled delayed tasks from the front of the queue. After 71 // calling this, GetNextDelayedWakeUp() is guaranteed to return a wake up time 72 // for a non-canceled task. 73 void RemoveAllCanceledDelayedTasksFromFront(LazyNow* lazy_now); 74 75 protected: 76 explicit WakeUpQueue( 77 scoped_refptr<const internal::AssociatedThreadId> associated_thread); 78 79 // Called every time the next `next_wake_up` changes. std::nullopt is used to 80 // cancel the next wake-up. Subclasses may use this to tell SequenceManager to 81 // schedule the next wake-up at the given time. 82 virtual void OnNextWakeUpChanged(LazyNow* lazy_now, 83 std::optional<WakeUp> next_wake_up) = 0; 84 85 virtual const char* GetName() const = 0; 86 87 private: 88 friend class MockWakeUpQueue; 89 90 struct ScheduledWakeUp { 91 WakeUp wake_up; 92 // RAW_PTR_EXCLUSION: Performance reasons (based on analysis of 93 // speedometer3). 94 RAW_PTR_EXCLUSION internal::TaskQueueImpl* queue = nullptr; 95 96 bool operator>(const ScheduledWakeUp& other) const { 97 return wake_up.latest_time() > other.wake_up.latest_time(); 98 } 99 SetHeapHandleScheduledWakeUp100 void SetHeapHandle(HeapHandle handle) { 101 DCHECK(handle.IsValid()); 102 queue->set_heap_handle(handle); 103 } 104 ClearHeapHandleScheduledWakeUp105 void ClearHeapHandle() { 106 DCHECK(queue->heap_handle().IsValid()); 107 queue->set_heap_handle(HeapHandle()); 108 } 109 GetHeapHandleScheduledWakeUp110 HeapHandle GetHeapHandle() const { return queue->heap_handle(); } 111 }; 112 113 IntrusiveHeap<ScheduledWakeUp, std::greater<>> wake_up_queue_; 114 int pending_high_res_wake_up_count_ = 0; 115 116 const scoped_refptr<const internal::AssociatedThreadId> associated_thread_; 117 }; 118 119 // Default WakeUpQueue implementation that forwards wake-ups to 120 // `sequence_manager_`. 121 class BASE_EXPORT DefaultWakeUpQueue : public WakeUpQueue { 122 public: 123 DefaultWakeUpQueue( 124 scoped_refptr<internal::AssociatedThreadId> associated_thread, 125 internal::SequenceManagerImpl* sequence_manager); 126 ~DefaultWakeUpQueue() override; 127 128 private: 129 // WakeUpQueue implementation: 130 void OnNextWakeUpChanged(LazyNow* lazy_now, 131 std::optional<WakeUp> wake_up) override; 132 const char* GetName() const override; 133 void UnregisterQueue(internal::TaskQueueImpl* queue) override; 134 135 raw_ptr<internal::SequenceManagerImpl> sequence_manager_; // Not owned. 136 }; 137 138 // WakeUpQueue implementation that doesn't sends wake-ups to 139 // any SequenceManager, such that task queues don't cause wake-ups. 140 class BASE_EXPORT NonWakingWakeUpQueue : public WakeUpQueue { 141 public: 142 explicit NonWakingWakeUpQueue( 143 scoped_refptr<internal::AssociatedThreadId> associated_thread); 144 ~NonWakingWakeUpQueue() override; 145 146 private: 147 // WakeUpQueue implementation: 148 void OnNextWakeUpChanged(LazyNow* lazy_now, 149 std::optional<WakeUp> wake_up) override; 150 const char* GetName() const override; 151 void UnregisterQueue(internal::TaskQueueImpl* queue) override; 152 }; 153 154 } // namespace internal 155 } // namespace sequence_manager 156 } // namespace base 157 158 #endif // BASE_TASK_SEQUENCE_MANAGER_WAKE_UP_QUEUE_H_ 159