| Index: base/task_scheduler/sequence.cc
|
| diff --git a/base/task_scheduler/sequence.cc b/base/task_scheduler/sequence.cc
|
| index 4ecb60568cb88a6c013a3fb23d94c629fa22135e..86e99f0a4c390907f101f99cf6a08d29b86f08a7 100644
|
| --- a/base/task_scheduler/sequence.cc
|
| +++ b/base/task_scheduler/sequence.cc
|
| @@ -36,16 +36,27 @@ const Task* Sequence::PeekTask() const {
|
| }
|
|
|
| bool Sequence::PopTask() {
|
| - AutoSchedulerLock auto_lock(lock_);
|
| - DCHECK(!queue_.empty());
|
| + // Delete the popped task outside the scope of |lock_|. This prevents a double
|
| + // acquisition of |lock_| if the task's destructor tries to post a task to
|
| + // this Sequence and reduces contention.
|
| + std::unique_ptr<Task> delete_outside_lock_scope;
|
| + bool sequence_empty_after_pop = false;
|
|
|
| - const int priority_index =
|
| - static_cast<int>(queue_.front()->traits.priority());
|
| - DCHECK_GT(num_tasks_per_priority_[priority_index], 0U);
|
| - --num_tasks_per_priority_[priority_index];
|
| + {
|
| + AutoSchedulerLock auto_lock(lock_);
|
| + DCHECK(!queue_.empty());
|
| +
|
| + const int priority_index =
|
| + static_cast<int>(queue_.front()->traits.priority());
|
| + DCHECK_GT(num_tasks_per_priority_[priority_index], 0U);
|
| + --num_tasks_per_priority_[priority_index];
|
| +
|
| + delete_outside_lock_scope = std::move(queue_.front());
|
| + queue_.pop();
|
| + sequence_empty_after_pop = queue_.empty();
|
| + }
|
|
|
| - queue_.pop();
|
| - return queue_.empty();
|
| + return sequence_empty_after_pop;
|
| }
|
|
|
| SequenceSortKey Sequence::GetSortKey() const {
|
|
|