Commit 1b3b02a4 authored by Gabriel Charette's avatar Gabriel Charette Committed by Commit Bot

[ScopedTaskEnvironment] Add MOCK_TIME support for ThreadPool tasks

Multi-threaded MOCK_TIME advances when either RunLoop::Run() or
ScopedTaskEnvironment::FastForward*() is active and the system reaches
an idle phase (both main thread and thread pool are out of immediate
tasks). It then advances by the minimum time delta necessary to make a
task able to run.

In a follow-up CL, I'll split MOCK_TIME off of MainThreadType (now that
it's no longer main thread specific) and migrate callers.

Bug: 946657
Change-Id: Id3da34ac066623291a8fca682fd13c9473e83e0b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1686776Reviewed-by: default avatarAlex Clarke <alexclarke@chromium.org>
Reviewed-by: default avatarFrançois Doray <fdoray@chromium.org>
Commit-Queue: Gabriel Charette <gab@chromium.org>
Cr-Commit-Position: refs/heads/master@{#676272}
parent 81116d05
...@@ -47,10 +47,10 @@ class BASE_EXPORT TimeDomain { ...@@ -47,10 +47,10 @@ class BASE_EXPORT TimeDomain {
// TODO(alexclarke): Make this main thread only. // TODO(alexclarke): Make this main thread only.
virtual TimeTicks Now() const = 0; virtual TimeTicks Now() const = 0;
// Computes the delay until the time when TimeDomain needs to wake up // Computes the delay until the time when TimeDomain needs to wake up some
// some TaskQueue. Specific time domains (e.g. virtual or throttled) may // TaskQueue on the main thread. Specific time domains (e.g. virtual or
// return TimeDelata() if TaskQueues have any delayed tasks they deem // throttled) may return TimeDelta() if TaskQueues have any delayed tasks they
// eligible to run. It's also allowed to advance time domains's internal // deem eligible to run. It's also allowed to advance time domains's internal
// clock when this method is called. // clock when this method is called.
// Can be called from main thread only. // Can be called from main thread only.
// NOTE: |lazy_now| and the return value are in the SequenceManager's time. // NOTE: |lazy_now| and the return value are in the SequenceManager's time.
......
...@@ -117,6 +117,13 @@ void DelayedTaskManager::ProcessRipeTasks() { ...@@ -117,6 +117,13 @@ void DelayedTaskManager::ProcessRipeTasks() {
} }
} }
Optional<TimeTicks> DelayedTaskManager::NextScheduledRunTime() const {
CheckedAutoLock auto_lock(queue_lock_);
if (delayed_task_queue_.empty())
return nullopt;
return delayed_task_queue_.Min().task.delayed_run_time;
}
TimeTicks DelayedTaskManager::GetTimeToScheduleProcessRipeTasksLockRequired() { TimeTicks DelayedTaskManager::GetTimeToScheduleProcessRipeTasksLockRequired() {
queue_lock_.AssertAcquired(); queue_lock_.AssertAcquired();
if (delayed_task_queue_.empty()) if (delayed_task_queue_.empty())
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/synchronization/atomic_flag.h" #include "base/synchronization/atomic_flag.h"
#include "base/task/common/checked_lock.h" #include "base/task/common/checked_lock.h"
#include "base/task/common/intrusive_heap.h" #include "base/task/common/intrusive_heap.h"
...@@ -49,6 +50,12 @@ class BASE_EXPORT DelayedTaskManager { ...@@ -49,6 +50,12 @@ class BASE_EXPORT DelayedTaskManager {
PostTaskNowCallback post_task_now_callback, PostTaskNowCallback post_task_now_callback,
scoped_refptr<TaskRunner> task_runner); scoped_refptr<TaskRunner> task_runner);
// Pop and post all the ripe tasks in the delayed task queue.
void ProcessRipeTasks();
// Returns the |delayed_run_time| of the next scheduled task, if any.
Optional<TimeTicks> NextScheduledRunTime() const;
private: private:
struct DelayedTask { struct DelayedTask {
DelayedTask(); DelayedTask();
...@@ -86,9 +93,6 @@ class BASE_EXPORT DelayedTaskManager { ...@@ -86,9 +93,6 @@ class BASE_EXPORT DelayedTaskManager {
DISALLOW_COPY_AND_ASSIGN(DelayedTask); DISALLOW_COPY_AND_ASSIGN(DelayedTask);
}; };
// Pop and post all the ripe tasks in the delayed task queue.
void ProcessRipeTasks();
// Get the time at which to schedule the next |ProcessRipeTasks()| execution, // Get the time at which to schedule the next |ProcessRipeTasks()| execution,
// or TimeTicks::Max() if none needs to be scheduled (i.e. no task, or next // or TimeTicks::Max() if none needs to be scheduled (i.e. no task, or next
// task already scheduled). // task already scheduled).
...@@ -108,7 +112,7 @@ class BASE_EXPORT DelayedTaskManager { ...@@ -108,7 +112,7 @@ class BASE_EXPORT DelayedTaskManager {
// it is never modified. It is therefore safe to access // it is never modified. It is therefore safe to access
// |service_thread_task_runner_| without synchronization once it is observed // |service_thread_task_runner_| without synchronization once it is observed
// that it is non-null. // that it is non-null.
CheckedLock queue_lock_; mutable CheckedLock queue_lock_;
scoped_refptr<TaskRunner> service_thread_task_runner_; scoped_refptr<TaskRunner> service_thread_task_runner_;
......
...@@ -160,6 +160,11 @@ class BASE_EXPORT TaskTracker { ...@@ -160,6 +160,11 @@ class BASE_EXPORT TaskTracker {
return tracked_ref_factory_.GetTrackedRef(); return tracked_ref_factory_.GetTrackedRef();
} }
// Returns true if there are task sources that haven't completed their
// execution (still queued or in progress). If it returns false: the side-
// effects of all completed tasks are guaranteed to be visible to the caller.
bool HasIncompleteTaskSourcesForTesting() const;
protected: protected:
// Runs and deletes |task| if |can_run_task| is true. Otherwise, just deletes // Runs and deletes |task| if |can_run_task| is true. Otherwise, just deletes
// |task|. |task| is always deleted in the environment where it runs or would // |task|. |task| is always deleted in the environment where it runs or would
...@@ -172,11 +177,6 @@ class BASE_EXPORT TaskTracker { ...@@ -172,11 +177,6 @@ class BASE_EXPORT TaskTracker {
const TaskTraits& traits, const TaskTraits& traits,
bool can_run_task); bool can_run_task);
// Returns true if there are task sources that haven't completed their
// execution (still queued or in progress). If it returns false: the side-
// effects of all completed tasks are guaranteed to be visible to the caller.
bool HasIncompleteTaskSourcesForTesting() const;
private: private:
friend class RegisteredTaskSource; friend class RegisteredTaskSource;
class State; class State;
......
...@@ -64,11 +64,13 @@ bool HasDisableBestEffortTasksSwitch() { ...@@ -64,11 +64,13 @@ bool HasDisableBestEffortTasksSwitch() {
ThreadPoolImpl::ThreadPoolImpl(StringPiece histogram_label) ThreadPoolImpl::ThreadPoolImpl(StringPiece histogram_label)
: ThreadPoolImpl(histogram_label, : ThreadPoolImpl(histogram_label,
std::make_unique<TaskTrackerImpl>(histogram_label)) {} std::make_unique<TaskTrackerImpl>(histogram_label),
DefaultTickClock::GetInstance()) {}
ThreadPoolImpl::ThreadPoolImpl(StringPiece histogram_label, ThreadPoolImpl::ThreadPoolImpl(StringPiece histogram_label,
std::unique_ptr<TaskTrackerImpl> task_tracker) std::unique_ptr<TaskTrackerImpl> task_tracker,
: thread_pool_clock_(DefaultTickClock::GetInstance()), const TickClock* tick_clock)
: thread_pool_clock_(tick_clock),
task_tracker_(std::move(task_tracker)), task_tracker_(std::move(task_tracker)),
service_thread_(std::make_unique<ServiceThread>( service_thread_(std::make_unique<ServiceThread>(
task_tracker_.get(), task_tracker_.get(),
...@@ -265,6 +267,16 @@ ThreadPoolImpl::CreateUpdateableSequencedTaskRunner(const TaskTraits& traits) { ...@@ -265,6 +267,16 @@ ThreadPoolImpl::CreateUpdateableSequencedTaskRunner(const TaskTraits& traits) {
return MakeRefCounted<PooledSequencedTaskRunner>(new_traits, this); return MakeRefCounted<PooledSequencedTaskRunner>(new_traits, this);
} }
Optional<TimeTicks> ThreadPoolImpl::NextScheduledRunTimeForTesting() const {
if (task_tracker_->HasIncompleteTaskSourcesForTesting())
return ThreadPoolClock::Now();
return delayed_task_manager_.NextScheduledRunTime();
}
void ThreadPoolImpl::ProcessRipeDelayedTasksForTesting() {
delayed_task_manager_.ProcessRipeTasks();
}
int ThreadPoolImpl::GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated( int ThreadPoolImpl::GetMaxConcurrentNonBlockedTasksWithTraitsDeprecated(
const TaskTraits& traits) const { const TaskTraits& traits) const {
// This method does not support getting the maximum number of BEST_EFFORT // This method does not support getting the maximum number of BEST_EFFORT
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/memory/ptr_util.h" #include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h" #include "base/memory/ref_counted.h"
#include "base/optional.h"
#include "base/sequence_checker.h" #include "base/sequence_checker.h"
#include "base/strings/string_piece.h" #include "base/strings/string_piece.h"
#include "base/synchronization/atomic_flag.h" #include "base/synchronization/atomic_flag.h"
...@@ -64,9 +65,11 @@ class BASE_EXPORT ThreadPoolImpl : public ThreadPoolInstance, ...@@ -64,9 +65,11 @@ class BASE_EXPORT ThreadPoolImpl : public ThreadPoolInstance,
//|histogram_label| is used to label histograms, it must not be empty. //|histogram_label| is used to label histograms, it must not be empty.
explicit ThreadPoolImpl(StringPiece histogram_label); explicit ThreadPoolImpl(StringPiece histogram_label);
// For testing only. Creates a ThreadPoolImpl with a custom TaskTracker. // For testing only. Creates a ThreadPoolImpl with a custom TaskTracker and
// TickClock.
ThreadPoolImpl(StringPiece histogram_label, ThreadPoolImpl(StringPiece histogram_label,
std::unique_ptr<TaskTrackerImpl> task_tracker); std::unique_ptr<TaskTrackerImpl> task_tracker,
const TickClock* tick_clock);
~ThreadPoolImpl() override; ~ThreadPoolImpl() override;
...@@ -101,6 +104,16 @@ class BASE_EXPORT ThreadPoolImpl : public ThreadPoolInstance, ...@@ -101,6 +104,16 @@ class BASE_EXPORT ThreadPoolImpl : public ThreadPoolInstance,
scoped_refptr<UpdateableSequencedTaskRunner> scoped_refptr<UpdateableSequencedTaskRunner>
CreateUpdateableSequencedTaskRunner(const TaskTraits& traits); CreateUpdateableSequencedTaskRunner(const TaskTraits& traits);
// Returns the TimeTicks of the next task scheduled on ThreadPool (Now() if
// immediate, nullopt if none). This is thread-safe, i.e., it's safe if tasks
// are being posted in parallel with this call but such a situation obviously
// results in a race as to whether this call will see the new tasks in time.
Optional<TimeTicks> NextScheduledRunTimeForTesting() const;
// Forces ripe delayed tasks to be posted (e.g. when time is mocked and
// advances faster than the real-time delay on ServiceThread).
void ProcessRipeDelayedTasksForTesting();
private: private:
// Invoked after |has_fence_| or |has_best_effort_fence_| is updated. Sets the // Invoked after |has_fence_| or |has_best_effort_fence_| is updated. Sets the
// CanRunPolicy in TaskTracker and wakes up workers as appropriate. // CanRunPolicy in TaskTracker and wakes up workers as appropriate.
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "base/task/sequence_manager/sequence_manager_impl.h" #include "base/task/sequence_manager/sequence_manager_impl.h"
#include "base/task/sequence_manager/time_domain.h" #include "base/task/sequence_manager/time_domain.h"
#include "base/task/thread_pool/thread_pool.h" #include "base/task/thread_pool/thread_pool.h"
#include "base/task/thread_pool/thread_pool_clock.h"
#include "base/task/thread_pool/thread_pool_impl.h" #include "base/task/thread_pool/thread_pool_impl.h"
#include "base/test/bind_test_util.h" #include "base/test/bind_test_util.h"
#include "base/test/test_mock_time_task_runner.h" #include "base/test/test_mock_time_task_runner.h"
...@@ -29,6 +30,7 @@ ...@@ -29,6 +30,7 @@
#include "base/threading/thread_restrictions.h" #include "base/threading/thread_restrictions.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/time/clock.h" #include "base/time/clock.h"
#include "base/time/default_tick_clock.h"
#include "base/time/tick_clock.h" #include "base/time/tick_clock.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/time/time_override.h" #include "base/time/time_override.h"
...@@ -112,6 +114,9 @@ class ScopedTaskEnvironment::TestTaskTracker ...@@ -112,6 +114,9 @@ class ScopedTaskEnvironment::TestTaskTracker
// thread, waiting for it to complete results in a deadlock...). // thread, waiting for it to complete results in a deadlock...).
bool DisallowRunTasks(); bool DisallowRunTasks();
// Returns true if tasks are currently allowed to run.
bool TasksAllowedToRun() const;
private: private:
friend class ScopedTaskEnvironment; friend class ScopedTaskEnvironment;
...@@ -122,7 +127,7 @@ class ScopedTaskEnvironment::TestTaskTracker ...@@ -122,7 +127,7 @@ class ScopedTaskEnvironment::TestTaskTracker
bool can_run_task) override; bool can_run_task) override;
// Synchronizes accesses to members below. // Synchronizes accesses to members below.
Lock lock_; mutable Lock lock_;
// True if running tasks is allowed. // True if running tasks is allowed.
bool can_run_tasks_ GUARDED_BY(lock_) = true; bool can_run_tasks_ GUARDED_BY(lock_) = true;
...@@ -192,6 +197,14 @@ class ScopedTaskEnvironment::MockTimeDomain ...@@ -192,6 +197,14 @@ class ScopedTaskEnvironment::MockTimeDomain
return nullptr; return nullptr;
} }
void SetThreadPool(internal::ThreadPoolImpl* thread_pool,
const TestTaskTracker* thread_pool_task_tracker) {
DCHECK(!thread_pool_);
DCHECK(!thread_pool_task_tracker_);
thread_pool_ = thread_pool;
thread_pool_task_tracker_ = thread_pool_task_tracker;
}
// sequence_manager::TimeDomain: // sequence_manager::TimeDomain:
sequence_manager::LazyNow CreateLazyNow() const override { sequence_manager::LazyNow CreateLazyNow() const override {
...@@ -239,7 +252,8 @@ class ScopedTaskEnvironment::MockTimeDomain ...@@ -239,7 +252,8 @@ class ScopedTaskEnvironment::MockTimeDomain
if (!auto_advance_on_idle_) if (!auto_advance_on_idle_)
return false; return false;
return FastForwardToNextTaskOrCap(TimeTicks::Max()); return FastForwardToNextTaskOrCap(TimeTicks::Max()) ==
NextTaskSource::kMainThread;
} }
const char* GetName() const override { return "MockTimeDomain"; } const char* GetName() const override { return "MockTimeDomain"; }
...@@ -247,20 +261,73 @@ class ScopedTaskEnvironment::MockTimeDomain ...@@ -247,20 +261,73 @@ class ScopedTaskEnvironment::MockTimeDomain
// TickClock implementation: // TickClock implementation:
TimeTicks NowTicks() const override { return Now(); } TimeTicks NowTicks() const override { return Now(); }
// Advances time to the next task or to |fast_forward_cap| (if it's not // Used by FastForwardToNextTaskOrCap() to return which task source time was
// Max()). Returns true if there's additional immediate work as a result // advanced to.
// of this call. enum class NextTaskSource {
bool FastForwardToNextTaskOrCap(TimeTicks fast_forward_cap) { // Out of tasks under |fast_forward_cap|.
kNone,
// There's now >=1 immediate task on the main thread.
kMainThread,
// There's now >=1 immediate task in the thread pool.
kThreadPool,
};
// Advances time to the first of : next main thread task, next thread pool
// task, or |fast_forward_cap| (if it's not Max()).
NextTaskSource FastForwardToNextTaskOrCap(TimeTicks fast_forward_cap) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_); DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
// We don't need to call ReclaimMemory here because // We don't need to call ReclaimMemory here because
// DelayTillNextTask will have dealt with cancelled delayed tasks for us. // DelayTillNextTask will have dealt with cancelled delayed tasks for us.
Optional<TimeTicks> next_task_time = NextScheduledRunTime(); Optional<TimeTicks> next_main_thread_task_time = NextScheduledRunTime();
// Consider the next thread pool tasks iff they're running.
Optional<TimeTicks> next_thread_pool_task_time;
if (thread_pool_ && thread_pool_task_tracker_->TasksAllowedToRun()) {
next_thread_pool_task_time =
thread_pool_->NextScheduledRunTimeForTesting();
}
// Custom comparison logic to consider nullopt the largest rather than
// smallest value. Could consider using TimeTicks::Max() instead of nullopt
// to represent out-of-tasks?
Optional<TimeTicks> next_task_time;
if (!next_main_thread_task_time) {
next_task_time = next_thread_pool_task_time;
} else if (!next_thread_pool_task_time) {
next_task_time = next_main_thread_task_time;
} else {
next_task_time =
std::min(*next_main_thread_task_time, *next_thread_pool_task_time);
}
if (next_task_time && *next_task_time <= fast_forward_cap) { if (next_task_time && *next_task_time <= fast_forward_cap) {
AutoLock lock(now_ticks_lock_); {
now_ticks_ = *next_task_time; AutoLock lock(now_ticks_lock_);
return true; // It's possible for |next_task_time| to be in the past in the following
// scenario:
// Start with Now() == 100ms
// Thread A : Post 200ms delayed task T (construct and enqueue)
// Thread B : Construct 20ms delayed task U
// => |delayed_run_time| == 120ms.
// Thread A : FastForwardToNextTaskOrCap() => fast-forwards to T @
// 300ms (task U is not yet in queue).
// Thread B : Complete enqueue of task U.
// Thread A : FastForwardToNextTaskOrCap() => must stay at 300ms and run
// U, not go back to 120ms.
// Hence we need std::max() to protect again this because construction
// and enqueuing isn't atomic in time (LazyNow support in
// base/task/thread_pool could help).
now_ticks_ = std::max(now_ticks_, *next_task_time);
}
if (next_task_time == next_thread_pool_task_time) {
// Let the thread pool know that it should post its now ripe delayed
// tasks.
thread_pool_->ProcessRipeDelayedTasksForTesting();
return NextTaskSource::kThreadPool;
}
return NextTaskSource::kMainThread;
} }
if (!fast_forward_cap.is_max()) { if (!fast_forward_cap.is_max()) {
...@@ -270,11 +337,15 @@ class ScopedTaskEnvironment::MockTimeDomain ...@@ -270,11 +337,15 @@ class ScopedTaskEnvironment::MockTimeDomain
now_ticks_ = std::max(now_ticks_, fast_forward_cap); now_ticks_ = std::max(now_ticks_, fast_forward_cap);
} }
return false; return NextTaskSource::kNone;
} }
void set_auto_advance_on_idle(bool auto_advance_on_idle) { // Sets |auto_advance_on_idle_| to |auto_advance_on_idle| and returns its
// previous value.
bool SetAutoAdvanceOnIdle(bool auto_advance_on_idle) {
const auto previous = auto_advance_on_idle_;
auto_advance_on_idle_ = auto_advance_on_idle; auto_advance_on_idle_ = auto_advance_on_idle;
return previous;
} }
private: private:
...@@ -287,6 +358,9 @@ class ScopedTaskEnvironment::MockTimeDomain ...@@ -287,6 +358,9 @@ class ScopedTaskEnvironment::MockTimeDomain
sequence_manager::SequenceManager* const sequence_manager_; sequence_manager::SequenceManager* const sequence_manager_;
internal::ThreadPoolImpl* thread_pool_ = nullptr;
const TestTaskTracker* thread_pool_task_tracker_ = nullptr;
std::unique_ptr<subtle::ScopedTimeClockOverrides> time_overrides_; std::unique_ptr<subtle::ScopedTimeClockOverrides> time_overrides_;
// Protects |now_ticks_| // Protects |now_ticks_|
...@@ -391,8 +465,14 @@ void ScopedTaskEnvironment::InitializeThreadPool() { ...@@ -391,8 +465,14 @@ void ScopedTaskEnvironment::InitializeThreadPool() {
auto task_tracker = std::make_unique<TestTaskTracker>(); auto task_tracker = std::make_unique<TestTaskTracker>();
task_tracker_ = task_tracker.get(); task_tracker_ = task_tracker.get();
ThreadPoolInstance::Set(std::make_unique<internal::ThreadPoolImpl>( const TickClock* tick_clock =
"ScopedTaskEnvironment", std::move(task_tracker))); mock_time_domain_ ? static_cast<TickClock*>(mock_time_domain_.get())
: DefaultTickClock::GetInstance();
auto thread_pool = std::make_unique<internal::ThreadPoolImpl>(
"ScopedTaskEnvironment", std::move(task_tracker), tick_clock);
if (mock_time_domain_)
mock_time_domain_->SetThreadPool(thread_pool.get(), task_tracker_);
ThreadPoolInstance::Set(std::move(thread_pool));
ThreadPoolInstance::Get()->Start(init_params); ThreadPoolInstance::Get()->Start(init_params);
} }
...@@ -571,14 +651,21 @@ void ScopedTaskEnvironment::RunUntilIdle() { ...@@ -571,14 +651,21 @@ void ScopedTaskEnvironment::RunUntilIdle() {
void ScopedTaskEnvironment::FastForwardBy(TimeDelta delta) { void ScopedTaskEnvironment::FastForwardBy(TimeDelta delta) {
DCHECK(mock_time_domain_); DCHECK(mock_time_domain_);
mock_time_domain_->set_auto_advance_on_idle(false); DCHECK_GE(delta, TimeDelta());
const bool was_auto_advancing = mock_time_domain_->SetAutoAdvanceOnIdle(false);
const bool could_run_tasks = task_tracker_->AllowRunTasks();
const TimeTicks fast_forward_until = mock_time_domain_->NowTicks() + delta; const TimeTicks fast_forward_until = mock_time_domain_->NowTicks() + delta;
do { do {
RunUntilIdle(); RunUntilIdle();
} while (mock_time_domain_->FastForwardToNextTaskOrCap(fast_forward_until)); } while (mock_time_domain_->FastForwardToNextTaskOrCap(fast_forward_until) !=
MockTimeDomain::NextTaskSource::kNone);
mock_time_domain_->set_auto_advance_on_idle(true); if (was_auto_advancing)
mock_time_domain_->SetAutoAdvanceOnIdle(true);
if (!could_run_tasks)
task_tracker_->DisallowRunTasks();
} }
void ScopedTaskEnvironment::FastForwardUntilNoTasksRemain() { void ScopedTaskEnvironment::FastForwardUntilNoTasksRemain() {
...@@ -640,6 +727,11 @@ bool ScopedTaskEnvironment::TestTaskTracker::AllowRunTasks() { ...@@ -640,6 +727,11 @@ bool ScopedTaskEnvironment::TestTaskTracker::AllowRunTasks() {
return could_run_tasks; return could_run_tasks;
} }
bool ScopedTaskEnvironment::TestTaskTracker::TasksAllowedToRun() const {
AutoLock auto_lock(lock_);
return can_run_tasks_;
}
bool ScopedTaskEnvironment::TestTaskTracker::DisallowRunTasks() { bool ScopedTaskEnvironment::TestTaskTracker::DisallowRunTasks() {
AutoLock auto_lock(lock_); AutoLock auto_lock(lock_);
......
...@@ -78,16 +78,12 @@ class ScopedTaskEnvironment { ...@@ -78,16 +78,12 @@ class ScopedTaskEnvironment {
DEFAULT, DEFAULT,
// The main thread doesn't pump system messages and uses a mock clock for // The main thread doesn't pump system messages and uses a mock clock for
// delayed tasks (controllable via FastForward*() methods). // delayed tasks (controllable via FastForward*() methods).
// TODO(gab): Make this the default |main_thread_type|. // TODO(gab): Make MOCK_TIME configurable independent of MainThreadType.
// TODO(gab): Also mock the ThreadPoolInstance's clock simultaneously (this
// currently only mocks the main thread's clock).
MOCK_TIME, MOCK_TIME,
// The main thread pumps UI messages. // The main thread pumps UI messages.
UI, UI,
// The main thread pumps UI messages and uses a mock clock for delayed tasks // The main thread pumps UI messages and uses a mock clock for delayed tasks
// (controllable via FastForward*() methods). // (controllable via FastForward*() methods).
// TODO(gab@): Enable mock time on all threads and make MOCK_TIME
// configurable independent of MainThreadType.
UI_MOCK_TIME, UI_MOCK_TIME,
// The main thread pumps asynchronous IO messages and supports the // The main thread pumps asynchronous IO messages and supports the
// FileDescriptorWatcher API on POSIX. // FileDescriptorWatcher API on POSIX.
...@@ -195,9 +191,9 @@ class ScopedTaskEnvironment { ...@@ -195,9 +191,9 @@ class ScopedTaskEnvironment {
void RunUntilIdle(); void RunUntilIdle();
// Only valid for instances with a MOCK_TIME MainThreadType. Fast-forwards // Only valid for instances with a MOCK_TIME MainThreadType. Fast-forwards
// virtual time by |delta|, causing all tasks on the main thread with a // virtual time by |delta|, causing all tasks on the main thread and thread
// remaining delay less than or equal to |delta| to be executed in their // pool with a remaining delay less than or equal to |delta| to be executed in
// natural order before this returns. |delta| must be non-negative. Upon // their natural order before this returns. |delta| must be non-negative. Upon
// returning from this method, NowTicks() will be >= the initial |NowTicks() + // returning from this method, NowTicks() will be >= the initial |NowTicks() +
// delta|. It is guaranteed to be == iff tasks executed in this // delta|. It is guaranteed to be == iff tasks executed in this
// FastForwardBy() didn't result in nested calls to time-advancing-methods. // FastForwardBy() didn't result in nested calls to time-advancing-methods.
...@@ -229,13 +225,13 @@ class ScopedTaskEnvironment { ...@@ -229,13 +225,13 @@ class ScopedTaskEnvironment {
// FastForwardBy(2ms) // FastForwardBy(2ms)
// ================================ // ================================
// Result: NowTicks() is 5ms further in the future. // Result: NowTicks() is 5ms further in the future.
//
// TODO(gab): Make this apply to ThreadPool delayed tasks as well
// (currently only main thread time is mocked).
void FastForwardBy(TimeDelta delta); void FastForwardBy(TimeDelta delta);
// Only valid for instances with a MOCK_TIME MainThreadType. // Only valid for instances with a MOCK_TIME MainThreadType.
// Short for FastForwardBy(TimeDelta::Max()). // Short for FastForwardBy(TimeDelta::Max()).
//
// WARNING: This has the same caveat as RunUntilIdle() and is even more likely
// to spin forever (any RepeatingTimer will cause this).
void FastForwardUntilNoTasksRemain(); void FastForwardUntilNoTasksRemain();
// Only valid for instances with a MOCK_TIME MainThreadType. Returns a // Only valid for instances with a MOCK_TIME MainThreadType. Returns a
......
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