Commit 0b6d16ef authored by Jesse McKenna's avatar Jesse McKenna Committed by Commit Bot

Replace Sequence lock with Sequence::Transaction class

Bug: 889029
Change-Id: Ia8ab74329953568bda37a324cc3a9b477acf732e
Reviewed-on: https://chromium-review.googlesource.com/c/1327548
Commit-Queue: Jesse McKenna <jessemckenna@google.com>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Cr-Commit-Position: refs/heads/master@{#606684}
parent dd644485
...@@ -100,7 +100,8 @@ scoped_refptr<Sequence> PlatformNativeWorkerPoolWin::GetWork() { ...@@ -100,7 +100,8 @@ scoped_refptr<Sequence> PlatformNativeWorkerPoolWin::GetWork() {
void PlatformNativeWorkerPoolWin::OnCanScheduleSequence( void PlatformNativeWorkerPoolWin::OnCanScheduleSequence(
scoped_refptr<Sequence> sequence) { scoped_refptr<Sequence> sequence) {
const SequenceSortKey sequence_sort_key = sequence->GetSortKey(); const SequenceSortKey sequence_sort_key =
sequence->BeginTransaction()->GetSortKey();
auto transaction(priority_queue_.BeginTransaction()); auto transaction(priority_queue_.BeginTransaction());
transaction->Push(std::move(sequence), sequence_sort_key); transaction->Push(std::move(sequence), sequence_sort_key);
......
...@@ -59,23 +59,27 @@ TEST(TaskSchedulerPriorityQueueTest, PushPopPeek) { ...@@ -59,23 +59,27 @@ TEST(TaskSchedulerPriorityQueueTest, PushPopPeek) {
// Create test sequences. // Create test sequences.
scoped_refptr<Sequence> sequence_a = scoped_refptr<Sequence> sequence_a =
MakeRefCounted<Sequence>(TaskTraits(TaskPriority::USER_VISIBLE)); MakeRefCounted<Sequence>(TaskTraits(TaskPriority::USER_VISIBLE));
sequence_a->PushTask(Task(FROM_HERE, DoNothing(), TimeDelta())); sequence_a->BeginTransaction()->PushTask(
SequenceSortKey sort_key_a = sequence_a->GetSortKey(); Task(FROM_HERE, DoNothing(), TimeDelta()));
SequenceSortKey sort_key_a = sequence_a->BeginTransaction()->GetSortKey();
scoped_refptr<Sequence> sequence_b = scoped_refptr<Sequence> sequence_b =
MakeRefCounted<Sequence>(TaskTraits(TaskPriority::USER_BLOCKING)); MakeRefCounted<Sequence>(TaskTraits(TaskPriority::USER_BLOCKING));
sequence_b->PushTask(Task(FROM_HERE, DoNothing(), TimeDelta())); sequence_b->BeginTransaction()->PushTask(
SequenceSortKey sort_key_b = sequence_b->GetSortKey(); Task(FROM_HERE, DoNothing(), TimeDelta()));
SequenceSortKey sort_key_b = sequence_b->BeginTransaction()->GetSortKey();
scoped_refptr<Sequence> sequence_c = scoped_refptr<Sequence> sequence_c =
MakeRefCounted<Sequence>(TaskTraits(TaskPriority::USER_BLOCKING)); MakeRefCounted<Sequence>(TaskTraits(TaskPriority::USER_BLOCKING));
sequence_c->PushTask(Task(FROM_HERE, DoNothing(), TimeDelta())); sequence_c->BeginTransaction()->PushTask(
SequenceSortKey sort_key_c = sequence_c->GetSortKey(); Task(FROM_HERE, DoNothing(), TimeDelta()));
SequenceSortKey sort_key_c = sequence_c->BeginTransaction()->GetSortKey();
scoped_refptr<Sequence> sequence_d = scoped_refptr<Sequence> sequence_d =
MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT)); MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT));
sequence_d->PushTask(Task(FROM_HERE, DoNothing(), TimeDelta())); sequence_d->BeginTransaction()->PushTask(
SequenceSortKey sort_key_d = sequence_d->GetSortKey(); Task(FROM_HERE, DoNothing(), TimeDelta()));
SequenceSortKey sort_key_d = sequence_d->BeginTransaction()->GetSortKey();
// Create a PriorityQueue and a Transaction. // Create a PriorityQueue and a Transaction.
PriorityQueue pq; PriorityQueue pq;
......
...@@ -112,7 +112,8 @@ class SchedulerWorkerDelegate : public SchedulerWorker::Delegate { ...@@ -112,7 +112,8 @@ class SchedulerWorkerDelegate : public SchedulerWorker::Delegate {
void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override {
DCHECK(sequence); DCHECK(sequence);
const SequenceSortKey sequence_sort_key = sequence->GetSortKey(); const SequenceSortKey sequence_sort_key =
sequence->BeginTransaction()->GetSortKey();
std::unique_ptr<PriorityQueue::Transaction> transaction( std::unique_ptr<PriorityQueue::Transaction> transaction(
priority_queue_.BeginTransaction()); priority_queue_.BeginTransaction());
transaction->Push(std::move(sequence), sequence_sort_key); transaction->Push(std::move(sequence), sequence_sort_key);
...@@ -223,8 +224,8 @@ class SchedulerWorkerCOMDelegate : public SchedulerWorkerDelegate { ...@@ -223,8 +224,8 @@ class SchedulerWorkerCOMDelegate : public SchedulerWorkerDelegate {
TimeDelta()); TimeDelta());
if (task_tracker_->WillPostTask(&pump_message_task, if (task_tracker_->WillPostTask(&pump_message_task,
TaskShutdownBehavior::SKIP_ON_SHUTDOWN)) { TaskShutdownBehavior::SKIP_ON_SHUTDOWN)) {
bool was_empty = bool was_empty = message_pump_sequence_->BeginTransaction()->PushTask(
message_pump_sequence_->PushTask(std::move(pump_message_task)); std::move(pump_message_task));
DCHECK(was_empty) << "GetWorkFromWindowsMessageQueue() does not expect " DCHECK(was_empty) << "GetWorkFromWindowsMessageQueue() does not expect "
"queueing of pump tasks."; "queueing of pump tasks.";
return message_pump_sequence_; return message_pump_sequence_;
...@@ -330,7 +331,8 @@ class SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunner ...@@ -330,7 +331,8 @@ class SchedulerSingleThreadTaskRunnerManager::SchedulerSingleThreadTaskRunner
} }
void PostTaskNow(Task task) { void PostTaskNow(Task task) {
const bool sequence_was_empty = sequence_->PushTask(std::move(task)); const bool sequence_was_empty =
sequence_->BeginTransaction()->PushTask(std::move(task));
if (sequence_was_empty) { if (sequence_was_empty) {
if (outer_->task_tracker_->WillScheduleSequence(sequence_, if (outer_->task_tracker_->WillScheduleSequence(sequence_,
GetDelegate())) { GetDelegate())) {
......
...@@ -59,7 +59,8 @@ void SchedulerWorkerPool::PostTaskWithSequenceNow( ...@@ -59,7 +59,8 @@ void SchedulerWorkerPool::PostTaskWithSequenceNow(
// in the past). // in the past).
DCHECK_LE(task.delayed_run_time, TimeTicks::Now()); DCHECK_LE(task.delayed_run_time, TimeTicks::Now());
const bool sequence_was_empty = sequence->PushTask(std::move(task)); const bool sequence_was_empty =
sequence->BeginTransaction()->PushTask(std::move(task));
if (sequence_was_empty) { if (sequence_was_empty) {
// Try to schedule |sequence| if it was empty before |task| was inserted // Try to schedule |sequence| if it was empty before |task| was inserted
// into it. Otherwise, one of these must be true: // into it. Otherwise, one of these must be true:
......
...@@ -280,7 +280,7 @@ void SchedulerWorkerPoolImpl::OnCanScheduleSequence( ...@@ -280,7 +280,7 @@ void SchedulerWorkerPoolImpl::OnCanScheduleSequence(
void SchedulerWorkerPoolImpl::PushSequenceToPriorityQueue( void SchedulerWorkerPoolImpl::PushSequenceToPriorityQueue(
scoped_refptr<Sequence> sequence) { scoped_refptr<Sequence> sequence) {
DCHECK(sequence); DCHECK(sequence);
const auto sequence_sort_key = sequence->GetSortKey(); const auto sequence_sort_key = sequence->BeginTransaction()->GetSortKey();
shared_priority_queue_.BeginTransaction()->Push(std::move(sequence), shared_priority_queue_.BeginTransaction()->Push(std::move(sequence),
sequence_sort_key); sequence_sort_key);
} }
......
...@@ -188,7 +188,7 @@ class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> { ...@@ -188,7 +188,7 @@ class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> {
TimeDelta()); TimeDelta());
EXPECT_TRUE(outer_->task_tracker_.WillPostTask( EXPECT_TRUE(outer_->task_tracker_.WillPostTask(
&task, sequence->traits().shutdown_behavior())); &task, sequence->traits().shutdown_behavior()));
sequence->PushTask(std::move(task)); sequence->BeginTransaction()->PushTask(std::move(task));
} }
ExpectCallToDidRunTask(); ExpectCallToDidRunTask();
...@@ -221,8 +221,10 @@ class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> { ...@@ -221,8 +221,10 @@ class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> {
// Verify that |sequence| contains TasksPerSequence() - 1 Tasks. // Verify that |sequence| contains TasksPerSequence() - 1 Tasks.
for (size_t i = 0; i < outer_->TasksPerSequence() - 1; ++i) { for (size_t i = 0; i < outer_->TasksPerSequence() - 1; ++i) {
EXPECT_TRUE(sequence->TakeTask()); std::unique_ptr<Sequence::Transaction> transaction =
EXPECT_EQ(i == outer_->TasksPerSequence() - 2, sequence->Pop()); sequence->BeginTransaction();
EXPECT_TRUE(transaction->TakeTask());
EXPECT_EQ(i == outer_->TasksPerSequence() - 2, transaction->Pop());
} }
// Add |sequence| to |re_enqueued_sequences_|. // Add |sequence| to |re_enqueued_sequences_|.
...@@ -455,7 +457,7 @@ class ControllableCleanupDelegate : public SchedulerWorkerDefaultDelegate { ...@@ -455,7 +457,7 @@ class ControllableCleanupDelegate : public SchedulerWorkerDefaultDelegate {
TimeDelta()); TimeDelta());
EXPECT_TRUE(task_tracker_->WillPostTask( EXPECT_TRUE(task_tracker_->WillPostTask(
&task, sequence->traits().shutdown_behavior())); &task, sequence->traits().shutdown_behavior()));
sequence->PushTask(std::move(task)); sequence->BeginTransaction()->PushTask(std::move(task));
sequence = sequence =
task_tracker_->WillScheduleSequence(std::move(sequence), nullptr); task_tracker_->WillScheduleSequence(std::move(sequence), nullptr);
EXPECT_TRUE(sequence); EXPECT_TRUE(sequence);
......
...@@ -8,71 +8,80 @@ ...@@ -8,71 +8,80 @@
#include "base/critical_closure.h" #include "base/critical_closure.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/time/time.h" #include "base/time/time.h"
namespace base { namespace base {
namespace internal { namespace internal {
Sequence::Sequence( Sequence::Transaction::Transaction(scoped_refptr<Sequence> sequence)
const TaskTraits& traits, : sequence_(sequence) {
scoped_refptr<SchedulerParallelTaskRunner> scheduler_parallel_task_runner) sequence_->lock_.Acquire();
: traits_(traits), }
scheduler_parallel_task_runner_(scheduler_parallel_task_runner) {}
Sequence::Transaction::~Transaction() {
sequence_->lock_.AssertAcquired();
sequence_->lock_.Release();
}
bool Sequence::PushTask(Task task) { bool Sequence::Transaction::PushTask(Task task) {
// Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167 // Use CHECK instead of DCHECK to crash earlier. See http://crbug.com/711167
// for details. // for details.
CHECK(task.task); CHECK(task.task);
DCHECK(task.sequenced_time.is_null()); DCHECK(task.sequenced_time.is_null());
task.sequenced_time = base::TimeTicks::Now(); task.sequenced_time = base::TimeTicks::Now();
task.task = task.task = sequence_->traits_.shutdown_behavior() ==
traits_.shutdown_behavior() == TaskShutdownBehavior::BLOCK_SHUTDOWN TaskShutdownBehavior::BLOCK_SHUTDOWN
? MakeCriticalClosure(std::move(task.task)) ? MakeCriticalClosure(std::move(task.task))
: std::move(task.task); : std::move(task.task);
AutoSchedulerLock auto_lock(lock_); sequence_->queue_.push(std::move(task));
queue_.push(std::move(task));
// Return true if the sequence was empty before the push. // Return true if the sequence was empty before the push.
return queue_.size() == 1; return sequence_->queue_.size() == 1;
} }
Optional<Task> Sequence::TakeTask() { Optional<Task> Sequence::Transaction::TakeTask() {
AutoSchedulerLock auto_lock(lock_); DCHECK(!sequence_->queue_.empty());
DCHECK(!queue_.empty()); DCHECK(sequence_->queue_.front().task);
DCHECK(queue_.front().task);
return std::move(queue_.front()); return std::move(sequence_->queue_.front());
} }
bool Sequence::Pop() { bool Sequence::Transaction::Pop() {
AutoSchedulerLock auto_lock(lock_); DCHECK(!sequence_->queue_.empty());
DCHECK(!queue_.empty()); DCHECK(!sequence_->queue_.front().task);
DCHECK(!queue_.front().task); sequence_->queue_.pop();
queue_.pop(); return sequence_->queue_.empty();
return queue_.empty();
} }
SequenceSortKey Sequence::GetSortKey() const { SequenceSortKey Sequence::Transaction::GetSortKey() const {
base::TimeTicks next_task_sequenced_time; DCHECK(!sequence_->queue_.empty());
{
AutoSchedulerLock auto_lock(lock_);
DCHECK(!queue_.empty());
// Save the sequenced time of the next task in the sequence. // Save the sequenced time of the next task in the sequence.
next_task_sequenced_time = queue_.front().sequenced_time; base::TimeTicks next_task_sequenced_time =
} sequence_->queue_.front().sequenced_time;
return SequenceSortKey(traits_.priority(), next_task_sequenced_time); return SequenceSortKey(sequence_->traits_.priority(),
next_task_sequenced_time);
} }
Sequence::Sequence(
const TaskTraits& traits,
scoped_refptr<SchedulerParallelTaskRunner> scheduler_parallel_task_runner)
: traits_(traits),
scheduler_parallel_task_runner_(scheduler_parallel_task_runner) {}
Sequence::~Sequence() { Sequence::~Sequence() {
if (scheduler_parallel_task_runner_) { if (scheduler_parallel_task_runner_) {
scheduler_parallel_task_runner_->UnregisterSequence(this); scheduler_parallel_task_runner_->UnregisterSequence(this);
} }
} }
std::unique_ptr<Sequence::Transaction> Sequence::BeginTransaction() {
return WrapUnique(new Transaction(this));
}
} // namespace internal } // namespace internal
} // namespace base } // namespace base
...@@ -43,6 +43,48 @@ namespace internal { ...@@ -43,6 +43,48 @@ namespace internal {
// This class is thread-safe. // This class is thread-safe.
class BASE_EXPORT Sequence : public RefCountedThreadSafe<Sequence> { class BASE_EXPORT Sequence : public RefCountedThreadSafe<Sequence> {
public: public:
// A Transaction can perform multiple operations atomically on a
// Sequence. While a Transaction is alive, it is guaranteed that nothing
// else will access the Sequence; the Sequence's lock is held for the
// lifetime of the Transaction.
class BASE_EXPORT Transaction {
public:
~Transaction();
// Adds |task| in a new slot at the end of the Sequence. Returns true if the
// Sequence was empty before this operation.
bool PushTask(Task task);
// Transfers ownership of the Task in the front slot of the Sequence to the
// caller. The front slot of the Sequence will be nullptr and remain until
// Pop(). Cannot be called on an empty Sequence or a Sequence whose front
// slot is already nullptr.
//
// Because this method cannot be called on an empty Sequence, the returned
// Optional<Task> is never nullptr. An Optional is used in preparation for
// the merge between TaskScheduler and TaskQueueManager (in Blink).
// https://crbug.com/783309
Optional<Task> TakeTask();
// Removes the front slot of the Sequence. The front slot must have been
// emptied by TakeTask() before this is called. Cannot be called on an empty
// Sequence. Returns true if the Sequence is empty after this operation.
bool Pop();
// Returns a SequenceSortKey representing the priority of the Sequence.
// Cannot be called on an empty Sequence.
SequenceSortKey GetSortKey() const;
private:
friend class Sequence;
explicit Transaction(scoped_refptr<Sequence> sequence);
const scoped_refptr<Sequence> sequence_;
DISALLOW_COPY_AND_ASSIGN(Transaction);
};
// |traits| is metadata that applies to all Tasks in the Sequence. // |traits| is metadata that applies to all Tasks in the Sequence.
// |scheduler_parallel_task_runner| is a reference to the // |scheduler_parallel_task_runner| is a reference to the
// SchedulerParallelTaskRunner that created this Sequence, if any. // SchedulerParallelTaskRunner that created this Sequence, if any.
...@@ -50,29 +92,9 @@ class BASE_EXPORT Sequence : public RefCountedThreadSafe<Sequence> { ...@@ -50,29 +92,9 @@ class BASE_EXPORT Sequence : public RefCountedThreadSafe<Sequence> {
scoped_refptr<SchedulerParallelTaskRunner> scoped_refptr<SchedulerParallelTaskRunner>
scheduler_parallel_task_runner = nullptr); scheduler_parallel_task_runner = nullptr);
// Adds |task| in a new slot at the end of the Sequence. Returns true if the // Begins a Transaction. This method cannot be called on a thread which has an
// Sequence was empty before this operation. // active Sequence::Transaction.
bool PushTask(Task task); std::unique_ptr<Transaction> BeginTransaction();
// Transfers ownership of the Task in the front slot of the Sequence to the
// caller. The front slot of the Sequence will be nullptr and remain until
// Pop(). Cannot be called on an empty Sequence or a Sequence whose front slot
// is already nullptr.
//
// Because this method cannot be called on an empty Sequence, the returned
// Optional<Task> is never nullptr. An Optional is used in preparation for the
// merge between TaskScheduler and TaskQueueManager (in Blink).
// https://crbug.com/783309
Optional<Task> TakeTask();
// Removes the front slot of the Sequence. The front slot must have been
// emptied by TakeTask() before this is called. Cannot be called on an empty
// Sequence. Returns true if the Sequence is empty after this operation.
bool Pop();
// Returns a SequenceSortKey representing the priority of the Sequence. Cannot
// be called on an empty Sequence.
SequenceSortKey GetSortKey() const;
// Returns a token that uniquely identifies this Sequence. // Returns a token that uniquely identifies this Sequence.
const SequenceToken& token() const { return token_; } const SequenceToken& token() const { return token_; }
......
...@@ -44,72 +44,74 @@ TEST(TaskSchedulerSequenceTest, PushTakeRemove) { ...@@ -44,72 +44,74 @@ TEST(TaskSchedulerSequenceTest, PushTakeRemove) {
testing::StrictMock<MockTask> mock_task_d; testing::StrictMock<MockTask> mock_task_d;
testing::StrictMock<MockTask> mock_task_e; testing::StrictMock<MockTask> mock_task_e;
scoped_refptr<Sequence> sequence = std::unique_ptr<Sequence::Transaction> transaction =
MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT)); MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT))
->BeginTransaction();
// Push task A in the sequence. PushTask() should return true since it's the // Push task A in the sequence. PushTask() should return true since it's the
// first task-> // first task->
EXPECT_TRUE(sequence->PushTask(CreateTask(&mock_task_a))); EXPECT_TRUE(transaction->PushTask(CreateTask(&mock_task_a)));
// Push task B, C and D in the sequence. PushTask() should return false since // Push task B, C and D in the sequence. PushTask() should return false since
// there is already a task in a sequence. // there is already a task in a sequence.
EXPECT_FALSE(sequence->PushTask(CreateTask(&mock_task_b))); EXPECT_FALSE(transaction->PushTask(CreateTask(&mock_task_b)));
EXPECT_FALSE(sequence->PushTask(CreateTask(&mock_task_c))); EXPECT_FALSE(transaction->PushTask(CreateTask(&mock_task_c)));
EXPECT_FALSE(sequence->PushTask(CreateTask(&mock_task_d))); EXPECT_FALSE(transaction->PushTask(CreateTask(&mock_task_d)));
// Take the task in front of the sequence. It should be task A. // Take the task in front of the sequence. It should be task A.
Optional<Task> task = sequence->TakeTask(); Optional<Task> task = transaction->TakeTask();
ExpectMockTask(&mock_task_a, &task.value()); ExpectMockTask(&mock_task_a, &task.value());
EXPECT_FALSE(task->sequenced_time.is_null()); EXPECT_FALSE(task->sequenced_time.is_null());
// Remove the empty slot. Task B should now be in front. // Remove the empty slot. Task B should now be in front.
EXPECT_FALSE(sequence->Pop()); EXPECT_FALSE(transaction->Pop());
task = sequence->TakeTask(); task = transaction->TakeTask();
ExpectMockTask(&mock_task_b, &task.value()); ExpectMockTask(&mock_task_b, &task.value());
EXPECT_FALSE(task->sequenced_time.is_null()); EXPECT_FALSE(task->sequenced_time.is_null());
// Remove the empty slot. Task C should now be in front. // Remove the empty slot. Task C should now be in front.
EXPECT_FALSE(sequence->Pop()); EXPECT_FALSE(transaction->Pop());
task = sequence->TakeTask(); task = transaction->TakeTask();
ExpectMockTask(&mock_task_c, &task.value()); ExpectMockTask(&mock_task_c, &task.value());
EXPECT_FALSE(task->sequenced_time.is_null()); EXPECT_FALSE(task->sequenced_time.is_null());
// Remove the empty slot. // Remove the empty slot.
EXPECT_FALSE(sequence->Pop()); EXPECT_FALSE(transaction->Pop());
// Push task E in the sequence. // Push task E in the sequence.
EXPECT_FALSE(sequence->PushTask(CreateTask(&mock_task_e))); EXPECT_FALSE(transaction->PushTask(CreateTask(&mock_task_e)));
// Task D should be in front. // Task D should be in front.
task = sequence->TakeTask(); task = transaction->TakeTask();
ExpectMockTask(&mock_task_d, &task.value()); ExpectMockTask(&mock_task_d, &task.value());
EXPECT_FALSE(task->sequenced_time.is_null()); EXPECT_FALSE(task->sequenced_time.is_null());
// Remove the empty slot. Task E should now be in front. // Remove the empty slot. Task E should now be in front.
EXPECT_FALSE(sequence->Pop()); EXPECT_FALSE(transaction->Pop());
task = sequence->TakeTask(); task = transaction->TakeTask();
ExpectMockTask(&mock_task_e, &task.value()); ExpectMockTask(&mock_task_e, &task.value());
EXPECT_FALSE(task->sequenced_time.is_null()); EXPECT_FALSE(task->sequenced_time.is_null());
// Remove the empty slot. The sequence should now be empty. // Remove the empty slot. The sequence should now be empty.
EXPECT_TRUE(sequence->Pop()); EXPECT_TRUE(transaction->Pop());
} }
// Verifies the sort key of a BEST_EFFORT sequence that contains one task. // Verifies the sort key of a BEST_EFFORT sequence that contains one task.
TEST(TaskSchedulerSequenceTest, GetSortKeyBestEffort) { TEST(TaskSchedulerSequenceTest, GetSortKeyBestEffort) {
// Create a BEST_EFFORT sequence with a task. // Create a BEST_EFFORT sequence with a task.
Task best_effort_task(FROM_HERE, DoNothing(), TimeDelta()); Task best_effort_task(FROM_HERE, DoNothing(), TimeDelta());
scoped_refptr<Sequence> best_effort_sequence = std::unique_ptr<Sequence::Transaction> best_effort_sequence_transaction =
MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT)); MakeRefCounted<Sequence>(TaskTraits(TaskPriority::BEST_EFFORT))
best_effort_sequence->PushTask(std::move(best_effort_task)); ->BeginTransaction();
best_effort_sequence_transaction->PushTask(std::move(best_effort_task));
// Get the sort key. // Get the sort key.
const SequenceSortKey best_effort_sort_key = const SequenceSortKey best_effort_sort_key =
best_effort_sequence->GetSortKey(); best_effort_sequence_transaction->GetSortKey();
// Take the task from the sequence, so that its sequenced time is available // Take the task from the sequence, so that its sequenced time is available
// for the check below. // for the check below.
auto take_best_effort_task = best_effort_sequence->TakeTask(); auto take_best_effort_task = best_effort_sequence_transaction->TakeTask();
// Verify the sort key. // Verify the sort key.
EXPECT_EQ(TaskPriority::BEST_EFFORT, best_effort_sort_key.priority()); EXPECT_EQ(TaskPriority::BEST_EFFORT, best_effort_sort_key.priority());
...@@ -117,7 +119,7 @@ TEST(TaskSchedulerSequenceTest, GetSortKeyBestEffort) { ...@@ -117,7 +119,7 @@ TEST(TaskSchedulerSequenceTest, GetSortKeyBestEffort) {
best_effort_sort_key.next_task_sequenced_time()); best_effort_sort_key.next_task_sequenced_time());
// Pop for correctness. // Pop for correctness.
best_effort_sequence->Pop(); best_effort_sequence_transaction->Pop();
} }
// Same as TaskSchedulerSequenceTest.GetSortKeyBestEffort, but with a // Same as TaskSchedulerSequenceTest.GetSortKeyBestEffort, but with a
...@@ -125,16 +127,18 @@ TEST(TaskSchedulerSequenceTest, GetSortKeyBestEffort) { ...@@ -125,16 +127,18 @@ TEST(TaskSchedulerSequenceTest, GetSortKeyBestEffort) {
TEST(TaskSchedulerSequenceTest, GetSortKeyForeground) { TEST(TaskSchedulerSequenceTest, GetSortKeyForeground) {
// Create a USER_VISIBLE sequence with a task. // Create a USER_VISIBLE sequence with a task.
Task foreground_task(FROM_HERE, DoNothing(), TimeDelta()); Task foreground_task(FROM_HERE, DoNothing(), TimeDelta());
scoped_refptr<Sequence> foreground_sequence = std::unique_ptr<Sequence::Transaction> foreground_sequence_transaction =
MakeRefCounted<Sequence>(TaskTraits(TaskPriority::USER_VISIBLE)); MakeRefCounted<Sequence>(TaskTraits(TaskPriority::USER_VISIBLE))
foreground_sequence->PushTask(std::move(foreground_task)); ->BeginTransaction();
foreground_sequence_transaction->PushTask(std::move(foreground_task));
// Get the sort key. // Get the sort key.
const SequenceSortKey foreground_sort_key = foreground_sequence->GetSortKey(); const SequenceSortKey foreground_sort_key =
foreground_sequence_transaction->GetSortKey();
// Take the task from the sequence, so that its sequenced time is available // Take the task from the sequence, so that its sequenced time is available
// for the check below. // for the check below.
auto take_foreground_task = foreground_sequence->TakeTask(); auto take_foreground_task = foreground_sequence_transaction->TakeTask();
// Verify the sort key. // Verify the sort key.
EXPECT_EQ(TaskPriority::USER_VISIBLE, foreground_sort_key.priority()); EXPECT_EQ(TaskPriority::USER_VISIBLE, foreground_sort_key.priority());
...@@ -142,32 +146,35 @@ TEST(TaskSchedulerSequenceTest, GetSortKeyForeground) { ...@@ -142,32 +146,35 @@ TEST(TaskSchedulerSequenceTest, GetSortKeyForeground) {
foreground_sort_key.next_task_sequenced_time()); foreground_sort_key.next_task_sequenced_time());
// Pop for correctness. // Pop for correctness.
foreground_sequence->Pop(); foreground_sequence_transaction->Pop();
} }
// Verify that a DCHECK fires if Pop() is called on a sequence whose front slot // Verify that a DCHECK fires if Pop() is called on a sequence whose front slot
// isn't empty. // isn't empty.
TEST(TaskSchedulerSequenceTest, PopNonEmptyFrontSlot) { TEST(TaskSchedulerSequenceTest, PopNonEmptyFrontSlot) {
scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(TaskTraits()); std::unique_ptr<Sequence::Transaction> transaction =
sequence->PushTask(Task(FROM_HERE, DoNothing(), TimeDelta())); MakeRefCounted<Sequence>(TaskTraits())->BeginTransaction();
transaction->PushTask(Task(FROM_HERE, DoNothing(), TimeDelta()));
EXPECT_DCHECK_DEATH({ sequence->Pop(); }); EXPECT_DCHECK_DEATH({ transaction->Pop(); });
} }
// Verify that a DCHECK fires if TakeTask() is called on a sequence whose front // Verify that a DCHECK fires if TakeTask() is called on a sequence whose front
// slot is empty. // slot is empty.
TEST(TaskSchedulerSequenceTest, TakeEmptyFrontSlot) { TEST(TaskSchedulerSequenceTest, TakeEmptyFrontSlot) {
scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(TaskTraits()); std::unique_ptr<Sequence::Transaction> transaction =
sequence->PushTask(Task(FROM_HERE, DoNothing(), TimeDelta())); MakeRefCounted<Sequence>(TaskTraits())->BeginTransaction();
transaction->PushTask(Task(FROM_HERE, DoNothing(), TimeDelta()));
EXPECT_TRUE(sequence->TakeTask()); EXPECT_TRUE(transaction->TakeTask());
EXPECT_DCHECK_DEATH({ sequence->TakeTask(); }); EXPECT_DCHECK_DEATH({ transaction->TakeTask(); });
} }
// Verify that a DCHECK fires if TakeTask() is called on an empty sequence. // Verify that a DCHECK fires if TakeTask() is called on an empty sequence.
TEST(TaskSchedulerSequenceTest, TakeEmptySequence) { TEST(TaskSchedulerSequenceTest, TakeEmptySequence) {
scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(TaskTraits()); std::unique_ptr<Sequence::Transaction> transaction =
EXPECT_DCHECK_DEATH({ sequence->TakeTask(); }); MakeRefCounted<Sequence>(TaskTraits())->BeginTransaction();
EXPECT_DCHECK_DEATH({ transaction->TakeTask(); });
} }
} // namespace internal } // namespace internal
......
...@@ -457,7 +457,7 @@ scoped_refptr<Sequence> TaskTracker::WillScheduleSequence( ...@@ -457,7 +457,7 @@ scoped_refptr<Sequence> TaskTracker::WillScheduleSequence(
scoped_refptr<Sequence> sequence, scoped_refptr<Sequence> sequence,
CanScheduleSequenceObserver* observer) { CanScheduleSequenceObserver* observer) {
DCHECK(sequence); DCHECK(sequence);
const SequenceSortKey sort_key = sequence->GetSortKey(); const SequenceSortKey sort_key = sequence->BeginTransaction()->GetSortKey();
const int priority_index = static_cast<int>(sort_key.priority()); const int priority_index = static_cast<int>(sort_key.priority());
AutoSchedulerLock auto_lock(preemption_state_[priority_index].lock); AutoSchedulerLock auto_lock(preemption_state_[priority_index].lock);
...@@ -483,7 +483,7 @@ scoped_refptr<Sequence> TaskTracker::RunAndPopNextTask( ...@@ -483,7 +483,7 @@ scoped_refptr<Sequence> TaskTracker::RunAndPopNextTask(
DCHECK(sequence); DCHECK(sequence);
// Run the next task in |sequence|. // Run the next task in |sequence|.
Optional<Task> task = sequence->TakeTask(); Optional<Task> task = sequence->BeginTransaction()->TakeTask();
// TODO(fdoray): Support TakeTask() returning null. https://crbug.com/783309 // TODO(fdoray): Support TakeTask() returning null. https://crbug.com/783309
DCHECK(task); DCHECK(task);
...@@ -502,7 +502,7 @@ scoped_refptr<Sequence> TaskTracker::RunAndPopNextTask( ...@@ -502,7 +502,7 @@ scoped_refptr<Sequence> TaskTracker::RunAndPopNextTask(
if (task->delayed_run_time.is_null()) if (task->delayed_run_time.is_null())
DecrementNumIncompleteUndelayedTasks(); DecrementNumIncompleteUndelayedTasks();
const bool sequence_is_empty_after_pop = sequence->Pop(); const bool sequence_is_empty_after_pop = sequence->BeginTransaction()->Pop();
const TaskPriority priority = sequence->traits().priority(); const TaskPriority priority = sequence->traits().priority();
// Never reschedule a Sequence emptied by Pop(). The contract is such that // Never reschedule a Sequence emptied by Pop(). The contract is such that
...@@ -870,9 +870,10 @@ scoped_refptr<Sequence> TaskTracker::ManageSequencesAfterRunningTask( ...@@ -870,9 +870,10 @@ scoped_refptr<Sequence> TaskTracker::ManageSequencesAfterRunningTask(
CanScheduleSequenceObserver* observer, CanScheduleSequenceObserver* observer,
TaskPriority task_priority) { TaskPriority task_priority) {
const TimeTicks next_task_sequenced_time = const TimeTicks next_task_sequenced_time =
just_ran_sequence just_ran_sequence ? just_ran_sequence->BeginTransaction()
? just_ran_sequence->GetSortKey().next_task_sequenced_time() ->GetSortKey()
: TimeTicks(); .next_task_sequenced_time()
: TimeTicks();
PreemptedSequence sequence_to_schedule; PreemptedSequence sequence_to_schedule;
int priority_index = static_cast<int>(task_priority); int priority_index = static_cast<int>(task_priority);
......
...@@ -898,7 +898,7 @@ TEST_F(TaskSchedulerTaskTrackerTest, CurrentSequenceToken) { ...@@ -898,7 +898,7 @@ TEST_F(TaskSchedulerTaskTrackerTest, CurrentSequenceToken) {
Task task(FROM_HERE, Bind(&ExpectSequenceToken, sequence_token), TimeDelta()); Task task(FROM_HERE, Bind(&ExpectSequenceToken, sequence_token), TimeDelta());
tracker_.WillPostTask(&task, sequence->traits().shutdown_behavior()); tracker_.WillPostTask(&task, sequence->traits().shutdown_behavior());
sequence->PushTask(std::move(task)); sequence->BeginTransaction()->PushTask(std::move(task));
EXPECT_FALSE(SequenceToken::GetForCurrentThread().IsValid()); EXPECT_FALSE(SequenceToken::GetForCurrentThread().IsValid());
sequence = tracker_.WillScheduleSequence(std::move(sequence), sequence = tracker_.WillScheduleSequence(std::move(sequence),
...@@ -1079,7 +1079,7 @@ TEST_F(TaskSchedulerTaskTrackerTest, ...@@ -1079,7 +1079,7 @@ TEST_F(TaskSchedulerTaskTrackerTest,
scoped_refptr<Sequence> sequence = scoped_refptr<Sequence> sequence =
test::CreateSequenceWithTask(std::move(task_1), default_traits); test::CreateSequenceWithTask(std::move(task_1), default_traits);
sequence->PushTask(std::move(task_2)); sequence->BeginTransaction()->PushTask(std::move(task_2));
EXPECT_EQ(sequence, tracker_.WillScheduleSequence(sequence, nullptr)); EXPECT_EQ(sequence, tracker_.WillScheduleSequence(sequence, nullptr));
EXPECT_EQ(sequence, tracker_.RunAndPopNextTask(sequence, nullptr)); EXPECT_EQ(sequence, tracker_.RunAndPopNextTask(sequence, nullptr));
...@@ -1227,7 +1227,7 @@ TEST_F(TaskSchedulerTaskTrackerTest, ...@@ -1227,7 +1227,7 @@ TEST_F(TaskSchedulerTaskTrackerTest,
TaskTraits best_effort_traits = TaskTraits(TaskPriority::BEST_EFFORT); TaskTraits best_effort_traits = TaskTraits(TaskPriority::BEST_EFFORT);
EXPECT_TRUE( EXPECT_TRUE(
tracker_.WillPostTask(&task_b_2, best_effort_traits.shutdown_behavior())); tracker_.WillPostTask(&task_b_2, best_effort_traits.shutdown_behavior()));
sequence_b->PushTask(std::move(task_b_2)); sequence_b->BeginTransaction()->PushTask(std::move(task_b_2));
testing::StrictMock<MockCanScheduleSequenceObserver> observer_b_2; testing::StrictMock<MockCanScheduleSequenceObserver> observer_b_2;
EXPECT_EQ(nullptr, tracker_.WillScheduleSequence(sequence_b, &observer_b_2)); EXPECT_EQ(nullptr, tracker_.WillScheduleSequence(sequence_b, &observer_b_2));
// The TaskPriority of the Sequence is unchanged by posting new tasks to it. // The TaskPriority of the Sequence is unchanged by posting new tasks to it.
...@@ -1335,7 +1335,7 @@ TEST_F(TaskSchedulerTaskTrackerTest, ...@@ -1335,7 +1335,7 @@ TEST_F(TaskSchedulerTaskTrackerTest,
TimeDelta()); TimeDelta());
EXPECT_TRUE( EXPECT_TRUE(
tracker.WillPostTask(&task_a_2, best_effort_traits.shutdown_behavior())); tracker.WillPostTask(&task_a_2, best_effort_traits.shutdown_behavior()));
sequence_a->PushTask(std::move(task_a_2)); sequence_a->BeginTransaction()->PushTask(std::move(task_a_2));
// Run the first task in |sequence_a|. RunAndPopNextTask() should return // Run the first task in |sequence_a|. RunAndPopNextTask() should return
// nullptr since |sequence_a| can't be rescheduled immediately. // nullptr since |sequence_a| can't be rescheduled immediately.
......
...@@ -21,7 +21,7 @@ MockSchedulerWorkerObserver::~MockSchedulerWorkerObserver() = default; ...@@ -21,7 +21,7 @@ MockSchedulerWorkerObserver::~MockSchedulerWorkerObserver() = default;
scoped_refptr<Sequence> CreateSequenceWithTask(Task task, scoped_refptr<Sequence> CreateSequenceWithTask(Task task,
const TaskTraits& traits) { const TaskTraits& traits) {
scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(traits); scoped_refptr<Sequence> sequence = MakeRefCounted<Sequence>(traits);
sequence->PushTask(std::move(task)); sequence->BeginTransaction()->PushTask(std::move(task));
return sequence; return sequence;
} }
......
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