| OLD | NEW |
| 1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "base/task_scheduler/scheduler_worker_thread.h" | 5 #include "base/task_scheduler/scheduler_worker_thread.h" |
| 6 | 6 |
| 7 #include <stddef.h> | 7 #include <stddef.h> |
| 8 | 8 |
| 9 #include <memory> | 9 #include <memory> |
| 10 #include <vector> | 10 #include <vector> |
| 11 | 11 |
| 12 #include "base/bind.h" | 12 #include "base/bind.h" |
| 13 #include "base/bind_helpers.h" | 13 #include "base/bind_helpers.h" |
| 14 #include "base/macros.h" | 14 #include "base/macros.h" |
| 15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
| 16 #include "base/synchronization/condition_variable.h" | 16 #include "base/synchronization/condition_variable.h" |
| 17 #include "base/task_scheduler/delayed_task_manager.h" |
| 18 #include "base/task_scheduler/priority_queue.h" |
| 17 #include "base/task_scheduler/scheduler_lock.h" | 19 #include "base/task_scheduler/scheduler_lock.h" |
| 18 #include "base/task_scheduler/sequence.h" | 20 #include "base/task_scheduler/sequence.h" |
| 19 #include "base/task_scheduler/task.h" | 21 #include "base/task_scheduler/task.h" |
| 20 #include "base/task_scheduler/task_tracker.h" | 22 #include "base/task_scheduler/task_tracker.h" |
| 21 #include "testing/gtest/include/gtest/gtest.h" | 23 #include "testing/gtest/include/gtest/gtest.h" |
| 22 | 24 |
| 23 namespace base { | 25 namespace base { |
| 24 namespace internal { | 26 namespace internal { |
| 25 namespace { | 27 namespace { |
| 26 | 28 |
| 27 const size_t kNumSequencesPerTest = 150; | 29 constexpr size_t kNumTasksPerTest = 150; |
| 28 | 30 |
| 29 // The test parameter is the number of Tasks per Sequence returned by GetWork(). | 31 // The test parameter is the number of Tasks per Sequence returned by GetWork(). |
| 30 class TaskSchedulerWorkerThreadTest : public testing::TestWithParam<size_t>, | 32 class TaskSchedulerWorkerThreadDelegateWorkTest |
| 31 public SchedulerWorkerThread::Delegate { | 33 : public testing::TestWithParam<size_t>, |
| 34 public SchedulerWorkerThread::Delegate { |
| 32 protected: | 35 protected: |
| 33 TaskSchedulerWorkerThreadTest() | 36 TaskSchedulerWorkerThreadDelegateWorkTest() |
| 34 : main_entry_called_(true, false), | 37 : delayed_task_manager_(Bind(&DoNothing)), |
| 38 main_entry_called_(true, false), |
| 35 num_get_work_cv_(lock_.CreateConditionVariable()) {} | 39 num_get_work_cv_(lock_.CreateConditionVariable()) {} |
| 36 | 40 |
| 37 void SetUp() override { | 41 void SetUp() override { |
| 38 worker_thread_ = SchedulerWorkerThread::CreateSchedulerWorkerThread( | 42 worker_thread_ = SchedulerWorkerThread::CreateSchedulerWorkerThread( |
| 39 ThreadPriority::NORMAL, this, &task_tracker_); | 43 ThreadPriority::NORMAL, this, &task_tracker_, &delayed_task_manager_, |
| 44 &dummy_priority_queue_); |
| 40 ASSERT_TRUE(worker_thread_); | 45 ASSERT_TRUE(worker_thread_); |
| 41 main_entry_called_.Wait(); | 46 main_entry_called_.Wait(); |
| 42 } | 47 } |
| 43 | 48 |
| 44 void TearDown() override { | 49 void TearDown() override { |
| 45 worker_thread_->JoinForTesting(); | 50 worker_thread_->JoinForTesting(); |
| 46 } | 51 } |
| 47 | 52 |
| 48 size_t TasksPerSequence() const { return GetParam(); } | 53 size_t TasksPerSequence() const { return GetParam(); } |
| 49 | 54 |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 86 // SchedulerWorkerThread::Delegate: | 91 // SchedulerWorkerThread::Delegate: |
| 87 void OnMainEntry() override { | 92 void OnMainEntry() override { |
| 88 // Without this |auto_lock|, OnMainEntry() could be called twice without | 93 // Without this |auto_lock|, OnMainEntry() could be called twice without |
| 89 // generating an error. | 94 // generating an error. |
| 90 AutoSchedulerLock auto_lock(lock_); | 95 AutoSchedulerLock auto_lock(lock_); |
| 91 EXPECT_FALSE(main_entry_called_.IsSignaled()); | 96 EXPECT_FALSE(main_entry_called_.IsSignaled()); |
| 92 main_entry_called_.Signal(); | 97 main_entry_called_.Signal(); |
| 93 } | 98 } |
| 94 | 99 |
| 95 scoped_refptr<Sequence> GetWork( | 100 scoped_refptr<Sequence> GetWork( |
| 96 SchedulerWorkerThread* worker_thread) override { | 101 SchedulerWorkerThread* worker_thread, |
| 102 PriorityQueue* alternate_priority_queue, |
| 103 bool* alternate_priority_queue_used) override { |
| 97 EXPECT_EQ(worker_thread_.get(), worker_thread); | 104 EXPECT_EQ(worker_thread_.get(), worker_thread); |
| 98 | 105 |
| 99 { | 106 { |
| 100 AutoSchedulerLock auto_lock(lock_); | 107 AutoSchedulerLock auto_lock(lock_); |
| 101 | 108 |
| 102 // Increment the number of times that this method has been called. | 109 // Increment the number of times that this method has been called. |
| 103 ++num_get_work_; | 110 ++num_get_work_; |
| 104 num_get_work_cv_->Signal(); | 111 num_get_work_cv_->Signal(); |
| 105 | 112 |
| 106 // Verify that this method isn't called more times than expected. | 113 // Verify that this method isn't called more times than expected. |
| 107 EXPECT_LE(num_get_work_, max_get_work_); | 114 EXPECT_LE(num_get_work_, max_get_work_); |
| 108 | 115 |
| 109 // Check if a Sequence should be returned. | 116 // Check if a Sequence should be returned. |
| 110 if (num_sequences_to_create_ == 0) | 117 if (num_sequences_to_create_ == 0) |
| 111 return nullptr; | 118 return nullptr; |
| 112 --num_sequences_to_create_; | 119 --num_sequences_to_create_; |
| 113 } | 120 } |
| 114 | 121 |
| 115 // Create a Sequence with TasksPerSequence() Tasks. | 122 // Create a Sequence with TasksPerSequence() Tasks. |
| 116 scoped_refptr<Sequence> sequence(new Sequence); | 123 scoped_refptr<Sequence> sequence(new Sequence); |
| 117 for (size_t i = 0; i < TasksPerSequence(); ++i) { | 124 for (size_t i = 0; i < TasksPerSequence(); ++i) { |
| 118 std::unique_ptr<Task> task(new Task( | 125 std::unique_ptr<Task> task(new Task( |
| 119 FROM_HERE, Bind(&TaskSchedulerWorkerThreadTest::RunTaskCallback, | 126 FROM_HERE, |
| 120 Unretained(this)), | 127 Bind(&TaskSchedulerWorkerThreadDelegateWorkTest::RunTaskCallback, |
| 128 Unretained(this)), |
| 121 TaskTraits(), TimeTicks())); | 129 TaskTraits(), TimeTicks())); |
| 122 EXPECT_TRUE(task_tracker_.WillPostTask(task.get())); | 130 EXPECT_TRUE(task_tracker_.WillPostTask(task.get())); |
| 123 sequence->PushTask(std::move(task)); | 131 sequence->PushTask(std::move(task)); |
| 124 } | 132 } |
| 125 | 133 |
| 126 { | 134 { |
| 127 // Add the Sequence to the vector of created Sequences. | 135 // Add the Sequence to the vector of created Sequences. |
| 128 AutoSchedulerLock auto_lock(lock_); | 136 AutoSchedulerLock auto_lock(lock_); |
| 129 created_sequences_.push_back(sequence); | 137 created_sequences_.push_back(sequence); |
| 130 } | 138 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 152 EXPECT_LE(enqueued_sequences_.size(), created_sequences_.size()); | 160 EXPECT_LE(enqueued_sequences_.size(), created_sequences_.size()); |
| 153 } | 161 } |
| 154 | 162 |
| 155 void RunTaskCallback() { | 163 void RunTaskCallback() { |
| 156 AutoSchedulerLock auto_lock(lock_); | 164 AutoSchedulerLock auto_lock(lock_); |
| 157 ++num_run_tasks_; | 165 ++num_run_tasks_; |
| 158 EXPECT_LE(num_run_tasks_, created_sequences_.size()); | 166 EXPECT_LE(num_run_tasks_, created_sequences_.size()); |
| 159 } | 167 } |
| 160 | 168 |
| 161 TaskTracker task_tracker_; | 169 TaskTracker task_tracker_; |
| 170 DelayedTaskManager delayed_task_manager_; |
| 171 PriorityQueue dummy_priority_queue_; |
| 162 | 172 |
| 163 // Synchronizes access to all members below. | 173 // Synchronizes access to all members below. |
| 164 mutable SchedulerLock lock_; | 174 mutable SchedulerLock lock_; |
| 165 | 175 |
| 166 // Signaled once OnMainEntry() has been called. | 176 // Signaled once OnMainEntry() has been called. |
| 167 WaitableEvent main_entry_called_; | 177 WaitableEvent main_entry_called_; |
| 168 | 178 |
| 169 // Number of Sequences that should be created by GetWork(). When this | 179 // Number of Sequences that should be created by GetWork(). When this |
| 170 // is 0, GetWork() returns nullptr. | 180 // is 0, GetWork() returns nullptr. |
| 171 size_t num_sequences_to_create_ = 0; | 181 size_t num_sequences_to_create_ = 0; |
| 172 | 182 |
| 173 // Number of times that GetWork() has been called. | 183 // Number of times that GetWork() has been called. |
| 174 size_t num_get_work_ = 0; | 184 size_t num_get_work_ = 0; |
| 175 | 185 |
| 176 // Maximum number of times that GetWork() can be called. | 186 // Maximum number of times that GetWork() can be called. |
| 177 size_t max_get_work_ = 0; | 187 size_t max_get_work_ = 0; |
| 178 | 188 |
| 179 // Condition variable signaled when |num_get_work_| is incremented. | 189 // Condition variable signaled when |num_get_work_| is incremented. |
| 180 std::unique_ptr<ConditionVariable> num_get_work_cv_; | 190 std::unique_ptr<ConditionVariable> num_get_work_cv_; |
| 181 | 191 |
| 182 // Sequences created by GetWork(). | 192 // Sequences created by GetWork(). |
| 183 std::vector<scoped_refptr<Sequence>> created_sequences_; | 193 std::vector<scoped_refptr<Sequence>> created_sequences_; |
| 184 | 194 |
| 185 // Sequences passed to EnqueueSequence(). | 195 // Sequences passed to EnqueueSequence(). |
| 186 std::vector<scoped_refptr<Sequence>> enqueued_sequences_; | 196 std::vector<scoped_refptr<Sequence>> enqueued_sequences_; |
| 187 | 197 |
| 188 // Number of times that RunTaskCallback() has been called. | 198 // Number of times that RunTaskCallback() has been called. |
| 189 size_t num_run_tasks_ = 0; | 199 size_t num_run_tasks_ = 0; |
| 190 | 200 |
| 191 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerThreadTest); | 201 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerThreadDelegateWorkTest); |
| 192 }; | 202 }; |
| 193 | 203 |
| 194 // Verify that when GetWork() continuously returns Sequences, all Tasks in these | 204 // Verify that when GetWork() continuously returns Sequences, all Tasks in these |
| 195 // Sequences run successfully. The test wakes up the SchedulerWorkerThread once. | 205 // Sequences run successfully. The test wakes up the SchedulerWorkerThread once. |
| 196 TEST_P(TaskSchedulerWorkerThreadTest, ContinuousWork) { | 206 TEST_P(TaskSchedulerWorkerThreadDelegateWorkTest, ContinuousWork) { |
| 197 // Set GetWork() to return |kNumSequencesPerTest| Sequences before starting to | 207 // Set GetWork() to return |kNumTasksPerTest| Sequences before starting to |
| 198 // return nullptr. | 208 // return nullptr. |
| 199 SetNumSequencesToCreate(kNumSequencesPerTest); | 209 SetNumSequencesToCreate(kNumTasksPerTest); |
| 200 | 210 |
| 201 // Expect |kNumSequencesPerTest| calls to GetWork() in which it returns a | 211 // Expect |kNumTasksPerTest| calls to GetWork() in which it returns a |
| 202 // Sequence and one call in which its returns nullptr. | 212 // Sequence and one call in which its returns nullptr. |
| 203 const size_t kExpectedNumGetWork = kNumSequencesPerTest + 1; | 213 constexpr size_t kExpectedNumGetWork = kNumTasksPerTest + 1; |
| 204 SetMaxGetWork(kExpectedNumGetWork); | 214 SetMaxGetWork(kExpectedNumGetWork); |
| 205 | 215 |
| 206 // Wake up |worker_thread_| and wait until GetWork() has been invoked the | 216 // Wake up |worker_thread_| and wait until GetWork() has been invoked the |
| 207 // expected amount of times. | 217 // expected amount of times. |
| 208 worker_thread_->WakeUp(); | 218 worker_thread_->WakeUp(); |
| 209 WaitForNumGetWork(kExpectedNumGetWork); | 219 WaitForNumGetWork(kExpectedNumGetWork); |
| 210 | 220 |
| 211 // All tasks should have run. | 221 // All tasks should have run. |
| 212 EXPECT_EQ(kNumSequencesPerTest, NumRunTasks()); | 222 EXPECT_EQ(kNumTasksPerTest, NumRunTasks()); |
| 213 | 223 |
| 214 // If Sequences returned by GetWork() contain more than one Task, they aren't | 224 // If Sequences returned by GetWork() contain more than one Task, they aren't |
| 215 // empty after the worker thread pops Tasks from them and thus should be | 225 // empty after the worker thread pops Tasks from them and thus should be |
| 216 // returned to EnqueueSequence(). | 226 // returned to EnqueueSequence(). |
| 217 if (TasksPerSequence() > 1) | 227 if (TasksPerSequence() > 1) |
| 218 EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); | 228 EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); |
| 219 else | 229 else |
| 220 EXPECT_TRUE(EnqueuedSequences().empty()); | 230 EXPECT_TRUE(EnqueuedSequences().empty()); |
| 221 } | 231 } |
| 222 | 232 |
| 223 // Verify that when GetWork() alternates between returning a Sequence and | 233 // Verify that when GetWork() alternates between returning a Sequence and |
| 224 // returning nullptr, all Tasks in the returned Sequences run successfully. The | 234 // returning nullptr, all Tasks in the returned Sequences run successfully. The |
| 225 // test wakes up the SchedulerWorkerThread once for each Sequence. | 235 // test wakes up the SchedulerWorkerThread once for each Sequence. |
| 226 TEST_P(TaskSchedulerWorkerThreadTest, IntermittentWork) { | 236 TEST_P(TaskSchedulerWorkerThreadDelegateWorkTest, IntermittentWork) { |
| 227 for (size_t i = 0; i < kNumSequencesPerTest; ++i) { | 237 for (size_t i = 0; i < kNumTasksPerTest; ++i) { |
| 228 // Set GetWork() to return 1 Sequence before starting to return | 238 // Set GetWork() to return 1 Sequence before starting to return |
| 229 // nullptr. | 239 // nullptr. |
| 230 SetNumSequencesToCreate(1); | 240 SetNumSequencesToCreate(1); |
| 231 | 241 |
| 232 // Expect |i + 1| calls to GetWork() in which it returns a Sequence and | 242 // Expect |i + 1| calls to GetWork() in which it returns a Sequence and |
| 233 // |i + 1| calls in which it returns nullptr. | 243 // |i + 1| calls in which it returns nullptr. |
| 234 const size_t expected_num_get_work = 2 * (i + 1); | 244 const size_t expected_num_get_work = 2 * (i + 1); |
| 235 SetMaxGetWork(expected_num_get_work); | 245 SetMaxGetWork(expected_num_get_work); |
| 236 | 246 |
| 237 // Wake up |worker_thread_| and wait until GetWork() has been invoked | 247 // Wake up |worker_thread_| and wait until GetWork() has been invoked |
| 238 // the expected amount of times. | 248 // the expected amount of times. |
| 239 worker_thread_->WakeUp(); | 249 worker_thread_->WakeUp(); |
| 240 WaitForNumGetWork(expected_num_get_work); | 250 WaitForNumGetWork(expected_num_get_work); |
| 241 | 251 |
| 242 // The Task should have run | 252 // The Task should have run |
| 243 EXPECT_EQ(i + 1, NumRunTasks()); | 253 EXPECT_EQ(i + 1, NumRunTasks()); |
| 244 | 254 |
| 245 // If Sequences returned by GetWork() contain more than one Task, they | 255 // If Sequences returned by GetWork() contain more than one Task, they |
| 246 // aren't empty after the worker thread pops Tasks from them and thus should | 256 // aren't empty after the worker thread pops Tasks from them and thus should |
| 247 // be returned to EnqueueSequence(). | 257 // be returned to EnqueueSequence(). |
| 248 if (TasksPerSequence() > 1) | 258 if (TasksPerSequence() > 1) |
| 249 EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); | 259 EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); |
| 250 else | 260 else |
| 251 EXPECT_TRUE(EnqueuedSequences().empty()); | 261 EXPECT_TRUE(EnqueuedSequences().empty()); |
| 252 } | 262 } |
| 253 } | 263 } |
| 254 | 264 |
| 255 INSTANTIATE_TEST_CASE_P(OneTaskPerSequence, | 265 INSTANTIATE_TEST_CASE_P(OneTaskPerSequence, |
| 256 TaskSchedulerWorkerThreadTest, | 266 TaskSchedulerWorkerThreadDelegateWorkTest, |
| 257 ::testing::Values(1)); | 267 ::testing::Values(1)); |
| 258 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, | 268 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, |
| 259 TaskSchedulerWorkerThreadTest, | 269 TaskSchedulerWorkerThreadDelegateWorkTest, |
| 260 ::testing::Values(2)); | 270 ::testing::Values(2)); |
| 261 | 271 |
| 272 class TaskSchedulerWorkerThreadSingleThreadedWorkTest |
| 273 : public testing::Test, |
| 274 public SchedulerWorkerThread::Delegate { |
| 275 protected: |
| 276 TaskSchedulerWorkerThreadSingleThreadedWorkTest() |
| 277 : delayed_task_manager_(Bind(&DoNothing)), |
| 278 num_run_tasks_cv_(lock_.CreateConditionVariable()) {} |
| 279 |
| 280 void SetUp() override { |
| 281 worker_thread_ = SchedulerWorkerThread::CreateSchedulerWorkerThread( |
| 282 ThreadPriority::NORMAL, this, &task_tracker_, &delayed_task_manager_, |
| 283 &dummy_priority_queue_); |
| 284 ASSERT_TRUE(worker_thread_); |
| 285 } |
| 286 |
| 287 void TearDown() override { worker_thread_->JoinForTesting(); } |
| 288 |
| 289 void PostTestTask(scoped_refptr<TaskRunner> task_runner) { |
| 290 size_t task_index; |
| 291 { |
| 292 AutoSchedulerLock auto_lock(lock_); |
| 293 task_index = num_posted_tasks_++; |
| 294 } |
| 295 task_runner->PostTask( |
| 296 FROM_HERE, |
| 297 Bind(&TaskSchedulerWorkerThreadSingleThreadedWorkTest::RunTaskCallback, |
| 298 Unretained(this), task_index, task_runner)); |
| 299 } |
| 300 |
| 301 void WaitForAllTasksToRun() { |
| 302 AutoSchedulerLock auto_lock(lock_); |
| 303 while (num_run_tasks_ < num_posted_tasks_) |
| 304 num_run_tasks_cv_->Wait(); |
| 305 } |
| 306 |
| 307 std::unique_ptr<SchedulerWorkerThread> worker_thread_; |
| 308 |
| 309 private: |
| 310 // SchedulerWorkerThread::Delegate: |
| 311 void OnMainEntry() override {} |
| 312 |
| 313 scoped_refptr<Sequence> GetWork( |
| 314 SchedulerWorkerThread* worker_thread, |
| 315 PriorityQueue* alternate_priority_queue, |
| 316 bool* alternate_priority_queue_used) override { |
| 317 EXPECT_EQ(worker_thread_.get(), worker_thread); |
| 318 |
| 319 // Return a Sequence from |alternate_priority_queue| or nullptr if it is |
| 320 // empty. |
| 321 auto transaction = alternate_priority_queue->BeginTransaction(); |
| 322 auto sequence = transaction->Peek().sequence; |
| 323 if (!sequence) |
| 324 return nullptr; |
| 325 *alternate_priority_queue_used = true; |
| 326 transaction->Pop(); |
| 327 return sequence; |
| 328 } |
| 329 |
| 330 void EnqueueSequence(scoped_refptr<Sequence> sequence) override { |
| 331 ADD_FAILURE() << "EnqueueSequence shouldn't be called in a test that only " |
| 332 "posts single-threaded Tasks."; |
| 333 } |
| 334 |
| 335 void RunTaskCallback(size_t index, scoped_refptr<TaskRunner> task_runner) { |
| 336 AutoSchedulerLock auto_lock(lock_); |
| 337 |
| 338 EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread()); |
| 339 |
| 340 // Verify that tasks run in posting order. |
| 341 EXPECT_EQ(num_run_tasks_, index); |
| 342 |
| 343 // Verify that we don't run more tasks than posted. |
| 344 ++num_run_tasks_; |
| 345 EXPECT_LE(num_run_tasks_, num_posted_tasks_); |
| 346 |
| 347 num_run_tasks_cv_->Signal(); |
| 348 } |
| 349 |
| 350 TaskTracker task_tracker_; |
| 351 DelayedTaskManager delayed_task_manager_; |
| 352 PriorityQueue dummy_priority_queue_; |
| 353 |
| 354 // Synchronizes access to all members below. |
| 355 mutable SchedulerLock lock_; |
| 356 |
| 357 // Number of tasks posted by PostTestTask(). |
| 358 size_t num_posted_tasks_ = 0; |
| 359 |
| 360 // Number of times that RunTaskCallback() has been called. |
| 361 size_t num_run_tasks_ = 0; |
| 362 |
| 363 // Condition variable signaled when |num_run_tasks_| is incremented. |
| 364 std::unique_ptr<ConditionVariable> num_run_tasks_cv_; |
| 365 |
| 366 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerThreadSingleThreadedWorkTest); |
| 367 }; |
| 368 |
| 369 TEST_F(TaskSchedulerWorkerThreadSingleThreadedWorkTest, ContinuousWork) { |
| 370 auto task_runner = worker_thread_->CreateTaskRunnerWithTraits(TaskTraits()); |
| 371 EXPECT_FALSE(task_runner->RunsTasksOnCurrentThread()); |
| 372 |
| 373 for (size_t i = 0; i < kNumTasksPerTest; ++i) |
| 374 PostTestTask(task_runner); |
| 375 WaitForAllTasksToRun(); |
| 376 } |
| 377 |
| 378 TEST_F(TaskSchedulerWorkerThreadSingleThreadedWorkTest, IntermittentWork) { |
| 379 auto task_runner = worker_thread_->CreateTaskRunnerWithTraits(TaskTraits()); |
| 380 EXPECT_FALSE(task_runner->RunsTasksOnCurrentThread()); |
| 381 |
| 382 for (size_t i = 0; i < kNumTasksPerTest; ++i) { |
| 383 PostTestTask(task_runner); |
| 384 WaitForAllTasksToRun(); |
| 385 } |
| 386 } |
| 387 |
| 262 } // namespace | 388 } // namespace |
| 263 } // namespace internal | 389 } // namespace internal |
| 264 } // namespace base | 390 } // namespace base |
| OLD | NEW |