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/task_tracker.h" | 5 #include "base/task_scheduler/task_tracker.h" |
6 | 6 |
7 #include <stdint.h> | 7 #include <stdint.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 #include <vector> | 10 #include <vector> |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
70 }; | 70 }; |
71 | 71 |
72 ThreadPostingAndRunningTask(TaskTracker* tracker, | 72 ThreadPostingAndRunningTask(TaskTracker* tracker, |
73 Task* task, | 73 Task* task, |
74 Action action, | 74 Action action, |
75 bool expect_post_succeeds) | 75 bool expect_post_succeeds) |
76 : SimpleThread("ThreadPostingAndRunningTask"), | 76 : SimpleThread("ThreadPostingAndRunningTask"), |
77 tracker_(tracker), | 77 tracker_(tracker), |
78 task_(task), | 78 task_(task), |
79 action_(action), | 79 action_(action), |
80 expect_post_succeeds_(expect_post_succeeds) {} | 80 expect_post_succeeds_(expect_post_succeeds) { |
81 EXPECT_TRUE(task_); | |
82 EXPECT_NE(Action::RUN, action_); | |
gab
2016/10/07 19:51:08
Add a comment around why this constructor is not s
fdoray
2016/10/07 20:30:31
Done.
| |
83 EXPECT_NE(Action::WILL_POST_AND_RUN, action_); | |
84 } | |
85 | |
86 ThreadPostingAndRunningTask(TaskTracker* tracker, | |
87 std::unique_ptr<Task> task, | |
88 Action action, | |
89 bool expect_post_succeeds) | |
90 : SimpleThread("ThreadPostingAndRunningTask"), | |
91 tracker_(tracker), | |
92 task_(task.get()), | |
93 owned_task_(std::move(task)), | |
94 action_(action), | |
95 expect_post_succeeds_(expect_post_succeeds) { | |
96 EXPECT_TRUE(task_); | |
97 } | |
81 | 98 |
82 private: | 99 private: |
83 void Run() override { | 100 void Run() override { |
84 bool post_succeeded = true; | 101 bool post_succeeded = true; |
85 if (action_ == Action::WILL_POST || action_ == Action::WILL_POST_AND_RUN) { | 102 if (action_ == Action::WILL_POST || action_ == Action::WILL_POST_AND_RUN) { |
86 post_succeeded = tracker_->WillPostTask(task_); | 103 post_succeeded = tracker_->WillPostTask(task_); |
87 EXPECT_EQ(expect_post_succeeds_, post_succeeded); | 104 EXPECT_EQ(expect_post_succeeds_, post_succeeded); |
88 } | 105 } |
89 if (post_succeeded && | 106 if (post_succeeded && |
90 (action_ == Action::RUN || action_ == Action::WILL_POST_AND_RUN)) { | 107 (action_ == Action::RUN || action_ == Action::WILL_POST_AND_RUN)) { |
91 tracker_->RunTask(task_, SequenceToken::Create()); | 108 EXPECT_TRUE(owned_task_); |
109 tracker_->RunTask(std::move(owned_task_), SequenceToken::Create()); | |
gab
2016/10/07 19:51:08
#include <utility>
fdoray
2016/10/07 20:30:31
Done.
| |
92 } | 110 } |
93 } | 111 } |
94 | 112 |
95 TaskTracker* const tracker_; | 113 TaskTracker* const tracker_; |
96 Task* const task_; | 114 Task* const task_; |
115 std::unique_ptr<Task> owned_task_; | |
97 const Action action_; | 116 const Action action_; |
98 const bool expect_post_succeeds_; | 117 const bool expect_post_succeeds_; |
99 | 118 |
100 DISALLOW_COPY_AND_ASSIGN(ThreadPostingAndRunningTask); | 119 DISALLOW_COPY_AND_ASSIGN(ThreadPostingAndRunningTask); |
101 }; | 120 }; |
102 | 121 |
103 class ScopedSetSingletonAllowed { | 122 class ScopedSetSingletonAllowed { |
104 public: | 123 public: |
105 ScopedSetSingletonAllowed(bool singleton_allowed) | 124 ScopedSetSingletonAllowed(bool singleton_allowed) |
106 : previous_value_( | 125 : previous_value_( |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
222 } // namespace | 241 } // namespace |
223 | 242 |
224 TEST_P(TaskSchedulerTaskTrackerTest, WillPostAndRunBeforeShutdown) { | 243 TEST_P(TaskSchedulerTaskTrackerTest, WillPostAndRunBeforeShutdown) { |
225 std::unique_ptr<Task> task(CreateTask(GetParam())); | 244 std::unique_ptr<Task> task(CreateTask(GetParam())); |
226 | 245 |
227 // Inform |task_tracker_| that |task| will be posted. | 246 // Inform |task_tracker_| that |task| will be posted. |
228 EXPECT_TRUE(tracker_.WillPostTask(task.get())); | 247 EXPECT_TRUE(tracker_.WillPostTask(task.get())); |
229 | 248 |
230 // Run the task. | 249 // Run the task. |
231 EXPECT_EQ(0U, NumTasksExecuted()); | 250 EXPECT_EQ(0U, NumTasksExecuted()); |
232 EXPECT_TRUE(tracker_.RunTask(task.get(), SequenceToken::Create())); | 251 EXPECT_TRUE(tracker_.RunTask(std::move(task), SequenceToken::Create())); |
233 EXPECT_EQ(1U, NumTasksExecuted()); | 252 EXPECT_EQ(1U, NumTasksExecuted()); |
234 | 253 |
235 // Shutdown() shouldn't block. | 254 // Shutdown() shouldn't block. |
236 tracker_.Shutdown(); | 255 tracker_.Shutdown(); |
237 } | 256 } |
238 | 257 |
239 TEST_P(TaskSchedulerTaskTrackerTest, WillPostAndRunLongTaskBeforeShutdown) { | 258 TEST_P(TaskSchedulerTaskTrackerTest, WillPostAndRunLongTaskBeforeShutdown) { |
240 // Create a task that will block until |event| is signaled. | 259 // Create a task that will block until |event| is signaled. |
241 WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC, | 260 WaitableEvent event(WaitableEvent::ResetPolicy::AUTOMATIC, |
242 WaitableEvent::InitialState::NOT_SIGNALED); | 261 WaitableEvent::InitialState::NOT_SIGNALED); |
243 Task blocked_task(FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&event)), | 262 auto blocked_task = base::MakeUnique<Task>( |
244 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta()); | 263 FROM_HERE, Bind(&WaitableEvent::Wait, Unretained(&event)), |
264 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta()); | |
245 | 265 |
246 // Inform |task_tracker_| that |blocked_task| will be posted. | 266 // Inform |task_tracker_| that |blocked_task| will be posted. |
247 EXPECT_TRUE(tracker_.WillPostTask(&blocked_task)); | 267 EXPECT_TRUE(tracker_.WillPostTask(blocked_task.get())); |
248 | 268 |
249 // Run the task asynchronouly. | 269 // Run the task asynchronouly. |
250 ThreadPostingAndRunningTask thread_running_task( | 270 ThreadPostingAndRunningTask thread_running_task( |
251 &tracker_, &blocked_task, ThreadPostingAndRunningTask::Action::RUN, | 271 &tracker_, std::move(blocked_task), |
252 false); | 272 ThreadPostingAndRunningTask::Action::RUN, false); |
253 thread_running_task.Start(); | 273 thread_running_task.Start(); |
254 | 274 |
255 // Initiate shutdown while the task is running. | 275 // Initiate shutdown while the task is running. |
256 CallShutdownAsync(); | 276 CallShutdownAsync(); |
257 | 277 |
258 if (GetParam() == TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN) { | 278 if (GetParam() == TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN) { |
259 // Shutdown should complete even with a CONTINUE_ON_SHUTDOWN in progress. | 279 // Shutdown should complete even with a CONTINUE_ON_SHUTDOWN in progress. |
260 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); | 280 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); |
261 } else { | 281 } else { |
262 // Shutdown should block with any non CONTINUE_ON_SHUTDOWN task in progress. | 282 // Shutdown should block with any non CONTINUE_ON_SHUTDOWN task in progress. |
(...skipping 21 matching lines...) Expand all Loading... | |
284 EXPECT_TRUE(tracker_.WillPostTask(block_shutdown_task.get())); | 304 EXPECT_TRUE(tracker_.WillPostTask(block_shutdown_task.get())); |
285 | 305 |
286 // Call Shutdown() asynchronously. | 306 // Call Shutdown() asynchronously. |
287 CallShutdownAsync(); | 307 CallShutdownAsync(); |
288 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); | 308 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); |
289 | 309 |
290 // Try to run |task|. It should only run it it's BLOCK_SHUTDOWN. Otherwise it | 310 // Try to run |task|. It should only run it it's BLOCK_SHUTDOWN. Otherwise it |
291 // should be discarded. | 311 // should be discarded. |
292 EXPECT_EQ(0U, NumTasksExecuted()); | 312 EXPECT_EQ(0U, NumTasksExecuted()); |
293 const bool should_run = GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN; | 313 const bool should_run = GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN; |
294 EXPECT_EQ(should_run, tracker_.RunTask(task.get(), SequenceToken::Create())); | 314 EXPECT_EQ(should_run, |
315 tracker_.RunTask(std::move(task), SequenceToken::Create())); | |
295 EXPECT_EQ(should_run ? 1U : 0U, NumTasksExecuted()); | 316 EXPECT_EQ(should_run ? 1U : 0U, NumTasksExecuted()); |
296 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); | 317 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); |
297 | 318 |
298 // Unblock shutdown by running the remaining BLOCK_SHUTDOWN task. | 319 // Unblock shutdown by running the remaining BLOCK_SHUTDOWN task. |
299 EXPECT_TRUE( | 320 EXPECT_TRUE(tracker_.RunTask(std::move(block_shutdown_task), |
300 tracker_.RunTask(block_shutdown_task.get(), SequenceToken::Create())); | 321 SequenceToken::Create())); |
301 EXPECT_EQ(should_run ? 2U : 1U, NumTasksExecuted()); | 322 EXPECT_EQ(should_run ? 2U : 1U, NumTasksExecuted()); |
302 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); | 323 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); |
303 } | 324 } |
304 | 325 |
305 TEST_P(TaskSchedulerTaskTrackerTest, WillPostBeforeShutdownRunAfterShutdown) { | 326 TEST_P(TaskSchedulerTaskTrackerTest, WillPostBeforeShutdownRunAfterShutdown) { |
306 // Inform |task_tracker_| that a task will be posted. | 327 // Inform |task_tracker_| that a task will be posted. |
307 std::unique_ptr<Task> task(CreateTask(GetParam())); | 328 std::unique_ptr<Task> task(CreateTask(GetParam())); |
308 EXPECT_TRUE(tracker_.WillPostTask(task.get())); | 329 EXPECT_TRUE(tracker_.WillPostTask(task.get())); |
309 | 330 |
310 // Call Shutdown() asynchronously. | 331 // Call Shutdown() asynchronously. |
311 CallShutdownAsync(); | 332 CallShutdownAsync(); |
312 EXPECT_EQ(0U, NumTasksExecuted()); | 333 EXPECT_EQ(0U, NumTasksExecuted()); |
313 | 334 |
314 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) { | 335 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) { |
315 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); | 336 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); |
316 | 337 |
317 // Run the task to unblock shutdown. | 338 // Run the task to unblock shutdown. |
318 EXPECT_TRUE(tracker_.RunTask(task.get(), SequenceToken::Create())); | 339 EXPECT_TRUE(tracker_.RunTask(std::move(task), SequenceToken::Create())); |
319 EXPECT_EQ(1U, NumTasksExecuted()); | 340 EXPECT_EQ(1U, NumTasksExecuted()); |
320 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); | 341 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); |
321 | 342 |
322 // It is not possible to test running a BLOCK_SHUTDOWN task posted before | 343 // It is not possible to test running a BLOCK_SHUTDOWN task posted before |
323 // shutdown after shutdown because Shutdown() won't return if there are | 344 // shutdown after shutdown because Shutdown() won't return if there are |
324 // pending BLOCK_SHUTDOWN tasks. | 345 // pending BLOCK_SHUTDOWN tasks. |
325 } else { | 346 } else { |
326 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); | 347 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); |
327 | 348 |
328 // The task shouldn't be allowed to run after shutdown. | 349 // The task shouldn't be allowed to run after shutdown. |
329 EXPECT_FALSE(tracker_.RunTask(task.get(), SequenceToken::Create())); | 350 EXPECT_FALSE(tracker_.RunTask(std::move(task), SequenceToken::Create())); |
330 EXPECT_EQ(0U, NumTasksExecuted()); | 351 EXPECT_EQ(0U, NumTasksExecuted()); |
331 } | 352 } |
332 } | 353 } |
333 | 354 |
334 TEST_P(TaskSchedulerTaskTrackerTest, WillPostAndRunDuringShutdown) { | 355 TEST_P(TaskSchedulerTaskTrackerTest, WillPostAndRunDuringShutdown) { |
335 // Inform |task_tracker_| that a BLOCK_SHUTDOWN task will be posted just to | 356 // Inform |task_tracker_| that a BLOCK_SHUTDOWN task will be posted just to |
336 // block shutdown. | 357 // block shutdown. |
337 std::unique_ptr<Task> block_shutdown_task( | 358 std::unique_ptr<Task> block_shutdown_task( |
338 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); | 359 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); |
339 EXPECT_TRUE(tracker_.WillPostTask(block_shutdown_task.get())); | 360 EXPECT_TRUE(tracker_.WillPostTask(block_shutdown_task.get())); |
340 | 361 |
341 // Call Shutdown() asynchronously. | 362 // Call Shutdown() asynchronously. |
342 CallShutdownAsync(); | 363 CallShutdownAsync(); |
343 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); | 364 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); |
344 | 365 |
345 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) { | 366 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) { |
346 // Inform |task_tracker_| that a BLOCK_SHUTDOWN task will be posted. | 367 // Inform |task_tracker_| that a BLOCK_SHUTDOWN task will be posted. |
347 std::unique_ptr<Task> task(CreateTask(GetParam())); | 368 std::unique_ptr<Task> task(CreateTask(GetParam())); |
348 EXPECT_TRUE(tracker_.WillPostTask(task.get())); | 369 EXPECT_TRUE(tracker_.WillPostTask(task.get())); |
349 | 370 |
350 // Run the BLOCK_SHUTDOWN task. | 371 // Run the BLOCK_SHUTDOWN task. |
351 EXPECT_EQ(0U, NumTasksExecuted()); | 372 EXPECT_EQ(0U, NumTasksExecuted()); |
352 EXPECT_TRUE(tracker_.RunTask(task.get(), SequenceToken::Create())); | 373 EXPECT_TRUE(tracker_.RunTask(std::move(task), SequenceToken::Create())); |
353 EXPECT_EQ(1U, NumTasksExecuted()); | 374 EXPECT_EQ(1U, NumTasksExecuted()); |
354 } else { | 375 } else { |
355 // It shouldn't be allowed to post a non BLOCK_SHUTDOWN task. | 376 // It shouldn't be allowed to post a non BLOCK_SHUTDOWN task. |
356 std::unique_ptr<Task> task(CreateTask(GetParam())); | 377 std::unique_ptr<Task> task(CreateTask(GetParam())); |
357 EXPECT_FALSE(tracker_.WillPostTask(task.get())); | 378 EXPECT_FALSE(tracker_.WillPostTask(task.get())); |
358 | 379 |
359 // Don't try to run the task, because it wasn't allowed to be posted. | 380 // Don't try to run the task, because it wasn't allowed to be posted. |
360 } | 381 } |
361 | 382 |
362 // Unblock shutdown by running |block_shutdown_task|. | 383 // Unblock shutdown by running |block_shutdown_task|. |
363 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); | 384 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); |
364 EXPECT_TRUE( | 385 EXPECT_TRUE(tracker_.RunTask(std::move(block_shutdown_task), |
365 tracker_.RunTask(block_shutdown_task.get(), SequenceToken::Create())); | 386 SequenceToken::Create())); |
366 EXPECT_EQ(GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN ? 2U : 1U, | 387 EXPECT_EQ(GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN ? 2U : 1U, |
367 NumTasksExecuted()); | 388 NumTasksExecuted()); |
368 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); | 389 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); |
369 } | 390 } |
370 | 391 |
371 TEST_P(TaskSchedulerTaskTrackerTest, WillPostAfterShutdown) { | 392 TEST_P(TaskSchedulerTaskTrackerTest, WillPostAfterShutdown) { |
372 tracker_.Shutdown(); | 393 tracker_.Shutdown(); |
373 | 394 |
374 std::unique_ptr<Task> task(CreateTask(GetParam())); | 395 std::unique_ptr<Task> task(CreateTask(GetParam())); |
375 | 396 |
(...skipping 17 matching lines...) Expand all Loading... | |
393 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta())); | 414 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta())); |
394 EXPECT_TRUE(tracker.WillPostTask(task.get())); | 415 EXPECT_TRUE(tracker.WillPostTask(task.get())); |
395 | 416 |
396 // Set the singleton allowed bit to the opposite of what it is expected to be | 417 // Set the singleton allowed bit to the opposite of what it is expected to be |
397 // when |tracker| runs |task| to verify that |tracker| actually sets the | 418 // when |tracker| runs |task| to verify that |tracker| actually sets the |
398 // correct value. | 419 // correct value. |
399 ScopedSetSingletonAllowed scoped_singleton_allowed(!can_use_singletons); | 420 ScopedSetSingletonAllowed scoped_singleton_allowed(!can_use_singletons); |
400 | 421 |
401 // Running the task should fail iff the task isn't allowed to use singletons. | 422 // Running the task should fail iff the task isn't allowed to use singletons. |
402 if (can_use_singletons) { | 423 if (can_use_singletons) { |
403 EXPECT_TRUE(tracker.RunTask(task.get(), SequenceToken::Create())); | 424 EXPECT_TRUE(tracker.RunTask(std::move(task), SequenceToken::Create())); |
404 } else { | 425 } else { |
405 EXPECT_DCHECK_DEATH( | 426 EXPECT_DCHECK_DEATH( |
406 { tracker.RunTask(task.get(), SequenceToken::Create()); }); | 427 { tracker.RunTask(std::move(task), SequenceToken::Create()); }); |
407 } | 428 } |
408 } | 429 } |
409 | 430 |
410 static void RunTaskRunnerHandleVerificationTask( | 431 static void RunTaskRunnerHandleVerificationTask( |
411 TaskTracker* tracker, | 432 TaskTracker* tracker, |
412 std::unique_ptr<Task> verify_task) { | 433 std::unique_ptr<Task> verify_task) { |
413 // Pretend |verify_task| is posted to respect TaskTracker's contract. | 434 // Pretend |verify_task| is posted to respect TaskTracker's contract. |
414 EXPECT_TRUE(tracker->WillPostTask(verify_task.get())); | 435 EXPECT_TRUE(tracker->WillPostTask(verify_task.get())); |
415 | 436 |
416 // Confirm that the test conditions are right (no TaskRunnerHandles set | 437 // Confirm that the test conditions are right (no TaskRunnerHandles set |
417 // already). | 438 // already). |
418 EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); | 439 EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); |
419 EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet()); | 440 EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet()); |
420 | 441 |
421 EXPECT_TRUE(tracker->RunTask(verify_task.get(), SequenceToken::Create())); | 442 EXPECT_TRUE( |
443 tracker->RunTask(std::move(verify_task), SequenceToken::Create())); | |
422 | 444 |
423 // TaskRunnerHandle state is reset outside of task's scope. | 445 // TaskRunnerHandle state is reset outside of task's scope. |
424 EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); | 446 EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); |
425 EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet()); | 447 EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet()); |
426 } | 448 } |
427 | 449 |
428 static void VerifyNoTaskRunnerHandle() { | 450 static void VerifyNoTaskRunnerHandle() { |
429 EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); | 451 EXPECT_FALSE(ThreadTaskRunnerHandle::IsSet()); |
430 EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet()); | 452 EXPECT_FALSE(SequencedTaskRunnerHandle::IsSet()); |
431 } | 453 } |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
491 TEST_P(TaskSchedulerTaskTrackerTest, FlushPendingDelayedTask) { | 513 TEST_P(TaskSchedulerTaskTrackerTest, FlushPendingDelayedTask) { |
492 const Task delayed_task(FROM_HERE, Bind(&DoNothing), | 514 const Task delayed_task(FROM_HERE, Bind(&DoNothing), |
493 TaskTraits().WithShutdownBehavior(GetParam()), | 515 TaskTraits().WithShutdownBehavior(GetParam()), |
494 TimeDelta::FromDays(1)); | 516 TimeDelta::FromDays(1)); |
495 tracker_.WillPostTask(&delayed_task); | 517 tracker_.WillPostTask(&delayed_task); |
496 // Flush() should return even if the delayed task didn't run. | 518 // Flush() should return even if the delayed task didn't run. |
497 tracker_.Flush(); | 519 tracker_.Flush(); |
498 } | 520 } |
499 | 521 |
500 TEST_P(TaskSchedulerTaskTrackerTest, FlushPendingUndelayedTask) { | 522 TEST_P(TaskSchedulerTaskTrackerTest, FlushPendingUndelayedTask) { |
501 const Task undelayed_task(FROM_HERE, Bind(&DoNothing), | 523 auto undelayed_task = base::MakeUnique<Task>( |
502 TaskTraits().WithShutdownBehavior(GetParam()), | 524 FROM_HERE, Bind(&DoNothing), |
503 TimeDelta()); | 525 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta()); |
504 tracker_.WillPostTask(&undelayed_task); | 526 tracker_.WillPostTask(undelayed_task.get()); |
505 | 527 |
506 // Flush() shouldn't return before the undelayed task runs. | 528 // Flush() shouldn't return before the undelayed task runs. |
507 CallFlushAsync(); | 529 CallFlushAsync(); |
508 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | 530 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
509 VERIFY_ASYNC_FLUSH_IN_PROGRESS(); | 531 VERIFY_ASYNC_FLUSH_IN_PROGRESS(); |
510 | 532 |
511 // Flush() should return after the undelayed task runs. | 533 // Flush() should return after the undelayed task runs. |
512 tracker_.RunTask(&undelayed_task, SequenceToken::Create()); | 534 tracker_.RunTask(std::move(undelayed_task), SequenceToken::Create()); |
513 WAIT_FOR_ASYNC_FLUSH_RETURNED(); | 535 WAIT_FOR_ASYNC_FLUSH_RETURNED(); |
514 } | 536 } |
515 | 537 |
516 TEST_P(TaskSchedulerTaskTrackerTest, PostTaskDuringFlush) { | 538 TEST_P(TaskSchedulerTaskTrackerTest, PostTaskDuringFlush) { |
517 const Task undelayed_task(FROM_HERE, Bind(&DoNothing), | 539 auto undelayed_task = base::MakeUnique<Task>( |
518 TaskTraits().WithShutdownBehavior(GetParam()), | 540 FROM_HERE, Bind(&DoNothing), |
519 TimeDelta()); | 541 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta()); |
520 tracker_.WillPostTask(&undelayed_task); | 542 tracker_.WillPostTask(undelayed_task.get()); |
521 | 543 |
522 // Flush() shouldn't return before the undelayed task runs. | 544 // Flush() shouldn't return before the undelayed task runs. |
523 CallFlushAsync(); | 545 CallFlushAsync(); |
524 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | 546 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
525 VERIFY_ASYNC_FLUSH_IN_PROGRESS(); | 547 VERIFY_ASYNC_FLUSH_IN_PROGRESS(); |
526 | 548 |
527 // Simulate posting another undelayed task. | 549 // Simulate posting another undelayed task. |
528 const Task other_undelayed_task(FROM_HERE, Bind(&DoNothing), | 550 auto other_undelayed_task = base::MakeUnique<Task>( |
529 TaskTraits().WithShutdownBehavior(GetParam()), | 551 FROM_HERE, Bind(&DoNothing), |
530 TimeDelta()); | 552 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta()); |
531 tracker_.WillPostTask(&other_undelayed_task); | 553 tracker_.WillPostTask(other_undelayed_task.get()); |
532 | 554 |
533 // Run the first undelayed task. | 555 // Run the first undelayed task. |
534 tracker_.RunTask(&undelayed_task, SequenceToken::Create()); | 556 tracker_.RunTask(std::move(undelayed_task), SequenceToken::Create()); |
535 | 557 |
536 // Flush() shouldn't return before the second undelayed task runs. | 558 // Flush() shouldn't return before the second undelayed task runs. |
537 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | 559 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
538 VERIFY_ASYNC_FLUSH_IN_PROGRESS(); | 560 VERIFY_ASYNC_FLUSH_IN_PROGRESS(); |
539 | 561 |
540 // Flush() should return after the second undelayed task runs. | 562 // Flush() should return after the second undelayed task runs. |
541 tracker_.RunTask(&other_undelayed_task, SequenceToken::Create()); | 563 tracker_.RunTask(std::move(other_undelayed_task), SequenceToken::Create()); |
542 WAIT_FOR_ASYNC_FLUSH_RETURNED(); | 564 WAIT_FOR_ASYNC_FLUSH_RETURNED(); |
543 } | 565 } |
544 | 566 |
545 TEST_P(TaskSchedulerTaskTrackerTest, RunDelayedTaskDuringFlush) { | 567 TEST_P(TaskSchedulerTaskTrackerTest, RunDelayedTaskDuringFlush) { |
546 // Simulate posting a delayed and an undelayed task. | 568 // Simulate posting a delayed and an undelayed task. |
547 const Task delayed_task(FROM_HERE, Bind(&DoNothing), | 569 auto delayed_task = base::MakeUnique<Task>( |
548 TaskTraits().WithShutdownBehavior(GetParam()), | 570 FROM_HERE, Bind(&DoNothing), |
549 TimeDelta::FromDays(1)); | 571 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta::FromDays(1)); |
550 tracker_.WillPostTask(&delayed_task); | 572 tracker_.WillPostTask(delayed_task.get()); |
551 const Task undelayed_task(FROM_HERE, Bind(&DoNothing), | 573 auto undelayed_task = base::MakeUnique<Task>( |
552 TaskTraits().WithShutdownBehavior(GetParam()), | 574 FROM_HERE, Bind(&DoNothing), |
553 TimeDelta()); | 575 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta()); |
554 tracker_.WillPostTask(&undelayed_task); | 576 tracker_.WillPostTask(undelayed_task.get()); |
555 | 577 |
556 // Flush() shouldn't return before the undelayed task runs. | 578 // Flush() shouldn't return before the undelayed task runs. |
557 CallFlushAsync(); | 579 CallFlushAsync(); |
558 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | 580 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
559 VERIFY_ASYNC_FLUSH_IN_PROGRESS(); | 581 VERIFY_ASYNC_FLUSH_IN_PROGRESS(); |
560 | 582 |
561 // Run the delayed task. | 583 // Run the delayed task. |
562 tracker_.RunTask(&delayed_task, SequenceToken::Create()); | 584 tracker_.RunTask(std::move(delayed_task), SequenceToken::Create()); |
563 | 585 |
564 // Flush() shouldn't return since there is still a pending undelayed | 586 // Flush() shouldn't return since there is still a pending undelayed |
565 // task. | 587 // task. |
566 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | 588 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
567 VERIFY_ASYNC_FLUSH_IN_PROGRESS(); | 589 VERIFY_ASYNC_FLUSH_IN_PROGRESS(); |
568 | 590 |
569 // Run the undelayed task. | 591 // Run the undelayed task. |
570 tracker_.RunTask(&undelayed_task, SequenceToken::Create()); | 592 tracker_.RunTask(std::move(undelayed_task), SequenceToken::Create()); |
571 | 593 |
572 // Flush() should now return. | 594 // Flush() should now return. |
573 WAIT_FOR_ASYNC_FLUSH_RETURNED(); | 595 WAIT_FOR_ASYNC_FLUSH_RETURNED(); |
574 } | 596 } |
575 | 597 |
576 TEST_P(TaskSchedulerTaskTrackerTest, FlushAfterShutdown) { | 598 TEST_P(TaskSchedulerTaskTrackerTest, FlushAfterShutdown) { |
577 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) | 599 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) |
578 return; | 600 return; |
579 | 601 |
580 // Simulate posting a task. | 602 // Simulate posting a task. |
581 const Task undelayed_task(FROM_HERE, Bind(&DoNothing), | 603 auto undelayed_task = base::MakeUnique<Task>( |
582 TaskTraits().WithShutdownBehavior(GetParam()), | 604 FROM_HERE, Bind(&DoNothing), |
583 TimeDelta()); | 605 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta()); |
584 tracker_.WillPostTask(&undelayed_task); | 606 tracker_.WillPostTask(undelayed_task.get()); |
585 | 607 |
586 // Shutdown() should return immediately since there are no pending | 608 // Shutdown() should return immediately since there are no pending |
587 // BLOCK_SHUTDOWN tasks. | 609 // BLOCK_SHUTDOWN tasks. |
588 tracker_.Shutdown(); | 610 tracker_.Shutdown(); |
589 | 611 |
590 // Flush() should return immediately after shutdown, even if an | 612 // Flush() should return immediately after shutdown, even if an |
591 // undelayed task hasn't run. | 613 // undelayed task hasn't run. |
592 tracker_.Flush(); | 614 tracker_.Flush(); |
593 } | 615 } |
594 | 616 |
595 TEST_P(TaskSchedulerTaskTrackerTest, ShutdownDuringFlush) { | 617 TEST_P(TaskSchedulerTaskTrackerTest, ShutdownDuringFlush) { |
596 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) | 618 if (GetParam() == TaskShutdownBehavior::BLOCK_SHUTDOWN) |
597 return; | 619 return; |
598 | 620 |
599 // Simulate posting a task. | 621 // Simulate posting a task. |
600 const Task undelayed_task(FROM_HERE, Bind(&DoNothing), | 622 auto undelayed_task = base::MakeUnique<Task>( |
601 TaskTraits().WithShutdownBehavior(GetParam()), | 623 FROM_HERE, Bind(&DoNothing), |
602 TimeDelta()); | 624 TaskTraits().WithShutdownBehavior(GetParam()), TimeDelta()); |
603 tracker_.WillPostTask(&undelayed_task); | 625 tracker_.WillPostTask(undelayed_task.get()); |
604 | 626 |
605 // Flush() shouldn't return before the undelayed task runs or | 627 // Flush() shouldn't return before the undelayed task runs or |
606 // shutdown completes. | 628 // shutdown completes. |
607 CallFlushAsync(); | 629 CallFlushAsync(); |
608 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | 630 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); |
609 VERIFY_ASYNC_FLUSH_IN_PROGRESS(); | 631 VERIFY_ASYNC_FLUSH_IN_PROGRESS(); |
610 | 632 |
611 // Shutdown() should return immediately since there are no pending | 633 // Shutdown() should return immediately since there are no pending |
612 // BLOCK_SHUTDOWN tasks. | 634 // BLOCK_SHUTDOWN tasks. |
613 tracker_.Shutdown(); | 635 tracker_.Shutdown(); |
(...skipping 20 matching lines...) Expand all Loading... | |
634 void ExpectSequenceToken(SequenceToken sequence_token) { | 656 void ExpectSequenceToken(SequenceToken sequence_token) { |
635 EXPECT_EQ(sequence_token, SequenceToken::GetForCurrentThread()); | 657 EXPECT_EQ(sequence_token, SequenceToken::GetForCurrentThread()); |
636 } | 658 } |
637 | 659 |
638 } // namespace | 660 } // namespace |
639 | 661 |
640 // Verify that SequenceToken::GetForCurrentThread() returns the Sequence's token | 662 // Verify that SequenceToken::GetForCurrentThread() returns the Sequence's token |
641 // when a Task runs. | 663 // when a Task runs. |
642 TEST_F(TaskSchedulerTaskTrackerTest, CurrentSequenceToken) { | 664 TEST_F(TaskSchedulerTaskTrackerTest, CurrentSequenceToken) { |
643 const SequenceToken sequence_token(SequenceToken::Create()); | 665 const SequenceToken sequence_token(SequenceToken::Create()); |
644 Task task(FROM_HERE, Bind(&ExpectSequenceToken, sequence_token), TaskTraits(), | 666 auto task = base::MakeUnique<Task>(FROM_HERE, |
645 TimeDelta()); | 667 Bind(&ExpectSequenceToken, sequence_token), |
646 tracker_.WillPostTask(&task); | 668 TaskTraits(), TimeDelta()); |
669 tracker_.WillPostTask(task.get()); | |
647 | 670 |
648 EXPECT_FALSE(SequenceToken::GetForCurrentThread().IsValid()); | 671 EXPECT_FALSE(SequenceToken::GetForCurrentThread().IsValid()); |
649 EXPECT_TRUE(tracker_.RunTask(&task, sequence_token)); | 672 EXPECT_TRUE(tracker_.RunTask(std::move(task), sequence_token)); |
650 EXPECT_FALSE(SequenceToken::GetForCurrentThread().IsValid()); | 673 EXPECT_FALSE(SequenceToken::GetForCurrentThread().IsValid()); |
651 } | 674 } |
652 | 675 |
653 TEST_F(TaskSchedulerTaskTrackerTest, LoadWillPostAndRunBeforeShutdown) { | 676 TEST_F(TaskSchedulerTaskTrackerTest, LoadWillPostAndRunBeforeShutdown) { |
654 // Post and run tasks asynchronously. | 677 // Post and run tasks asynchronously. |
655 std::vector<std::unique_ptr<Task>> tasks; | |
656 std::vector<std::unique_ptr<ThreadPostingAndRunningTask>> threads; | 678 std::vector<std::unique_ptr<ThreadPostingAndRunningTask>> threads; |
657 | 679 |
658 for (size_t i = 0; i < kLoadTestNumIterations; ++i) { | 680 for (size_t i = 0; i < kLoadTestNumIterations; ++i) { |
659 tasks.push_back(CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)); | |
660 threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( | 681 threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( |
661 &tracker_, tasks.back().get(), | 682 &tracker_, CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN), |
662 ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, true)); | 683 ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, true)); |
663 threads.back()->Start(); | 684 threads.back()->Start(); |
664 | 685 |
665 tasks.push_back(CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)); | |
666 threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( | 686 threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( |
667 &tracker_, tasks.back().get(), | 687 &tracker_, CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN), |
668 ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, true)); | 688 ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, true)); |
669 threads.back()->Start(); | 689 threads.back()->Start(); |
670 | 690 |
671 tasks.push_back(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); | |
672 threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( | 691 threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( |
673 &tracker_, tasks.back().get(), | 692 &tracker_, CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN), |
674 ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, true)); | 693 ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, true)); |
675 threads.back()->Start(); | 694 threads.back()->Start(); |
676 } | 695 } |
677 | 696 |
678 for (const auto& thread : threads) | 697 for (const auto& thread : threads) |
679 thread->Join(); | 698 thread->Join(); |
680 | 699 |
681 // Expect all tasks to be executed. | 700 // Expect all tasks to be executed. |
682 EXPECT_EQ(kLoadTestNumIterations * 3, NumTasksExecuted()); | 701 EXPECT_EQ(kLoadTestNumIterations * 3, NumTasksExecuted()); |
683 | 702 |
(...skipping 29 matching lines...) Expand all Loading... | |
713 | 732 |
714 for (const auto& thread : post_threads) | 733 for (const auto& thread : post_threads) |
715 thread->Join(); | 734 thread->Join(); |
716 | 735 |
717 // Call Shutdown() asynchronously. | 736 // Call Shutdown() asynchronously. |
718 CallShutdownAsync(); | 737 CallShutdownAsync(); |
719 | 738 |
720 // Run tasks asynchronously. | 739 // Run tasks asynchronously. |
721 std::vector<std::unique_ptr<ThreadPostingAndRunningTask>> run_threads; | 740 std::vector<std::unique_ptr<ThreadPostingAndRunningTask>> run_threads; |
722 | 741 |
723 for (const auto& task : tasks) { | 742 for (auto& task : tasks) { |
724 run_threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( | 743 run_threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( |
725 &tracker_, task.get(), ThreadPostingAndRunningTask::Action::RUN, | 744 &tracker_, std::move(task), ThreadPostingAndRunningTask::Action::RUN, |
726 false)); | 745 false)); |
727 run_threads.back()->Start(); | 746 run_threads.back()->Start(); |
728 } | 747 } |
729 | 748 |
730 for (const auto& thread : run_threads) | 749 for (const auto& thread : run_threads) |
731 thread->Join(); | 750 thread->Join(); |
732 | 751 |
733 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); | 752 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); |
734 | 753 |
735 // Expect BLOCK_SHUTDOWN tasks to have been executed. | 754 // Expect BLOCK_SHUTDOWN tasks to have been executed. |
736 EXPECT_EQ(kLoadTestNumIterations, NumTasksExecuted()); | 755 EXPECT_EQ(kLoadTestNumIterations, NumTasksExecuted()); |
737 } | 756 } |
738 | 757 |
739 TEST_F(TaskSchedulerTaskTrackerTest, LoadWillPostAndRunDuringShutdown) { | 758 TEST_F(TaskSchedulerTaskTrackerTest, LoadWillPostAndRunDuringShutdown) { |
740 // Inform |task_tracker_| that a BLOCK_SHUTDOWN task will be posted just to | 759 // Inform |task_tracker_| that a BLOCK_SHUTDOWN task will be posted just to |
741 // block shutdown. | 760 // block shutdown. |
742 std::unique_ptr<Task> block_shutdown_task( | 761 std::unique_ptr<Task> block_shutdown_task( |
743 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); | 762 CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); |
744 EXPECT_TRUE(tracker_.WillPostTask(block_shutdown_task.get())); | 763 EXPECT_TRUE(tracker_.WillPostTask(block_shutdown_task.get())); |
745 | 764 |
746 // Call Shutdown() asynchronously. | 765 // Call Shutdown() asynchronously. |
747 CallShutdownAsync(); | 766 CallShutdownAsync(); |
748 | 767 |
749 // Post and run tasks asynchronously. | 768 // Post and run tasks asynchronously. |
750 std::vector<std::unique_ptr<Task>> tasks; | |
751 std::vector<std::unique_ptr<ThreadPostingAndRunningTask>> threads; | 769 std::vector<std::unique_ptr<ThreadPostingAndRunningTask>> threads; |
752 | 770 |
753 for (size_t i = 0; i < kLoadTestNumIterations; ++i) { | 771 for (size_t i = 0; i < kLoadTestNumIterations; ++i) { |
754 tasks.push_back(CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN)); | |
755 threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( | 772 threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( |
756 &tracker_, tasks.back().get(), | 773 &tracker_, CreateTask(TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN), |
757 ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, false)); | 774 ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, false)); |
758 threads.back()->Start(); | 775 threads.back()->Start(); |
759 | 776 |
760 tasks.push_back(CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN)); | |
761 threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( | 777 threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( |
762 &tracker_, tasks.back().get(), | 778 &tracker_, CreateTask(TaskShutdownBehavior::SKIP_ON_SHUTDOWN), |
763 ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, false)); | 779 ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, false)); |
764 threads.back()->Start(); | 780 threads.back()->Start(); |
765 | 781 |
766 tasks.push_back(CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN)); | |
767 threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( | 782 threads.push_back(MakeUnique<ThreadPostingAndRunningTask>( |
768 &tracker_, tasks.back().get(), | 783 &tracker_, CreateTask(TaskShutdownBehavior::BLOCK_SHUTDOWN), |
769 ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, true)); | 784 ThreadPostingAndRunningTask::Action::WILL_POST_AND_RUN, true)); |
770 threads.back()->Start(); | 785 threads.back()->Start(); |
771 } | 786 } |
772 | 787 |
773 for (const auto& thread : threads) | 788 for (const auto& thread : threads) |
774 thread->Join(); | 789 thread->Join(); |
775 | 790 |
776 // Expect BLOCK_SHUTDOWN tasks to have been executed. | 791 // Expect BLOCK_SHUTDOWN tasks to have been executed. |
777 EXPECT_EQ(kLoadTestNumIterations, NumTasksExecuted()); | 792 EXPECT_EQ(kLoadTestNumIterations, NumTasksExecuted()); |
778 | 793 |
779 // Shutdown() shouldn't return before |block_shutdown_task| is executed. | 794 // Shutdown() shouldn't return before |block_shutdown_task| is executed. |
780 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); | 795 VERIFY_ASYNC_SHUTDOWN_IN_PROGRESS(); |
781 | 796 |
782 // Unblock shutdown by running |block_shutdown_task|. | 797 // Unblock shutdown by running |block_shutdown_task|. |
783 EXPECT_TRUE( | 798 EXPECT_TRUE(tracker_.RunTask(std::move(block_shutdown_task), |
784 tracker_.RunTask(block_shutdown_task.get(), SequenceToken::Create())); | 799 SequenceToken::Create())); |
785 EXPECT_EQ(kLoadTestNumIterations + 1, NumTasksExecuted()); | 800 EXPECT_EQ(kLoadTestNumIterations + 1, NumTasksExecuted()); |
786 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); | 801 WAIT_FOR_ASYNC_SHUTDOWN_COMPLETED(); |
787 } | 802 } |
788 | 803 |
789 } // namespace internal | 804 } // namespace internal |
790 } // namespace base | 805 } // namespace base |
OLD | NEW |