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