blob: 6d59dc3d9fc811a1ebb00a26e976dda28a83ca0a [file] [log] [blame]
fdoraya1f53b72017-04-06 15:16:571// Copyright 2017 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/test/scoped_task_environment.h"
6
fdorayb199f1be2017-05-29 23:00:037#include "base/bind_helpers.h"
Alexander Timin011df9a2018-10-16 20:15:578#include "base/lazy_instance.h"
fdorayb199f1be2017-05-29 23:00:039#include "base/logging.h"
Jeremy Romane6533c72018-03-05 17:44:4610#include "base/memory/ptr_util.h"
Alexander Timin4f9c35c2018-11-01 20:15:2011#include "base/message_loop/message_loop.h"
fdoraya1f53b72017-04-06 15:16:5712#include "base/run_loop.h"
fdorayb199f1be2017-05-29 23:00:0313#include "base/synchronization/condition_variable.h"
14#include "base/synchronization/lock.h"
Gabriel Charette44db1422018-08-06 11:19:3315#include "base/task/post_task.h"
Alex Clarke2ded1722018-12-13 12:55:2016#include "base/task/sequence_manager/sequence_manager_impl.h"
17#include "base/task/sequence_manager/time_domain.h"
Gabriel Charette44db1422018-08-06 11:19:3318#include "base/task/task_scheduler/task_scheduler.h"
Gabriel Charette04b138f2018-08-06 00:03:2219#include "base/task/task_scheduler/task_scheduler_impl.h"
Gabriel Charetted4723a32017-11-24 00:11:1820#include "base/test/test_mock_time_task_runner.h"
Wezd9e4cb772019-01-09 03:07:0321#include "base/test/test_timeouts.h"
Gabriel Charette723d8fc2018-03-22 16:42:4322#include "base/threading/sequence_local_storage_map.h"
Alexander Timin011df9a2018-10-16 20:15:5723#include "base/threading/thread_local.h"
Gabriel Charette881ffae2018-04-19 21:21:0424#include "base/threading/thread_restrictions.h"
fdorayb199f1be2017-05-29 23:00:0325#include "base/threading/thread_task_runner_handle.h"
Carlos Caballeroa6f990322018-12-06 14:45:0626#include "base/time/clock.h"
27#include "base/time/tick_clock.h"
fdoraya1f53b72017-04-06 15:16:5728#include "base/time/time.h"
Alex Clarke2ded1722018-12-13 12:55:2029#include "base/time/time_override.h"
Wezd9e4cb772019-01-09 03:07:0330#include "testing/gtest/include/gtest/gtest.h"
fdoraya1f53b72017-04-06 15:16:5731
Sami Kyostila91153b12018-11-28 11:57:2532#if defined(OS_POSIX) || defined(OS_FUCHSIA)
Gabriel Charette9d8482ea2018-04-11 11:35:0733#include "base/files/file_descriptor_watcher_posix.h"
34#endif
35
fdoraya1f53b72017-04-06 15:16:5736namespace base {
37namespace test {
38
Matt Giuca43644432017-11-22 07:27:1839namespace {
40
Alexander Timin011df9a2018-10-16 20:15:5741LazyInstance<ThreadLocalPointer<ScopedTaskEnvironment::LifetimeObserver>>::Leaky
42 environment_lifetime_observer;
43
Alex Clarke2ded1722018-12-13 12:55:2044base::Optional<MessageLoop::Type> GetMessageLoopTypeForMainThreadType(
Gabriel Charetted4723a32017-11-24 00:11:1845 ScopedTaskEnvironment::MainThreadType main_thread_type) {
46 switch (main_thread_type) {
47 case ScopedTaskEnvironment::MainThreadType::DEFAULT:
Gabriel Charetted4723a32017-11-24 00:11:1848 case ScopedTaskEnvironment::MainThreadType::MOCK_TIME:
Alex Clarke2ded1722018-12-13 12:55:2049 return MessageLoop::TYPE_DEFAULT;
Gabriel Charetted4723a32017-11-24 00:11:1850 case ScopedTaskEnvironment::MainThreadType::UI:
Alex Clarke2ded1722018-12-13 12:55:2051 case ScopedTaskEnvironment::MainThreadType::UI_MOCK_TIME:
52 return MessageLoop::TYPE_UI;
Gabriel Charetted4723a32017-11-24 00:11:1853 case ScopedTaskEnvironment::MainThreadType::IO:
Alex Clarke2ded1722018-12-13 12:55:2054 case ScopedTaskEnvironment::MainThreadType::IO_MOCK_TIME:
55 return MessageLoop::TYPE_IO;
Matt Giuca43644432017-11-22 07:27:1856 }
Gabriel Charetted4723a32017-11-24 00:11:1857 NOTREACHED();
Alex Clarke2ded1722018-12-13 12:55:2058 return base::nullopt;
59}
60
61std::unique_ptr<sequence_manager::SequenceManager>
62CreateSequenceManagerForMainThreadType(
63 ScopedTaskEnvironment::MainThreadType main_thread_type) {
64 auto type = GetMessageLoopTypeForMainThreadType(main_thread_type);
65 if (!type) {
66 return nullptr;
67 } else {
68 auto settings = base::sequence_manager::SequenceManager::Settings{
69 .message_loop_type = *type};
70 return sequence_manager::CreateSequenceManagerOnCurrentThreadWithPump(
71 MessageLoop::CreateMessagePumpForType(*type), std::move(settings));
72 }
Gabriel Charetted4723a32017-11-24 00:11:1873}
Matt Giuca43644432017-11-22 07:27:1874
Carlos Caballeroa6f990322018-12-06 14:45:0675class TickClockBasedClock : public Clock {
76 public:
77 explicit TickClockBasedClock(const TickClock* tick_clock)
78 : tick_clock_(*tick_clock),
79 start_ticks_(tick_clock_.NowTicks()),
80 start_time_(Time::UnixEpoch()) {}
81
82 Time Now() const override {
83 return start_time_ + (tick_clock_.NowTicks() - start_ticks_);
84 }
85
86 private:
87 const TickClock& tick_clock_;
88 const TimeTicks start_ticks_;
89 const Time start_time_;
90};
91
Matt Giuca43644432017-11-22 07:27:1892} // namespace
93
Alex Clarke2ded1722018-12-13 12:55:2094class ScopedTaskEnvironment::MockTimeDomain
95 : public sequence_manager::TimeDomain,
96 public TickClock {
97 public:
98 explicit MockTimeDomain(ScopedTaskEnvironment::NowSource now_source) {
99 DCHECK_EQ(nullptr, current_mock_time_domain_);
100 current_mock_time_domain_ = this;
101 if (now_source == ScopedTaskEnvironment::NowSource::MAIN_THREAD_MOCK_TIME) {
102 time_overrides_ = std::make_unique<subtle::ScopedTimeClockOverrides>(
103 &MockTimeDomain::GetTime, &MockTimeDomain::GetTimeTicks, nullptr);
104 }
105 }
106
107 ~MockTimeDomain() override {
108 DCHECK_EQ(this, current_mock_time_domain_);
109 current_mock_time_domain_ = nullptr;
110 }
111
112 static MockTimeDomain* current_mock_time_domain_;
113
114 static Time GetTime() {
115 return Time::UnixEpoch() + (current_mock_time_domain_->Now() - TimeTicks());
116 }
117
118 static TimeTicks GetTimeTicks() { return current_mock_time_domain_->Now(); }
119
120 using TimeDomain::NextScheduledRunTime;
121
122 static std::unique_ptr<ScopedTaskEnvironment::MockTimeDomain> Create(
123 ScopedTaskEnvironment::MainThreadType main_thread_type,
124 ScopedTaskEnvironment::NowSource now_source) {
125 if (main_thread_type == MainThreadType::MOCK_TIME ||
126 main_thread_type == MainThreadType::UI_MOCK_TIME ||
127 main_thread_type == MainThreadType::IO_MOCK_TIME) {
128 return std::make_unique<ScopedTaskEnvironment::MockTimeDomain>(
129 now_source);
130 }
131 return nullptr;
132 }
133
134 // sequence_manager::TimeDomain:
135
136 sequence_manager::LazyNow CreateLazyNow() const override {
137 base::AutoLock lock(now_ticks_lock_);
138 return sequence_manager::LazyNow(now_ticks_);
139 }
140
141 TimeTicks Now() const override {
142 // This can be called from any thread.
143 base::AutoLock lock(now_ticks_lock_);
144 return now_ticks_;
145 }
146
147 Optional<TimeDelta> DelayTillNextTask(
148 sequence_manager::LazyNow* lazy_now) override {
149 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
150
151 // Make sure TimeDomain::NextScheduledRunTime has taken canceled tasks into
152 // account, ReclaimMemory sweeps canceled delayed tasks.
153 sequence_manager()->ReclaimMemory();
154 Optional<TimeTicks> run_time = NextScheduledRunTime();
155 // Check if we've run out of tasks.
156 if (!run_time)
157 return base::nullopt;
158
159 // Check if we have a task that should be running now.
160 if (run_time <= now_ticks_)
161 return base::TimeDelta();
162
163 // The next task is a future delayed task. Since we're using mock time, we
164 // don't want an actual OS level delayed wake up scheduled, so pretend we
165 // have no more work. This will result in MaybeFastForwardToNextTask getting
166 // called which lets us advance |now_ticks_|.
167 return base::nullopt;
168 }
169
170 // This method is called when the underlying message pump has run out of
171 // non-delayed work.
172 bool MaybeFastForwardToNextTask(bool quit_when_idle_requested) override {
173 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
174 // If we're being externally controlled by a RunLoop in client code, check
175 // if the RunLoop is due to quit when idle, if so we don't want to advance
176 // mock time.
177 if (stop_when_message_pump_is_idle_ && quit_when_idle_requested)
178 return false;
179
180 // We don't need to call ReclaimMemory here because
181 // DelayTillNextTask will have dealt with cancelled delayed tasks for us.
182 Optional<TimeTicks> run_time = NextScheduledRunTime();
183 if (!run_time) {
184 // We've run out of tasks, but ScopedTaskEnvironment::FastForwardBy
185 // requires the virtual time to be consumed.
186 if (now_ticks_ < allow_advance_until_ && !allow_advance_until_.is_max())
187 SetTime(allow_advance_until_);
188 return false;
189 }
190
191 // Don't advance past |allow_advance_until_|.
192 DCHECK_GT(*run_time, now_ticks_);
193 TimeTicks time_to_advance_to = std::min(allow_advance_until_, *run_time);
194 if (time_to_advance_to <= now_ticks_)
195 return false;
196
197 SetTime(time_to_advance_to);
198
199 // Make sure a DoWork is scheduled.
200 return true;
201 }
202
203 const char* GetName() const override { return "MockTimeDomain"; }
204
205 // TickClock implementation:
206 TimeTicks NowTicks() const override { return Now(); }
207
208 // Allows time to advance when reaching idle, until
209 // |now_ticks_ == advance_until|. No-op if |advance_until <= now_ticks_|.
210 // Doesn't schedule work by itself.
211 void SetAllowTimeToAutoAdvanceUntil(TimeTicks advance_until) {
212 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
213 allow_advance_until_ = advance_until;
214 }
215
216 void SetStopWhenMessagePumpIsIdle(bool stop_when_message_pump_is_idle) {
217 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
218 stop_when_message_pump_is_idle_ = stop_when_message_pump_is_idle;
219 }
220
221 private:
222 void SetTime(TimeTicks time) {
223 DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
224 DCHECK_LE(time, allow_advance_until_);
225
226 base::AutoLock lock(now_ticks_lock_);
227 now_ticks_ = time;
228 }
229
230 SEQUENCE_CHECKER(sequence_checker_);
231
232 std::unique_ptr<subtle::ScopedTimeClockOverrides> time_overrides_;
233
234 // By default we want RunLoop.Run() to advance virtual time due to the API
235 // contract.
236 TimeTicks allow_advance_until_ = TimeTicks::Max();
237 bool stop_when_message_pump_is_idle_ = true;
238
239 // Protects |now_ticks_|
240 mutable Lock now_ticks_lock_;
241
242 // Only ever written to from the main sequence.
243 // TODO(alexclarke): We can't override now by default with now_ticks_ staring
244 // from zero because many tests have checks that TimeTicks::Now() returns a
245 // non-zero result.
246 TimeTicks now_ticks_;
247};
248
249ScopedTaskEnvironment::MockTimeDomain*
250 ScopedTaskEnvironment::MockTimeDomain::current_mock_time_domain_ = nullptr;
251
fdorayb199f1be2017-05-29 23:00:03252class ScopedTaskEnvironment::TestTaskTracker
253 : public internal::TaskSchedulerImpl::TaskTrackerImpl {
254 public:
255 TestTaskTracker();
256
fdorayb199f1be2017-05-29 23:00:03257 // Allow running tasks.
Gabriel Charetted4723a32017-11-24 00:11:18258 void AllowRunTasks();
fdorayb199f1be2017-05-29 23:00:03259
Gabriel Charetted4723a32017-11-24 00:11:18260 // Disallow running tasks. Returns true on success; success requires there to
261 // be no tasks currently running. Returns false if >0 tasks are currently
262 // running. Prior to returning false, it will attempt to block until at least
263 // one task has completed (in an attempt to avoid callers busy-looping
264 // DisallowRunTasks() calls with the same set of slowly ongoing tasks). This
265 // block attempt will also have a short timeout (in an attempt to prevent the
266 // fallout of blocking: if the only task remaining is blocked on the main
267 // thread, waiting for it to complete results in a deadlock...).
fdorayb199f1be2017-05-29 23:00:03268 bool DisallowRunTasks();
269
270 private:
271 friend class ScopedTaskEnvironment;
272
273 // internal::TaskSchedulerImpl::TaskTrackerImpl:
Robert Liaod07daf92017-12-18 01:38:07274 void RunOrSkipTask(internal::Task task,
Francois Doraya038ca72017-09-17 03:26:06275 internal::Sequence* sequence,
Jesse McKennac331b12a72018-11-21 22:39:03276 const TaskTraits& traits,
Francois Doraya038ca72017-09-17 03:26:06277 bool can_run_task) override;
fdorayb199f1be2017-05-29 23:00:03278
279 // Synchronizes accesses to members below.
280 Lock lock_;
281
fdorayb199f1be2017-05-29 23:00:03282 // True if running tasks is allowed.
283 bool can_run_tasks_ = true;
284
285 // Signaled when |can_run_tasks_| becomes true.
286 ConditionVariable can_run_tasks_cv_;
287
Gabriel Charetted4723a32017-11-24 00:11:18288 // Signaled when a task is completed.
289 ConditionVariable task_completed_;
290
fdorayb199f1be2017-05-29 23:00:03291 // Number of tasks that are currently running.
292 int num_tasks_running_ = 0;
293
294 DISALLOW_COPY_AND_ASSIGN(TestTaskTracker);
295};
296
297ScopedTaskEnvironment::ScopedTaskEnvironment(
298 MainThreadType main_thread_type,
Alex Clarke2ded1722018-12-13 12:55:20299 ExecutionMode execution_control_mode,
300 NowSource now_source,
Alex Clarke3cf9cd8e2019-01-08 08:40:00301 trait_helpers::NotATraitTag)
Alex Clarke1052bb02018-12-14 09:44:16302 : main_thread_type_(main_thread_type),
303 execution_control_mode_(execution_control_mode),
Alex Clarke2ded1722018-12-13 12:55:20304 mock_time_domain_(MockTimeDomain::Create(main_thread_type, now_source)),
305 sequence_manager_(
306 CreateSequenceManagerForMainThreadType(main_thread_type)),
307 task_queue_(CreateDefaultTaskQueue()),
308 mock_clock_(mock_time_domain_ ? std::make_unique<TickClockBasedClock>(
309 mock_time_domain_.get())
310 : nullptr),
Sami Kyostila91153b12018-11-28 11:57:25311#if defined(OS_POSIX) || defined(OS_FUCHSIA)
Alexander Timin6247f6a91a2018-10-27 15:40:10312 file_descriptor_watcher_(main_thread_type == MainThreadType::IO
313 ? std::make_unique<FileDescriptorWatcher>(
Alex Clarke2ded1722018-12-13 12:55:20314 task_queue_->task_runner())
Alexander Timin6247f6a91a2018-10-27 15:40:10315 : nullptr),
Sami Kyostila91153b12018-11-28 11:57:25316#endif // defined(OS_POSIX) || defined(OS_FUCHSIA)
Wezd9e4cb772019-01-09 03:07:03317 task_tracker_(new TestTaskTracker()),
318 // TODO(https://crbug.com/918724): Enable Run() timeouts even for
319 // instances created with *MOCK_TIME, and determine whether the timeout
320 // can be reduced from action_max_timeout() to action_timeout().
321 run_loop_timeout_(
322 mock_time_domain_ ? TimeDelta() : TestTimeouts::action_max_timeout(),
323 BindRepeating([]() { LOG(FATAL) << "Run() timed out."; })) {
Alex Clarke2ded1722018-12-13 12:55:20324 CHECK(now_source == NowSource::REAL_TIME || mock_time_domain_)
325 << "NowSource must be REAL_TIME unless we're using mock time";
Alex Clarke1052bb02018-12-14 09:44:16326 CHECK(!base::ThreadTaskRunnerHandle::IsSet());
Wezeb4e9952018-08-28 22:15:47327 CHECK(!TaskScheduler::GetInstance())
328 << "Someone has already initialized TaskScheduler. If nothing in your "
329 "test does so, then a test that ran earlier may have initialized one, "
330 "and leaked it. base::TestSuite will trap leaked globals, unless "
331 "someone has explicitly disabled it with "
332 "DisableCheckForLeakedGlobals().";
fdoraya1f53b72017-04-06 15:16:57333
Alex Clarke2ded1722018-12-13 12:55:20334 sequence_manager_->SetDefaultTaskRunner(task_queue_->task_runner());
335
Marijn Kruisselbrinkcbc3df82017-07-06 19:25:59336 // Instantiate a TaskScheduler with 2 threads in each of its 4 pools. Threads
fdoraya1f53b72017-04-06 15:16:57337 // stay alive even when they don't have work.
Marijn Kruisselbrinkcbc3df82017-07-06 19:25:59338 // Each pool uses two threads to prevent deadlocks in unit tests that have a
339 // sequence that uses WithBaseSyncPrimitives() to wait on the result of
340 // another sequence. This isn't perfect (doesn't solve wait chains) but solves
341 // the basic use case for now.
342 // TODO(fdoray/jeffreyhe): Make the TaskScheduler dynamically replace blocked
343 // threads and get rid of this limitation. http://crbug.com/738104
344 constexpr int kMaxThreads = 2;
fdoraya1f53b72017-04-06 15:16:57345 const TimeDelta kSuggestedReclaimTime = TimeDelta::Max();
Jeffrey Hefbf000f42017-07-26 22:44:45346 const SchedulerWorkerPoolParams worker_pool_params(kMaxThreads,
347 kSuggestedReclaimTime);
Jeremy Roman9532f252017-08-16 23:27:24348 TaskScheduler::SetInstance(std::make_unique<internal::TaskSchedulerImpl>(
fdorayb199f1be2017-05-29 23:00:03349 "ScopedTaskEnvironment", WrapUnique(task_tracker_)));
fdoraya1f53b72017-04-06 15:16:57350 task_scheduler_ = TaskScheduler::GetInstance();
Gabriel Charette438472322018-11-16 14:42:38351 TaskScheduler::GetInstance()->Start({
352 worker_pool_params, worker_pool_params, worker_pool_params,
353 worker_pool_params
354#if defined(OS_WIN)
355 ,
356 // Enable the MTA in unit tests to match the browser process'
357 // TaskScheduler configuration.
358 //
359 // This has the adverse side-effect of enabling the MTA in non-browser
360 // unit tests as well but the downside there is not as bad as not having
361 // it in browser unit tests. It just means some COM asserts may pass in
362 // unit tests where they wouldn't in integration tests or prod. That's
363 // okay because unit tests are already generally very loose on allowing
364 // I/O, waits, etc. Such misuse will still be caught in later phases
365 // (and COM usage should already be pretty much inexistent in sandboxed
366 // processes).
367 TaskScheduler::InitParams::SharedWorkerPoolEnvironment::COM_MTA
368#endif
369 });
fdorayb199f1be2017-05-29 23:00:03370
371 if (execution_control_mode_ == ExecutionMode::QUEUED)
372 CHECK(task_tracker_->DisallowRunTasks());
Alexander Timin011df9a2018-10-16 20:15:57373
374 LifetimeObserver* observer = environment_lifetime_observer.Get().Get();
375 if (observer) {
376 observer->OnScopedTaskEnvironmentCreated(main_thread_type,
377 GetMainThreadTaskRunner());
378 }
fdoraya1f53b72017-04-06 15:16:57379}
380
381ScopedTaskEnvironment::~ScopedTaskEnvironment() {
gab13c37ee2017-05-18 17:47:44382 // Ideally this would RunLoop().RunUntilIdle() here to catch any errors or
383 // infinite post loop in the remaining work but this isn't possible right now
384 // because base::~MessageLoop() didn't use to do this and adding it here would
385 // make the migration away from MessageLoop that much harder.
fdorayb199f1be2017-05-29 23:00:03386 CHECK_EQ(TaskScheduler::GetInstance(), task_scheduler_);
fdoray6044a51d2017-04-13 12:04:20387 // Without FlushForTesting(), DeleteSoon() and ReleaseSoon() tasks could be
388 // skipped, resulting in memory leaks.
Gabriel Charetted4723a32017-11-24 00:11:18389 task_tracker_->AllowRunTasks();
fdoray6044a51d2017-04-13 12:04:20390 TaskScheduler::GetInstance()->FlushForTesting();
fdoraya1f53b72017-04-06 15:16:57391 TaskScheduler::GetInstance()->Shutdown();
392 TaskScheduler::GetInstance()->JoinForTesting();
Gabriel Charette881ffae2018-04-19 21:21:04393 // Destroying TaskScheduler state can result in waiting on worker threads.
394 // Make sure this is allowed to avoid flaking tests that have disallowed waits
395 // on their main thread.
396 ScopedAllowBaseSyncPrimitivesForTesting allow_waits_to_destroy_task_tracker;
fdoraya1f53b72017-04-06 15:16:57397 TaskScheduler::SetInstance(nullptr);
Alex Clarke1052bb02018-12-14 09:44:16398 task_queue_ = nullptr;
399 NotifyDestructionObserversAndReleaseSequenceManager();
400}
401
402void ScopedTaskEnvironment::
403 NotifyDestructionObserversAndReleaseSequenceManager() {
404 // A derived classes may call this method early.
405 if (!sequence_manager_)
406 return;
Alexander Timin011df9a2018-10-16 20:15:57407
408 LifetimeObserver* observer = environment_lifetime_observer.Get().Get();
409 if (observer)
410 observer->OnScopedTaskEnvironmentDestroyed();
Alex Clarke2ded1722018-12-13 12:55:20411
Alex Clarke2ded1722018-12-13 12:55:20412 if (mock_time_domain_)
413 sequence_manager_->UnregisterTimeDomain(mock_time_domain_.get());
Alex Clarke1052bb02018-12-14 09:44:16414
415 sequence_manager_.reset();
Alex Clarke2ded1722018-12-13 12:55:20416}
417
418scoped_refptr<sequence_manager::TaskQueue>
419ScopedTaskEnvironment::CreateDefaultTaskQueue() {
420 if (mock_time_domain_)
421 sequence_manager_->RegisterTimeDomain(mock_time_domain_.get());
422
423 return sequence_manager_->CreateTaskQueue(
424 sequence_manager::TaskQueue::Spec("scoped_task_environment_default")
425 .SetTimeDomain(mock_time_domain_.get()));
Alexander Timin011df9a2018-10-16 20:15:57426}
427
428void ScopedTaskEnvironment::SetLifetimeObserver(
429 ScopedTaskEnvironment::LifetimeObserver* lifetime_observer) {
430 DCHECK_NE(!!environment_lifetime_observer.Get().Get(), !!lifetime_observer);
431 environment_lifetime_observer.Get().Set(lifetime_observer);
fdoraya1f53b72017-04-06 15:16:57432}
433
fdoray812f4162017-05-16 15:34:51434scoped_refptr<base::SingleThreadTaskRunner>
435ScopedTaskEnvironment::GetMainThreadTaskRunner() {
Alex Clarke2ded1722018-12-13 12:55:20436 return task_queue_->task_runner();
fdoray812f4162017-05-16 15:34:51437}
438
Gabriel Charette328703242018-04-25 18:07:29439bool ScopedTaskEnvironment::MainThreadHasPendingTask() const {
Alex Clarke2ded1722018-12-13 12:55:20440 sequence_manager::internal::SequenceManagerImpl* sequence_manager_impl =
441 static_cast<sequence_manager::internal::SequenceManagerImpl*>(
442 sequence_manager_.get());
443 // ReclaimMemory sweeps canceled delayed tasks.
444 sequence_manager_impl->ReclaimMemory();
445 // Unfortunately this API means different things depending on whether mock
446 // time is used or not. If MockTime is used then tests want to know if there
447 // are any delayed or non-delayed tasks, otherwise only non-delayed tasks are
448 // considered.
449 if (mock_time_domain_)
450 return sequence_manager_impl->HasTasks();
451 return !sequence_manager_impl->IsIdleForTesting();
Gabriel Charette328703242018-04-25 18:07:29452}
453
fdorayf2b4d832017-05-10 12:24:33454void ScopedTaskEnvironment::RunUntilIdle() {
Alex Clarke2ded1722018-12-13 12:55:20455 // Prevent virtual time from advancing while within this call.
456 if (mock_time_domain_)
457 mock_time_domain_->SetAllowTimeToAutoAdvanceUntil(TimeTicks());
458
Gabriel Charetted4723a32017-11-24 00:11:18459 // TODO(gab): This can be heavily simplified to essentially:
460 // bool HasMainThreadTasks() {
461 // if (message_loop_)
462 // return !message_loop_->IsIdleForTesting();
463 // return mock_time_task_runner_->NextPendingTaskDelay().is_zero();
464 // }
465 // while (task_tracker_->HasIncompleteTasks() || HasMainThreadTasks()) {
466 // base::RunLoop().RunUntilIdle();
467 // // Avoid busy-looping.
468 // if (task_tracker_->HasIncompleteTasks())
469 // PlatformThread::Sleep(TimeDelta::FromMilliSeconds(1));
470 // }
Gabriel Charette650ec6c12018-07-30 17:28:35471 // Update: This can likely be done now that MessageLoop::IsIdleForTesting()
472 // checks all queues.
Gabriel Charetted4723a32017-11-24 00:11:18473 //
474 // Other than that it works because once |task_tracker_->HasIncompleteTasks()|
475 // is false we know for sure that the only thing that can make it true is a
476 // main thread task (ScopedTaskEnvironment owns all the threads). As such we
477 // can't racily see it as false on the main thread and be wrong as if it the
478 // main thread sees the atomic count at zero, it's the only one that can make
479 // it go up. And the only thing that can make it go up on the main thread are
480 // main thread tasks and therefore we're done if there aren't any left.
481 //
482 // This simplification further allows simplification of DisallowRunTasks().
483 //
484 // This can also be simplified even further once TaskTracker becomes directly
485 // aware of main thread tasks. https://crbug.com/660078.
486
Matt Giuca43644432017-11-22 07:27:18487 for (;;) {
Gabriel Charetted4723a32017-11-24 00:11:18488 task_tracker_->AllowRunTasks();
fdorayf2b4d832017-05-10 12:24:33489
Gabriel Charetted4723a32017-11-24 00:11:18490 // First run as many tasks as possible on the main thread in parallel with
491 // tasks in TaskScheduler. This increases likelihood of TSAN catching
492 // threading errors and eliminates possibility of hangs should a
493 // TaskScheduler task synchronously block on a main thread task
494 // (TaskScheduler::FlushForTesting() can't be used here for that reason).
495 RunLoop().RunUntilIdle();
fdorayb199f1be2017-05-29 23:00:03496
Gabriel Charetted4723a32017-11-24 00:11:18497 // Then halt TaskScheduler. DisallowRunTasks() failing indicates that there
498 // were TaskScheduler tasks currently running. In that case, try again from
499 // top when DisallowRunTasks() yields control back to this thread as they
500 // may have posted main thread tasks.
501 if (!task_tracker_->DisallowRunTasks())
Matt Wolenetz7ab03b12017-08-09 18:32:37502 continue;
fdorayb199f1be2017-05-29 23:00:03503
Gabriel Charetted4723a32017-11-24 00:11:18504 // Once TaskScheduler is halted. Run any remaining main thread tasks (which
505 // may have been posted by TaskScheduler tasks that completed between the
506 // above main thread RunUntilIdle() and TaskScheduler DisallowRunTasks()).
507 // Note: this assumes that no main thread task synchronously blocks on a
508 // TaskScheduler tasks (it certainly shouldn't); this call could otherwise
509 // hang.
510 RunLoop().RunUntilIdle();
511
512 // The above RunUntilIdle() guarantees there are no remaining main thread
513 // tasks (the TaskScheduler being halted during the last RunUntilIdle() is
514 // key as it prevents a task being posted to it racily with it determining
515 // it had no work remaining). Therefore, we're done if there is no more work
516 // on TaskScheduler either (there can be TaskScheduler work remaining if
517 // DisallowRunTasks() preempted work and/or the last RunUntilIdle() posted
518 // more TaskScheduler tasks).
519 // Note: this last |if| couldn't be turned into a |do {} while();|. A
520 // conditional loop makes it such that |continue;| results in checking the
521 // condition (not unconditionally loop again) which would be incorrect for
522 // the above logic as it'd then be possible for a TaskScheduler task to be
523 // running during the DisallowRunTasks() test, causing it to fail, but then
524 // post to the main thread and complete before the loop's condition is
Gabriel Charetted97b0592018-01-03 18:28:59525 // verified which could result in HasIncompleteUndelayedTasksForTesting()
526 // returning false and the loop erroneously exiting with a pending task on
527 // the main thread.
528 if (!task_tracker_->HasIncompleteUndelayedTasksForTesting())
fdorayb199f1be2017-05-29 23:00:03529 break;
fdorayb199f1be2017-05-29 23:00:03530 }
Gabriel Charetted4723a32017-11-24 00:11:18531
532 // The above loop always ends with running tasks being disallowed. Re-enable
533 // parallel execution before returning unless in ExecutionMode::QUEUED.
534 if (execution_control_mode_ != ExecutionMode::QUEUED)
535 task_tracker_->AllowRunTasks();
Alex Clarke2ded1722018-12-13 12:55:20536
537 if (mock_time_domain_)
538 mock_time_domain_->SetAllowTimeToAutoAdvanceUntil(TimeTicks::Max());
Gabriel Charetted4723a32017-11-24 00:11:18539}
540
541void ScopedTaskEnvironment::FastForwardBy(TimeDelta delta) {
Alex Clarke2ded1722018-12-13 12:55:20542 MessageLoopCurrent::ScopedNestableTaskAllower allow;
543 DCHECK(mock_time_domain_);
544 mock_time_domain_->SetStopWhenMessagePumpIsIdle(false);
545 mock_time_domain_->SetAllowTimeToAutoAdvanceUntil(mock_time_domain_->Now() +
546 delta);
547 RunLoop().RunUntilIdle();
548 mock_time_domain_->SetStopWhenMessagePumpIsIdle(true);
549 mock_time_domain_->SetAllowTimeToAutoAdvanceUntil(TimeTicks::Max());
Gabriel Charetted4723a32017-11-24 00:11:18550}
551
552void ScopedTaskEnvironment::FastForwardUntilNoTasksRemain() {
Alex Clarke2ded1722018-12-13 12:55:20553 // TimeTicks::operator+(TimeDelta) uses saturated arithmetic so it's safe to
554 // pass in TimeDelta::Max().
555 FastForwardBy(TimeDelta::Max());
fdorayb199f1be2017-05-29 23:00:03556}
557
Carlos Caballeroa6f990322018-12-06 14:45:06558const TickClock* ScopedTaskEnvironment::GetMockTickClock() const {
Alex Clarke2ded1722018-12-13 12:55:20559 DCHECK(mock_time_domain_);
560 return mock_time_domain_.get();
tzik9fd63852018-03-08 06:14:18561}
562
Robbie McElrath57129d72018-09-05 22:58:26563base::TimeTicks ScopedTaskEnvironment::NowTicks() const {
Alex Clarke2ded1722018-12-13 12:55:20564 DCHECK(mock_time_domain_);
565 return mock_time_domain_->Now();
Robbie McElrath57129d72018-09-05 22:58:26566}
567
Carlos Caballeroa6f990322018-12-06 14:45:06568const Clock* ScopedTaskEnvironment::GetMockClock() const {
569 DCHECK(mock_clock_);
570 return mock_clock_.get();
571}
572
Bence Békyb71838b2018-04-19 18:23:38573size_t ScopedTaskEnvironment::GetPendingMainThreadTaskCount() const {
Alex Clarke2ded1722018-12-13 12:55:20574 // ReclaimMemory sweeps canceled delayed tasks.
575 sequence_manager_->ReclaimMemory();
576 return sequence_manager_->GetPendingTaskCountForTesting();
Bence Békyb71838b2018-04-19 18:23:38577}
578
579TimeDelta ScopedTaskEnvironment::NextMainThreadPendingTaskDelay() const {
Alex Clarke2ded1722018-12-13 12:55:20580 // ReclaimMemory sweeps canceled delayed tasks.
581 sequence_manager_->ReclaimMemory();
582 DCHECK(mock_time_domain_);
583 Optional<TimeTicks> run_time = mock_time_domain_->NextScheduledRunTime();
584 if (run_time)
585 return *run_time - mock_time_domain_->Now();
586 return TimeDelta::Max();
Bence Békyb71838b2018-04-19 18:23:38587}
588
fdorayb199f1be2017-05-29 23:00:03589ScopedTaskEnvironment::TestTaskTracker::TestTaskTracker()
Gabriel Charette5b74dcb2018-01-19 11:00:53590 : internal::TaskSchedulerImpl::TaskTrackerImpl("ScopedTaskEnvironment"),
591 can_run_tasks_cv_(&lock_),
592 task_completed_(&lock_) {}
fdorayb199f1be2017-05-29 23:00:03593
Gabriel Charetted4723a32017-11-24 00:11:18594void ScopedTaskEnvironment::TestTaskTracker::AllowRunTasks() {
fdorayb199f1be2017-05-29 23:00:03595 AutoLock auto_lock(lock_);
596 can_run_tasks_ = true;
597 can_run_tasks_cv_.Broadcast();
598}
599
600bool ScopedTaskEnvironment::TestTaskTracker::DisallowRunTasks() {
601 AutoLock auto_lock(lock_);
602
603 // Can't disallow run task if there are tasks running.
Gabriel Charetted4723a32017-11-24 00:11:18604 if (num_tasks_running_ > 0) {
605 // Attempt to wait a bit so that the caller doesn't busy-loop with the same
606 // set of pending work. A short wait is required to avoid deadlock
607 // scenarios. See DisallowRunTasks()'s declaration for more details.
608 task_completed_.TimedWait(TimeDelta::FromMilliseconds(1));
fdorayb199f1be2017-05-29 23:00:03609 return false;
Gabriel Charetted4723a32017-11-24 00:11:18610 }
fdorayb199f1be2017-05-29 23:00:03611
612 can_run_tasks_ = false;
613 return true;
614}
615
Francois Doraya038ca72017-09-17 03:26:06616void ScopedTaskEnvironment::TestTaskTracker::RunOrSkipTask(
Robert Liaod07daf92017-12-18 01:38:07617 internal::Task task,
Francois Doraya038ca72017-09-17 03:26:06618 internal::Sequence* sequence,
Jesse McKennac331b12a72018-11-21 22:39:03619 const TaskTraits& traits,
Francois Doraya038ca72017-09-17 03:26:06620 bool can_run_task) {
fdorayb199f1be2017-05-29 23:00:03621 {
622 AutoLock auto_lock(lock_);
623
624 while (!can_run_tasks_)
625 can_run_tasks_cv_.Wait();
626
627 ++num_tasks_running_;
628 }
629
Francois Doraya038ca72017-09-17 03:26:06630 internal::TaskSchedulerImpl::TaskTrackerImpl::RunOrSkipTask(
Jesse McKennac331b12a72018-11-21 22:39:03631 std::move(task), sequence, traits, can_run_task);
fdorayb199f1be2017-05-29 23:00:03632
633 {
634 AutoLock auto_lock(lock_);
635
636 CHECK_GT(num_tasks_running_, 0);
637 CHECK(can_run_tasks_);
638
fdorayb199f1be2017-05-29 23:00:03639 --num_tasks_running_;
fdorayf2b4d832017-05-10 12:24:33640
Gabriel Charetted4723a32017-11-24 00:11:18641 task_completed_.Broadcast();
Matt Giuca43644432017-11-22 07:27:18642 }
643}
644
fdoraya1f53b72017-04-06 15:16:57645} // namespace test
646} // namespace base