Commit 45bcfa5f authored by Jesse McKenna's avatar Jesse McKenna Committed by Commit Bot

TaskScheduler: Clear PriorityQueue during SchedulerWorkerDelegate:: and...

TaskScheduler: Clear PriorityQueue during SchedulerWorkerDelegate:: and SchedulerSingleThreadTaskRunnerManager::JoinForTesting

Bug: 889029
Change-Id: I543909faf8b66abf9a3866bc5aea8cc89277c8bb
Reviewed-on: https://chromium-review.googlesource.com/c/1338140
Commit-Queue: Jesse McKenna <jessemckenna@google.com>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/master@{#608595}
parent 5fb3f7af
...@@ -147,11 +147,30 @@ size_t PriorityQueue::Transaction::Size() const { ...@@ -147,11 +147,30 @@ size_t PriorityQueue::Transaction::Size() const {
PriorityQueue::PriorityQueue() = default; PriorityQueue::PriorityQueue() = default;
PriorityQueue::~PriorityQueue() = default; PriorityQueue::~PriorityQueue() {
if (is_flush_sequences_on_destroy_enabled_) {
while (!container_.empty()) {
scoped_refptr<Sequence> sequence = BeginTransaction()->PopSequence();
{
std::unique_ptr<Sequence::Transaction> sequence_transaction =
sequence->BeginTransaction();
while (!sequence_transaction->IsEmpty()) {
sequence_transaction->TakeTask();
sequence_transaction->Pop();
}
}
}
}
}
std::unique_ptr<PriorityQueue::Transaction> PriorityQueue::BeginTransaction() { std::unique_ptr<PriorityQueue::Transaction> PriorityQueue::BeginTransaction() {
return WrapUnique(new Transaction(this)); return WrapUnique(new Transaction(this));
} }
void PriorityQueue::EnableFlushSequencesOnDestroyForTesting() {
DCHECK(!is_flush_sequences_on_destroy_enabled_);
is_flush_sequences_on_destroy_enabled_ = true;
}
} // namespace internal } // namespace internal
} // namespace base } // namespace base
...@@ -90,6 +90,11 @@ class BASE_EXPORT PriorityQueue { ...@@ -90,6 +90,11 @@ class BASE_EXPORT PriorityQueue {
// PriorityQueue. // PriorityQueue.
std::unique_ptr<Transaction> BeginTransaction(); std::unique_ptr<Transaction> BeginTransaction();
// Set the PriorityQueue to empty all its Sequences of Tasks when it is
// destroyed; needed to prevent memory leaks caused by a reference cycle
// (Sequence -> Task -> TaskRunner -> Sequence...) during test teardown.
void EnableFlushSequencesOnDestroyForTesting();
const SchedulerLock* container_lock() const { return &container_lock_; } const SchedulerLock* container_lock() const { return &container_lock_; }
private: private:
...@@ -104,6 +109,9 @@ class BASE_EXPORT PriorityQueue { ...@@ -104,6 +109,9 @@ class BASE_EXPORT PriorityQueue {
ContainerType container_; ContainerType container_;
// Should only be enabled by EnableFlushSequencesOnDestroyForTesting().
bool is_flush_sequences_on_destroy_enabled_ = false;
DISALLOW_COPY_AND_ASSIGN(PriorityQueue); DISALLOW_COPY_AND_ASSIGN(PriorityQueue);
}; };
......
...@@ -129,6 +129,10 @@ class SchedulerWorkerDelegate : public SchedulerWorker::Delegate { ...@@ -129,6 +129,10 @@ class SchedulerWorkerDelegate : public SchedulerWorker::Delegate {
void OnMainExit(SchedulerWorker* /* worker */) override {} void OnMainExit(SchedulerWorker* /* worker */) override {}
void EnableFlushPriorityQueueSequencesOnDestroyForTesting() {
priority_queue_.EnableFlushSequencesOnDestroyForTesting();
}
private: private:
const std::string thread_name_; const std::string thread_name_;
const SchedulerWorker::ThreadLabel thread_label_; const SchedulerWorker::ThreadLabel thread_label_;
...@@ -486,8 +490,11 @@ void SchedulerSingleThreadTaskRunnerManager::JoinForTesting() { ...@@ -486,8 +490,11 @@ void SchedulerSingleThreadTaskRunnerManager::JoinForTesting() {
local_workers = std::move(workers_); local_workers = std::move(workers_);
} }
for (const auto& worker : local_workers) for (const auto& worker : local_workers) {
static_cast<SchedulerWorkerDelegate*>(worker->delegate())
->EnableFlushPriorityQueueSequencesOnDestroyForTesting();
worker->JoinForTesting(); worker->JoinForTesting();
}
{ {
AutoSchedulerLock auto_lock(lock_); AutoSchedulerLock auto_lock(lock_);
......
...@@ -355,6 +355,8 @@ void SchedulerWorkerPoolImpl::JoinForTesting() { ...@@ -355,6 +355,8 @@ void SchedulerWorkerPoolImpl::JoinForTesting() {
for (const auto& worker : workers_copy) for (const auto& worker : workers_copy)
worker->JoinForTesting(); worker->JoinForTesting();
shared_priority_queue_.EnableFlushSequencesOnDestroyForTesting();
AutoSchedulerLock auto_lock(lock_); AutoSchedulerLock auto_lock(lock_);
DCHECK(workers_ == workers_copy); DCHECK(workers_ == workers_copy);
// Release |workers_| to clear their TrackedRef against |this|. // Release |workers_| to clear their TrackedRef against |this|.
......
...@@ -43,21 +43,21 @@ bool Sequence::Transaction::PushTask(Task task) { ...@@ -43,21 +43,21 @@ bool Sequence::Transaction::PushTask(Task task) {
} }
Optional<Task> Sequence::Transaction::TakeTask() { Optional<Task> Sequence::Transaction::TakeTask() {
DCHECK(!sequence_->queue_.empty()); DCHECK(!IsEmpty());
DCHECK(sequence_->queue_.front().task); DCHECK(sequence_->queue_.front().task);
return std::move(sequence_->queue_.front()); return std::move(sequence_->queue_.front());
} }
bool Sequence::Transaction::Pop() { bool Sequence::Transaction::Pop() {
DCHECK(!sequence_->queue_.empty()); DCHECK(!IsEmpty());
DCHECK(!sequence_->queue_.front().task); DCHECK(!sequence_->queue_.front().task);
sequence_->queue_.pop(); sequence_->queue_.pop();
return sequence_->queue_.empty(); return IsEmpty();
} }
SequenceSortKey Sequence::Transaction::GetSortKey() const { SequenceSortKey Sequence::Transaction::GetSortKey() const {
DCHECK(!sequence_->queue_.empty()); DCHECK(!IsEmpty());
// Save the sequenced time of the next task in the sequence. // Save the sequenced time of the next task in the sequence.
base::TimeTicks next_task_sequenced_time = base::TimeTicks next_task_sequenced_time =
...@@ -67,6 +67,10 @@ SequenceSortKey Sequence::Transaction::GetSortKey() const { ...@@ -67,6 +67,10 @@ SequenceSortKey Sequence::Transaction::GetSortKey() const {
next_task_sequenced_time); next_task_sequenced_time);
} }
bool Sequence::Transaction::IsEmpty() const {
return sequence_->queue_.empty();
}
void Sequence::SetHeapHandle(const HeapHandle& handle) { void Sequence::SetHeapHandle(const HeapHandle& handle) {
heap_handle_ = handle; heap_handle_ = handle;
} }
......
...@@ -76,6 +76,8 @@ class BASE_EXPORT Sequence : public RefCountedThreadSafe<Sequence> { ...@@ -76,6 +76,8 @@ class BASE_EXPORT Sequence : public RefCountedThreadSafe<Sequence> {
// Cannot be called on an empty Sequence. // Cannot be called on an empty Sequence.
SequenceSortKey GetSortKey() const; SequenceSortKey GetSortKey() const;
bool IsEmpty() const;
scoped_refptr<Sequence> sequence() { return sequence_; } scoped_refptr<Sequence> sequence() { return sequence_; }
private: private:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment