#include "base/task/sequence_manager/wake_up_queue.h"
#include <optional>
#include "base/task/sequence_manager/associated_thread_id.h"
#include "base/task/sequence_manager/sequence_manager_impl.h"
#include "base/task/sequence_manager/task_queue_impl.h"
#include "base/threading/thread_checker.h"
namespace base::sequence_manager::internal {
WakeUpQueue::WakeUpQueue(
scoped_refptr<const internal::AssociatedThreadId> associated_thread)
: associated_thread_(std::move(associated_thread)) {}
WakeUpQueue::~WakeUpQueue() {
DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
}
void WakeUpQueue::RemoveAllCanceledDelayedTasksFromFront(LazyNow* lazy_now) {
while (!wake_up_queue_.empty()) {
auto* top_queue = wake_up_queue_.top().queue;
if (!top_queue->RemoveAllCanceledDelayedTasksFromFront(lazy_now)) {
break;
}
}
}
void WakeUpQueue::SetNextWakeUpForQueue(internal::TaskQueueImpl* queue,
LazyNow* lazy_now,
std::optional<WakeUp> wake_up) {
DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
DCHECK_EQ(queue->wake_up_queue(), this);
DCHECK(queue->IsQueueEnabled() || !wake_up);
std::optional<WakeUp> previous_wake_up = GetNextDelayedWakeUp();
if (wake_up) {
if (queue->heap_handle().IsValid()) {
wake_up_queue_.Replace(queue->heap_handle(), {wake_up.value(), queue});
} else {
wake_up_queue_.insert({wake_up.value(), queue});
}
} else {
if (queue->heap_handle().IsValid()) {
wake_up_queue_.erase(queue->heap_handle());
}
}
std::optional<WakeUp> new_wake_up = GetNextDelayedWakeUp();
if (new_wake_up != previous_wake_up) {
OnNextWakeUpChanged(lazy_now, GetNextDelayedWakeUp());
}
}
void WakeUpQueue::MoveReadyDelayedTasksToWorkQueues(
LazyNow* lazy_now,
EnqueueOrder enqueue_order) {
DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
bool update_needed = false;
while (!wake_up_queue_.empty() &&
wake_up_queue_.top().wake_up.earliest_time() <= lazy_now->Now()) {
internal::TaskQueueImpl* queue = wake_up_queue_.top().queue;
queue->OnWakeUp(lazy_now, enqueue_order);
update_needed = true;
}
if (!update_needed || wake_up_queue_.empty()) {
return;
}
internal::TaskQueueImpl* queue = wake_up_queue_.top().queue;
queue->UpdateWakeUp(lazy_now);
while (!wake_up_queue_.empty()) {
internal::TaskQueueImpl* old_queue =
std::exchange(queue, wake_up_queue_.top().queue);
if (old_queue == queue) {
break;
}
queue->UpdateWakeUp(lazy_now);
}
}
std::optional<WakeUp> WakeUpQueue::GetNextDelayedWakeUp() const {
DCHECK_CALLED_ON_VALID_THREAD(associated_thread_->thread_checker);
if (wake_up_queue_.empty()) {
return std::nullopt;
}
WakeUp wake_up = wake_up_queue_.top().wake_up;
return wake_up;
}
Value::Dict WakeUpQueue::AsValue(TimeTicks now) const {
Value::Dict state;
state.Set("name", GetName());
state.Set("registered_delay_count", checked_cast<int>(wake_up_queue_.size()));
if (!wake_up_queue_.empty()) {
TimeDelta delay = wake_up_queue_.top().wake_up.time - now;
state.Set("next_delay_ms", delay.InMillisecondsF());
}
return state;
}
DefaultWakeUpQueue::DefaultWakeUpQueue(
scoped_refptr<internal::AssociatedThreadId> associated_thread,
internal::SequenceManagerImpl* sequence_manager)
: WakeUpQueue(std::move(associated_thread)),
sequence_manager_(sequence_manager) {}
DefaultWakeUpQueue::~DefaultWakeUpQueue() = default;
void DefaultWakeUpQueue::OnNextWakeUpChanged(LazyNow* lazy_now,
std::optional<WakeUp> wake_up) {
sequence_manager_->SetNextWakeUp(lazy_now, wake_up);
}
void DefaultWakeUpQueue::UnregisterQueue(internal::TaskQueueImpl* queue) {
DCHECK_EQ(queue->wake_up_queue(), this);
LazyNow lazy_now(sequence_manager_->main_thread_clock());
SetNextWakeUpForQueue(queue, &lazy_now, std::nullopt);
}
const char* DefaultWakeUpQueue::GetName() const {
return "DefaultWakeUpQueue";
}
NonWakingWakeUpQueue::NonWakingWakeUpQueue(
scoped_refptr<internal::AssociatedThreadId> associated_thread)
: WakeUpQueue(std::move(associated_thread)) {}
NonWakingWakeUpQueue::~NonWakingWakeUpQueue() = default;
void NonWakingWakeUpQueue::OnNextWakeUpChanged(LazyNow* lazy_now,
std::optional<WakeUp> wake_up) {}
const char* NonWakingWakeUpQueue::GetName() const {
return "NonWakingWakeUpQueue";
}
void NonWakingWakeUpQueue::UnregisterQueue(internal::TaskQueueImpl* queue) {
DCHECK_EQ(queue->wake_up_queue(), this);
SetNextWakeUpForQueue(queue, nullptr, std::nullopt);
}
}