• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2017 The Chromium Authors
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/task_environment.h"
6 
7 #include <algorithm>
8 #include <memory>
9 #include <ostream>
10 
11 #include "base/check.h"
12 #include "base/debug/stack_trace.h"
13 #include "base/functional/callback_forward.h"
14 #include "base/functional/callback_helpers.h"
15 #include "base/lazy_instance.h"
16 #include "base/location.h"
17 #include "base/logging.h"
18 #include "base/memory/ptr_util.h"
19 #include "base/memory/raw_ptr.h"
20 #include "base/memory/raw_ref.h"
21 #include "base/message_loop/message_pump.h"
22 #include "base/message_loop/message_pump_type.h"
23 #include "base/no_destructor.h"
24 #include "base/process/process.h"
25 #include "base/run_loop.h"
26 #include "base/synchronization/condition_variable.h"
27 #include "base/synchronization/lock.h"
28 #include "base/task/common/lazy_now.h"
29 #include "base/task/sequence_manager/sequence_manager.h"
30 #include "base/task/sequence_manager/sequence_manager_impl.h"
31 #include "base/task/sequence_manager/time_domain.h"
32 #include "base/task/single_thread_task_runner.h"
33 #include "base/task/thread_pool/thread_pool_impl.h"
34 #include "base/task/thread_pool/thread_pool_instance.h"
35 #include "base/test/bind.h"
36 #include "base/test/test_mock_time_task_runner.h"
37 #include "base/test/test_timeouts.h"
38 #include "base/thread_annotations.h"
39 #include "base/threading/platform_thread.h"
40 #include "base/threading/sequence_local_storage_map.h"
41 #include "base/threading/thread_checker_impl.h"
42 #include "base/threading/thread_local.h"
43 #include "base/threading/thread_restrictions.h"
44 #include "base/time/clock.h"
45 #include "base/time/tick_clock.h"
46 #include "base/time/time.h"
47 #include "base/time/time_override.h"
48 #include "build/build_config.h"
49 #include "testing/gtest/include/gtest/gtest.h"
50 
51 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
52 #include "base/files/file_descriptor_watcher_posix.h"
53 #include "third_party/abseil-cpp/absl/types/optional.h"
54 #endif
55 
56 #if BUILDFLAG(ENABLE_BASE_TRACING)
57 #include "base/trace_event/trace_log.h"  // nogncheck
58 #endif                                   // BUILDFLAG(ENABLE_BASE_TRACING)
59 
60 namespace base {
61 namespace test {
62 
63 namespace {
64 
GetDestructionObservers()65 ObserverList<TaskEnvironment::DestructionObserver>& GetDestructionObservers() {
66   static NoDestructor<ObserverList<TaskEnvironment::DestructionObserver>>
67       instance;
68   return *instance;
69 }
70 
71 // A pointer to the current TestTaskTracker, if any, constant throughout the
72 // lifetime of a ThreadPoolInstance managed by a TaskEnvironment.
73 TaskEnvironment::TestTaskTracker* g_task_tracker = nullptr;
74 
GetMessagePumpTypeForMainThreadType(TaskEnvironment::MainThreadType main_thread_type)75 base::MessagePumpType GetMessagePumpTypeForMainThreadType(
76     TaskEnvironment::MainThreadType main_thread_type) {
77   switch (main_thread_type) {
78     case TaskEnvironment::MainThreadType::DEFAULT:
79       return MessagePumpType::DEFAULT;
80     case TaskEnvironment::MainThreadType::UI:
81       return MessagePumpType::UI;
82     case TaskEnvironment::MainThreadType::IO:
83       return MessagePumpType::IO;
84   }
85   NOTREACHED();
86   return MessagePumpType::DEFAULT;
87 }
88 
89 std::unique_ptr<sequence_manager::SequenceManager>
CreateSequenceManagerForMainThreadType(TaskEnvironment::MainThreadType main_thread_type,sequence_manager::SequenceManager::PrioritySettings priority_settings)90 CreateSequenceManagerForMainThreadType(
91     TaskEnvironment::MainThreadType main_thread_type,
92     sequence_manager::SequenceManager::PrioritySettings priority_settings) {
93   auto type = GetMessagePumpTypeForMainThreadType(main_thread_type);
94   return sequence_manager::CreateSequenceManagerOnCurrentThreadWithPump(
95       MessagePump::Create(type),
96       base::sequence_manager::SequenceManager::Settings::Builder()
97           .SetMessagePumpType(type)
98           .SetPrioritySettings(std::move(priority_settings))
99           .Build());
100 }
101 
102 class TickClockBasedClock : public Clock {
103  public:
TickClockBasedClock(const TickClock * tick_clock)104   explicit TickClockBasedClock(const TickClock* tick_clock)
105       : tick_clock_(*tick_clock),
106         start_ticks_(tick_clock_->NowTicks()),
107         start_time_(Time::UnixEpoch()) {}
108 
Now() const109   Time Now() const override {
110     return start_time_ + (tick_clock_->NowTicks() - start_ticks_);
111   }
112 
113  private:
114   const raw_ref<const TickClock> tick_clock_;
115   const TimeTicks start_ticks_;
116   const Time start_time_;
117 };
118 
119 }  // namespace
120 
121 class TaskEnvironment::TestTaskTracker
122     : public internal::ThreadPoolImpl::TaskTrackerImpl {
123  public:
124   TestTaskTracker();
125 
126   TestTaskTracker(const TestTaskTracker&) = delete;
127   TestTaskTracker& operator=(const TestTaskTracker&) = delete;
128 
129   // Allow running tasks. Returns whether tasks were previously allowed to run.
130   bool AllowRunTasks();
131 
132   // Disallow running tasks. Returns true on success; success requires there to
133   // be no tasks currently running. Returns false if >0 tasks are currently
134   // running. Prior to returning false, it will attempt to block until at least
135   // one task has completed (in an attempt to avoid callers busy-looping
136   // DisallowRunTasks() calls with the same set of slowly ongoing tasks).
137   // Returns false if none of the ongoing tasks complete within |timeout| in an
138   // attempt to prevent a deadlock in the event that the only task remaining is
139   // blocked on the main thread.
140   bool DisallowRunTasks(TimeDelta timeout = Milliseconds(1));
141 
142   // Returns true if tasks are currently allowed to run.
143   bool TasksAllowedToRun() const;
144 
145   // For debugging purposes. Returns a string with information about all the
146   // currently running tasks on the thread pool.
147   std::string DescribeRunningTasks() const;
148 
149   // Returns true if this is invoked on this TaskTracker's owning thread
150   // (i.e. test main thread).
OnControllerThread() const151   bool OnControllerThread() const {
152     return controller_thread_checker_.CalledOnValidThread();
153   }
154 
155  private:
156   friend class TaskEnvironment;
157 
158   // internal::ThreadPoolImpl::TaskTrackerImpl:
159   void RunTask(internal::Task task,
160                internal::TaskSource* sequence,
161                const TaskTraits& traits) override;
162   void BeginCompleteShutdown(base::WaitableEvent& shutdown_event) override;
163   void AssertFlushForTestingAllowed() override;
164 
165   // Synchronizes accesses to members below.
166   mutable Lock lock_;
167 
168   // True if running tasks is allowed.
169   bool can_run_tasks_ GUARDED_BY(lock_) = true;
170 
171   // Signaled when |can_run_tasks_| becomes true.
172   ConditionVariable can_run_tasks_cv_ GUARDED_BY(lock_);
173 
174   // Signaled when a task is completed.
175   ConditionVariable task_completed_cv_ GUARDED_BY(lock_);
176 
177   // Next task number so that each task has some unique-ish id.
178   int64_t next_task_number_ GUARDED_BY(lock_) = 1;
179   // The set of tasks currently running, keyed by the id from
180   // |next_task_number_|.
181   base::flat_map<int64_t, Location> running_tasks_ GUARDED_BY(lock_);
182 
183   // Used to implement OnControllerThread().
184   ThreadCheckerImpl controller_thread_checker_;
185 };
186 
187 class TaskEnvironment::MockTimeDomain : public sequence_manager::TimeDomain {
188  public:
MockTimeDomain(sequence_manager::internal::SequenceManagerImpl * sequence_manager)189   explicit MockTimeDomain(
190       sequence_manager::internal::SequenceManagerImpl* sequence_manager)
191       : sequence_manager_(sequence_manager) {
192     DCHECK_EQ(nullptr, current_mock_time_domain_);
193     current_mock_time_domain_ = this;
194   }
195 
~MockTimeDomain()196   ~MockTimeDomain() override {
197     DCHECK_EQ(this, current_mock_time_domain_);
198     current_mock_time_domain_ = nullptr;
199   }
200 
201   static MockTimeDomain* current_mock_time_domain_;
202 
GetTime()203   static Time GetTime() {
204     return Time::UnixEpoch() +
205            (current_mock_time_domain_->NowTicks() - TimeTicks());
206   }
207 
GetTimeTicks()208   static TimeTicks GetTimeTicks() {
209     return current_mock_time_domain_->NowTicks();
210   }
211 
AdvanceClock(TimeDelta delta)212   void AdvanceClock(TimeDelta delta) {
213     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
214     {
215       AutoLock lock(now_ticks_lock_);
216       now_ticks_ += delta;
217     }
218     if (thread_pool_) {
219       thread_pool_->ProcessRipeDelayedTasksForTesting();
220     }
221   }
222 
SetThreadPool(internal::ThreadPoolImpl * thread_pool,const TestTaskTracker * thread_pool_task_tracker)223   void SetThreadPool(internal::ThreadPoolImpl* thread_pool,
224                      const TestTaskTracker* thread_pool_task_tracker) {
225     DCHECK(!thread_pool_);
226     DCHECK(!thread_pool_task_tracker_);
227     thread_pool_ = thread_pool;
228     thread_pool_task_tracker_ = thread_pool_task_tracker;
229   }
230 
231   // sequence_manager::TimeDomain:
232 
233   // This method is called when the underlying message pump has run out of
234   // non-delayed work. Advances time to the next task unless
235   // |quit_when_idle_requested| or TaskEnvironment controls mock time.
MaybeFastForwardToWakeUp(absl::optional<sequence_manager::WakeUp> next_wake_up,bool quit_when_idle_requested)236   bool MaybeFastForwardToWakeUp(
237       absl::optional<sequence_manager::WakeUp> next_wake_up,
238       bool quit_when_idle_requested) override {
239     if (quit_when_idle_requested) {
240       return false;
241     }
242 
243     return FastForwardToNextTaskOrCap(next_wake_up, TimeTicks::Max()) ==
244            NextTaskSource::kMainThreadHasWork;
245   }
246 
GetName() const247   const char* GetName() const override { return "MockTimeDomain"; }
248 
249   // TickClock implementation:
NowTicks() const250   TimeTicks NowTicks() const override {
251     // This can be called from any thread.
252     AutoLock lock(now_ticks_lock_);
253     return now_ticks_;
254   }
255 
256   // Used by FastForwardToNextTaskOrCap() to return which task source time was
257   // advanced to.
258   enum class NextTaskSource {
259     // Out of tasks under |fast_forward_cap|.
260     kNone,
261     // There's now >=1 immediate task on the main thread (ThreadPool might have
262     // some too).
263     kMainThreadHasWork,
264     // There's now >=1 immediate task in the thread pool.
265     kThreadPoolOnly,
266   };
267 
268   // Advances time to the first of : next main thread delayed task, next thread
269   // pool task, or |fast_forward_cap| (if it's not Max()). Ignores immediate
270   // tasks, expected to be called after being just idle, racily scheduling
271   // immediate tasks doesn't affect the outcome of this call.
FastForwardToNextTaskOrCap(absl::optional<sequence_manager::WakeUp> next_main_thread_wake_up,TimeTicks fast_forward_cap)272   NextTaskSource FastForwardToNextTaskOrCap(
273       absl::optional<sequence_manager::WakeUp> next_main_thread_wake_up,
274       TimeTicks fast_forward_cap) {
275     DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
276 
277     // Consider the next thread pool tasks iff they're running.
278     absl::optional<TimeTicks> next_thread_pool_task_time;
279     if (thread_pool_ && thread_pool_task_tracker_->TasksAllowedToRun()) {
280       next_thread_pool_task_time =
281           thread_pool_->NextScheduledRunTimeForTesting();
282     }
283 
284     // Custom comparison logic to consider nullopt the largest rather than
285     // smallest value. Could consider using TimeTicks::Max() instead of nullopt
286     // to represent out-of-tasks?
287     absl::optional<TimeTicks> next_task_time;
288     if (!next_main_thread_wake_up) {
289       next_task_time = next_thread_pool_task_time;
290     } else if (!next_thread_pool_task_time) {
291       next_task_time = next_main_thread_wake_up->time;
292     } else {
293       next_task_time =
294           std::min(next_main_thread_wake_up->time, *next_thread_pool_task_time);
295     }
296 
297     if (next_task_time && *next_task_time <= fast_forward_cap) {
298       {
299         AutoLock lock(now_ticks_lock_);
300         // It's possible for |next_task_time| to be in the past in the following
301         // scenario:
302         // Start with Now() == 100ms
303         // Thread A : Post 200ms delayed task T (construct and enqueue)
304         // Thread B : Construct 20ms delayed task U
305         //              => |delayed_run_time| == 120ms.
306         // Thread A : FastForwardToNextTaskOrCap() => fast-forwards to T @
307         //            300ms (task U is not yet in queue).
308         // Thread B : Complete enqueue of task U.
309         // Thread A : FastForwardToNextTaskOrCap() => must stay at 300ms and run
310         //            U, not go back to 120ms.
311         // Hence we need std::max() to protect against this because construction
312         // and enqueuing isn't atomic in time (LazyNow support in
313         // base/task/thread_pool could help).
314         now_ticks_ = std::max(now_ticks_, *next_task_time);
315       }
316 
317       if (next_task_time == next_thread_pool_task_time) {
318         thread_pool_->ProcessRipeDelayedTasksForTesting();
319       }
320 
321       if (next_main_thread_wake_up &&
322           next_task_time == next_main_thread_wake_up->time) {
323         return NextTaskSource::kMainThreadHasWork;
324       }
325 
326       // The main thread doesn't have immediate work so it'll go to sleep after
327       // returning from this call. We must make sure it wakes up when the
328       // ThreadPool is done or the test may stall : crbug.com/1263149.
329       //
330       // Note: It is necessary to reach in SequenceManagerImpl to ScheduleWork
331       // instead of alternatives to waking the main thread, like posting a
332       // no-op task, as alternatives would prevent the main thread from
333       // achieving quiescence (which some task monitoring tests verify).
334       thread_pool_->FlushAsyncForTesting(BindOnce(
335           &sequence_manager::internal::SequenceManagerImpl::ScheduleWork,
336           Unretained(sequence_manager_)));
337       return NextTaskSource::kThreadPoolOnly;
338     }
339 
340     if (!fast_forward_cap.is_max()) {
341       AutoLock lock(now_ticks_lock_);
342       // It's possible that Now() is already beyond |fast_forward_cap| when the
343       // caller nests multiple FastForwardBy() calls.
344       now_ticks_ = std::max(now_ticks_, fast_forward_cap);
345     }
346 
347     return NextTaskSource::kNone;
348   }
349 
350  private:
351   SEQUENCE_CHECKER(sequence_checker_);
352 
353   raw_ptr<internal::ThreadPoolImpl, DanglingUntriaged> thread_pool_ = nullptr;
354   raw_ptr<const TestTaskTracker, DanglingUntriaged> thread_pool_task_tracker_ =
355       nullptr;
356 
357   const raw_ptr<sequence_manager::internal::SequenceManagerImpl,
358                 DanglingUntriaged>
359       sequence_manager_;
360 
361   // Protects |now_ticks_|
362   mutable Lock now_ticks_lock_;
363 
364   // Only ever written to from the main sequence. Start from real Now() instead
365   // of zero to give a more realistic view to tests.
GUARDED_BY(now_ticks_lock_)366   TimeTicks now_ticks_ GUARDED_BY(now_ticks_lock_){
367       base::subtle::TimeTicksNowIgnoringOverride()
368           .SnappedToNextTick(TimeTicks(), Milliseconds(1))};
369 };
370 
371 TaskEnvironment::MockTimeDomain*
372     TaskEnvironment::MockTimeDomain::current_mock_time_domain_ = nullptr;
373 
TaskEnvironment(sequence_manager::SequenceManager::PrioritySettings priority_settings,TimeSource time_source,MainThreadType main_thread_type,ThreadPoolExecutionMode thread_pool_execution_mode,ThreadingMode threading_mode,ThreadPoolCOMEnvironment thread_pool_com_environment,bool subclass_creates_default_taskrunner,trait_helpers::NotATraitTag)374 TaskEnvironment::TaskEnvironment(
375     sequence_manager::SequenceManager::PrioritySettings priority_settings,
376     TimeSource time_source,
377     MainThreadType main_thread_type,
378     ThreadPoolExecutionMode thread_pool_execution_mode,
379     ThreadingMode threading_mode,
380     ThreadPoolCOMEnvironment thread_pool_com_environment,
381     bool subclass_creates_default_taskrunner,
382     trait_helpers::NotATraitTag)
383     : main_thread_type_(main_thread_type),
384       thread_pool_execution_mode_(thread_pool_execution_mode),
385       threading_mode_(threading_mode),
386       thread_pool_com_environment_(thread_pool_com_environment),
387       subclass_creates_default_taskrunner_(subclass_creates_default_taskrunner),
388       sequence_manager_(
389           CreateSequenceManagerForMainThreadType(main_thread_type,
390                                                  std::move(priority_settings))),
391       mock_time_domain_(
392           time_source != TimeSource::SYSTEM_TIME
393               ? std::make_unique<TaskEnvironment::MockTimeDomain>(
394                     static_cast<
395                         sequence_manager::internal::SequenceManagerImpl*>(
396                         sequence_manager_.get()))
397               : nullptr),
398       time_overrides_(time_source == TimeSource::MOCK_TIME
399                           ? std::make_unique<subtle::ScopedTimeClockOverrides>(
400                                 &MockTimeDomain::GetTime,
401                                 &MockTimeDomain::GetTimeTicks,
402                                 nullptr)
403                           : nullptr),
404       mock_clock_(mock_time_domain_ ? std::make_unique<TickClockBasedClock>(
405                                           mock_time_domain_.get())
406                                     : nullptr),
407       scoped_lazy_task_runner_list_for_testing_(
408           std::make_unique<internal::ScopedLazyTaskRunnerListForTesting>()),
409       // TODO(https://crbug.com/922098): Enable Run() timeouts even for
410       // instances created with TimeSource::MOCK_TIME.
411       run_loop_timeout_(
412           mock_time_domain_
413               ? nullptr
414               : std::make_unique<ScopedRunLoopTimeout>(
415                     FROM_HERE,
416                     TestTimeouts::action_timeout(),
417                     BindRepeating(&sequence_manager::SequenceManager::
418                                       DescribeAllPendingTasks,
419                                   Unretained(sequence_manager_.get())))) {
420   CHECK(!base::SingleThreadTaskRunner::HasCurrentDefault());
421   // If |subclass_creates_default_taskrunner| is true then initialization is
422   // deferred until DeferredInitFromSubclass().
423   if (!subclass_creates_default_taskrunner) {
424     task_queue_ =
425         sequence_manager_->CreateTaskQueue(sequence_manager::TaskQueue::Spec(
426             sequence_manager::QueueName::TASK_ENVIRONMENT_DEFAULT_TQ));
427     task_runner_ = task_queue_->task_runner();
428     sequence_manager_->SetDefaultTaskRunner(task_runner_);
429     if (mock_time_domain_) {
430       sequence_manager_->SetTimeDomain(mock_time_domain_.get());
431     }
432     CHECK(base::SingleThreadTaskRunner::HasCurrentDefault())
433         << "SingleThreadTaskRunner::CurrentDefaultHandle should've been set "
434            "now.";
435     CompleteInitialization();
436   }
437 
438   if (threading_mode_ != ThreadingMode::MAIN_THREAD_ONLY) {
439     InitializeThreadPool();
440   }
441 
442   if (thread_pool_execution_mode_ == ThreadPoolExecutionMode::QUEUED &&
443       task_tracker_) {
444     CHECK(task_tracker_->DisallowRunTasks());
445   }
446 }
447 
448 // static
CreateThreadPool()449 TaskEnvironment::TestTaskTracker* TaskEnvironment::CreateThreadPool() {
450   CHECK(!ThreadPoolInstance::Get())
451       << "Someone has already installed a ThreadPoolInstance. If nothing in "
452          "your test does so, then a test that ran earlier may have installed "
453          "one and leaked it. base::TestSuite will trap leaked globals, unless "
454          "someone has explicitly disabled it with "
455          "DisableCheckForLeakedGlobals().";
456 
457   auto task_tracker = std::make_unique<TestTaskTracker>();
458   TestTaskTracker* raw_task_tracker = task_tracker.get();
459   // Disable background threads to avoid hangs when flushing background tasks.
460   auto thread_pool = std::make_unique<internal::ThreadPoolImpl>(
461       std::string(), std::move(task_tracker),
462       /*use_background_threads=*/false);
463   ThreadPoolInstance::Set(std::move(thread_pool));
464   DCHECK(!g_task_tracker);
465   g_task_tracker = raw_task_tracker;
466   return raw_task_tracker;
467 }
468 
InitializeThreadPool()469 void TaskEnvironment::InitializeThreadPool() {
470 #if BUILDFLAG(ENABLE_BASE_TRACING)
471   // Force the creation of TraceLog instance before starting ThreadPool and
472   // creating additional threads to avoid race conditions.
473   trace_event::TraceLog::GetInstance();
474 #endif  // BUILDFLAG(ENABLE_BASE_TRACING)
475 
476   task_tracker_ = CreateThreadPool();
477   if (mock_time_domain_) {
478     mock_time_domain_->SetThreadPool(
479         static_cast<internal::ThreadPoolImpl*>(ThreadPoolInstance::Get()),
480         task_tracker_);
481   }
482 
483   ThreadPoolInstance::InitParams init_params(kNumForegroundThreadPoolThreads);
484   init_params.suggested_reclaim_time = TimeDelta::Max();
485 #if BUILDFLAG(IS_WIN)
486   if (thread_pool_com_environment_ == ThreadPoolCOMEnvironment::COM_MTA) {
487     init_params.common_thread_pool_environment =
488         ThreadPoolInstance::InitParams::CommonThreadPoolEnvironment::COM_MTA;
489   }
490 #endif
491   ThreadPoolInstance::Get()->Start(init_params);
492 }
493 
CompleteInitialization()494 void TaskEnvironment::CompleteInitialization() {
495   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
496 
497 #if BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
498   if (main_thread_type() == MainThreadType::IO) {
499     file_descriptor_watcher_ =
500         std::make_unique<FileDescriptorWatcher>(GetMainThreadTaskRunner());
501   }
502 #endif  // BUILDFLAG(IS_POSIX) || BUILDFLAG(IS_FUCHSIA)
503 }
504 
505 TaskEnvironment::TaskEnvironment(TaskEnvironment&& other) = default;
506 
~TaskEnvironment()507 TaskEnvironment::~TaskEnvironment() {
508   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
509   DestroyTaskEnvironment();
510 }
511 
DestroyTaskEnvironment()512 void TaskEnvironment::DestroyTaskEnvironment() {
513   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
514 
515   // If we've been moved or already destroyed (i.e. subclass invoked
516   // DestroyTaskEnvironment() before ~TaskEnvironment()) then bail out.
517   if (!owns_instance_) {
518     return;
519   }
520   owns_instance_.reset();
521 
522   for (auto& observer : GetDestructionObservers()) {
523     observer.WillDestroyCurrentTaskEnvironment();
524   }
525 
526   ShutdownAndJoinThreadPool();
527   task_queue_ = nullptr;
528   // SequenceManagerImpl must outlive the threads in the ThreadPoolInstance()
529   // (ShutdownAndJoinThreadPool() above) as TaskEnvironment::MockTimeDomain can
530   // invoke its SequenceManagerImpl* from worker threads.
531   // Additionally, Tasks owned by `sequence_manager_` can have referencees to
532   // PooledTaskRunnerDelegates. These are owned by the thread pool, so destroy
533   // `sequence_manager` before the thread pool itself.
534   sequence_manager_.reset();
535   DestroyThreadPool();
536 }
537 
ShutdownAndJoinThreadPool()538 void TaskEnvironment::ShutdownAndJoinThreadPool() {
539   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
540 
541   if (threading_mode_ == ThreadingMode::MAIN_THREAD_ONLY) {
542     return;
543   }
544   DCHECK(ThreadPoolInstance::Get());
545 
546   // Ideally this would RunLoop().RunUntilIdle() here to catch any errors or
547   // infinite post loop in the remaining work but this isn't possible right now
548   // because base::~MessageLoop() didn't use to do this and adding it here would
549   // make the migration away from MessageLoop that much harder.
550 
551   // Without FlushForTesting(), DeleteSoon() and ReleaseSoon() tasks could be
552   // skipped, resulting in memory leaks.
553   task_tracker_->AllowRunTasks();
554   ThreadPoolInstance::Get()->FlushForTesting();
555   ThreadPoolInstance::Get()->Shutdown();
556   ThreadPoolInstance::Get()->JoinForTesting();
557   DCHECK_EQ(g_task_tracker, task_tracker_);
558   g_task_tracker = nullptr;
559 }
560 
DestroyThreadPool()561 void TaskEnvironment::DestroyThreadPool() {
562   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
563 
564   if (threading_mode_ == ThreadingMode::MAIN_THREAD_ONLY) {
565     return;
566   }
567   DCHECK(ThreadPoolInstance::Get());
568 
569   // Task runner lists will be destroyed when resetting thread pool instance.
570   scoped_lazy_task_runner_list_for_testing_.reset();
571 
572   // Destroying ThreadPoolInstance state can result in waiting on worker
573   // threads. Make sure this is allowed to avoid flaking tests that have
574   // disallowed waits on their main thread.
575   ScopedAllowBaseSyncPrimitivesForTesting allow_waits_to_destroy_task_tracker;
576   ThreadPoolInstance::Set(nullptr);
577 }
578 
GetMockTimeDomain() const579 sequence_manager::TimeDomain* TaskEnvironment::GetMockTimeDomain() const {
580   return mock_time_domain_.get();
581 }
582 
sequence_manager() const583 sequence_manager::SequenceManager* TaskEnvironment::sequence_manager() const {
584   DCHECK(subclass_creates_default_taskrunner_);
585   return sequence_manager_.get();
586 }
587 
DeferredInitFromSubclass(scoped_refptr<base::SingleThreadTaskRunner> task_runner)588 void TaskEnvironment::DeferredInitFromSubclass(
589     scoped_refptr<base::SingleThreadTaskRunner> task_runner) {
590   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
591 
592   task_runner_ = std::move(task_runner);
593   sequence_manager_->SetDefaultTaskRunner(task_runner_);
594   CompleteInitialization();
595 }
596 
597 scoped_refptr<base::SingleThreadTaskRunner>
GetMainThreadTaskRunner()598 TaskEnvironment::GetMainThreadTaskRunner() {
599   DCHECK(task_runner_);
600   return task_runner_;
601 }
602 
MainThreadIsIdle() const603 bool TaskEnvironment::MainThreadIsIdle() const {
604   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
605 
606   sequence_manager::internal::SequenceManagerImpl* sequence_manager_impl =
607       static_cast<sequence_manager::internal::SequenceManagerImpl*>(
608           sequence_manager_.get());
609   // ReclaimMemory sweeps canceled delayed tasks.
610   sequence_manager_impl->ReclaimMemory();
611   return sequence_manager_impl->IsIdleForTesting();
612 }
613 
QuitClosure()614 RepeatingClosure TaskEnvironment::QuitClosure() {
615   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
616 
617   if (!run_until_quit_loop_) {
618     run_until_quit_loop_ =
619         std::make_unique<RunLoop>(RunLoop::Type::kNestableTasksAllowed);
620   }
621 
622   return run_until_quit_loop_->QuitClosure();
623 }
624 
RunUntilQuit()625 void TaskEnvironment::RunUntilQuit() {
626   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
627   DCHECK(run_until_quit_loop_)
628       << "QuitClosure() not called before RunUntilQuit()";
629 
630   const bool could_run_tasks = task_tracker_->AllowRunTasks();
631 
632   run_until_quit_loop_->Run();
633   // Make the next call to RunUntilQuit() use a new RunLoop. This also
634   // invalidates all existing quit closures.
635   run_until_quit_loop_.reset();
636 
637   if (!could_run_tasks) {
638     EXPECT_TRUE(
639         task_tracker_->DisallowRunTasks(TestTimeouts::action_max_timeout()))
640         << "Could not bring ThreadPool back to ThreadPoolExecutionMode::QUEUED "
641            "after Quit() because some tasks were long running:\n"
642         << task_tracker_->DescribeRunningTasks();
643   }
644 }
645 
RunUntilIdle()646 void TaskEnvironment::RunUntilIdle() {
647   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
648 
649   if (threading_mode_ == ThreadingMode::MAIN_THREAD_ONLY) {
650     RunLoop(RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
651     return;
652   }
653 
654   // TODO(gab): This can be heavily simplified to essentially:
655   //     bool HasMainThreadTasks() {
656   //      if (message_loop_)
657   //        return !message_loop_->IsIdleForTesting();
658   //      return mock_time_task_runner_->NextPendingTaskDelay().is_zero();
659   //     }
660   //     while (task_tracker_->HasIncompleteTasks() || HasMainThreadTasks()) {
661   //       base::RunLoop().RunUntilIdle();
662   //       // Avoid busy-looping.
663   //       if (task_tracker_->HasIncompleteTasks())
664   //         PlatformThread::Sleep(Milliseconds(1));
665   //     }
666   // Update: This can likely be done now that MessageLoop::IsIdleForTesting()
667   // checks all queues.
668   //
669   // Other than that it works because once |task_tracker_->HasIncompleteTasks()|
670   // is false we know for sure that the only thing that can make it true is a
671   // main thread task (TaskEnvironment owns all the threads). As such we can't
672   // racily see it as false on the main thread and be wrong as if it the main
673   // thread sees the atomic count at zero, it's the only one that can make it go
674   // up. And the only thing that can make it go up on the main thread are main
675   // thread tasks and therefore we're done if there aren't any left.
676   //
677   // This simplification further allows simplification of DisallowRunTasks().
678   //
679   // This can also be simplified even further once TaskTracker becomes directly
680   // aware of main thread tasks. https://crbug.com/660078.
681 
682   const bool could_run_tasks = task_tracker_->AllowRunTasks();
683 
684   for (;;) {
685     task_tracker_->AllowRunTasks();
686 
687     // First run as many tasks as possible on the main thread in parallel with
688     // tasks in ThreadPool. This increases likelihood of TSAN catching
689     // threading errors and eliminates possibility of hangs should a
690     // ThreadPool task synchronously block on a main thread task
691     // (ThreadPoolInstance::FlushForTesting() can't be used here for that
692     // reason).
693     RunLoop(RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
694 
695     // Then halt ThreadPool. DisallowRunTasks() failing indicates that there
696     // were ThreadPool tasks currently running. In that case, try again from
697     // top when DisallowRunTasks() yields control back to this thread as they
698     // may have posted main thread tasks.
699     if (!task_tracker_->DisallowRunTasks()) {
700       continue;
701     }
702 
703     // Once ThreadPool is halted. Run any remaining main thread tasks (which
704     // may have been posted by ThreadPool tasks that completed between the
705     // above main thread RunUntilIdle() and ThreadPool DisallowRunTasks()).
706     // Note: this assumes that no main thread task synchronously blocks on a
707     // ThreadPool tasks (it certainly shouldn't); this call could otherwise
708     // hang.
709     RunLoop(RunLoop::Type::kNestableTasksAllowed).RunUntilIdle();
710 
711     // The above RunUntilIdle() guarantees there are no remaining main thread
712     // tasks (the ThreadPool being halted during the last RunUntilIdle() is
713     // key as it prevents a task being posted to it racily with it determining
714     // it had no work remaining). Therefore, we're done if there is no more work
715     // on ThreadPool either (there can be ThreadPool work remaining if
716     // DisallowRunTasks() preempted work and/or the last RunUntilIdle() posted
717     // more ThreadPool tasks).
718     // Note: this last |if| couldn't be turned into a |do {} while();|. A
719     // conditional loop makes it such that |continue;| results in checking the
720     // condition (not unconditionally loop again) which would be incorrect for
721     // the above logic as it'd then be possible for a ThreadPool task to be
722     // running during the DisallowRunTasks() test, causing it to fail, but then
723     // post to the main thread and complete before the loop's condition is
724     // verified which could result in HasIncompleteUndelayedTasksForTesting()
725     // returning false and the loop erroneously exiting with a pending task on
726     // the main thread.
727     if (!task_tracker_->HasIncompleteTaskSourcesForTesting()) {
728       break;
729     }
730   }
731 
732   // The above loop always ends with running tasks being disallowed. Re-enable
733   // parallel execution before returning if it was allowed at the beginning of
734   // this call.
735   if (could_run_tasks) {
736     task_tracker_->AllowRunTasks();
737   }
738 }
739 
FastForwardBy(TimeDelta delta)740 void TaskEnvironment::FastForwardBy(TimeDelta delta) {
741   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
742   DCHECK(mock_time_domain_);
743   DCHECK_GE(delta, TimeDelta());
744 
745   const bool could_run_tasks = task_tracker_ && task_tracker_->AllowRunTasks();
746 
747   const TimeTicks fast_forward_until = mock_time_domain_->NowTicks() + delta;
748   do {
749     RunUntilIdle();
750     // ReclaimMemory sweeps canceled delayed tasks, making sure
751     // FastForwardToNextTaskOrCap isn't affected by canceled tasks.
752     sequence_manager_->ReclaimMemory();
753   } while (mock_time_domain_->FastForwardToNextTaskOrCap(
754                sequence_manager_->GetNextDelayedWakeUp(), fast_forward_until) !=
755            MockTimeDomain::NextTaskSource::kNone);
756 
757   if (task_tracker_ && !could_run_tasks) {
758     task_tracker_->DisallowRunTasks();
759   }
760 }
761 
FastForwardUntilNoTasksRemain()762 void TaskEnvironment::FastForwardUntilNoTasksRemain() {
763   // TimeTicks::operator+(TimeDelta) uses saturated arithmetic so it's safe to
764   // pass in TimeDelta::Max().
765   FastForwardBy(TimeDelta::Max());
766 }
767 
AdvanceClock(TimeDelta delta)768 void TaskEnvironment::AdvanceClock(TimeDelta delta) {
769   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
770   DCHECK(mock_time_domain_);
771   DCHECK_GE(delta, TimeDelta());
772   mock_time_domain_->AdvanceClock(delta);
773 }
774 
GetMockTickClock() const775 const TickClock* TaskEnvironment::GetMockTickClock() const {
776   DCHECK(mock_time_domain_);
777   return mock_time_domain_.get();
778 }
779 
NowTicks() const780 base::TimeTicks TaskEnvironment::NowTicks() const {
781   DCHECK(mock_time_domain_);
782   return mock_time_domain_->NowTicks();
783 }
784 
GetMockClock() const785 const Clock* TaskEnvironment::GetMockClock() const {
786   DCHECK(mock_clock_);
787   return mock_clock_.get();
788 }
789 
GetPendingMainThreadTaskCount() const790 size_t TaskEnvironment::GetPendingMainThreadTaskCount() const {
791   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
792 
793   // ReclaimMemory sweeps canceled delayed tasks.
794   sequence_manager_->ReclaimMemory();
795   return sequence_manager_->GetPendingTaskCountForTesting();
796 }
797 
NextMainThreadPendingTaskDelay() const798 TimeDelta TaskEnvironment::NextMainThreadPendingTaskDelay() const {
799   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
800 
801   // ReclaimMemory sweeps canceled delayed tasks.
802   sequence_manager_->ReclaimMemory();
803   DCHECK(mock_time_domain_);
804   LazyNow lazy_now(mock_time_domain_->NowTicks());
805   if (!sequence_manager_->IsIdleForTesting()) {
806     return TimeDelta();
807   }
808   absl::optional<sequence_manager::WakeUp> wake_up =
809       sequence_manager_->GetNextDelayedWakeUp();
810   return wake_up ? wake_up->time - lazy_now.Now() : TimeDelta::Max();
811 }
812 
NextTaskIsDelayed() const813 bool TaskEnvironment::NextTaskIsDelayed() const {
814   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
815 
816   TimeDelta delay = NextMainThreadPendingTaskDelay();
817   return !delay.is_zero() && !delay.is_max();
818 }
819 
DescribeCurrentTasks() const820 void TaskEnvironment::DescribeCurrentTasks() const {
821   DCHECK_CALLED_ON_VALID_THREAD(main_thread_checker_);
822   LOG(INFO) << task_tracker_->DescribeRunningTasks();
823   LOG(INFO) << sequence_manager_->DescribeAllPendingTasks();
824 }
825 
DetachFromThread()826 void TaskEnvironment::DetachFromThread() {
827   DETACH_FROM_THREAD(main_thread_checker_);
828   if (task_tracker_) {
829     task_tracker_->controller_thread_checker_.DetachFromThread();
830   }
831 }
832 
833 // static
AddDestructionObserver(DestructionObserver * observer)834 void TaskEnvironment::AddDestructionObserver(DestructionObserver* observer) {
835   GetDestructionObservers().AddObserver(observer);
836 }
837 
838 // static
RemoveDestructionObserver(DestructionObserver * observer)839 void TaskEnvironment::RemoveDestructionObserver(DestructionObserver* observer) {
840   GetDestructionObservers().RemoveObserver(observer);
841 }
842 
ParallelExecutionFence(const char * error_message)843 TaskEnvironment::ParallelExecutionFence::ParallelExecutionFence(
844     const char* error_message) {
845   CHECK(!g_task_tracker || g_task_tracker->OnControllerThread())
846       << error_message;
847   if (g_task_tracker) {
848     // Do not attempt to install a fence post shutdown, the only remaining tasks
849     // at that point are CONTINUE_ON_SHUTDOWN and attempting to wait for them
850     // causes more issues (test timeouts) than the fence solves (data races on
851     // global state). CONTINUE_ON_SHUTDOWN tasks should generally not be
852     // touching global state and while not all users of ParallelExecutionFence
853     // (FeatureList) guard against access from CONTINUE_ON_SHUTDOWN tasks, any
854     // such tasks abusing this would be flagged by TSAN and have to be fixed
855     // manually. Note: this is only relevant in browser tests as unit tests
856     // already go through a full join in TaskEnvironment::DestroyThreadPool().
857     previously_allowed_to_run_ = g_task_tracker->TasksAllowedToRun() &&
858                                  !g_task_tracker->IsShutdownComplete();
859 
860     // DisallowRunTasks typically yields back if it fails to reach quiescence
861     // within 1ms. This is typically done to let the main thread run tasks that
862     // could potentially be blocking main thread tasks. In this case however,
863     // main thread making progress while installing the fence would be more
864     // surprising. So allow more time but report errors after a while.
865     while (previously_allowed_to_run_ &&
866            !g_task_tracker->DisallowRunTasks(Seconds(5))) {
867       LOG(WARNING) << "Installing ParallelExecutionFence is slow because of "
868                       "these running tasks:\n"
869                    << g_task_tracker->DescribeRunningTasks()
870                    << "\nParallelExecutionFence requested by:\n"
871                    << debug::StackTrace();
872     }
873   } else if (ThreadPoolInstance::Get()) {
874     LOG(WARNING)
875         << "ParallelExecutionFence is ineffective when ThreadPoolInstance is "
876            "not managed by a TaskEnvironment.\n"
877            "Test fixtures should use a TaskEnvironment member or statically "
878            "invoke TaskEnvironment::CreateThreadPool() + "
879            "ThreadPoolInstance::Get()->StartWithDefaultParams() when the "
880            "former is not possible.";
881   }
882 }
883 
~ParallelExecutionFence()884 TaskEnvironment::ParallelExecutionFence::~ParallelExecutionFence() {
885   if (previously_allowed_to_run_) {
886     g_task_tracker->AllowRunTasks();
887   }
888 }
889 
TestTaskTracker()890 TaskEnvironment::TestTaskTracker::TestTaskTracker()
891     : can_run_tasks_cv_(&lock_), task_completed_cv_(&lock_) {
892   // Consider threads blocked on these as idle (avoids instantiating
893   // ScopedBlockingCalls and confusing some //base internals tests).
894   can_run_tasks_cv_.declare_only_used_while_idle();
895   task_completed_cv_.declare_only_used_while_idle();
896 }
897 
AllowRunTasks()898 bool TaskEnvironment::TestTaskTracker::AllowRunTasks() {
899   AutoLock auto_lock(lock_);
900   const bool could_run_tasks = can_run_tasks_;
901   can_run_tasks_ = true;
902   can_run_tasks_cv_.Broadcast();
903   return could_run_tasks;
904 }
905 
TasksAllowedToRun() const906 bool TaskEnvironment::TestTaskTracker::TasksAllowedToRun() const {
907   AutoLock auto_lock(lock_);
908   return can_run_tasks_;
909 }
910 
DisallowRunTasks(TimeDelta timeout)911 bool TaskEnvironment::TestTaskTracker::DisallowRunTasks(TimeDelta timeout) {
912   // Disallowing task running should only be done from the main thread to avoid
913   // racing with shutdown.
914   DCHECK(OnControllerThread());
915 
916   AutoLock auto_lock(lock_);
917 
918   // Can't disallow run task if there are tasks running.
919   for (TimeTicks now = subtle::TimeTicksNowIgnoringOverride(),
920                  end = now + timeout;
921        !running_tasks_.empty() && now < end;
922        now = subtle::TimeTicksNowIgnoringOverride()) {
923     task_completed_cv_.TimedWait(end - now);
924   }
925   // Timed out waiting for running tasks, yield to caller.
926   if (!running_tasks_.empty()) {
927     // This condition should never be sought after shutdown and this call
928     // shouldn't be racing shutdown either per the above `OnControllerThread()`
929     // contract.
930     DCHECK(!IsShutdownComplete());
931     return false;
932   }
933 
934   can_run_tasks_ = false;
935   return true;
936 }
937 
RunTask(internal::Task task,internal::TaskSource * sequence,const TaskTraits & traits)938 void TaskEnvironment::TestTaskTracker::RunTask(internal::Task task,
939                                                internal::TaskSource* sequence,
940                                                const TaskTraits& traits) {
941   const Location posted_from = task.posted_from;
942   int task_number;
943   {
944     AutoLock auto_lock(lock_);
945 
946     while (!can_run_tasks_) {
947       can_run_tasks_cv_.Wait();
948     }
949 
950     task_number = next_task_number_++;
951     auto pair = running_tasks_.emplace(task_number, posted_from);
952     CHECK(pair.second);  // If false, the |task_number| was already present.
953   }
954 
955   // Using TimeTicksNowIgnoringOverride() because in tests that mock time,
956   // Now() can advance very far very fast, and that's not a problem. This is
957   // watching for tests that have actually long running tasks which cause our
958   // test suites to run slowly.
959   base::TimeTicks before = base::subtle::TimeTicksNowIgnoringOverride();
960   internal::ThreadPoolImpl::TaskTrackerImpl::RunTask(std::move(task), sequence,
961                                                      traits);
962   base::TimeTicks after = base::subtle::TimeTicksNowIgnoringOverride();
963 
964   const TimeDelta kTimeout = TestTimeouts::action_max_timeout();
965   if ((after - before) > kTimeout) {
966     ADD_FAILURE() << "TaskEnvironment: RunTask took more than "
967                   << kTimeout.InSeconds() << " seconds. Posted from "
968                   << posted_from.ToString();
969   }
970 
971   {
972     AutoLock auto_lock(lock_);
973     CHECK(can_run_tasks_);
974     size_t found = running_tasks_.erase(task_number);
975     CHECK_EQ(1u, found);
976 
977     task_completed_cv_.Broadcast();
978   }
979 }
980 
DescribeRunningTasks() const981 std::string TaskEnvironment::TestTaskTracker::DescribeRunningTasks() const {
982   base::flat_map<int64_t, Location> running_tasks_copy;
983   {
984     AutoLock auto_lock(lock_);
985     running_tasks_copy = running_tasks_;
986   }
987   std::string running_tasks_str = "ThreadPool currently running tasks:";
988   if (running_tasks_copy.empty()) {
989     running_tasks_str += " none.";
990   } else {
991     for (auto& pair : running_tasks_copy) {
992       running_tasks_str += "\n  Task posted from: " + pair.second.ToString();
993     }
994   }
995   return running_tasks_str;
996 }
997 
BeginCompleteShutdown(base::WaitableEvent & shutdown_event)998 void TaskEnvironment::TestTaskTracker::BeginCompleteShutdown(
999     base::WaitableEvent& shutdown_event) {
1000   const TimeDelta kTimeout = TestTimeouts::action_max_timeout();
1001   if (shutdown_event.TimedWait(kTimeout)) {
1002     return;  // All tasks completed in time, yay! Yield back to shutdown.
1003   }
1004 
1005   // If we had to wait too long for the shutdown tasks to complete, then we
1006   // should fail the test and report which tasks are currently running.
1007   std::string failure_tasks = DescribeRunningTasks();
1008 
1009   ADD_FAILURE() << "TaskEnvironment: CompleteShutdown took more than "
1010                 << kTimeout.InSeconds() << " seconds.\n"
1011                 << failure_tasks;
1012   base::Process::TerminateCurrentProcessImmediately(-1);
1013 }
1014 
AssertFlushForTestingAllowed()1015 void TaskEnvironment::TestTaskTracker::AssertFlushForTestingAllowed() {
1016   AutoLock auto_lock(lock_);
1017   ASSERT_TRUE(can_run_tasks_)
1018       << "FlushForTesting() requires ThreadPool tasks to be allowed to run or "
1019          "it will hang. Note: DisallowRunTasks happens implicitly on-and-off "
1020          "during TaskEnvironment::RunUntilIdle and main thread tasks running "
1021          "under it should thus never FlushForTesting().";
1022 }
1023 
1024 }  // namespace test
1025 }  // namespace base
1026