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/synchronization/condition_variable.h" | 16 #include "base/synchronization/condition_variable.h" |
| 17 #include "base/synchronization/waitable_event.h" | 17 #include "base/synchronization/waitable_event.h" |
| 18 #include "base/task_scheduler/scheduler_lock.h" | 18 #include "base/task_scheduler/scheduler_lock.h" |
| 19 #include "base/task_scheduler/sequence.h" | 19 #include "base/task_scheduler/sequence.h" |
| 20 #include "base/task_scheduler/task.h" | 20 #include "base/task_scheduler/task.h" |
| 21 #include "base/task_scheduler/task_tracker.h" | 21 #include "base/task_scheduler/task_tracker.h" |
| 22 #include "base/test/test_timeouts.h" | |
| 22 #include "base/threading/platform_thread.h" | 23 #include "base/threading/platform_thread.h" |
| 23 #include "base/time/time.h" | 24 #include "base/time/time.h" |
| 24 #include "build/build_config.h" | 25 #include "build/build_config.h" |
| 25 #include "testing/gmock/include/gmock/gmock.h" | 26 #include "testing/gmock/include/gmock/gmock.h" |
| 26 #include "testing/gtest/include/gtest/gtest.h" | 27 #include "testing/gtest/include/gtest/gtest.h" |
| 27 | 28 |
| 28 #if defined(OS_WIN) | 29 #if defined(OS_WIN) |
| 29 #include <objbase.h> | 30 #include <objbase.h> |
| 30 #endif | 31 #endif |
| 31 | 32 |
| (...skipping 316 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 348 TaskSchedulerWorkerTest, | 349 TaskSchedulerWorkerTest, |
| 349 ::testing::Values(1)); | 350 ::testing::Values(1)); |
| 350 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, | 351 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, |
| 351 TaskSchedulerWorkerTest, | 352 TaskSchedulerWorkerTest, |
| 352 ::testing::Values(2)); | 353 ::testing::Values(2)); |
| 353 | 354 |
| 354 namespace { | 355 namespace { |
| 355 | 356 |
| 356 class ControllableDetachDelegate : public SchedulerWorkerDefaultDelegate { | 357 class ControllableDetachDelegate : public SchedulerWorkerDefaultDelegate { |
| 357 public: | 358 public: |
| 358 ControllableDetachDelegate(TaskTracker* task_tracker) | 359 ControllableDetachDelegate() |
| 359 : task_tracker_(task_tracker), | 360 : work_processed_(WaitableEvent::ResetPolicy::MANUAL, |
| 360 work_processed_(WaitableEvent::ResetPolicy::MANUAL, | |
| 361 WaitableEvent::InitialState::NOT_SIGNALED), | 361 WaitableEvent::InitialState::NOT_SIGNALED), |
| 362 detach_requested_(WaitableEvent::ResetPolicy::MANUAL, | 362 detach_requested_(WaitableEvent::ResetPolicy::MANUAL, |
| 363 WaitableEvent::InitialState::NOT_SIGNALED), | 363 WaitableEvent::InitialState::NOT_SIGNALED), |
| 364 detached_(WaitableEvent::ResetPolicy::MANUAL, | 364 detached_(WaitableEvent::ResetPolicy::MANUAL, |
| 365 WaitableEvent::InitialState::NOT_SIGNALED) { | 365 WaitableEvent::InitialState::NOT_SIGNALED) {} |
| 366 EXPECT_TRUE(task_tracker_); | |
| 367 } | |
| 368 | 366 |
| 369 ~ControllableDetachDelegate() override = default; | 367 ~ControllableDetachDelegate() override = default; |
| 370 | 368 |
| 371 // SchedulerWorker::Delegate: | 369 // SchedulerWorker::Delegate: |
| 372 MOCK_METHOD1(OnMainEntry, void(SchedulerWorker* worker)); | 370 MOCK_METHOD1(OnMainEntry, void(SchedulerWorker* worker)); |
| 373 | 371 |
| 374 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) | 372 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) |
| 375 override { | 373 override { |
| 376 // Sends one item of work to signal |work_processed_|. On subsequent calls, | 374 // 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. | 375 // sends nullptr to indicate there's no more work to be done. |
| 378 if (work_requested_) | 376 if (work_requested_) |
| 379 return nullptr; | 377 return nullptr; |
| 380 | 378 |
| 381 work_requested_ = true; | 379 work_requested_ = true; |
| 382 scoped_refptr<Sequence> sequence(new Sequence); | 380 scoped_refptr<Sequence> sequence(new Sequence); |
| 383 std::unique_ptr<Task> task(new Task( | 381 std::unique_ptr<Task> task(new Task( |
| 384 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&work_processed_)), | 382 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&work_processed_)), |
| 385 TaskTraits(), TimeDelta())); | 383 TaskTraits(), TimeDelta())); |
| 386 EXPECT_TRUE(task_tracker_->WillPostTask(task.get())); | 384 EXPECT_TRUE(task_tracker_.WillPostTask(task.get())); |
| 387 sequence->PushTask(std::move(task)); | 385 sequence->PushTask(std::move(task)); |
| 388 return sequence; | 386 return sequence; |
| 389 } | 387 } |
| 390 | 388 |
| 391 void DidRunTask() override {} | 389 void DidRunTask() override {} |
| 392 | 390 |
| 393 bool CanDetach(SchedulerWorker* worker) override { | 391 bool CanDetach(SchedulerWorker* worker) override { |
| 394 detach_requested_.Signal(); | 392 detach_requested_.Signal(); |
| 395 return can_detach_; | 393 return can_detach_; |
| 396 } | 394 } |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 412 void WaitForDetach() { detached_.Wait(); } | 410 void WaitForDetach() { detached_.Wait(); } |
| 413 | 411 |
| 414 void ResetState() { | 412 void ResetState() { |
| 415 work_requested_ = false; | 413 work_requested_ = false; |
| 416 work_processed_.Reset(); | 414 work_processed_.Reset(); |
| 417 detach_requested_.Reset(); | 415 detach_requested_.Reset(); |
| 418 } | 416 } |
| 419 | 417 |
| 420 void set_can_detach(bool can_detach) { can_detach_ = can_detach; } | 418 void set_can_detach(bool can_detach) { can_detach_ = can_detach; } |
| 421 | 419 |
| 420 // This delegate owns the TaskTracker because during detachment, threads may | |
| 421 // outlive the test case. | |
|
fdoray
2017/02/08 17:59:02
I think this is no longer true if you do https://c
robliao
2017/02/11 02:13:34
That is true. Removed.
| |
| 422 TaskTracker* task_tracker() { return &task_tracker_; } | |
| 423 | |
| 422 private: | 424 private: |
| 423 TaskTracker* const task_tracker_; | 425 TaskTracker task_tracker_; |
| 424 bool work_requested_ = false; | 426 bool work_requested_ = false; |
| 425 bool can_detach_ = false; | 427 bool can_detach_ = false; |
| 426 WaitableEvent work_processed_; | 428 WaitableEvent work_processed_; |
| 427 WaitableEvent detach_requested_; | 429 WaitableEvent detach_requested_; |
| 428 WaitableEvent detached_; | 430 WaitableEvent detached_; |
| 429 | 431 |
| 430 DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate); | 432 DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate); |
| 431 }; | 433 }; |
| 432 | 434 |
| 433 } // namespace | 435 } // namespace |
| 434 | 436 |
| 435 TEST(TaskSchedulerWorkerTest, WorkerDetaches) { | 437 TEST(TaskSchedulerWorkerTest, WorkerDetaches) { |
| 436 TaskTracker task_tracker; | |
| 437 // Will be owned by SchedulerWorker. | 438 // Will be owned by SchedulerWorker. |
| 438 ControllableDetachDelegate* delegate = | 439 ControllableDetachDelegate* delegate = |
| 439 new StrictMock<ControllableDetachDelegate>(&task_tracker); | 440 new StrictMock<ControllableDetachDelegate>(); |
| 440 delegate->set_can_detach(true); | 441 delegate->set_can_detach(true); |
| 441 EXPECT_CALL(*delegate, OnMainEntry(_)); | 442 EXPECT_CALL(*delegate, OnMainEntry(_)); |
| 442 std::unique_ptr<SchedulerWorker> worker = | 443 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create( |
| 443 SchedulerWorker::Create( | 444 ThreadPriority::NORMAL, WrapUnique(delegate), delegate->task_tracker(), |
| 444 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | 445 SchedulerWorker::InitialState::ALIVE); |
| 445 SchedulerWorker::InitialState::ALIVE); | |
| 446 worker->WakeUp(); | 446 worker->WakeUp(); |
| 447 delegate->WaitForWorkToRun(); | 447 delegate->WaitForWorkToRun(); |
| 448 Mock::VerifyAndClear(delegate); | 448 Mock::VerifyAndClear(delegate); |
| 449 delegate->WaitForDetachRequest(); | 449 delegate->WaitForDetachRequest(); |
| 450 delegate->WaitForDetach(); | 450 delegate->WaitForDetach(); |
| 451 ASSERT_FALSE(worker->ThreadAliveForTesting()); | 451 ASSERT_FALSE(worker->ThreadAliveForTesting()); |
| 452 } | 452 } |
| 453 | 453 |
| 454 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) { | 454 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndSelfDestroys) { |
| 455 TaskTracker task_tracker; | 455 // This test shouldn't crash or leak resources. |
| 456 // Will be owned by SchedulerWorker. | 456 // Will be owned by SchedulerWorker. |
| 457 ControllableDetachDelegate* delegate = | 457 ControllableDetachDelegate* delegate = |
| 458 new StrictMock<ControllableDetachDelegate>(&task_tracker); | 458 new StrictMock<ControllableDetachDelegate>(); |
| 459 delegate->set_can_detach(true); | 459 delegate->set_can_detach(true); |
| 460 EXPECT_CALL(*delegate, OnMainEntry(_)); | 460 EXPECT_CALL(*delegate, OnMainEntry(_)); |
| 461 std::unique_ptr<SchedulerWorker> worker = | 461 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create( |
| 462 SchedulerWorker::Create( | 462 ThreadPriority::NORMAL, WrapUnique(delegate), delegate->task_tracker(), |
| 463 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | 463 SchedulerWorker::InitialState::ALIVE); |
| 464 SchedulerWorker::InitialState::ALIVE); | 464 worker->WakeUp(); |
| 465 SchedulerWorker::DestroyAfterDetachment(std::move(worker)); | |
| 466 // Give a chance for the other thread to clean up. | |
|
fdoray
2017/02/08 17:59:02
You could signal an event in ~ControllableDetachDe
robliao
2017/02/11 02:13:34
I went with a refcounted event instead.
| |
| 467 PlatformThread::Sleep(TestTimeouts::tiny_timeout()); | |
| 468 } | |
| 469 | |
| 470 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) { | |
| 471 // Will be owned by SchedulerWorker. | |
| 472 ControllableDetachDelegate* delegate = | |
| 473 new StrictMock<ControllableDetachDelegate>(); | |
| 474 delegate->set_can_detach(true); | |
| 475 EXPECT_CALL(*delegate, OnMainEntry(_)); | |
| 476 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create( | |
| 477 ThreadPriority::NORMAL, WrapUnique(delegate), delegate->task_tracker(), | |
| 478 SchedulerWorker::InitialState::ALIVE); | |
| 465 worker->WakeUp(); | 479 worker->WakeUp(); |
| 466 delegate->WaitForWorkToRun(); | 480 delegate->WaitForWorkToRun(); |
| 467 Mock::VerifyAndClear(delegate); | 481 Mock::VerifyAndClear(delegate); |
| 468 delegate->WaitForDetachRequest(); | 482 delegate->WaitForDetachRequest(); |
| 469 delegate->WaitForDetach(); | 483 delegate->WaitForDetach(); |
| 470 ASSERT_FALSE(worker->ThreadAliveForTesting()); | 484 ASSERT_FALSE(worker->ThreadAliveForTesting()); |
| 471 | 485 |
| 472 delegate->ResetState(); | 486 delegate->ResetState(); |
| 473 delegate->set_can_detach(false); | 487 delegate->set_can_detach(false); |
| 474 // Expect OnMainEntry() to be called when SchedulerWorker recreates its | 488 // Expect OnMainEntry() to be called when SchedulerWorker recreates its |
| 475 // thread. | 489 // thread. |
| 476 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); | 490 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); |
| 477 worker->WakeUp(); | 491 worker->WakeUp(); |
| 478 delegate->WaitForWorkToRun(); | 492 delegate->WaitForWorkToRun(); |
| 479 Mock::VerifyAndClear(delegate); | 493 Mock::VerifyAndClear(delegate); |
| 480 delegate->WaitForDetachRequest(); | 494 delegate->WaitForDetachRequest(); |
| 481 delegate->WaitForDetach(); | 495 delegate->WaitForDetach(); |
| 482 ASSERT_TRUE(worker->ThreadAliveForTesting()); | 496 ASSERT_TRUE(worker->ThreadAliveForTesting()); |
| 483 worker->JoinForTesting(); | 497 worker->JoinForTesting(); |
| 484 } | 498 } |
| 485 | 499 |
| 486 TEST(TaskSchedulerWorkerTest, CreateDetached) { | 500 TEST(TaskSchedulerWorkerTest, CreateDetached) { |
| 487 TaskTracker task_tracker; | |
| 488 // Will be owned by SchedulerWorker. | 501 // Will be owned by SchedulerWorker. |
| 489 ControllableDetachDelegate* delegate = | 502 ControllableDetachDelegate* delegate = |
| 490 new StrictMock<ControllableDetachDelegate>(&task_tracker); | 503 new StrictMock<ControllableDetachDelegate>(); |
| 491 std::unique_ptr<SchedulerWorker> worker = | 504 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create( |
| 492 SchedulerWorker::Create( | 505 ThreadPriority::NORMAL, WrapUnique(delegate), delegate->task_tracker(), |
| 493 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | 506 SchedulerWorker::InitialState::DETACHED); |
| 494 SchedulerWorker::InitialState::DETACHED); | |
| 495 ASSERT_FALSE(worker->ThreadAliveForTesting()); | 507 ASSERT_FALSE(worker->ThreadAliveForTesting()); |
| 496 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); | 508 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); |
| 497 worker->WakeUp(); | 509 worker->WakeUp(); |
| 498 delegate->WaitForWorkToRun(); | 510 delegate->WaitForWorkToRun(); |
| 499 Mock::VerifyAndClear(delegate); | 511 Mock::VerifyAndClear(delegate); |
| 500 delegate->WaitForDetachRequest(); | 512 delegate->WaitForDetachRequest(); |
| 501 ASSERT_TRUE(worker->ThreadAliveForTesting()); | 513 ASSERT_TRUE(worker->ThreadAliveForTesting()); |
| 502 worker->JoinForTesting(); | 514 worker->JoinForTesting(); |
| 503 } | 515 } |
| 504 | 516 |
| (...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 676 // COM library wasn't already initialized on the thread. | 688 // COM library wasn't already initialized on the thread. |
| 677 EXPECT_EQ(S_OK, delegate_raw->coinitialize_hresult()); | 689 EXPECT_EQ(S_OK, delegate_raw->coinitialize_hresult()); |
| 678 | 690 |
| 679 worker->JoinForTesting(); | 691 worker->JoinForTesting(); |
| 680 } | 692 } |
| 681 | 693 |
| 682 #endif // defined(OS_WIN) | 694 #endif // defined(OS_WIN) |
| 683 | 695 |
| 684 } // namespace internal | 696 } // namespace internal |
| 685 } // namespace base | 697 } // namespace base |
| OLD | NEW |