diff options
Diffstat (limited to 'base/task_scheduler')
-rw-r--r-- | base/task_scheduler/scheduler_lock_impl.cc | 23 | ||||
-rw-r--r-- | base/task_scheduler/scheduler_lock_unittest.cc | 14 | ||||
-rw-r--r-- | base/task_scheduler/scoped_set_task_priority_for_current_thread.cc | 41 | ||||
-rw-r--r-- | base/task_scheduler/scoped_set_task_priority_for_current_thread.h | 36 | ||||
-rw-r--r-- | base/task_scheduler/scoped_set_task_priority_for_current_thread_unittest.cc | 26 | ||||
-rw-r--r-- | base/task_scheduler/sequence.cc | 26 | ||||
-rw-r--r-- | base/task_scheduler/sequence.h | 38 | ||||
-rw-r--r-- | base/task_scheduler/sequence_unittest.cc | 93 | ||||
-rw-r--r-- | base/task_scheduler/task.cc | 12 | ||||
-rw-r--r-- | base/task_scheduler/task.h | 11 | ||||
-rw-r--r-- | base/task_scheduler/task_traits.cc | 56 | ||||
-rw-r--r-- | base/task_scheduler/task_traits.h | 84 | ||||
-rw-r--r-- | base/task_scheduler/test_utils.h | 19 |
13 files changed, 121 insertions, 358 deletions
diff --git a/base/task_scheduler/scheduler_lock_impl.cc b/base/task_scheduler/scheduler_lock_impl.cc index d60f25939b..7480e18da1 100644 --- a/base/task_scheduler/scheduler_lock_impl.cc +++ b/base/task_scheduler/scheduler_lock_impl.cc @@ -67,30 +67,19 @@ class SafeAcquisitionTracker { // Otherwise, make sure that the previous lock acquired is an allowed // predecessor. AutoLock auto_lock(allowed_predecessor_map_lock_); - // Using at() is exception-safe here as |lock| was registered already. const SchedulerLockImpl* allowed_predecessor = allowed_predecessor_map_.at(lock); DCHECK_EQ(acquired_locks->back(), allowed_predecessor); } - // Asserts that |lock|'s registered predecessor is safe. Because - // SchedulerLocks are registered at construction time and any predecessor - // specified on a SchedulerLock must already exist, the first registered - // SchedulerLock in a potential chain must have a null predecessor and is thus - // cycle-free. Any subsequent SchedulerLock with a predecessor must come from - // the set of registered SchedulerLocks. Since the registered SchedulerLocks - // only contain cycle-free SchedulerLocks, this subsequent SchedulerLock is - // itself cycle-free and may be safely added to the registered SchedulerLock - // set. void AssertSafePredecessor(const SchedulerLockImpl* lock) const { allowed_predecessor_map_lock_.AssertAcquired(); - // Using at() is exception-safe here as |lock| was registered already. - const SchedulerLockImpl* predecessor = allowed_predecessor_map_.at(lock); - if (predecessor) { - DCHECK(allowed_predecessor_map_.find(predecessor) != - allowed_predecessor_map_.end()) - << "SchedulerLock was registered before its predecessor. " - << "Potential cycle detected"; + for (const SchedulerLockImpl* predecessor = + allowed_predecessor_map_.at(lock); + predecessor != nullptr; + predecessor = allowed_predecessor_map_.at(predecessor)) { + DCHECK_NE(predecessor, lock) << + "Scheduler lock predecessor cycle detected."; } } diff --git a/base/task_scheduler/scheduler_lock_unittest.cc b/base/task_scheduler/scheduler_lock_unittest.cc index 55182479aa..daa50257f1 100644 --- a/base/task_scheduler/scheduler_lock_unittest.cc +++ b/base/task_scheduler/scheduler_lock_unittest.cc @@ -10,7 +10,7 @@ #include "base/macros.h" #include "base/rand_util.h" #include "base/synchronization/waitable_event.h" -#include "base/test/gtest_util.h" +#include "base/task_scheduler/test_utils.h" #include "base/threading/platform_thread.h" #include "base/threading/simple_thread.h" #include "testing/gtest/include/gtest/gtest.h" @@ -131,7 +131,7 @@ TEST(TaskSchedulerLock, AcquirePredecessorWrongOrder) { EXPECT_DCHECK_DEATH({ lock.Acquire(); predecessor.Acquire(); - }); + }, ""); } TEST(TaskSchedulerLock, AcquireNonPredecessor) { @@ -140,7 +140,7 @@ TEST(TaskSchedulerLock, AcquireNonPredecessor) { EXPECT_DCHECK_DEATH({ lock1.Acquire(); lock2.Acquire(); - }); + }, ""); } TEST(TaskSchedulerLock, AcquireMultipleLocksInOrder) { @@ -172,7 +172,7 @@ TEST(TaskSchedulerLock, AcquireMultipleLocksNoTransitivity) { EXPECT_DCHECK_DEATH({ lock1.Acquire(); lock3.Acquire(); - }); + }, ""); } TEST(TaskSchedulerLock, AcquireLocksDifferentThreadsSafely) { @@ -258,7 +258,7 @@ TEST(TaskSchedulerLock, SelfReferentialLock) { SchedulerLock lock; }; - EXPECT_DCHECK_DEATH({ SelfReferentialLock lock; }); + EXPECT_DCHECK_DEATH({ SelfReferentialLock lock; }, ""); } TEST(TaskSchedulerLock, PredecessorCycle) { @@ -269,7 +269,7 @@ TEST(TaskSchedulerLock, PredecessorCycle) { SchedulerLock lock2; }; - EXPECT_DCHECK_DEATH({ LockCycle cycle; }); + EXPECT_DCHECK_DEATH({ LockCycle cycle; }, ""); } TEST(TaskSchedulerLock, PredecessorLongerCycle) { @@ -288,7 +288,7 @@ TEST(TaskSchedulerLock, PredecessorLongerCycle) { SchedulerLock lock5; }; - EXPECT_DCHECK_DEATH({ LockCycle cycle; }); + EXPECT_DCHECK_DEATH({ LockCycle cycle; }, ""); } } // namespace diff --git a/base/task_scheduler/scoped_set_task_priority_for_current_thread.cc b/base/task_scheduler/scoped_set_task_priority_for_current_thread.cc deleted file mode 100644 index a163863d0f..0000000000 --- a/base/task_scheduler/scoped_set_task_priority_for_current_thread.cc +++ /dev/null @@ -1,41 +0,0 @@ -// 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_scheduler/scoped_set_task_priority_for_current_thread.h" - -#include "base/lazy_instance.h" -#include "base/logging.h" -#include "base/threading/thread_local.h" - -namespace base { -namespace internal { - -namespace { - -LazyInstance<ThreadLocalPointer<const TaskPriority>>::Leaky - tls_task_priority_for_current_thread = LAZY_INSTANCE_INITIALIZER; - -} // namespace - -ScopedSetTaskPriorityForCurrentThread::ScopedSetTaskPriorityForCurrentThread( - TaskPriority priority) - : priority_(priority) { - DCHECK(!tls_task_priority_for_current_thread.Get().Get()); - tls_task_priority_for_current_thread.Get().Set(&priority_); -} - -ScopedSetTaskPriorityForCurrentThread:: - ~ScopedSetTaskPriorityForCurrentThread() { - DCHECK_EQ(&priority_, tls_task_priority_for_current_thread.Get().Get()); - tls_task_priority_for_current_thread.Get().Set(nullptr); -} - -TaskPriority GetTaskPriorityForCurrentThread() { - const TaskPriority* priority = - tls_task_priority_for_current_thread.Get().Get(); - return priority ? *priority : TaskPriority::USER_VISIBLE; -} - -} // namespace internal -} // namespace base diff --git a/base/task_scheduler/scoped_set_task_priority_for_current_thread.h b/base/task_scheduler/scoped_set_task_priority_for_current_thread.h deleted file mode 100644 index 4508911d9c..0000000000 --- a/base/task_scheduler/scoped_set_task_priority_for_current_thread.h +++ /dev/null @@ -1,36 +0,0 @@ -// 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. - -#ifndef BASE_TASK_SCHEDULER_SCOPED_SET_TASK_PRIORITY_FOR_CURRENT_THREAD_H_ -#define BASE_TASK_SCHEDULER_SCOPED_SET_TASK_PRIORITY_FOR_CURRENT_THREAD_H_ - -#include "base/base_export.h" -#include "base/macros.h" -#include "base/task_scheduler/task_traits.h" - -namespace base { -namespace internal { - -class BASE_EXPORT ScopedSetTaskPriorityForCurrentThread { - public: - // Within the scope of this object, GetTaskPriorityForCurrentThread() will - // return |priority|. - ScopedSetTaskPriorityForCurrentThread(TaskPriority priority); - ~ScopedSetTaskPriorityForCurrentThread(); - - private: - const TaskPriority priority_; - - DISALLOW_COPY_AND_ASSIGN(ScopedSetTaskPriorityForCurrentThread); -}; - -// Returns the priority of the TaskScheduler task running on the current thread, -// or TaskPriority::USER_VISIBLE if no TaskScheduler task is running on the -// current thread. -BASE_EXPORT TaskPriority GetTaskPriorityForCurrentThread(); - -} // namespace internal -} // namespace base - -#endif // BASE_TASK_SCHEDULER_SCOPED_SET_TASK_PRIORITY_FOR_CURRENT_THREAD_H_ diff --git a/base/task_scheduler/scoped_set_task_priority_for_current_thread_unittest.cc b/base/task_scheduler/scoped_set_task_priority_for_current_thread_unittest.cc deleted file mode 100644 index c497af6770..0000000000 --- a/base/task_scheduler/scoped_set_task_priority_for_current_thread_unittest.cc +++ /dev/null @@ -1,26 +0,0 @@ -// 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_scheduler/scoped_set_task_priority_for_current_thread.h" - -#include "base/task_scheduler/task_traits.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace internal { - -TEST(TaskSchedulerScopedSetTaskPriorityForCurrentThreadTest, - ScopedSetTaskPriorityForCurrentThread) { - EXPECT_EQ(TaskPriority::USER_VISIBLE, GetTaskPriorityForCurrentThread()); - { - ScopedSetTaskPriorityForCurrentThread - scoped_set_task_priority_for_current_thread( - TaskPriority::USER_BLOCKING); - EXPECT_EQ(TaskPriority::USER_BLOCKING, GetTaskPriorityForCurrentThread()); - } - EXPECT_EQ(TaskPriority::USER_VISIBLE, GetTaskPriorityForCurrentThread()); -} - -} // namespace internal -} // namespace base diff --git a/base/task_scheduler/sequence.cc b/base/task_scheduler/sequence.cc index 601b5402d0..4ecb60568c 100644 --- a/base/task_scheduler/sequence.cc +++ b/base/task_scheduler/sequence.cc @@ -26,30 +26,24 @@ bool Sequence::PushTask(std::unique_ptr<Task> task) { return queue_.size() == 1; } -std::unique_ptr<Task> Sequence::TakeTask() { +const Task* Sequence::PeekTask() const { AutoSchedulerLock auto_lock(lock_); - DCHECK(!queue_.empty()); - DCHECK(queue_.front()); - 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]; + if (queue_.empty()) + return nullptr; - return std::move(queue_.front()); + return queue_.front().get(); } -TaskTraits Sequence::PeekTaskTraits() const { +bool Sequence::PopTask() { AutoSchedulerLock auto_lock(lock_); DCHECK(!queue_.empty()); - DCHECK(queue_.front()); - return queue_.front()->traits; -} -bool Sequence::Pop() { - AutoSchedulerLock auto_lock(lock_); - DCHECK(!queue_.empty()); - DCHECK(!queue_.front()); + 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]; + queue_.pop(); return queue_.empty(); } diff --git a/base/task_scheduler/sequence.h b/base/task_scheduler/sequence.h index ed1d0ac401..3fa037fa35 100644 --- a/base/task_scheduler/sequence.h +++ b/base/task_scheduler/sequence.h @@ -13,7 +13,6 @@ #include "base/base_export.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "base/sequence_token.h" #include "base/task_scheduler/scheduler_lock.h" #include "base/task_scheduler/sequence_sort_key.h" #include "base/task_scheduler/task.h" @@ -22,10 +21,7 @@ namespace base { namespace internal { -// A Sequence holds slots each containing up to a single Task that must be -// executed in posting order. -// -// In comments below, an "empty Sequence" is a Sequence with no slot. +// A sequence holds tasks that must be executed in posting order. // // Note: there is a known refcounted-ownership cycle in the Scheduler // architecture: Sequence -> Task -> TaskRunner -> Sequence -> ... @@ -44,38 +40,26 @@ class BASE_EXPORT Sequence : public RefCountedThreadSafe<Sequence> { public: Sequence(); - // Adds |task| in a new slot at the end of the Sequence. Returns true if the - // Sequence was empty before this operation. + // Adds |task| at the end of the sequence's queue. Returns true if the + // sequence was empty before this operation. bool PushTask(std::unique_ptr<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. - std::unique_ptr<Task> TakeTask(); - - // Returns the TaskTraits of the Task in front of the Sequence. Cannot be - // called on an empty Sequence or on a Sequence whose front slot is empty. - TaskTraits PeekTaskTraits() const; + // Returns the task in front of the sequence's queue, if any. + const Task* PeekTask() const; - // 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(); + // Removes the task in front of the sequence's queue. Returns true if the + // sequence is empty after this operation. Cannot be called on an empty + // sequence. + bool PopTask(); - // Returns a SequenceSortKey representing the priority of the Sequence. Cannot - // be called on an empty Sequence. + // 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. - const SequenceToken& token() const { return token_; } - private: friend class RefCountedThreadSafe<Sequence>; ~Sequence(); - const SequenceToken token_ = SequenceToken::Create(); - // Synchronizes access to all members. mutable SchedulerLock lock_; diff --git a/base/task_scheduler/sequence_unittest.cc b/base/task_scheduler/sequence_unittest.cc index c45d8a87d0..6a15299e1e 100644 --- a/base/task_scheduler/sequence_unittest.cc +++ b/base/task_scheduler/sequence_unittest.cc @@ -4,12 +4,7 @@ #include "base/task_scheduler/sequence.h" -#include <utility> - -#include "base/bind.h" #include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/test/gtest_util.h" #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" @@ -18,7 +13,6 @@ namespace internal { namespace { - class TaskSchedulerSequenceTest : public testing::Test { public: TaskSchedulerSequenceTest() @@ -62,7 +56,7 @@ class TaskSchedulerSequenceTest : public testing::Test { std::unique_ptr<Task> task_e_owned_; // Raw pointers to those same tasks for verification. This is needed because - // the unique_ptrs above no longer point to the tasks once they have been + // the scoped_ptrs above no longer point to the tasks once they have been // moved into a Sequence. const Task* task_a_; const Task* task_b_; @@ -76,54 +70,54 @@ class TaskSchedulerSequenceTest : public testing::Test { } // namespace -TEST_F(TaskSchedulerSequenceTest, PushTakeRemove) { +TEST_F(TaskSchedulerSequenceTest, PushPopPeek) { scoped_refptr<Sequence> sequence(new Sequence); // Push task A in the sequence. Its sequenced time should be updated and it // should be in front of the sequence. EXPECT_TRUE(sequence->PushTask(std::move(task_a_owned_))); EXPECT_FALSE(task_a_->sequenced_time.is_null()); - EXPECT_EQ(task_a_->traits.priority(), sequence->PeekTaskTraits().priority()); + EXPECT_EQ(task_a_, sequence->PeekTask()); // Push task B, C and D in the sequence. Their sequenced time should be // updated and task A should always remain in front of the sequence. EXPECT_FALSE(sequence->PushTask(std::move(task_b_owned_))); EXPECT_FALSE(task_b_->sequenced_time.is_null()); - EXPECT_EQ(task_a_->traits.priority(), sequence->PeekTaskTraits().priority()); + EXPECT_EQ(task_a_, sequence->PeekTask()); EXPECT_FALSE(sequence->PushTask(std::move(task_c_owned_))); EXPECT_FALSE(task_c_->sequenced_time.is_null()); - EXPECT_EQ(task_a_->traits.priority(), sequence->PeekTaskTraits().priority()); + EXPECT_EQ(task_a_, sequence->PeekTask()); EXPECT_FALSE(sequence->PushTask(std::move(task_d_owned_))); EXPECT_FALSE(task_d_->sequenced_time.is_null()); - EXPECT_EQ(task_a_->traits.priority(), sequence->PeekTaskTraits().priority()); + EXPECT_EQ(task_a_, sequence->PeekTask()); - // Get the task in front of the sequence. It should be task A. - EXPECT_EQ(task_a_, sequence->TakeTask().get()); + // Pop task A. Task B should now be in front. + EXPECT_FALSE(sequence->PopTask()); + EXPECT_EQ(task_b_, sequence->PeekTask()); - // Remove the empty slot. Task B should now be in front. - EXPECT_FALSE(sequence->Pop()); - EXPECT_EQ(task_b_, sequence->TakeTask().get()); + // Pop task B. Task C should now be in front. + EXPECT_FALSE(sequence->PopTask()); + EXPECT_EQ(task_c_, sequence->PeekTask()); - // Remove the empty slot. Task C should now be in front. - EXPECT_FALSE(sequence->Pop()); - EXPECT_EQ(task_c_, sequence->TakeTask().get()); + // Pop task C. Task D should now be in front. + EXPECT_FALSE(sequence->PopTask()); + EXPECT_EQ(task_d_, sequence->PeekTask()); - // Remove the empty slot. Task D should now be in front. - EXPECT_FALSE(sequence->Pop()); - EXPECT_EQ(task_d_, sequence->TakeTask().get()); - - // Push task E in the sequence. Its sequenced time should be updated. + // Push task E in the sequence. Its sequenced time should be updated and + // task D should remain in front. EXPECT_FALSE(sequence->PushTask(std::move(task_e_owned_))); EXPECT_FALSE(task_e_->sequenced_time.is_null()); + EXPECT_EQ(task_d_, sequence->PeekTask()); - // Remove the empty slot. Task E should now be in front. - EXPECT_FALSE(sequence->Pop()); - EXPECT_EQ(task_e_, sequence->TakeTask().get()); + // Pop task D. Task E should now be in front. + EXPECT_FALSE(sequence->PopTask()); + EXPECT_EQ(task_e_, sequence->PeekTask()); - // Remove the empty slot. The sequence should now be empty. - EXPECT_TRUE(sequence->Pop()); + // Pop task E. The sequence should now be empty. + EXPECT_TRUE(sequence->PopTask()); + EXPECT_EQ(nullptr, sequence->PeekTask()); } TEST_F(TaskSchedulerSequenceTest, GetSortKey) { @@ -158,24 +152,21 @@ TEST_F(TaskSchedulerSequenceTest, GetSortKey) { // Pop task A. The highest priority is still USER_BLOCKING. The task in front // of the sequence is now task B. - sequence->TakeTask(); - sequence->Pop(); + sequence->PopTask(); EXPECT_EQ( SequenceSortKey(TaskPriority::USER_BLOCKING, task_b_->sequenced_time), sequence->GetSortKey()); // Pop task B. The highest priority is still USER_BLOCKING. The task in front // of the sequence is now task C. - sequence->TakeTask(); - sequence->Pop(); + sequence->PopTask(); EXPECT_EQ( SequenceSortKey(TaskPriority::USER_BLOCKING, task_c_->sequenced_time), sequence->GetSortKey()); // Pop task C. The highest priority is still USER_BLOCKING. The task in front // of the sequence is now task D. - sequence->TakeTask(); - sequence->Pop(); + sequence->PopTask(); EXPECT_EQ( SequenceSortKey(TaskPriority::USER_BLOCKING, task_d_->sequenced_time), sequence->GetSortKey()); @@ -189,38 +180,10 @@ TEST_F(TaskSchedulerSequenceTest, GetSortKey) { // Pop task D. The highest priority is now from task E (BACKGROUND). The // task in front of the sequence is now task E. - sequence->TakeTask(); - sequence->Pop(); + sequence->PopTask(); EXPECT_EQ(SequenceSortKey(TaskPriority::BACKGROUND, task_e_->sequenced_time), sequence->GetSortKey()); } -// Verify that a DCHECK fires if Pop() is called on a sequence whose front slot -// isn't empty. -TEST_F(TaskSchedulerSequenceTest, PopNonEmptyFrontSlot) { - scoped_refptr<Sequence> sequence(new Sequence); - sequence->PushTask( - MakeUnique<Task>(FROM_HERE, Bind(&DoNothing), TaskTraits(), TimeDelta())); - - EXPECT_DCHECK_DEATH({ sequence->Pop(); }); -} - -// Verify that a DCHECK fires if TakeTask() is called on a sequence whose front -// slot is empty. -TEST_F(TaskSchedulerSequenceTest, TakeEmptyFrontSlot) { - scoped_refptr<Sequence> sequence(new Sequence); - sequence->PushTask( - MakeUnique<Task>(FROM_HERE, Bind(&DoNothing), TaskTraits(), TimeDelta())); - - EXPECT_TRUE(sequence->TakeTask()); - EXPECT_DCHECK_DEATH({ sequence->TakeTask(); }); -} - -// Verify that a DCHECK fires if TakeTask() is called on an empty sequence. -TEST_F(TaskSchedulerSequenceTest, TakeEmptySequence) { - scoped_refptr<Sequence> sequence(new Sequence); - EXPECT_DCHECK_DEATH({ sequence->TakeTask(); }); -} - } // namespace internal } // namespace base diff --git a/base/task_scheduler/task.cc b/base/task_scheduler/task.cc index 3780c16dcb..8a589a2021 100644 --- a/base/task_scheduler/task.cc +++ b/base/task_scheduler/task.cc @@ -10,20 +10,12 @@ namespace internal { Task::Task(const tracked_objects::Location& posted_from, const Closure& task, const TaskTraits& traits, - TimeDelta delay) + const TimeDelta& delay) : PendingTask(posted_from, task, delay.is_zero() ? TimeTicks() : TimeTicks::Now() + delay, false), // Not nestable. - // Prevent a delayed BLOCK_SHUTDOWN task from blocking shutdown before - // being scheduled by changing its shutdown behavior to SKIP_ON_SHUTDOWN. - traits(!delay.is_zero() && - traits.shutdown_behavior() == - TaskShutdownBehavior::BLOCK_SHUTDOWN - ? TaskTraits(traits).WithShutdownBehavior( - TaskShutdownBehavior::SKIP_ON_SHUTDOWN) - : traits), - delay(delay) {} + traits(traits) {} Task::~Task() = default; diff --git a/base/task_scheduler/task.h b/base/task_scheduler/task.h index c5b9bdb53b..2b53c690fd 100644 --- a/base/task_scheduler/task.h +++ b/base/task_scheduler/task.h @@ -23,22 +23,17 @@ namespace internal { // profiling inherited from PendingTask. struct BASE_EXPORT Task : public PendingTask { // |posted_from| is the site the task was posted from. |task| is the closure - // to run. |traits_in| is metadata about the task. |delay| is a delay that - // must expire before the Task runs. If |delay| is non-zero and the shutdown - // behavior in |traits| is BLOCK_SHUTDOWN, the shutdown behavior is - // automatically adjusted to SKIP_ON_SHUTDOWN. + // to run. |traits| is metadata about the task. |delay| is a delay that must + // expire before the Task runs. Task(const tracked_objects::Location& posted_from, const Closure& task, const TaskTraits& traits, - TimeDelta delay); + const TimeDelta& delay); ~Task(); // The TaskTraits of this task. const TaskTraits traits; - // The delay that must expire before the task runs. - const TimeDelta delay; - // The time at which the task was inserted in its sequence. For an undelayed // task, this happens at post time. For a delayed task, this happens some // time after the task's delay has expired. If the task hasn't been inserted diff --git a/base/task_scheduler/task_traits.cc b/base/task_scheduler/task_traits.cc index 6acf3244f5..dd55535852 100644 --- a/base/task_scheduler/task_traits.cc +++ b/base/task_scheduler/task_traits.cc @@ -8,29 +8,20 @@ #include <ostream> -#include "base/logging.h" -#include "base/task_scheduler/scoped_set_task_priority_for_current_thread.h" - namespace base { // Do not rely on defaults hard-coded below beyond the guarantees described in // the header; anything else is subject to change. Tasks should explicitly // request defaults if the behavior is critical to the task. TaskTraits::TaskTraits() - : may_block_(false), - with_base_sync_primitives_(false), - priority_(internal::GetTaskPriorityForCurrentThread()), + : with_file_io_(false), + priority_(TaskPriority::BACKGROUND), shutdown_behavior_(TaskShutdownBehavior::SKIP_ON_SHUTDOWN) {} TaskTraits::~TaskTraits() = default; -TaskTraits& TaskTraits::MayBlock() { - may_block_ = true; - return *this; -} - -TaskTraits& TaskTraits::WithBaseSyncPrimitives() { - with_base_sync_primitives_ = true; +TaskTraits& TaskTraits::WithFileIO() { + with_file_io_ = true; return *this; } @@ -45,41 +36,34 @@ TaskTraits& TaskTraits::WithShutdownBehavior( return *this; } -const char* TaskPriorityToString(TaskPriority task_priority) { +std::ostream& operator<<(std::ostream& os, const TaskPriority& task_priority) { switch (task_priority) { case TaskPriority::BACKGROUND: - return "BACKGROUND"; + os << "BACKGROUND"; + break; case TaskPriority::USER_VISIBLE: - return "USER_VISIBLE"; + os << "USER_VISIBLE"; + break; case TaskPriority::USER_BLOCKING: - return "USER_BLOCKING"; + os << "USER_BLOCKING"; + break; } - NOTREACHED(); - return ""; + return os; } -const char* TaskShutdownBehaviorToString( - TaskShutdownBehavior shutdown_behavior) { +std::ostream& operator<<(std::ostream& os, + const TaskShutdownBehavior& shutdown_behavior) { switch (shutdown_behavior) { case TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN: - return "CONTINUE_ON_SHUTDOWN"; + os << "CONTINUE_ON_SHUTDOWN"; + break; case TaskShutdownBehavior::SKIP_ON_SHUTDOWN: - return "SKIP_ON_SHUTDOWN"; + os << "SKIP_ON_SHUTDOWN"; + break; case TaskShutdownBehavior::BLOCK_SHUTDOWN: - return "BLOCK_SHUTDOWN"; + os << "BLOCK_SHUTDOWN"; + break; } - NOTREACHED(); - return ""; -} - -std::ostream& operator<<(std::ostream& os, const TaskPriority& task_priority) { - os << TaskPriorityToString(task_priority); - return os; -} - -std::ostream& operator<<(std::ostream& os, - const TaskShutdownBehavior& shutdown_behavior) { - os << TaskShutdownBehaviorToString(shutdown_behavior); return os; } diff --git a/base/task_scheduler/task_traits.h b/base/task_scheduler/task_traits.h index 435fdac9af..0c0d304dcf 100644 --- a/base/task_scheduler/task_traits.h +++ b/base/task_scheduler/task_traits.h @@ -78,57 +78,19 @@ enum class TaskShutdownBehavior { // Describes metadata for a single task or a group of tasks. class BASE_EXPORT TaskTraits { public: - // Constructs a default TaskTraits for tasks that - // (1) don't block (ref. MayBlock() and WithBaseSyncPrimitives()), - // (2) prefer inheriting the current priority to specifying their own, and - // (3) can either block shutdown or be skipped on shutdown - // (TaskScheduler implementation is free to choose a fitting default). - // Tasks that require stricter guarantees and/or know the specific - // TaskPriority appropriate for them should highlight those by requesting + // Constructs a default TaskTraits for tasks with + // (1) no I/O, + // (2) low priority, and + // (3) may block shutdown or be skipped on shutdown. + // Tasks that require stricter guarantees should highlight those by requesting // explicit traits below. TaskTraits(); TaskTraits(const TaskTraits& other) = default; TaskTraits& operator=(const TaskTraits& other) = default; ~TaskTraits(); - // Tasks with this trait may block. This includes but is not limited to tasks - // that wait on synchronous file I/O operations: read or write a file from - // disk, interact with a pipe or a socket, rename or delete a file, enumerate - // files in a directory, etc. This trait isn't required for the mere use of - // locks. For tasks that block on base/ synchronization primitives, see - // WithBaseSyncPrimitives(). - TaskTraits& MayBlock(); - - // Tasks with this trait will pass base::AssertWaitAllowed(), i.e. will be - // allowed on the following methods : - // - base::WaitableEvent::Wait - // - base::ConditionVariable::Wait - // - base::PlatformThread::Join - // - base::PlatformThread::Sleep - // - base::Process::WaitForExit - // - base::Process::WaitForExitWithTimeout - // - // Tasks should generally not use these methods. - // - // Instead of waiting on a WaitableEvent or a ConditionVariable, put the work - // that should happen after the wait in a callback and post that callback from - // where the WaitableEvent or ConditionVariable would have been signaled. If - // something needs to be scheduled after many tasks have executed, use - // base::BarrierClosure. - // - // Avoid creating threads. Instead, use - // base::Create(Sequenced|SingleTreaded)TaskRunnerWithTraits(). If a thread is - // really needed, make it non-joinable and add cleanup work at the end of the - // thread's main function (if using base::Thread, override Cleanup()). - // - // On Windows, join processes asynchronously using base::win::ObjectWatcher. - // - // MayBlock() must be specified in conjunction with this trait if and only if - // removing usage of methods listed above in the labeled tasks would still - // result in tasks that may block (per MayBlock()'s definition). - // - // In doubt, consult with //base/task_scheduler/OWNERS. - TaskTraits& WithBaseSyncPrimitives(); + // Allows tasks with these traits to do file I/O. + TaskTraits& WithFileIO(); // Applies |priority| to tasks with these traits. TaskTraits& WithPriority(TaskPriority priority); @@ -136,11 +98,8 @@ class BASE_EXPORT TaskTraits { // Applies |shutdown_behavior| to tasks with these traits. TaskTraits& WithShutdownBehavior(TaskShutdownBehavior shutdown_behavior); - // Returns true if tasks with these traits may block. - bool may_block() const { return may_block_; } - - // Returns true if tasks with these traits may use base/ sync primitives. - bool with_base_sync_primitives() const { return with_base_sync_primitives_; } + // Returns true if file I/O is allowed by these traits. + bool with_file_io() const { return with_file_io_; } // Returns the priority of tasks with these traits. TaskPriority priority() const { return priority_; } @@ -149,22 +108,29 @@ class BASE_EXPORT TaskTraits { TaskShutdownBehavior shutdown_behavior() const { return shutdown_behavior_; } private: - bool may_block_; - bool with_base_sync_primitives_; + bool with_file_io_; TaskPriority priority_; TaskShutdownBehavior shutdown_behavior_; }; -// Returns string literals for the enums defined in this file. These methods -// should only be used for tracing and debugging. -BASE_EXPORT const char* TaskPriorityToString(TaskPriority task_priority); -BASE_EXPORT const char* TaskShutdownBehaviorToString( - TaskShutdownBehavior task_priority); +// Describes how tasks are executed by a task runner. +enum class ExecutionMode { + // Can execute multiple tasks at a time in any order. + PARALLEL, + + // Executes one task at a time in posting order. The sequence’s priority is + // equivalent to the highest priority pending task in the sequence. + SEQUENCED, -// Stream operators so that the enums defined in this file can be used in -// DCHECK and EXPECT statements. + // Executes one task at a time on a single thread in posting order. + SINGLE_THREADED, +}; + +// Stream operators so TaskPriority and TaskShutdownBehavior can be used in +// DCHECK statements. BASE_EXPORT std::ostream& operator<<(std::ostream& os, const TaskPriority& shutdown_behavior); + BASE_EXPORT std::ostream& operator<<( std::ostream& os, const TaskShutdownBehavior& shutdown_behavior); diff --git a/base/task_scheduler/test_utils.h b/base/task_scheduler/test_utils.h index dbd1227f52..bafd09aa2a 100644 --- a/base/task_scheduler/test_utils.h +++ b/base/task_scheduler/test_utils.h @@ -5,16 +5,15 @@ #ifndef BASE_TASK_SCHEDULER_TEST_UTILS_H_ #define BASE_TASK_SCHEDULER_TEST_UTILS_H_ -namespace base { -namespace internal { -namespace test { +#include "base/logging.h" +#include "build/build_config.h" +#include "testing/gtest/include/gtest/gtest.h" -// An enumeration of possible task scheduler TaskRunner types. Used to -// parametrize relevant task_scheduler tests. -enum class ExecutionMode { PARALLEL, SEQUENCED, SINGLE_THREADED }; - -} // namespace test -} // namespace internal -} // namespace base +// Death tests misbehave on Android. +#if DCHECK_IS_ON() && defined(GTEST_HAS_DEATH_TEST) && !defined(OS_ANDROID) +#define EXPECT_DCHECK_DEATH(statement, regex) EXPECT_DEATH(statement, regex) +#else +#define EXPECT_DCHECK_DEATH(statement, regex) +#endif #endif // BASE_TASK_SCHEDULER_TEST_UTILS_H_ |