Home | History | Annotate | Download | only in sequence_manager
      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