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