Chromium Code Reviews| 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.h" | 5 #include "base/task_scheduler/scheduler_worker.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/memory/ref_counted.h" | |
| 16 #include "base/synchronization/condition_variable.h" | 17 #include "base/synchronization/condition_variable.h" |
| 17 #include "base/synchronization/waitable_event.h" | 18 #include "base/synchronization/waitable_event.h" |
| 18 #include "base/task_scheduler/scheduler_lock.h" | 19 #include "base/task_scheduler/scheduler_lock.h" |
| 19 #include "base/task_scheduler/sequence.h" | 20 #include "base/task_scheduler/sequence.h" |
| 20 #include "base/task_scheduler/task.h" | 21 #include "base/task_scheduler/task.h" |
| 21 #include "base/task_scheduler/task_tracker.h" | 22 #include "base/task_scheduler/task_tracker.h" |
| 23 #include "base/test/test_timeouts.h" | |
| 22 #include "base/threading/platform_thread.h" | 24 #include "base/threading/platform_thread.h" |
| 25 #include "base/threading/simple_thread.h" | |
| 23 #include "base/time/time.h" | 26 #include "base/time/time.h" |
| 24 #include "build/build_config.h" | 27 #include "build/build_config.h" |
| 25 #include "testing/gmock/include/gmock/gmock.h" | 28 #include "testing/gmock/include/gmock/gmock.h" |
| 26 #include "testing/gtest/include/gtest/gtest.h" | 29 #include "testing/gtest/include/gtest/gtest.h" |
| 27 | 30 |
| 28 #if defined(OS_WIN) | 31 #if defined(OS_WIN) |
| 29 #include <objbase.h> | 32 #include <objbase.h> |
| 30 #endif | 33 #endif |
| 31 | 34 |
| 32 using testing::_; | 35 using testing::_; |
| (...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 114 std::vector<scoped_refptr<Sequence>> CreatedSequences() { | 117 std::vector<scoped_refptr<Sequence>> CreatedSequences() { |
| 115 AutoSchedulerLock auto_lock(lock_); | 118 AutoSchedulerLock auto_lock(lock_); |
| 116 return created_sequences_; | 119 return created_sequences_; |
| 117 } | 120 } |
| 118 | 121 |
| 119 std::vector<scoped_refptr<Sequence>> EnqueuedSequences() { | 122 std::vector<scoped_refptr<Sequence>> EnqueuedSequences() { |
| 120 AutoSchedulerLock auto_lock(lock_); | 123 AutoSchedulerLock auto_lock(lock_); |
| 121 return re_enqueued_sequences_; | 124 return re_enqueued_sequences_; |
| 122 } | 125 } |
| 123 | 126 |
| 124 std::unique_ptr<SchedulerWorker> worker_; | 127 scoped_refptr<SchedulerWorker> worker_; |
| 125 | 128 |
| 126 private: | 129 private: |
| 127 class TestSchedulerWorkerDelegate : public SchedulerWorkerDefaultDelegate { | 130 class TestSchedulerWorkerDelegate : public SchedulerWorkerDefaultDelegate { |
| 128 public: | 131 public: |
| 129 TestSchedulerWorkerDelegate(TaskSchedulerWorkerTest* outer) | 132 TestSchedulerWorkerDelegate(TaskSchedulerWorkerTest* outer) |
| 130 : outer_(outer) {} | 133 : outer_(outer) {} |
| 131 | 134 |
| 132 ~TestSchedulerWorkerDelegate() override { | 135 ~TestSchedulerWorkerDelegate() override { |
| 133 EXPECT_FALSE(IsCallToDidRunTaskExpected()); | 136 EXPECT_FALSE(IsCallToDidRunTaskExpected()); |
| 134 } | 137 } |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 348 TaskSchedulerWorkerTest, | 351 TaskSchedulerWorkerTest, |
| 349 ::testing::Values(1)); | 352 ::testing::Values(1)); |
| 350 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, | 353 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, |
| 351 TaskSchedulerWorkerTest, | 354 TaskSchedulerWorkerTest, |
| 352 ::testing::Values(2)); | 355 ::testing::Values(2)); |
| 353 | 356 |
| 354 namespace { | 357 namespace { |
| 355 | 358 |
| 356 class ControllableDetachDelegate : public SchedulerWorkerDefaultDelegate { | 359 class ControllableDetachDelegate : public SchedulerWorkerDefaultDelegate { |
| 357 public: | 360 public: |
| 361 class Controls : public RefCountedThreadSafe<Controls> { | |
| 362 public: | |
| 363 Controls() | |
| 364 : work_running_(WaitableEvent::ResetPolicy::MANUAL, | |
| 365 WaitableEvent::InitialState::SIGNALED), | |
| 366 work_processed_(WaitableEvent::ResetPolicy::MANUAL, | |
| 367 WaitableEvent::InitialState::NOT_SIGNALED), | |
| 368 detach_requested_(WaitableEvent::ResetPolicy::MANUAL, | |
| 369 WaitableEvent::InitialState::NOT_SIGNALED), | |
| 370 detached_(WaitableEvent::ResetPolicy::MANUAL, | |
| 371 WaitableEvent::InitialState::NOT_SIGNALED), | |
| 372 can_detach_block_(WaitableEvent::ResetPolicy::MANUAL, | |
| 373 WaitableEvent::InitialState::SIGNALED), | |
| 374 destroyed_(WaitableEvent::ResetPolicy::MANUAL, | |
| 375 WaitableEvent::InitialState::NOT_SIGNALED) {} | |
| 376 | |
| 377 void HaveWorkBlock() { work_running_.Reset(); } | |
| 378 | |
| 379 void UnblockWork() { work_running_.Signal(); } | |
| 380 | |
| 381 void MakeCanDetachBlock() { can_detach_block_.Reset(); } | |
| 382 | |
| 383 void UnblockCanDetach() { can_detach_block_.Signal(); } | |
| 384 | |
| 385 void WaitForWorkToRun() { work_processed_.Wait(); } | |
| 386 | |
| 387 void WaitForDetachRequest() { detach_requested_.Wait(); } | |
| 388 | |
| 389 void WaitForDetach() { detached_.Wait(); } | |
| 390 | |
| 391 void WaitForDelegateDestroy() { destroyed_.Wait(); } | |
| 392 | |
| 393 void ResetState() { | |
|
fdoray
2017/02/17 16:43:41
Reset all members in order of declaration?
robliao
2017/02/17 19:24:36
Done.
| |
| 394 work_requested_ = false; | |
| 395 work_running_.Signal(); | |
| 396 work_processed_.Reset(); | |
| 397 detach_requested_.Reset(); | |
| 398 can_detach_block_.Signal(); | |
| 399 } | |
| 400 | |
| 401 void set_can_detach(bool can_detach) { can_detach_ = can_detach; } | |
| 402 | |
| 403 private: | |
| 404 friend class ControllableDetachDelegate; | |
| 405 friend class RefCountedThreadSafe<Controls>; | |
| 406 ~Controls() = default; | |
| 407 | |
| 408 WaitableEvent work_running_; | |
| 409 WaitableEvent work_processed_; | |
| 410 WaitableEvent detach_requested_; | |
| 411 WaitableEvent detached_; | |
| 412 WaitableEvent can_detach_block_; | |
| 413 WaitableEvent destroyed_; | |
| 414 | |
| 415 bool can_detach_ = false; | |
| 416 bool work_requested_ = false; | |
| 417 | |
| 418 DISALLOW_COPY_AND_ASSIGN(Controls); | |
| 419 }; | |
| 420 | |
| 358 ControllableDetachDelegate(TaskTracker* task_tracker) | 421 ControllableDetachDelegate(TaskTracker* task_tracker) |
| 359 : task_tracker_(task_tracker), | 422 : task_tracker_(task_tracker), controls_(new Controls()) {} |
| 360 work_processed_(WaitableEvent::ResetPolicy::MANUAL, | |
| 361 WaitableEvent::InitialState::NOT_SIGNALED), | |
| 362 detach_requested_(WaitableEvent::ResetPolicy::MANUAL, | |
| 363 WaitableEvent::InitialState::NOT_SIGNALED), | |
| 364 detached_(WaitableEvent::ResetPolicy::MANUAL, | |
| 365 WaitableEvent::InitialState::NOT_SIGNALED) { | |
| 366 EXPECT_TRUE(task_tracker_); | |
| 367 } | |
| 368 | 423 |
| 369 ~ControllableDetachDelegate() override = default; | 424 ~ControllableDetachDelegate() override { controls_->destroyed_.Signal(); } |
| 370 | |
| 371 // SchedulerWorker::Delegate: | |
| 372 MOCK_METHOD1(OnMainEntry, void(SchedulerWorker* worker)); | |
| 373 | 425 |
| 374 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) | 426 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) |
| 375 override { | 427 override { |
| 376 // Sends one item of work to signal |work_processed_|. On subsequent calls, | 428 // Sends one item of work to signal |work_processed_|. On subsequent calls, |
| 377 // sends nullptr to indicate there's no more work to be done. | 429 // sends nullptr to indicate there's no more work to be done. |
| 378 if (work_requested_) | 430 if (controls_->work_requested_) |
| 379 return nullptr; | 431 return nullptr; |
| 380 | 432 |
| 381 work_requested_ = true; | 433 controls_->work_requested_ = true; |
| 382 scoped_refptr<Sequence> sequence(new Sequence); | 434 scoped_refptr<Sequence> sequence(new Sequence); |
| 383 std::unique_ptr<Task> task(new Task( | 435 std::unique_ptr<Task> task(new Task( |
| 384 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&work_processed_)), | 436 FROM_HERE, |
| 385 TaskTraits(), TimeDelta())); | 437 Bind( |
| 438 [](WaitableEvent* work_processed, WaitableEvent* work_running) { | |
| 439 work_processed->Signal(); | |
| 440 work_running->Wait(); | |
| 441 }, | |
| 442 Unretained(&controls_->work_processed_), | |
| 443 Unretained(&controls_->work_running_)), | |
| 444 TaskTraits().WithBaseSyncPrimitives().WithShutdownBehavior( | |
| 445 TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN), | |
| 446 TimeDelta())); | |
| 386 EXPECT_TRUE(task_tracker_->WillPostTask(task.get())); | 447 EXPECT_TRUE(task_tracker_->WillPostTask(task.get())); |
| 387 sequence->PushTask(std::move(task)); | 448 sequence->PushTask(std::move(task)); |
| 388 return sequence; | 449 return sequence; |
| 389 } | 450 } |
| 390 | 451 |
| 391 void DidRunTask() override {} | 452 void DidRunTask() override {} |
| 392 | 453 |
| 393 bool CanDetach(SchedulerWorker* worker) override { | 454 bool CanDetach(SchedulerWorker* worker) override { |
| 394 detach_requested_.Signal(); | 455 // Saving |can_detach_| now so that callers waiting on |detach_requested_| |
| 395 return can_detach_; | 456 // have the thread go to sleep and then allow detachment. |
| 457 bool can_detach = controls_->can_detach_; | |
| 458 controls_->detach_requested_.Signal(); | |
| 459 controls_->can_detach_block_.Wait(); | |
| 460 return can_detach; | |
| 396 } | 461 } |
| 397 | 462 |
| 398 void OnDetach() override { | 463 void OnDetach() override { |
| 399 EXPECT_TRUE(can_detach_); | 464 EXPECT_TRUE(controls_->can_detach_); |
| 400 EXPECT_TRUE(detach_requested_.IsSignaled()); | 465 EXPECT_TRUE(controls_->detach_requested_.IsSignaled()); |
| 401 detached_.Signal(); | 466 controls_->detached_.Signal(); |
| 402 } | 467 } |
| 403 | 468 |
| 404 void WaitForWorkToRun() { | 469 // ControllableDetachDelegate: |
| 405 work_processed_.Wait(); | 470 scoped_refptr<Controls> controls() { return controls_; } |
| 406 } | |
| 407 | |
| 408 void WaitForDetachRequest() { | |
| 409 detach_requested_.Wait(); | |
| 410 } | |
| 411 | |
| 412 void WaitForDetach() { detached_.Wait(); } | |
| 413 | |
| 414 void ResetState() { | |
| 415 work_requested_ = false; | |
| 416 work_processed_.Reset(); | |
| 417 detach_requested_.Reset(); | |
| 418 } | |
| 419 | |
| 420 void set_can_detach(bool can_detach) { can_detach_ = can_detach; } | |
| 421 | 471 |
| 422 private: | 472 private: |
| 473 scoped_refptr<Sequence> work_sequence_; | |
| 423 TaskTracker* const task_tracker_; | 474 TaskTracker* const task_tracker_; |
| 424 bool work_requested_ = false; | 475 scoped_refptr<Controls> controls_; |
| 425 bool can_detach_ = false; | |
| 426 WaitableEvent work_processed_; | |
| 427 WaitableEvent detach_requested_; | |
| 428 WaitableEvent detached_; | |
| 429 | 476 |
| 430 DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate); | 477 DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate); |
| 431 }; | 478 }; |
| 432 | 479 |
| 480 class MockedControllableDetachDelegate : public ControllableDetachDelegate { | |
| 481 public: | |
| 482 MockedControllableDetachDelegate(TaskTracker* task_tracker) | |
| 483 : ControllableDetachDelegate(task_tracker){}; | |
| 484 ~MockedControllableDetachDelegate() = default; | |
| 485 ; | |
|
fdoray
2017/02/17 16:43:41
extra ;
robliao
2017/02/17 19:24:36
Done.
| |
| 486 | |
| 487 // SchedulerWorker::Delegate: | |
| 488 MOCK_METHOD1(OnMainEntry, void(SchedulerWorker* worker)); | |
| 489 | |
| 490 private: | |
| 491 DISALLOW_COPY_AND_ASSIGN(MockedControllableDetachDelegate); | |
| 492 }; | |
| 493 | |
| 433 } // namespace | 494 } // namespace |
| 434 | 495 |
| 435 TEST(TaskSchedulerWorkerTest, WorkerDetaches) { | 496 TEST(TaskSchedulerWorkerTest, WorkerDetaches) { |
| 436 TaskTracker task_tracker; | 497 TaskTracker task_tracker; |
| 437 // Will be owned by SchedulerWorker. | 498 // Will be owned by SchedulerWorker. |
| 438 ControllableDetachDelegate* delegate = | 499 MockedControllableDetachDelegate* delegate = |
| 439 new StrictMock<ControllableDetachDelegate>(&task_tracker); | 500 new StrictMock<MockedControllableDetachDelegate>(&task_tracker); |
| 440 delegate->set_can_detach(true); | 501 scoped_refptr<ControllableDetachDelegate::Controls> controls = |
| 502 delegate->controls(); | |
| 503 controls->set_can_detach(true); | |
| 441 EXPECT_CALL(*delegate, OnMainEntry(_)); | 504 EXPECT_CALL(*delegate, OnMainEntry(_)); |
| 442 std::unique_ptr<SchedulerWorker> worker = | 505 scoped_refptr<SchedulerWorker> worker = SchedulerWorker::Create( |
| 443 SchedulerWorker::Create( | 506 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, |
| 444 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | 507 SchedulerWorker::InitialState::ALIVE); |
| 445 SchedulerWorker::InitialState::ALIVE); | 508 worker->WakeUp(); |
| 446 worker->WakeUp(); | 509 controls->WaitForWorkToRun(); |
| 447 delegate->WaitForWorkToRun(); | |
| 448 Mock::VerifyAndClear(delegate); | 510 Mock::VerifyAndClear(delegate); |
| 449 delegate->WaitForDetachRequest(); | 511 controls->WaitForDetachRequest(); |
| 450 delegate->WaitForDetach(); | 512 controls->WaitForDetach(); |
| 451 ASSERT_FALSE(worker->ThreadAliveForTesting()); | 513 ASSERT_FALSE(worker->ThreadAliveForTesting()); |
| 452 } | 514 } |
| 453 | 515 |
| 516 TEST(TaskSchedulerWorkerTest, WorkerReleasesBeforeDetach) { | |
| 517 TaskTracker task_tracker; | |
| 518 // Will be owned by SchedulerWorker. | |
| 519 // No mock here as that's reasonably covered by other tests and the delegate | |
| 520 // may destroy on a different thread. Mocks aren't designed with that in mind. | |
| 521 std::unique_ptr<ControllableDetachDelegate> delegate = | |
| 522 MakeUnique<ControllableDetachDelegate>(&task_tracker); | |
| 523 scoped_refptr<ControllableDetachDelegate::Controls> controls = | |
| 524 delegate->controls(); | |
| 525 | |
| 526 controls->set_can_detach(true); | |
| 527 controls->MakeCanDetachBlock(); | |
| 528 | |
| 529 scoped_refptr<SchedulerWorker> worker = SchedulerWorker::Create( | |
| 530 ThreadPriority::NORMAL, std::move(delegate), &task_tracker, | |
| 531 SchedulerWorker::InitialState::ALIVE); | |
| 532 worker->WakeUp(); | |
| 533 | |
| 534 controls->WaitForDetachRequest(); | |
| 535 worker->RequestThreadTermination(); | |
| 536 worker = nullptr; | |
| 537 controls->UnblockCanDetach(); | |
| 538 controls->WaitForDelegateDestroy(); | |
| 539 } | |
| 540 | |
| 541 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndSelfDestroysAfterDetach) { | |
| 542 TaskTracker task_tracker; | |
| 543 // Will be owned by SchedulerWorker. | |
| 544 // No mock here as that's reasonably covered by other tests and the delegate | |
| 545 // may destroy on a different thread. Mocks aren't designed with that in mind. | |
| 546 std::unique_ptr<ControllableDetachDelegate> delegate = | |
| 547 MakeUnique<ControllableDetachDelegate>(&task_tracker); | |
| 548 scoped_refptr<ControllableDetachDelegate::Controls> controls = | |
| 549 delegate->controls(); | |
| 550 | |
| 551 controls->set_can_detach(true); | |
| 552 | |
| 553 scoped_refptr<SchedulerWorker> worker = SchedulerWorker::Create( | |
| 554 ThreadPriority::NORMAL, std::move(delegate), &task_tracker, | |
| 555 SchedulerWorker::InitialState::ALIVE); | |
| 556 worker->WakeUp(); | |
| 557 | |
| 558 controls->WaitForDetach(); | |
| 559 worker->RequestThreadTermination(); | |
| 560 worker = nullptr; | |
| 561 controls->WaitForDelegateDestroy(); | |
| 562 } | |
| 563 | |
| 564 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndSelfDestroysDuringWork) { | |
| 565 TaskTracker task_tracker; | |
| 566 // Will be owned by SchedulerWorker. | |
| 567 // No mock here as that's reasonably covered by other tests and the delegate | |
| 568 // may destroy on a different thread. Mocks aren't designed with that in mind. | |
| 569 std::unique_ptr<ControllableDetachDelegate> delegate = | |
| 570 MakeUnique<ControllableDetachDelegate>(&task_tracker); | |
| 571 scoped_refptr<ControllableDetachDelegate::Controls> controls = | |
| 572 delegate->controls(); | |
| 573 | |
| 574 controls->set_can_detach(true); | |
| 575 controls->HaveWorkBlock(); | |
| 576 | |
| 577 scoped_refptr<SchedulerWorker> worker = SchedulerWorker::Create( | |
| 578 ThreadPriority::NORMAL, std::move(delegate), &task_tracker, | |
| 579 SchedulerWorker::InitialState::ALIVE); | |
| 580 worker->WakeUp(); | |
| 581 | |
| 582 controls->WaitForWorkToRun(); | |
| 583 worker->RequestThreadTermination(); | |
| 584 worker = nullptr; | |
| 585 controls->UnblockWork(); | |
| 586 controls->WaitForDelegateDestroy(); | |
| 587 } | |
| 588 | |
| 589 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndSelfDestroysDuringWait) { | |
| 590 TaskTracker task_tracker; | |
| 591 // Will be owned by SchedulerWorker. | |
| 592 // No mock here as that's reasonably covered by other tests and the delegate | |
| 593 // may destroy on a different thread. Mocks aren't designed with that in mind. | |
| 594 std::unique_ptr<ControllableDetachDelegate> delegate = | |
| 595 MakeUnique<ControllableDetachDelegate>(&task_tracker); | |
| 596 scoped_refptr<ControllableDetachDelegate::Controls> controls = | |
| 597 delegate->controls(); | |
| 598 | |
| 599 scoped_refptr<SchedulerWorker> worker = SchedulerWorker::Create( | |
| 600 ThreadPriority::NORMAL, std::move(delegate), &task_tracker, | |
| 601 SchedulerWorker::InitialState::ALIVE); | |
| 602 worker->WakeUp(); | |
| 603 | |
| 604 controls->WaitForDetachRequest(); | |
| 605 controls->set_can_detach(true); | |
| 606 worker->RequestThreadTermination(); | |
| 607 worker = nullptr; | |
| 608 controls->WaitForDelegateDestroy(); | |
| 609 } | |
| 610 | |
| 611 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndSelfDestroysDuringShutdown) { | |
| 612 TaskTracker task_tracker; | |
| 613 // Will be owned by SchedulerWorker. | |
| 614 // No mock here as that's reasonably covered by other tests and the delegate | |
| 615 // may destroy on a different thread. Mocks aren't designed with that in mind. | |
| 616 std::unique_ptr<ControllableDetachDelegate> delegate = | |
| 617 MakeUnique<ControllableDetachDelegate>(&task_tracker); | |
| 618 scoped_refptr<ControllableDetachDelegate::Controls> controls = | |
| 619 delegate->controls(); | |
| 620 | |
| 621 controls->HaveWorkBlock(); | |
| 622 | |
| 623 scoped_refptr<SchedulerWorker> worker = SchedulerWorker::Create( | |
| 624 ThreadPriority::NORMAL, std::move(delegate), &task_tracker, | |
| 625 SchedulerWorker::InitialState::ALIVE); | |
| 626 worker->WakeUp(); | |
| 627 | |
| 628 controls->WaitForWorkToRun(); | |
| 629 task_tracker.Shutdown(); | |
| 630 worker->RequestThreadTermination(); | |
| 631 worker = nullptr; | |
| 632 controls->UnblockWork(); | |
| 633 controls->WaitForDelegateDestroy(); | |
| 634 } | |
| 635 | |
| 636 namespace { | |
| 637 | |
| 638 class CallJoinFromDifferentThread : public SimpleThread { | |
| 639 public: | |
| 640 CallJoinFromDifferentThread(SchedulerWorker* worker_to_join) | |
| 641 : SimpleThread("SchedulerWorkerJoinThread"), | |
| 642 worker_to_join_(worker_to_join) {} | |
| 643 | |
| 644 ~CallJoinFromDifferentThread() override = default; | |
| 645 | |
| 646 void Run() override { worker_to_join_->JoinForTesting(); } | |
| 647 | |
| 648 private: | |
| 649 SchedulerWorker* const worker_to_join_; | |
| 650 DISALLOW_COPY_AND_ASSIGN(CallJoinFromDifferentThread); | |
| 651 }; | |
| 652 | |
| 653 } // namespace | |
| 654 | |
| 655 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndSelfDestroysDuringJoin) { | |
| 656 TaskTracker task_tracker; | |
| 657 // Will be owned by SchedulerWorker. | |
| 658 // No mock here as that's reasonably covered by other tests and the | |
| 659 // delegate may destroy on a different thread. Mocks aren't designed with that | |
| 660 // in mind. | |
| 661 std::unique_ptr<ControllableDetachDelegate> delegate = | |
| 662 MakeUnique<ControllableDetachDelegate>(&task_tracker); | |
| 663 scoped_refptr<ControllableDetachDelegate::Controls> controls = | |
| 664 delegate->controls(); | |
| 665 | |
| 666 controls->HaveWorkBlock(); | |
| 667 | |
| 668 scoped_refptr<SchedulerWorker> worker = SchedulerWorker::Create( | |
| 669 ThreadPriority::NORMAL, std::move(delegate), &task_tracker, | |
| 670 SchedulerWorker::InitialState::ALIVE); | |
| 671 worker->WakeUp(); | |
| 672 | |
| 673 controls->WaitForWorkToRun(); | |
| 674 CallJoinFromDifferentThread join_from_different_thread(worker.get()); | |
| 675 join_from_different_thread.Start(); | |
| 676 // While Start blocks until the thread starts, that doesn't cover the actual | |
| 677 // join call. Yield here to give the other thread a chance to call | |
| 678 // JoinForTesting(). | |
| 679 PlatformThread::YieldCurrentThread(); | |
| 680 worker->RequestThreadTermination(); | |
| 681 worker = nullptr; | |
| 682 controls->UnblockWork(); | |
| 683 controls->WaitForDelegateDestroy(); | |
| 684 join_from_different_thread.Join(); | |
| 685 } | |
| 686 | |
| 454 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) { | 687 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) { |
| 455 TaskTracker task_tracker; | 688 TaskTracker task_tracker; |
| 456 // Will be owned by SchedulerWorker. | 689 // Will be owned by SchedulerWorker. |
| 457 ControllableDetachDelegate* delegate = | 690 MockedControllableDetachDelegate* delegate = |
| 458 new StrictMock<ControllableDetachDelegate>(&task_tracker); | 691 new StrictMock<MockedControllableDetachDelegate>(&task_tracker); |
| 459 delegate->set_can_detach(true); | 692 scoped_refptr<ControllableDetachDelegate::Controls> controls = |
| 693 delegate->controls(); | |
| 694 | |
| 695 controls->set_can_detach(true); | |
| 460 EXPECT_CALL(*delegate, OnMainEntry(_)); | 696 EXPECT_CALL(*delegate, OnMainEntry(_)); |
| 461 std::unique_ptr<SchedulerWorker> worker = | 697 scoped_refptr<SchedulerWorker> worker = SchedulerWorker::Create( |
| 462 SchedulerWorker::Create( | 698 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, |
| 463 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | 699 SchedulerWorker::InitialState::ALIVE); |
| 464 SchedulerWorker::InitialState::ALIVE); | 700 worker->WakeUp(); |
| 465 worker->WakeUp(); | 701 controls->WaitForWorkToRun(); |
| 466 delegate->WaitForWorkToRun(); | |
| 467 Mock::VerifyAndClear(delegate); | 702 Mock::VerifyAndClear(delegate); |
| 468 delegate->WaitForDetachRequest(); | 703 controls->WaitForDetachRequest(); |
| 469 delegate->WaitForDetach(); | 704 controls->WaitForDetach(); |
| 470 ASSERT_FALSE(worker->ThreadAliveForTesting()); | 705 ASSERT_FALSE(worker->ThreadAliveForTesting()); |
| 471 | 706 |
| 472 delegate->ResetState(); | 707 controls->ResetState(); |
| 473 delegate->set_can_detach(false); | 708 controls->set_can_detach(false); |
| 474 // Expect OnMainEntry() to be called when SchedulerWorker recreates its | 709 // Expect OnMainEntry() to be called when SchedulerWorker recreates its |
| 475 // thread. | 710 // thread. |
| 476 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); | 711 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); |
| 477 worker->WakeUp(); | 712 worker->WakeUp(); |
| 478 delegate->WaitForWorkToRun(); | 713 controls->WaitForWorkToRun(); |
| 479 Mock::VerifyAndClear(delegate); | 714 Mock::VerifyAndClear(delegate); |
| 480 delegate->WaitForDetachRequest(); | 715 controls->WaitForDetachRequest(); |
| 481 delegate->WaitForDetach(); | 716 controls->WaitForDetach(); |
| 482 ASSERT_TRUE(worker->ThreadAliveForTesting()); | 717 ASSERT_TRUE(worker->ThreadAliveForTesting()); |
| 483 worker->JoinForTesting(); | 718 worker->JoinForTesting(); |
| 484 } | 719 } |
| 485 | 720 |
| 486 TEST(TaskSchedulerWorkerTest, CreateDetached) { | 721 TEST(TaskSchedulerWorkerTest, CreateDetached) { |
| 487 TaskTracker task_tracker; | 722 TaskTracker task_tracker; |
| 488 // Will be owned by SchedulerWorker. | 723 // Will be owned by SchedulerWorker. |
| 489 ControllableDetachDelegate* delegate = | 724 MockedControllableDetachDelegate* delegate = |
| 490 new StrictMock<ControllableDetachDelegate>(&task_tracker); | 725 new StrictMock<MockedControllableDetachDelegate>(&task_tracker); |
| 491 std::unique_ptr<SchedulerWorker> worker = | 726 scoped_refptr<ControllableDetachDelegate::Controls> controls = |
| 492 SchedulerWorker::Create( | 727 delegate->controls(); |
| 493 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | 728 scoped_refptr<SchedulerWorker> worker = SchedulerWorker::Create( |
| 494 SchedulerWorker::InitialState::DETACHED); | 729 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, |
| 730 SchedulerWorker::InitialState::DETACHED); | |
| 495 ASSERT_FALSE(worker->ThreadAliveForTesting()); | 731 ASSERT_FALSE(worker->ThreadAliveForTesting()); |
| 496 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); | 732 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); |
| 497 worker->WakeUp(); | 733 worker->WakeUp(); |
| 498 delegate->WaitForWorkToRun(); | 734 controls->WaitForWorkToRun(); |
| 499 Mock::VerifyAndClear(delegate); | 735 Mock::VerifyAndClear(delegate); |
| 500 delegate->WaitForDetachRequest(); | 736 controls->WaitForDetachRequest(); |
| 501 ASSERT_TRUE(worker->ThreadAliveForTesting()); | 737 ASSERT_TRUE(worker->ThreadAliveForTesting()); |
| 502 worker->JoinForTesting(); | 738 worker->JoinForTesting(); |
| 503 } | 739 } |
| 504 | 740 |
| 505 namespace { | 741 namespace { |
| 506 | 742 |
| 507 class ExpectThreadPriorityDelegate : public SchedulerWorkerDefaultDelegate { | 743 class ExpectThreadPriorityDelegate : public SchedulerWorkerDefaultDelegate { |
| 508 public: | 744 public: |
| 509 ExpectThreadPriorityDelegate() | 745 ExpectThreadPriorityDelegate() |
| 510 : priority_verified_in_get_work_event_( | 746 : priority_verified_in_get_work_event_( |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 553 TaskTracker task_tracker; | 789 TaskTracker task_tracker; |
| 554 | 790 |
| 555 std::unique_ptr<ExpectThreadPriorityDelegate> delegate( | 791 std::unique_ptr<ExpectThreadPriorityDelegate> delegate( |
| 556 new ExpectThreadPriorityDelegate); | 792 new ExpectThreadPriorityDelegate); |
| 557 ExpectThreadPriorityDelegate* delegate_raw = delegate.get(); | 793 ExpectThreadPriorityDelegate* delegate_raw = delegate.get(); |
| 558 delegate_raw->SetExpectedThreadPriority( | 794 delegate_raw->SetExpectedThreadPriority( |
| 559 PlatformThread::CanIncreaseCurrentThreadPriority() | 795 PlatformThread::CanIncreaseCurrentThreadPriority() |
| 560 ? ThreadPriority::BACKGROUND | 796 ? ThreadPriority::BACKGROUND |
| 561 : ThreadPriority::NORMAL); | 797 : ThreadPriority::NORMAL); |
| 562 | 798 |
| 563 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create( | 799 scoped_refptr<SchedulerWorker> worker = SchedulerWorker::Create( |
| 564 ThreadPriority::BACKGROUND, std::move(delegate), &task_tracker, | 800 ThreadPriority::BACKGROUND, std::move(delegate), &task_tracker, |
| 565 SchedulerWorker::InitialState::ALIVE); | 801 SchedulerWorker::InitialState::ALIVE); |
| 566 | 802 |
| 567 // Verify that the initial thread priority is BACKGROUND (or NORMAL if thread | 803 // Verify that the initial thread priority is BACKGROUND (or NORMAL if thread |
| 568 // priority can't be increased). | 804 // priority can't be increased). |
| 569 worker->WakeUp(); | 805 worker->WakeUp(); |
| 570 delegate_raw->WaitForPriorityVerifiedInGetWork(); | 806 delegate_raw->WaitForPriorityVerifiedInGetWork(); |
| 571 | 807 |
| 572 // Verify that the thread priority is bumped to NORMAL during shutdown. | 808 // Verify that the thread priority is bumped to NORMAL during shutdown. |
| 573 delegate_raw->SetExpectedThreadPriority(ThreadPriority::NORMAL); | 809 delegate_raw->SetExpectedThreadPriority(ThreadPriority::NORMAL); |
| 574 task_tracker.SetHasShutdownStartedForTesting(); | 810 task_tracker.SetHasShutdownStartedForTesting(); |
| 575 worker->WakeUp(); | 811 worker->WakeUp(); |
| 576 delegate_raw->WaitForPriorityVerifiedInGetWork(); | 812 delegate_raw->WaitForPriorityVerifiedInGetWork(); |
| 577 | 813 |
| 578 worker->JoinForTesting(); | 814 worker->JoinForTesting(); |
| 579 } | 815 } |
| 580 | 816 |
| 581 TEST(TaskSchedulerWorkerTest, BumpPriorityOfDetachedThreadDuringShutdown) { | 817 TEST(TaskSchedulerWorkerTest, BumpPriorityOfDetachedThreadDuringShutdown) { |
| 582 TaskTracker task_tracker; | 818 TaskTracker task_tracker; |
| 583 | 819 |
| 584 std::unique_ptr<ExpectThreadPriorityDelegate> delegate( | 820 std::unique_ptr<ExpectThreadPriorityDelegate> delegate( |
| 585 new ExpectThreadPriorityDelegate); | 821 new ExpectThreadPriorityDelegate); |
| 586 ExpectThreadPriorityDelegate* delegate_raw = delegate.get(); | 822 ExpectThreadPriorityDelegate* delegate_raw = delegate.get(); |
| 587 delegate_raw->SetExpectedThreadPriority(ThreadPriority::NORMAL); | 823 delegate_raw->SetExpectedThreadPriority(ThreadPriority::NORMAL); |
| 588 | 824 |
| 589 // Create a DETACHED thread. | 825 // Create a DETACHED thread. |
| 590 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create( | 826 scoped_refptr<SchedulerWorker> worker = SchedulerWorker::Create( |
| 591 ThreadPriority::BACKGROUND, std::move(delegate), &task_tracker, | 827 ThreadPriority::BACKGROUND, std::move(delegate), &task_tracker, |
| 592 SchedulerWorker::InitialState::DETACHED); | 828 SchedulerWorker::InitialState::DETACHED); |
| 593 | 829 |
| 594 // Pretend that shutdown has started. | 830 // Pretend that shutdown has started. |
| 595 task_tracker.SetHasShutdownStartedForTesting(); | 831 task_tracker.SetHasShutdownStartedForTesting(); |
| 596 | 832 |
| 597 // Wake up the thread and verify that its priority is NORMAL when | 833 // Wake up the thread and verify that its priority is NORMAL when |
| 598 // OnMainEntry() and GetWork() are called. | 834 // OnMainEntry() and GetWork() are called. |
| 599 worker->WakeUp(); | 835 worker->WakeUp(); |
| 600 delegate_raw->WaitForPriorityVerifiedInGetWork(); | 836 delegate_raw->WaitForPriorityVerifiedInGetWork(); |
| (...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 676 // COM library wasn't already initialized on the thread. | 912 // COM library wasn't already initialized on the thread. |
| 677 EXPECT_EQ(S_OK, delegate_raw->coinitialize_hresult()); | 913 EXPECT_EQ(S_OK, delegate_raw->coinitialize_hresult()); |
| 678 | 914 |
| 679 worker->JoinForTesting(); | 915 worker->JoinForTesting(); |
| 680 } | 916 } |
| 681 | 917 |
| 682 #endif // defined(OS_WIN) | 918 #endif // defined(OS_WIN) |
| 683 | 919 |
| 684 } // namespace internal | 920 } // namespace internal |
| 685 } // namespace base | 921 } // namespace base |
| OLD | NEW |