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
TimeDomain()14 TimeDomain::TimeDomain() : sequence_manager_(nullptr) {}
15
~TimeDomain()16 TimeDomain::~TimeDomain() {
17 DCHECK(main_thread_checker_.CalledOnValidThread());
18 }
19
OnRegisterWithSequenceManager(internal::SequenceManagerImpl * sequence_manager)20 void TimeDomain::OnRegisterWithSequenceManager(
21 internal::SequenceManagerImpl* sequence_manager) {
22 DCHECK(sequence_manager);
23 DCHECK(!sequence_manager_);
24 sequence_manager_ = sequence_manager;
25 }
26
sequence_manager() const27 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
SetNextDelayedDoWork(LazyNow * lazy_now,TimeTicks run_time)36 void TimeDomain::SetNextDelayedDoWork(LazyNow* lazy_now, TimeTicks run_time) {
37 sequence_manager_->SetNextDelayedDoWork(lazy_now, run_time);
38 }
39
RequestDoWork()40 void TimeDomain::RequestDoWork() {
41 sequence_manager_->MaybeScheduleImmediateWork(FROM_HERE);
42 }
43
UnregisterQueue(internal::TaskQueueImpl * queue)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
SetNextWakeUpForQueue(internal::TaskQueueImpl * queue,Optional<internal::TaskQueueImpl::DelayedWakeUp> wake_up,LazyNow * lazy_now)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
WakeUpReadyDelayedQueues(LazyNow * lazy_now)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
NextScheduledRunTime() const112 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
AsValueInto(trace_event::TracedValue * state) const119 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
AsValueIntoInternal(trace_event::TracedValue * state) const131 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