| // Copyright 2016 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "base/task/task_scheduler/sequence.h" |
| |
| #include <utility> |
| |
| #include "base/critical_closure.h" |
| #include "base/feature_list.h" |
| #include "base/logging.h" |
| #include "base/memory/ptr_util.h" |
| #include "base/task/task_features.h" |
| #include "base/time/time.h" |
| |
| namespace base { |
| namespace internal { |
| |
| SequenceAndTransaction::SequenceAndTransaction( |
| scoped_refptr<Sequence> sequence_in, |
| Sequence::Transaction transaction_in) |
| : sequence(std::move(sequence_in)), |
| transaction(std::move(transaction_in)) {} |
| |
| SequenceAndTransaction::SequenceAndTransaction(SequenceAndTransaction&& other) = |
| default; |
| |
| SequenceAndTransaction::~SequenceAndTransaction() = default; |
| |
| Sequence::Transaction::Transaction(Sequence* sequence) : sequence_(sequence) { |
| sequence_->lock_.Acquire(); |
| } |
| |
| Sequence::Transaction::Transaction(Sequence::Transaction&& other) |
| : sequence_(other.sequence()) { |
| other.sequence_ = nullptr; |
| } |
| |
| Sequence::Transaction::~Transaction() { |
| if (sequence_) { |
| sequence_->lock_.AssertAcquired(); |
| sequence_->lock_.Release(); |
| } |
| } |
| |
| bool Sequence::Transaction::PushTask(Task task) { |
| // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167 |
| // for details. |
| CHECK(task.task); |
| DCHECK(task.queue_time.is_null()); |
| task.queue_time = base::TimeTicks::Now(); |
| |
| task.task = sequence_->traits_.shutdown_behavior() == |
| TaskShutdownBehavior::BLOCK_SHUTDOWN |
| ? MakeCriticalClosure(std::move(task.task)) |
| : std::move(task.task); |
| |
| sequence_->queue_.push(std::move(task)); |
| |
| // Return true if the sequence was empty before the push. |
| return sequence_->queue_.size() == 1; |
| } |
| |
| Optional<Task> Sequence::Transaction::TakeTask() { |
| DCHECK(!IsEmpty()); |
| DCHECK(sequence_->queue_.front().task); |
| |
| return std::move(sequence_->queue_.front()); |
| } |
| |
| bool Sequence::Transaction::Pop() { |
| DCHECK(!IsEmpty()); |
| DCHECK(!sequence_->queue_.front().task); |
| sequence_->queue_.pop(); |
| return IsEmpty(); |
| } |
| |
| SequenceSortKey Sequence::Transaction::GetSortKey() const { |
| DCHECK(!IsEmpty()); |
| |
| // Save the sequenced time of the next task in the sequence. |
| base::TimeTicks next_task_queue_time = sequence_->queue_.front().queue_time; |
| |
| return SequenceSortKey(sequence_->traits_.priority(), next_task_queue_time); |
| } |
| |
| bool Sequence::Transaction::IsEmpty() const { |
| return sequence_->queue_.empty(); |
| } |
| |
| void Sequence::Transaction::UpdatePriority(TaskPriority priority) { |
| if (FeatureList::IsEnabled(kAllTasksUserBlocking)) |
| return; |
| sequence_->traits_.UpdatePriority(priority); |
| } |
| |
| void Sequence::SetHeapHandle(const HeapHandle& handle) { |
| heap_handle_ = handle; |
| } |
| |
| void Sequence::ClearHeapHandle() { |
| heap_handle_ = HeapHandle(); |
| } |
| |
| Sequence::Sequence( |
| const TaskTraits& traits, |
| scoped_refptr<SchedulerParallelTaskRunner> scheduler_parallel_task_runner) |
| : traits_(traits), |
| scheduler_parallel_task_runner_(scheduler_parallel_task_runner) {} |
| |
| Sequence::~Sequence() { |
| if (scheduler_parallel_task_runner_) { |
| scheduler_parallel_task_runner_->UnregisterSequence(this); |
| } |
| } |
| |
| Sequence::Transaction Sequence::BeginTransaction() { |
| return Transaction(this); |
| } |
| |
| // static |
| SequenceAndTransaction SequenceAndTransaction::FromSequence( |
| scoped_refptr<Sequence> sequence) { |
| DCHECK(sequence); |
| Sequence::Transaction transaction(sequence->BeginTransaction()); |
| return SequenceAndTransaction(std::move(sequence), std::move(transaction)); |
| } |
| |
| } // namespace internal |
| } // namespace base |