xref: /aosp_15_r20/external/libchrome/base/test/scoped_task_environment.cc (revision 635a864187cb8b6c713ff48b7e790a6b21769273)
1*635a8641SAndroid Build Coastguard Worker // Copyright 2017 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker 
5*635a8641SAndroid Build Coastguard Worker #include "base/test/scoped_task_environment.h"
6*635a8641SAndroid Build Coastguard Worker 
7*635a8641SAndroid Build Coastguard Worker #include "base/bind_helpers.h"
8*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
9*635a8641SAndroid Build Coastguard Worker #include "base/memory/ptr_util.h"
10*635a8641SAndroid Build Coastguard Worker #include "base/message_loop/message_loop.h"
11*635a8641SAndroid Build Coastguard Worker #include "base/run_loop.h"
12*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/condition_variable.h"
13*635a8641SAndroid Build Coastguard Worker #include "base/synchronization/lock.h"
14*635a8641SAndroid Build Coastguard Worker #include "base/task_scheduler/post_task.h"
15*635a8641SAndroid Build Coastguard Worker #include "base/task_scheduler/task_scheduler.h"
16*635a8641SAndroid Build Coastguard Worker #include "base/task_scheduler/task_scheduler_impl.h"
17*635a8641SAndroid Build Coastguard Worker #include "base/test/test_mock_time_task_runner.h"
18*635a8641SAndroid Build Coastguard Worker #include "base/threading/sequence_local_storage_map.h"
19*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_restrictions.h"
20*635a8641SAndroid Build Coastguard Worker #include "base/threading/thread_task_runner_handle.h"
21*635a8641SAndroid Build Coastguard Worker #include "base/time/time.h"
22*635a8641SAndroid Build Coastguard Worker 
23*635a8641SAndroid Build Coastguard Worker #if defined(OS_POSIX)
24*635a8641SAndroid Build Coastguard Worker #include "base/files/file_descriptor_watcher_posix.h"
25*635a8641SAndroid Build Coastguard Worker #endif
26*635a8641SAndroid Build Coastguard Worker 
27*635a8641SAndroid Build Coastguard Worker namespace base {
28*635a8641SAndroid Build Coastguard Worker namespace test {
29*635a8641SAndroid Build Coastguard Worker 
30*635a8641SAndroid Build Coastguard Worker namespace {
31*635a8641SAndroid Build Coastguard Worker 
CreateMessageLoopForMainThreadType(ScopedTaskEnvironment::MainThreadType main_thread_type)32*635a8641SAndroid Build Coastguard Worker std::unique_ptr<MessageLoop> CreateMessageLoopForMainThreadType(
33*635a8641SAndroid Build Coastguard Worker     ScopedTaskEnvironment::MainThreadType main_thread_type) {
34*635a8641SAndroid Build Coastguard Worker   switch (main_thread_type) {
35*635a8641SAndroid Build Coastguard Worker     case ScopedTaskEnvironment::MainThreadType::DEFAULT:
36*635a8641SAndroid Build Coastguard Worker       return std::make_unique<MessageLoop>(MessageLoop::TYPE_DEFAULT);
37*635a8641SAndroid Build Coastguard Worker     case ScopedTaskEnvironment::MainThreadType::MOCK_TIME:
38*635a8641SAndroid Build Coastguard Worker       return nullptr;
39*635a8641SAndroid Build Coastguard Worker     case ScopedTaskEnvironment::MainThreadType::UI:
40*635a8641SAndroid Build Coastguard Worker       return std::make_unique<MessageLoop>(MessageLoop::TYPE_UI);
41*635a8641SAndroid Build Coastguard Worker     case ScopedTaskEnvironment::MainThreadType::IO:
42*635a8641SAndroid Build Coastguard Worker       return std::make_unique<MessageLoop>(MessageLoop::TYPE_IO);
43*635a8641SAndroid Build Coastguard Worker   }
44*635a8641SAndroid Build Coastguard Worker   NOTREACHED();
45*635a8641SAndroid Build Coastguard Worker   return nullptr;
46*635a8641SAndroid Build Coastguard Worker }
47*635a8641SAndroid Build Coastguard Worker 
48*635a8641SAndroid Build Coastguard Worker }  // namespace
49*635a8641SAndroid Build Coastguard Worker 
50*635a8641SAndroid Build Coastguard Worker class ScopedTaskEnvironment::TestTaskTracker
51*635a8641SAndroid Build Coastguard Worker     : public internal::TaskSchedulerImpl::TaskTrackerImpl {
52*635a8641SAndroid Build Coastguard Worker  public:
53*635a8641SAndroid Build Coastguard Worker   TestTaskTracker();
54*635a8641SAndroid Build Coastguard Worker 
55*635a8641SAndroid Build Coastguard Worker   // Allow running tasks.
56*635a8641SAndroid Build Coastguard Worker   void AllowRunTasks();
57*635a8641SAndroid Build Coastguard Worker 
58*635a8641SAndroid Build Coastguard Worker   // Disallow running tasks. Returns true on success; success requires there to
59*635a8641SAndroid Build Coastguard Worker   // be no tasks currently running. Returns false if >0 tasks are currently
60*635a8641SAndroid Build Coastguard Worker   // running. Prior to returning false, it will attempt to block until at least
61*635a8641SAndroid Build Coastguard Worker   // one task has completed (in an attempt to avoid callers busy-looping
62*635a8641SAndroid Build Coastguard Worker   // DisallowRunTasks() calls with the same set of slowly ongoing tasks). This
63*635a8641SAndroid Build Coastguard Worker   // block attempt will also have a short timeout (in an attempt to prevent the
64*635a8641SAndroid Build Coastguard Worker   // fallout of blocking: if the only task remaining is blocked on the main
65*635a8641SAndroid Build Coastguard Worker   // thread, waiting for it to complete results in a deadlock...).
66*635a8641SAndroid Build Coastguard Worker   bool DisallowRunTasks();
67*635a8641SAndroid Build Coastguard Worker 
68*635a8641SAndroid Build Coastguard Worker  private:
69*635a8641SAndroid Build Coastguard Worker   friend class ScopedTaskEnvironment;
70*635a8641SAndroid Build Coastguard Worker 
71*635a8641SAndroid Build Coastguard Worker   // internal::TaskSchedulerImpl::TaskTrackerImpl:
72*635a8641SAndroid Build Coastguard Worker   void RunOrSkipTask(internal::Task task,
73*635a8641SAndroid Build Coastguard Worker                      internal::Sequence* sequence,
74*635a8641SAndroid Build Coastguard Worker                      bool can_run_task) override;
75*635a8641SAndroid Build Coastguard Worker 
76*635a8641SAndroid Build Coastguard Worker   // Synchronizes accesses to members below.
77*635a8641SAndroid Build Coastguard Worker   Lock lock_;
78*635a8641SAndroid Build Coastguard Worker 
79*635a8641SAndroid Build Coastguard Worker   // True if running tasks is allowed.
80*635a8641SAndroid Build Coastguard Worker   bool can_run_tasks_ = true;
81*635a8641SAndroid Build Coastguard Worker 
82*635a8641SAndroid Build Coastguard Worker   // Signaled when |can_run_tasks_| becomes true.
83*635a8641SAndroid Build Coastguard Worker   ConditionVariable can_run_tasks_cv_;
84*635a8641SAndroid Build Coastguard Worker 
85*635a8641SAndroid Build Coastguard Worker   // Signaled when a task is completed.
86*635a8641SAndroid Build Coastguard Worker   ConditionVariable task_completed_;
87*635a8641SAndroid Build Coastguard Worker 
88*635a8641SAndroid Build Coastguard Worker   // Number of tasks that are currently running.
89*635a8641SAndroid Build Coastguard Worker   int num_tasks_running_ = 0;
90*635a8641SAndroid Build Coastguard Worker 
91*635a8641SAndroid Build Coastguard Worker   DISALLOW_COPY_AND_ASSIGN(TestTaskTracker);
92*635a8641SAndroid Build Coastguard Worker };
93*635a8641SAndroid Build Coastguard Worker 
ScopedTaskEnvironment(MainThreadType main_thread_type,ExecutionMode execution_control_mode)94*635a8641SAndroid Build Coastguard Worker ScopedTaskEnvironment::ScopedTaskEnvironment(
95*635a8641SAndroid Build Coastguard Worker     MainThreadType main_thread_type,
96*635a8641SAndroid Build Coastguard Worker     ExecutionMode execution_control_mode)
97*635a8641SAndroid Build Coastguard Worker     : execution_control_mode_(execution_control_mode),
98*635a8641SAndroid Build Coastguard Worker       message_loop_(CreateMessageLoopForMainThreadType(main_thread_type)),
99*635a8641SAndroid Build Coastguard Worker       mock_time_task_runner_(
100*635a8641SAndroid Build Coastguard Worker           main_thread_type == MainThreadType::MOCK_TIME
101*635a8641SAndroid Build Coastguard Worker               ? MakeRefCounted<TestMockTimeTaskRunner>(
102*635a8641SAndroid Build Coastguard Worker                     TestMockTimeTaskRunner::Type::kBoundToThread)
103*635a8641SAndroid Build Coastguard Worker               : nullptr),
104*635a8641SAndroid Build Coastguard Worker       slsm_for_mock_time_(
105*635a8641SAndroid Build Coastguard Worker           main_thread_type == MainThreadType::MOCK_TIME
106*635a8641SAndroid Build Coastguard Worker               ? std::make_unique<internal::SequenceLocalStorageMap>()
107*635a8641SAndroid Build Coastguard Worker               : nullptr),
108*635a8641SAndroid Build Coastguard Worker       slsm_registration_for_mock_time_(
109*635a8641SAndroid Build Coastguard Worker           main_thread_type == MainThreadType::MOCK_TIME
110*635a8641SAndroid Build Coastguard Worker               ? std::make_unique<
111*635a8641SAndroid Build Coastguard Worker                     internal::ScopedSetSequenceLocalStorageMapForCurrentThread>(
112*635a8641SAndroid Build Coastguard Worker                     slsm_for_mock_time_.get())
113*635a8641SAndroid Build Coastguard Worker               : nullptr),
114*635a8641SAndroid Build Coastguard Worker #if defined(OS_POSIX)
115*635a8641SAndroid Build Coastguard Worker       file_descriptor_watcher_(
116*635a8641SAndroid Build Coastguard Worker           main_thread_type == MainThreadType::IO
117*635a8641SAndroid Build Coastguard Worker               ? std::make_unique<FileDescriptorWatcher>(
118*635a8641SAndroid Build Coastguard Worker                     static_cast<MessageLoopForIO*>(message_loop_.get()))
119*635a8641SAndroid Build Coastguard Worker               : nullptr),
120*635a8641SAndroid Build Coastguard Worker #endif  // defined(OS_POSIX)
121*635a8641SAndroid Build Coastguard Worker       task_tracker_(new TestTaskTracker()) {
122*635a8641SAndroid Build Coastguard Worker   CHECK(!TaskScheduler::GetInstance());
123*635a8641SAndroid Build Coastguard Worker 
124*635a8641SAndroid Build Coastguard Worker   // Instantiate a TaskScheduler with 2 threads in each of its 4 pools. Threads
125*635a8641SAndroid Build Coastguard Worker   // stay alive even when they don't have work.
126*635a8641SAndroid Build Coastguard Worker   // Each pool uses two threads to prevent deadlocks in unit tests that have a
127*635a8641SAndroid Build Coastguard Worker   // sequence that uses WithBaseSyncPrimitives() to wait on the result of
128*635a8641SAndroid Build Coastguard Worker   // another sequence. This isn't perfect (doesn't solve wait chains) but solves
129*635a8641SAndroid Build Coastguard Worker   // the basic use case for now.
130*635a8641SAndroid Build Coastguard Worker   // TODO(fdoray/jeffreyhe): Make the TaskScheduler dynamically replace blocked
131*635a8641SAndroid Build Coastguard Worker   // threads and get rid of this limitation. http://crbug.com/738104
132*635a8641SAndroid Build Coastguard Worker   constexpr int kMaxThreads = 2;
133*635a8641SAndroid Build Coastguard Worker   const TimeDelta kSuggestedReclaimTime = TimeDelta::Max();
134*635a8641SAndroid Build Coastguard Worker   const SchedulerWorkerPoolParams worker_pool_params(kMaxThreads,
135*635a8641SAndroid Build Coastguard Worker                                                      kSuggestedReclaimTime);
136*635a8641SAndroid Build Coastguard Worker   TaskScheduler::SetInstance(std::make_unique<internal::TaskSchedulerImpl>(
137*635a8641SAndroid Build Coastguard Worker       "ScopedTaskEnvironment", WrapUnique(task_tracker_)));
138*635a8641SAndroid Build Coastguard Worker   task_scheduler_ = TaskScheduler::GetInstance();
139*635a8641SAndroid Build Coastguard Worker   TaskScheduler::GetInstance()->Start({worker_pool_params, worker_pool_params,
140*635a8641SAndroid Build Coastguard Worker                                        worker_pool_params, worker_pool_params});
141*635a8641SAndroid Build Coastguard Worker 
142*635a8641SAndroid Build Coastguard Worker   if (execution_control_mode_ == ExecutionMode::QUEUED)
143*635a8641SAndroid Build Coastguard Worker     CHECK(task_tracker_->DisallowRunTasks());
144*635a8641SAndroid Build Coastguard Worker }
145*635a8641SAndroid Build Coastguard Worker 
~ScopedTaskEnvironment()146*635a8641SAndroid Build Coastguard Worker ScopedTaskEnvironment::~ScopedTaskEnvironment() {
147*635a8641SAndroid Build Coastguard Worker   // Ideally this would RunLoop().RunUntilIdle() here to catch any errors or
148*635a8641SAndroid Build Coastguard Worker   // infinite post loop in the remaining work but this isn't possible right now
149*635a8641SAndroid Build Coastguard Worker   // because base::~MessageLoop() didn't use to do this and adding it here would
150*635a8641SAndroid Build Coastguard Worker   // make the migration away from MessageLoop that much harder.
151*635a8641SAndroid Build Coastguard Worker   CHECK_EQ(TaskScheduler::GetInstance(), task_scheduler_);
152*635a8641SAndroid Build Coastguard Worker   // Without FlushForTesting(), DeleteSoon() and ReleaseSoon() tasks could be
153*635a8641SAndroid Build Coastguard Worker   // skipped, resulting in memory leaks.
154*635a8641SAndroid Build Coastguard Worker   task_tracker_->AllowRunTasks();
155*635a8641SAndroid Build Coastguard Worker   TaskScheduler::GetInstance()->FlushForTesting();
156*635a8641SAndroid Build Coastguard Worker   TaskScheduler::GetInstance()->Shutdown();
157*635a8641SAndroid Build Coastguard Worker   TaskScheduler::GetInstance()->JoinForTesting();
158*635a8641SAndroid Build Coastguard Worker   // Destroying TaskScheduler state can result in waiting on worker threads.
159*635a8641SAndroid Build Coastguard Worker   // Make sure this is allowed to avoid flaking tests that have disallowed waits
160*635a8641SAndroid Build Coastguard Worker   // on their main thread.
161*635a8641SAndroid Build Coastguard Worker   ScopedAllowBaseSyncPrimitivesForTesting allow_waits_to_destroy_task_tracker;
162*635a8641SAndroid Build Coastguard Worker   TaskScheduler::SetInstance(nullptr);
163*635a8641SAndroid Build Coastguard Worker }
164*635a8641SAndroid Build Coastguard Worker 
165*635a8641SAndroid Build Coastguard Worker scoped_refptr<base::SingleThreadTaskRunner>
GetMainThreadTaskRunner()166*635a8641SAndroid Build Coastguard Worker ScopedTaskEnvironment::GetMainThreadTaskRunner() {
167*635a8641SAndroid Build Coastguard Worker   if (message_loop_)
168*635a8641SAndroid Build Coastguard Worker     return message_loop_->task_runner();
169*635a8641SAndroid Build Coastguard Worker   DCHECK(mock_time_task_runner_);
170*635a8641SAndroid Build Coastguard Worker   return mock_time_task_runner_;
171*635a8641SAndroid Build Coastguard Worker }
172*635a8641SAndroid Build Coastguard Worker 
MainThreadHasPendingTask() const173*635a8641SAndroid Build Coastguard Worker bool ScopedTaskEnvironment::MainThreadHasPendingTask() const {
174*635a8641SAndroid Build Coastguard Worker   if (message_loop_)
175*635a8641SAndroid Build Coastguard Worker     return !message_loop_->IsIdleForTesting();
176*635a8641SAndroid Build Coastguard Worker   DCHECK(mock_time_task_runner_);
177*635a8641SAndroid Build Coastguard Worker   return mock_time_task_runner_->HasPendingTask();
178*635a8641SAndroid Build Coastguard Worker }
179*635a8641SAndroid Build Coastguard Worker 
RunUntilIdle()180*635a8641SAndroid Build Coastguard Worker void ScopedTaskEnvironment::RunUntilIdle() {
181*635a8641SAndroid Build Coastguard Worker   // TODO(gab): This can be heavily simplified to essentially:
182*635a8641SAndroid Build Coastguard Worker   //     bool HasMainThreadTasks() {
183*635a8641SAndroid Build Coastguard Worker   //      if (message_loop_)
184*635a8641SAndroid Build Coastguard Worker   //        return !message_loop_->IsIdleForTesting();
185*635a8641SAndroid Build Coastguard Worker   //      return mock_time_task_runner_->NextPendingTaskDelay().is_zero();
186*635a8641SAndroid Build Coastguard Worker   //     }
187*635a8641SAndroid Build Coastguard Worker   //     while (task_tracker_->HasIncompleteTasks() || HasMainThreadTasks()) {
188*635a8641SAndroid Build Coastguard Worker   //       base::RunLoop().RunUntilIdle();
189*635a8641SAndroid Build Coastguard Worker   //       // Avoid busy-looping.
190*635a8641SAndroid Build Coastguard Worker   //       if (task_tracker_->HasIncompleteTasks())
191*635a8641SAndroid Build Coastguard Worker   //         PlatformThread::Sleep(TimeDelta::FromMilliSeconds(1));
192*635a8641SAndroid Build Coastguard Worker   //     }
193*635a8641SAndroid Build Coastguard Worker   // Challenge: HasMainThreadTasks() requires support for proper
194*635a8641SAndroid Build Coastguard Worker   // IncomingTaskQueue::IsIdleForTesting() (check all queues).
195*635a8641SAndroid Build Coastguard Worker   //
196*635a8641SAndroid Build Coastguard Worker   // Other than that it works because once |task_tracker_->HasIncompleteTasks()|
197*635a8641SAndroid Build Coastguard Worker   // is false we know for sure that the only thing that can make it true is a
198*635a8641SAndroid Build Coastguard Worker   // main thread task (ScopedTaskEnvironment owns all the threads). As such we
199*635a8641SAndroid Build Coastguard Worker   // can't racily see it as false on the main thread and be wrong as if it the
200*635a8641SAndroid Build Coastguard Worker   // main thread sees the atomic count at zero, it's the only one that can make
201*635a8641SAndroid Build Coastguard Worker   // it go up. And the only thing that can make it go up on the main thread are
202*635a8641SAndroid Build Coastguard Worker   // main thread tasks and therefore we're done if there aren't any left.
203*635a8641SAndroid Build Coastguard Worker   //
204*635a8641SAndroid Build Coastguard Worker   // This simplification further allows simplification of DisallowRunTasks().
205*635a8641SAndroid Build Coastguard Worker   //
206*635a8641SAndroid Build Coastguard Worker   // This can also be simplified even further once TaskTracker becomes directly
207*635a8641SAndroid Build Coastguard Worker   // aware of main thread tasks. https://crbug.com/660078.
208*635a8641SAndroid Build Coastguard Worker 
209*635a8641SAndroid Build Coastguard Worker   for (;;) {
210*635a8641SAndroid Build Coastguard Worker     task_tracker_->AllowRunTasks();
211*635a8641SAndroid Build Coastguard Worker 
212*635a8641SAndroid Build Coastguard Worker     // First run as many tasks as possible on the main thread in parallel with
213*635a8641SAndroid Build Coastguard Worker     // tasks in TaskScheduler. This increases likelihood of TSAN catching
214*635a8641SAndroid Build Coastguard Worker     // threading errors and eliminates possibility of hangs should a
215*635a8641SAndroid Build Coastguard Worker     // TaskScheduler task synchronously block on a main thread task
216*635a8641SAndroid Build Coastguard Worker     // (TaskScheduler::FlushForTesting() can't be used here for that reason).
217*635a8641SAndroid Build Coastguard Worker     RunLoop().RunUntilIdle();
218*635a8641SAndroid Build Coastguard Worker 
219*635a8641SAndroid Build Coastguard Worker     // Then halt TaskScheduler. DisallowRunTasks() failing indicates that there
220*635a8641SAndroid Build Coastguard Worker     // were TaskScheduler tasks currently running. In that case, try again from
221*635a8641SAndroid Build Coastguard Worker     // top when DisallowRunTasks() yields control back to this thread as they
222*635a8641SAndroid Build Coastguard Worker     // may have posted main thread tasks.
223*635a8641SAndroid Build Coastguard Worker     if (!task_tracker_->DisallowRunTasks())
224*635a8641SAndroid Build Coastguard Worker       continue;
225*635a8641SAndroid Build Coastguard Worker 
226*635a8641SAndroid Build Coastguard Worker     // Once TaskScheduler is halted. Run any remaining main thread tasks (which
227*635a8641SAndroid Build Coastguard Worker     // may have been posted by TaskScheduler tasks that completed between the
228*635a8641SAndroid Build Coastguard Worker     // above main thread RunUntilIdle() and TaskScheduler DisallowRunTasks()).
229*635a8641SAndroid Build Coastguard Worker     // Note: this assumes that no main thread task synchronously blocks on a
230*635a8641SAndroid Build Coastguard Worker     // TaskScheduler tasks (it certainly shouldn't); this call could otherwise
231*635a8641SAndroid Build Coastguard Worker     // hang.
232*635a8641SAndroid Build Coastguard Worker     RunLoop().RunUntilIdle();
233*635a8641SAndroid Build Coastguard Worker 
234*635a8641SAndroid Build Coastguard Worker     // The above RunUntilIdle() guarantees there are no remaining main thread
235*635a8641SAndroid Build Coastguard Worker     // tasks (the TaskScheduler being halted during the last RunUntilIdle() is
236*635a8641SAndroid Build Coastguard Worker     // key as it prevents a task being posted to it racily with it determining
237*635a8641SAndroid Build Coastguard Worker     // it had no work remaining). Therefore, we're done if there is no more work
238*635a8641SAndroid Build Coastguard Worker     // on TaskScheduler either (there can be TaskScheduler work remaining if
239*635a8641SAndroid Build Coastguard Worker     // DisallowRunTasks() preempted work and/or the last RunUntilIdle() posted
240*635a8641SAndroid Build Coastguard Worker     // more TaskScheduler tasks).
241*635a8641SAndroid Build Coastguard Worker     // Note: this last |if| couldn't be turned into a |do {} while();|. A
242*635a8641SAndroid Build Coastguard Worker     // conditional loop makes it such that |continue;| results in checking the
243*635a8641SAndroid Build Coastguard Worker     // condition (not unconditionally loop again) which would be incorrect for
244*635a8641SAndroid Build Coastguard Worker     // the above logic as it'd then be possible for a TaskScheduler task to be
245*635a8641SAndroid Build Coastguard Worker     // running during the DisallowRunTasks() test, causing it to fail, but then
246*635a8641SAndroid Build Coastguard Worker     // post to the main thread and complete before the loop's condition is
247*635a8641SAndroid Build Coastguard Worker     // verified which could result in HasIncompleteUndelayedTasksForTesting()
248*635a8641SAndroid Build Coastguard Worker     // returning false and the loop erroneously exiting with a pending task on
249*635a8641SAndroid Build Coastguard Worker     // the main thread.
250*635a8641SAndroid Build Coastguard Worker     if (!task_tracker_->HasIncompleteUndelayedTasksForTesting())
251*635a8641SAndroid Build Coastguard Worker       break;
252*635a8641SAndroid Build Coastguard Worker   }
253*635a8641SAndroid Build Coastguard Worker 
254*635a8641SAndroid Build Coastguard Worker   // The above loop always ends with running tasks being disallowed. Re-enable
255*635a8641SAndroid Build Coastguard Worker   // parallel execution before returning unless in ExecutionMode::QUEUED.
256*635a8641SAndroid Build Coastguard Worker   if (execution_control_mode_ != ExecutionMode::QUEUED)
257*635a8641SAndroid Build Coastguard Worker     task_tracker_->AllowRunTasks();
258*635a8641SAndroid Build Coastguard Worker }
259*635a8641SAndroid Build Coastguard Worker 
FastForwardBy(TimeDelta delta)260*635a8641SAndroid Build Coastguard Worker void ScopedTaskEnvironment::FastForwardBy(TimeDelta delta) {
261*635a8641SAndroid Build Coastguard Worker   DCHECK(mock_time_task_runner_);
262*635a8641SAndroid Build Coastguard Worker   mock_time_task_runner_->FastForwardBy(delta);
263*635a8641SAndroid Build Coastguard Worker }
264*635a8641SAndroid Build Coastguard Worker 
FastForwardUntilNoTasksRemain()265*635a8641SAndroid Build Coastguard Worker void ScopedTaskEnvironment::FastForwardUntilNoTasksRemain() {
266*635a8641SAndroid Build Coastguard Worker   DCHECK(mock_time_task_runner_);
267*635a8641SAndroid Build Coastguard Worker   mock_time_task_runner_->FastForwardUntilNoTasksRemain();
268*635a8641SAndroid Build Coastguard Worker }
269*635a8641SAndroid Build Coastguard Worker 
GetMockTickClock()270*635a8641SAndroid Build Coastguard Worker const TickClock* ScopedTaskEnvironment::GetMockTickClock() {
271*635a8641SAndroid Build Coastguard Worker   DCHECK(mock_time_task_runner_);
272*635a8641SAndroid Build Coastguard Worker   return mock_time_task_runner_->GetMockTickClock();
273*635a8641SAndroid Build Coastguard Worker }
274*635a8641SAndroid Build Coastguard Worker 
DeprecatedGetMockTickClock()275*635a8641SAndroid Build Coastguard Worker std::unique_ptr<TickClock> ScopedTaskEnvironment::DeprecatedGetMockTickClock() {
276*635a8641SAndroid Build Coastguard Worker   DCHECK(mock_time_task_runner_);
277*635a8641SAndroid Build Coastguard Worker   return mock_time_task_runner_->DeprecatedGetMockTickClock();
278*635a8641SAndroid Build Coastguard Worker }
279*635a8641SAndroid Build Coastguard Worker 
GetPendingMainThreadTaskCount() const280*635a8641SAndroid Build Coastguard Worker size_t ScopedTaskEnvironment::GetPendingMainThreadTaskCount() const {
281*635a8641SAndroid Build Coastguard Worker   DCHECK(mock_time_task_runner_);
282*635a8641SAndroid Build Coastguard Worker   return mock_time_task_runner_->GetPendingTaskCount();
283*635a8641SAndroid Build Coastguard Worker }
284*635a8641SAndroid Build Coastguard Worker 
NextMainThreadPendingTaskDelay() const285*635a8641SAndroid Build Coastguard Worker TimeDelta ScopedTaskEnvironment::NextMainThreadPendingTaskDelay() const {
286*635a8641SAndroid Build Coastguard Worker   DCHECK(mock_time_task_runner_);
287*635a8641SAndroid Build Coastguard Worker   return mock_time_task_runner_->NextPendingTaskDelay();
288*635a8641SAndroid Build Coastguard Worker }
289*635a8641SAndroid Build Coastguard Worker 
TestTaskTracker()290*635a8641SAndroid Build Coastguard Worker ScopedTaskEnvironment::TestTaskTracker::TestTaskTracker()
291*635a8641SAndroid Build Coastguard Worker     : internal::TaskSchedulerImpl::TaskTrackerImpl("ScopedTaskEnvironment"),
292*635a8641SAndroid Build Coastguard Worker       can_run_tasks_cv_(&lock_),
293*635a8641SAndroid Build Coastguard Worker       task_completed_(&lock_) {}
294*635a8641SAndroid Build Coastguard Worker 
AllowRunTasks()295*635a8641SAndroid Build Coastguard Worker void ScopedTaskEnvironment::TestTaskTracker::AllowRunTasks() {
296*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(lock_);
297*635a8641SAndroid Build Coastguard Worker   can_run_tasks_ = true;
298*635a8641SAndroid Build Coastguard Worker   can_run_tasks_cv_.Broadcast();
299*635a8641SAndroid Build Coastguard Worker }
300*635a8641SAndroid Build Coastguard Worker 
DisallowRunTasks()301*635a8641SAndroid Build Coastguard Worker bool ScopedTaskEnvironment::TestTaskTracker::DisallowRunTasks() {
302*635a8641SAndroid Build Coastguard Worker   AutoLock auto_lock(lock_);
303*635a8641SAndroid Build Coastguard Worker 
304*635a8641SAndroid Build Coastguard Worker   // Can't disallow run task if there are tasks running.
305*635a8641SAndroid Build Coastguard Worker   if (num_tasks_running_ > 0) {
306*635a8641SAndroid Build Coastguard Worker     // Attempt to wait a bit so that the caller doesn't busy-loop with the same
307*635a8641SAndroid Build Coastguard Worker     // set of pending work. A short wait is required to avoid deadlock
308*635a8641SAndroid Build Coastguard Worker     // scenarios. See DisallowRunTasks()'s declaration for more details.
309*635a8641SAndroid Build Coastguard Worker     task_completed_.TimedWait(TimeDelta::FromMilliseconds(1));
310*635a8641SAndroid Build Coastguard Worker     return false;
311*635a8641SAndroid Build Coastguard Worker   }
312*635a8641SAndroid Build Coastguard Worker 
313*635a8641SAndroid Build Coastguard Worker   can_run_tasks_ = false;
314*635a8641SAndroid Build Coastguard Worker   return true;
315*635a8641SAndroid Build Coastguard Worker }
316*635a8641SAndroid Build Coastguard Worker 
RunOrSkipTask(internal::Task task,internal::Sequence * sequence,bool can_run_task)317*635a8641SAndroid Build Coastguard Worker void ScopedTaskEnvironment::TestTaskTracker::RunOrSkipTask(
318*635a8641SAndroid Build Coastguard Worker     internal::Task task,
319*635a8641SAndroid Build Coastguard Worker     internal::Sequence* sequence,
320*635a8641SAndroid Build Coastguard Worker     bool can_run_task) {
321*635a8641SAndroid Build Coastguard Worker   {
322*635a8641SAndroid Build Coastguard Worker     AutoLock auto_lock(lock_);
323*635a8641SAndroid Build Coastguard Worker 
324*635a8641SAndroid Build Coastguard Worker     while (!can_run_tasks_)
325*635a8641SAndroid Build Coastguard Worker       can_run_tasks_cv_.Wait();
326*635a8641SAndroid Build Coastguard Worker 
327*635a8641SAndroid Build Coastguard Worker     ++num_tasks_running_;
328*635a8641SAndroid Build Coastguard Worker   }
329*635a8641SAndroid Build Coastguard Worker 
330*635a8641SAndroid Build Coastguard Worker   internal::TaskSchedulerImpl::TaskTrackerImpl::RunOrSkipTask(
331*635a8641SAndroid Build Coastguard Worker       std::move(task), sequence, can_run_task);
332*635a8641SAndroid Build Coastguard Worker 
333*635a8641SAndroid Build Coastguard Worker   {
334*635a8641SAndroid Build Coastguard Worker     AutoLock auto_lock(lock_);
335*635a8641SAndroid Build Coastguard Worker 
336*635a8641SAndroid Build Coastguard Worker     CHECK_GT(num_tasks_running_, 0);
337*635a8641SAndroid Build Coastguard Worker     CHECK(can_run_tasks_);
338*635a8641SAndroid Build Coastguard Worker 
339*635a8641SAndroid Build Coastguard Worker     --num_tasks_running_;
340*635a8641SAndroid Build Coastguard Worker 
341*635a8641SAndroid Build Coastguard Worker     task_completed_.Broadcast();
342*635a8641SAndroid Build Coastguard Worker   }
343*635a8641SAndroid Build Coastguard Worker }
344*635a8641SAndroid Build Coastguard Worker 
345*635a8641SAndroid Build Coastguard Worker }  // namespace test
346*635a8641SAndroid Build Coastguard Worker }  // namespace base
347