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 5 #include "base/task/sequence_manager/time_domain.h" 6 7 #include "base/task/sequence_manager/sequence_manager_impl.h" 8 #include "base/task/sequence_manager/task_queue_impl.h" 9 #include "base/task/sequence_manager/work_queue.h" 10 11 namespace base { 12 namespace sequence_manager { 13 14 TimeDomain::TimeDomain() : sequence_manager_(nullptr) {} 15 16 TimeDomain::~TimeDomain() { 17 DCHECK(main_thread_checker_.CalledOnValidThread()); 18 } 19 20 void TimeDomain::OnRegisterWithSequenceManager( 21 internal::SequenceManagerImpl* sequence_manager) { 22 DCHECK(sequence_manager); 23 DCHECK(!sequence_manager_); 24 sequence_manager_ = sequence_manager; 25 } 26 27 SequenceManager* TimeDomain::sequence_manager() const { 28 DCHECK(sequence_manager_); 29 return sequence_manager_; 30 } 31 32 // TODO(kraynov): https://crbug.com/857101 Consider making an interface 33 // for SequenceManagerImpl which will expose SetNextDelayedDoWork and 34 // MaybeScheduleImmediateWork methods to make the functions below pure-virtual. 35 36 void TimeDomain::SetNextDelayedDoWork(LazyNow* lazy_now, TimeTicks run_time) { 37 sequence_manager_->SetNextDelayedDoWork(lazy_now, run_time); 38 } 39 40 void TimeDomain::RequestDoWork() { 41 sequence_manager_->MaybeScheduleImmediateWork(FROM_HERE); 42 } 43 44 void TimeDomain::UnregisterQueue(internal::TaskQueueImpl* queue) { 45 DCHECK(main_thread_checker_.CalledOnValidThread()); 46 DCHECK_EQ(queue->GetTimeDomain(), this); 47 LazyNow lazy_now(CreateLazyNow()); 48 SetNextWakeUpForQueue(queue, nullopt, &lazy_now); 49 } 50 51 void TimeDomain::SetNextWakeUpForQueue( 52 internal::TaskQueueImpl* queue, 53 Optional<internal::TaskQueueImpl::DelayedWakeUp> wake_up, 54 LazyNow* lazy_now) { 55 DCHECK(main_thread_checker_.CalledOnValidThread()); 56 DCHECK_EQ(queue->GetTimeDomain(), this); 57 DCHECK(queue->IsQueueEnabled() || !wake_up); 58 59 Optional<TimeTicks> previous_wake_up; 60 if (!delayed_wake_up_queue_.empty()) 61 previous_wake_up = delayed_wake_up_queue_.Min().wake_up.time; 62 63 if (wake_up) { 64 // Insert a new wake-up into the heap. 65 if (queue->heap_handle().IsValid()) { 66 // O(log n) 67 delayed_wake_up_queue_.ChangeKey(queue->heap_handle(), 68 {wake_up.value(), queue}); 69 } else { 70 // O(log n) 71 delayed_wake_up_queue_.insert({wake_up.value(), queue}); 72 } 73 } else { 74 // Remove a wake-up from heap if present. 75 if (queue->heap_handle().IsValid()) 76 delayed_wake_up_queue_.erase(queue->heap_handle()); 77 } 78 79 Optional<TimeTicks> new_wake_up; 80 if (!delayed_wake_up_queue_.empty()) 81 new_wake_up = delayed_wake_up_queue_.Min().wake_up.time; 82 83 // TODO(kraynov): https://crbug.com/857101 Review the relationship with 84 // SequenceManager's time. Right now it's not an issue since 85 // VirtualTimeDomain doesn't invoke SequenceManager itself. 86 87 if (new_wake_up) { 88 if (new_wake_up != previous_wake_up) { 89 // Update the wake-up. 90 SetNextDelayedDoWork(lazy_now, new_wake_up.value()); 91 } 92 } else { 93 if (previous_wake_up) { 94 // No new wake-up to be set, cancel the previous one. 95 SetNextDelayedDoWork(lazy_now, TimeTicks::Max()); 96 } 97 } 98 } 99 100 void TimeDomain::WakeUpReadyDelayedQueues(LazyNow* lazy_now) { 101 DCHECK(main_thread_checker_.CalledOnValidThread()); 102 // Wake up any queues with pending delayed work. Note std::multimap stores 103 // the elements sorted by key, so the begin() iterator points to the earliest 104 // queue to wake-up. 105 while (!delayed_wake_up_queue_.empty() && 106 delayed_wake_up_queue_.Min().wake_up.time <= lazy_now->Now()) { 107 internal::TaskQueueImpl* queue = delayed_wake_up_queue_.Min().queue; 108 queue->WakeUpForDelayedWork(lazy_now); 109 } 110 } 111 112 Optional<TimeTicks> TimeDomain::NextScheduledRunTime() const { 113 DCHECK(main_thread_checker_.CalledOnValidThread()); 114 if (delayed_wake_up_queue_.empty()) 115 return nullopt; 116 return delayed_wake_up_queue_.Min().wake_up.time; 117 } 118 119 void TimeDomain::AsValueInto(trace_event::TracedValue* state) const { 120 state->BeginDictionary(); 121 state->SetString("name", GetName()); 122 state->SetInteger("registered_delay_count", delayed_wake_up_queue_.size()); 123 if (!delayed_wake_up_queue_.empty()) { 124 TimeDelta delay = delayed_wake_up_queue_.Min().wake_up.time - Now(); 125 state->SetDouble("next_delay_ms", delay.InMillisecondsF()); 126 } 127 AsValueIntoInternal(state); 128 state->EndDictionary(); 129 } 130 131 void TimeDomain::AsValueIntoInternal(trace_event::TracedValue* state) const { 132 // Can be overriden to trace some additional state. 133 } 134 135 } // namespace sequence_manager 136 } // namespace base 137