| 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> |
| (...skipping 23 matching lines...) Expand all Loading... |
| 34 namespace internal { | 34 namespace internal { |
| 35 namespace { | 35 namespace { |
| 36 | 36 |
| 37 const size_t kNumSequencesPerTest = 150; | 37 const size_t kNumSequencesPerTest = 150; |
| 38 | 38 |
| 39 class SchedulerWorkerDefaultDelegate : public SchedulerWorker::Delegate { | 39 class SchedulerWorkerDefaultDelegate : public SchedulerWorker::Delegate { |
| 40 public: | 40 public: |
| 41 SchedulerWorkerDefaultDelegate() = default; | 41 SchedulerWorkerDefaultDelegate() = default; |
| 42 | 42 |
| 43 // SchedulerWorker::Delegate: | 43 // SchedulerWorker::Delegate: |
| 44 void OnMainEntry(SchedulerWorker* worker, | 44 void OnMainEntry(SchedulerWorker* worker) override {} |
| 45 const TimeDelta& detach_duration) override {} | |
| 46 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { | 45 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { |
| 47 return nullptr; | 46 return nullptr; |
| 48 } | 47 } |
| 49 void DidRunTaskWithPriority(TaskPriority task_priority, | 48 void DidRunTaskWithPriority(TaskPriority task_priority, |
| 50 const TimeDelta& task_latency) override { | 49 const TimeDelta& task_latency) override { |
| 51 ADD_FAILURE() << "Unexpected call to DidRunTaskWithPriority()"; | 50 ADD_FAILURE() << "Unexpected call to DidRunTaskWithPriority()"; |
| 52 } | 51 } |
| 53 void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { | 52 void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { |
| 54 ADD_FAILURE() << "Unexpected call to ReEnqueueSequence()"; | 53 ADD_FAILURE() << "Unexpected call to ReEnqueueSequence()"; |
| 55 } | 54 } |
| 56 TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); } | 55 TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); } |
| 57 bool CanDetach(SchedulerWorker* worker) override { return false; } | 56 bool CanDetach(SchedulerWorker* worker) override { return false; } |
| 57 void OnDetach() override { ADD_FAILURE() << "Unexpected call to OnDetach()"; } |
| 58 | 58 |
| 59 private: | 59 private: |
| 60 DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerDefaultDelegate); | 60 DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerDefaultDelegate); |
| 61 }; | 61 }; |
| 62 | 62 |
| 63 // The test parameter is the number of Tasks per Sequence returned by GetWork(). | 63 // The test parameter is the number of Tasks per Sequence returned by GetWork(). |
| 64 class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> { | 64 class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> { |
| 65 protected: | 65 protected: |
| 66 TaskSchedulerWorkerTest() | 66 TaskSchedulerWorkerTest() |
| 67 : main_entry_called_(WaitableEvent::ResetPolicy::MANUAL, | 67 : main_entry_called_(WaitableEvent::ResetPolicy::MANUAL, |
| (...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 124 class TestSchedulerWorkerDelegate : public SchedulerWorkerDefaultDelegate { | 124 class TestSchedulerWorkerDelegate : public SchedulerWorkerDefaultDelegate { |
| 125 public: | 125 public: |
| 126 TestSchedulerWorkerDelegate(TaskSchedulerWorkerTest* outer) | 126 TestSchedulerWorkerDelegate(TaskSchedulerWorkerTest* outer) |
| 127 : outer_(outer) {} | 127 : outer_(outer) {} |
| 128 | 128 |
| 129 ~TestSchedulerWorkerDelegate() override { | 129 ~TestSchedulerWorkerDelegate() override { |
| 130 EXPECT_FALSE(IsCallToDidRunTaskWithPriorityExpected()); | 130 EXPECT_FALSE(IsCallToDidRunTaskWithPriorityExpected()); |
| 131 } | 131 } |
| 132 | 132 |
| 133 // SchedulerWorker::Delegate: | 133 // SchedulerWorker::Delegate: |
| 134 void OnMainEntry(SchedulerWorker* worker, | 134 void OnMainEntry(SchedulerWorker* worker) override { |
| 135 const TimeDelta& detach_duration) override { | |
| 136 outer_->worker_set_.Wait(); | 135 outer_->worker_set_.Wait(); |
| 137 EXPECT_EQ(outer_->worker_.get(), worker); | 136 EXPECT_EQ(outer_->worker_.get(), worker); |
| 138 EXPECT_FALSE(IsCallToDidRunTaskWithPriorityExpected()); | 137 EXPECT_FALSE(IsCallToDidRunTaskWithPriorityExpected()); |
| 139 | 138 |
| 140 // Without synchronization, OnMainEntry() could be called twice without | 139 // Without synchronization, OnMainEntry() could be called twice without |
| 141 // generating an error. | 140 // generating an error. |
| 142 AutoSchedulerLock auto_lock(outer_->lock_); | 141 AutoSchedulerLock auto_lock(outer_->lock_); |
| 143 EXPECT_FALSE(outer_->main_entry_called_.IsSignaled()); | 142 EXPECT_FALSE(outer_->main_entry_called_.IsSignaled()); |
| 144 outer_->main_entry_called_.Signal(); | 143 outer_->main_entry_called_.Signal(); |
| 145 } | 144 } |
| (...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 356 | 355 |
| 357 namespace { | 356 namespace { |
| 358 | 357 |
| 359 class ControllableDetachDelegate : public SchedulerWorkerDefaultDelegate { | 358 class ControllableDetachDelegate : public SchedulerWorkerDefaultDelegate { |
| 360 public: | 359 public: |
| 361 ControllableDetachDelegate(TaskTracker* task_tracker) | 360 ControllableDetachDelegate(TaskTracker* task_tracker) |
| 362 : task_tracker_(task_tracker), | 361 : task_tracker_(task_tracker), |
| 363 work_processed_(WaitableEvent::ResetPolicy::MANUAL, | 362 work_processed_(WaitableEvent::ResetPolicy::MANUAL, |
| 364 WaitableEvent::InitialState::NOT_SIGNALED), | 363 WaitableEvent::InitialState::NOT_SIGNALED), |
| 365 detach_requested_(WaitableEvent::ResetPolicy::MANUAL, | 364 detach_requested_(WaitableEvent::ResetPolicy::MANUAL, |
| 366 WaitableEvent::InitialState::NOT_SIGNALED) { | 365 WaitableEvent::InitialState::NOT_SIGNALED), |
| 366 detached_(WaitableEvent::ResetPolicy::MANUAL, |
| 367 WaitableEvent::InitialState::NOT_SIGNALED) { |
| 367 EXPECT_TRUE(task_tracker_); | 368 EXPECT_TRUE(task_tracker_); |
| 368 } | 369 } |
| 369 | 370 |
| 370 ~ControllableDetachDelegate() override = default; | 371 ~ControllableDetachDelegate() override = default; |
| 371 | 372 |
| 372 // SchedulerWorker::Delegate: | 373 // SchedulerWorker::Delegate: |
| 373 MOCK_METHOD2(OnMainEntry, | 374 MOCK_METHOD1(OnMainEntry, void(SchedulerWorker* worker)); |
| 374 void(SchedulerWorker* worker, const TimeDelta& detach_duration)); | |
| 375 | 375 |
| 376 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) | 376 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) |
| 377 override { | 377 override { |
| 378 // Sends one item of work to signal |work_processed_|. On subsequent calls, | 378 // Sends one item of work to signal |work_processed_|. On subsequent calls, |
| 379 // sends nullptr to indicate there's no more work to be done. | 379 // sends nullptr to indicate there's no more work to be done. |
| 380 if (work_requested_) | 380 if (work_requested_) |
| 381 return nullptr; | 381 return nullptr; |
| 382 | 382 |
| 383 work_requested_ = true; | 383 work_requested_ = true; |
| 384 scoped_refptr<Sequence> sequence(new Sequence); | 384 scoped_refptr<Sequence> sequence(new Sequence); |
| 385 std::unique_ptr<Task> task(new Task( | 385 std::unique_ptr<Task> task(new Task( |
| 386 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&work_processed_)), | 386 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&work_processed_)), |
| 387 TaskTraits(), TimeDelta())); | 387 TaskTraits(), TimeDelta())); |
| 388 EXPECT_TRUE(task_tracker_->WillPostTask(task.get())); | 388 EXPECT_TRUE(task_tracker_->WillPostTask(task.get())); |
| 389 sequence->PushTask(std::move(task)); | 389 sequence->PushTask(std::move(task)); |
| 390 return sequence; | 390 return sequence; |
| 391 } | 391 } |
| 392 | 392 |
| 393 void DidRunTaskWithPriority(TaskPriority task, | 393 void DidRunTaskWithPriority(TaskPriority task, |
| 394 const TimeDelta& task_latency) override {} | 394 const TimeDelta& task_latency) override {} |
| 395 | 395 |
| 396 bool CanDetach(SchedulerWorker* worker) override { | 396 bool CanDetach(SchedulerWorker* worker) override { |
| 397 detach_requested_.Signal(); | 397 detach_requested_.Signal(); |
| 398 return can_detach_; | 398 return can_detach_; |
| 399 } | 399 } |
| 400 | 400 |
| 401 void OnDetach() override { |
| 402 EXPECT_TRUE(can_detach_); |
| 403 EXPECT_TRUE(detach_requested_.IsSignaled()); |
| 404 detached_.Signal(); |
| 405 } |
| 406 |
| 401 void WaitForWorkToRun() { | 407 void WaitForWorkToRun() { |
| 402 work_processed_.Wait(); | 408 work_processed_.Wait(); |
| 403 } | 409 } |
| 404 | 410 |
| 405 void WaitForDetachRequest() { | 411 void WaitForDetachRequest() { |
| 406 detach_requested_.Wait(); | 412 detach_requested_.Wait(); |
| 407 } | 413 } |
| 408 | 414 |
| 415 void WaitForDetach() { detached_.Wait(); } |
| 416 |
| 409 void ResetState() { | 417 void ResetState() { |
| 410 work_requested_ = false; | 418 work_requested_ = false; |
| 411 work_processed_.Reset(); | 419 work_processed_.Reset(); |
| 412 detach_requested_.Reset(); | 420 detach_requested_.Reset(); |
| 413 } | 421 } |
| 414 | 422 |
| 415 void set_can_detach(bool can_detach) { can_detach_ = can_detach; } | 423 void set_can_detach(bool can_detach) { can_detach_ = can_detach; } |
| 416 | 424 |
| 417 private: | 425 private: |
| 418 TaskTracker* const task_tracker_; | 426 TaskTracker* const task_tracker_; |
| 419 bool work_requested_ = false; | 427 bool work_requested_ = false; |
| 420 bool can_detach_ = false; | 428 bool can_detach_ = false; |
| 421 WaitableEvent work_processed_; | 429 WaitableEvent work_processed_; |
| 422 WaitableEvent detach_requested_; | 430 WaitableEvent detach_requested_; |
| 431 WaitableEvent detached_; |
| 423 | 432 |
| 424 DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate); | 433 DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate); |
| 425 }; | 434 }; |
| 426 | 435 |
| 427 } // namespace | 436 } // namespace |
| 428 | 437 |
| 429 TEST(TaskSchedulerWorkerTest, WorkerDetaches) { | 438 TEST(TaskSchedulerWorkerTest, WorkerDetaches) { |
| 430 TaskTracker task_tracker; | 439 TaskTracker task_tracker; |
| 431 // Will be owned by SchedulerWorker. | 440 // Will be owned by SchedulerWorker. |
| 432 ControllableDetachDelegate* delegate = | 441 ControllableDetachDelegate* delegate = |
| 433 new StrictMock<ControllableDetachDelegate>(&task_tracker); | 442 new StrictMock<ControllableDetachDelegate>(&task_tracker); |
| 434 delegate->set_can_detach(true); | 443 delegate->set_can_detach(true); |
| 435 EXPECT_CALL(*delegate, OnMainEntry(_, TimeDelta::Max())); | 444 EXPECT_CALL(*delegate, OnMainEntry(_)); |
| 436 std::unique_ptr<SchedulerWorker> worker = | 445 std::unique_ptr<SchedulerWorker> worker = |
| 437 SchedulerWorker::Create( | 446 SchedulerWorker::Create( |
| 438 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | 447 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, |
| 439 SchedulerWorker::InitialState::ALIVE); | 448 SchedulerWorker::InitialState::ALIVE); |
| 440 worker->WakeUp(); | 449 worker->WakeUp(); |
| 441 delegate->WaitForWorkToRun(); | 450 delegate->WaitForWorkToRun(); |
| 442 Mock::VerifyAndClear(delegate); | 451 Mock::VerifyAndClear(delegate); |
| 443 delegate->WaitForDetachRequest(); | 452 delegate->WaitForDetachRequest(); |
| 444 // Sleep to give a chance for the detach to happen. A yield is too short. | 453 delegate->WaitForDetach(); |
| 445 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | |
| 446 ASSERT_FALSE(worker->ThreadAliveForTesting()); | 454 ASSERT_FALSE(worker->ThreadAliveForTesting()); |
| 447 } | 455 } |
| 448 | 456 |
| 449 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) { | 457 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) { |
| 450 TaskTracker task_tracker; | 458 TaskTracker task_tracker; |
| 451 // Will be owned by SchedulerWorker. | 459 // Will be owned by SchedulerWorker. |
| 452 ControllableDetachDelegate* delegate = | 460 ControllableDetachDelegate* delegate = |
| 453 new StrictMock<ControllableDetachDelegate>(&task_tracker); | 461 new StrictMock<ControllableDetachDelegate>(&task_tracker); |
| 454 delegate->set_can_detach(true); | 462 delegate->set_can_detach(true); |
| 455 EXPECT_CALL(*delegate, OnMainEntry(_, TimeDelta::Max())); | 463 EXPECT_CALL(*delegate, OnMainEntry(_)); |
| 456 std::unique_ptr<SchedulerWorker> worker = | 464 std::unique_ptr<SchedulerWorker> worker = |
| 457 SchedulerWorker::Create( | 465 SchedulerWorker::Create( |
| 458 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | 466 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, |
| 459 SchedulerWorker::InitialState::ALIVE); | 467 SchedulerWorker::InitialState::ALIVE); |
| 460 worker->WakeUp(); | 468 worker->WakeUp(); |
| 461 delegate->WaitForWorkToRun(); | 469 delegate->WaitForWorkToRun(); |
| 462 Mock::VerifyAndClear(delegate); | 470 Mock::VerifyAndClear(delegate); |
| 463 delegate->WaitForDetachRequest(); | 471 delegate->WaitForDetachRequest(); |
| 464 // Sleep to give a chance for the detach to happen. A yield is too short. | 472 delegate->WaitForDetach(); |
| 465 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | |
| 466 ASSERT_FALSE(worker->ThreadAliveForTesting()); | 473 ASSERT_FALSE(worker->ThreadAliveForTesting()); |
| 467 | 474 |
| 468 delegate->ResetState(); | 475 delegate->ResetState(); |
| 469 delegate->set_can_detach(false); | 476 delegate->set_can_detach(false); |
| 470 // When SchedulerWorker recreates its thread, expect OnMainEntry() to be | 477 // Expect OnMainEntry() to be called when SchedulerWorker recreates its |
| 471 // called with a detach duration which is not TimeDelta::Max(). | 478 // thread. |
| 472 EXPECT_CALL(*delegate, OnMainEntry(worker.get(), Ne(TimeDelta::Max()))); | 479 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); |
| 473 worker->WakeUp(); | 480 worker->WakeUp(); |
| 474 delegate->WaitForWorkToRun(); | 481 delegate->WaitForWorkToRun(); |
| 475 Mock::VerifyAndClear(delegate); | 482 Mock::VerifyAndClear(delegate); |
| 476 delegate->WaitForDetachRequest(); | 483 delegate->WaitForDetachRequest(); |
| 477 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | 484 delegate->WaitForDetach(); |
| 478 ASSERT_TRUE(worker->ThreadAliveForTesting()); | 485 ASSERT_TRUE(worker->ThreadAliveForTesting()); |
| 479 worker->JoinForTesting(); | 486 worker->JoinForTesting(); |
| 480 } | 487 } |
| 481 | 488 |
| 482 TEST(TaskSchedulerWorkerTest, CreateDetached) { | 489 TEST(TaskSchedulerWorkerTest, CreateDetached) { |
| 483 TaskTracker task_tracker; | 490 TaskTracker task_tracker; |
| 484 // Will be owned by SchedulerWorker. | 491 // Will be owned by SchedulerWorker. |
| 485 ControllableDetachDelegate* delegate = | 492 ControllableDetachDelegate* delegate = |
| 486 new StrictMock<ControllableDetachDelegate>(&task_tracker); | 493 new StrictMock<ControllableDetachDelegate>(&task_tracker); |
| 487 std::unique_ptr<SchedulerWorker> worker = | 494 std::unique_ptr<SchedulerWorker> worker = |
| 488 SchedulerWorker::Create( | 495 SchedulerWorker::Create( |
| 489 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | 496 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, |
| 490 SchedulerWorker::InitialState::DETACHED); | 497 SchedulerWorker::InitialState::DETACHED); |
| 491 ASSERT_FALSE(worker->ThreadAliveForTesting()); | 498 ASSERT_FALSE(worker->ThreadAliveForTesting()); |
| 492 EXPECT_CALL(*delegate, OnMainEntry(worker.get(), TimeDelta::Max())); | 499 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); |
| 493 worker->WakeUp(); | 500 worker->WakeUp(); |
| 494 delegate->WaitForWorkToRun(); | 501 delegate->WaitForWorkToRun(); |
| 495 Mock::VerifyAndClear(delegate); | 502 Mock::VerifyAndClear(delegate); |
| 496 delegate->WaitForDetachRequest(); | 503 delegate->WaitForDetachRequest(); |
| 497 ASSERT_TRUE(worker->ThreadAliveForTesting()); | 504 ASSERT_TRUE(worker->ThreadAliveForTesting()); |
| 498 worker->JoinForTesting(); | 505 worker->JoinForTesting(); |
| 499 } | 506 } |
| 500 | 507 |
| 501 namespace { | 508 namespace { |
| 502 | 509 |
| 503 class ExpectThreadPriorityDelegate : public SchedulerWorkerDefaultDelegate { | 510 class ExpectThreadPriorityDelegate : public SchedulerWorkerDefaultDelegate { |
| 504 public: | 511 public: |
| 505 ExpectThreadPriorityDelegate() | 512 ExpectThreadPriorityDelegate() |
| 506 : priority_verified_in_get_work_event_( | 513 : priority_verified_in_get_work_event_( |
| 507 WaitableEvent::ResetPolicy::AUTOMATIC, | 514 WaitableEvent::ResetPolicy::AUTOMATIC, |
| 508 WaitableEvent::InitialState::NOT_SIGNALED), | 515 WaitableEvent::InitialState::NOT_SIGNALED), |
| 509 expected_thread_priority_(ThreadPriority::BACKGROUND) {} | 516 expected_thread_priority_(ThreadPriority::BACKGROUND) {} |
| 510 | 517 |
| 511 void SetExpectedThreadPriority(ThreadPriority expected_thread_priority) { | 518 void SetExpectedThreadPriority(ThreadPriority expected_thread_priority) { |
| 512 expected_thread_priority_ = expected_thread_priority; | 519 expected_thread_priority_ = expected_thread_priority; |
| 513 } | 520 } |
| 514 | 521 |
| 515 void WaitForPriorityVerifiedInGetWork() { | 522 void WaitForPriorityVerifiedInGetWork() { |
| 516 priority_verified_in_get_work_event_.Wait(); | 523 priority_verified_in_get_work_event_.Wait(); |
| 517 } | 524 } |
| 518 | 525 |
| 519 // SchedulerWorker::Delegate: | 526 // SchedulerWorker::Delegate: |
| 520 void OnMainEntry(SchedulerWorker* worker, | 527 void OnMainEntry(SchedulerWorker* worker) override { VerifyThreadPriority(); } |
| 521 const TimeDelta& detach_duration) override { | |
| 522 VerifyThreadPriority(); | |
| 523 } | |
| 524 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { | 528 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { |
| 525 VerifyThreadPriority(); | 529 VerifyThreadPriority(); |
| 526 priority_verified_in_get_work_event_.Signal(); | 530 priority_verified_in_get_work_event_.Signal(); |
| 527 return nullptr; | 531 return nullptr; |
| 528 } | 532 } |
| 529 | 533 |
| 530 private: | 534 private: |
| 531 void VerifyThreadPriority() { | 535 void VerifyThreadPriority() { |
| 532 AutoSchedulerLock auto_lock(expected_thread_priority_lock_); | 536 AutoSchedulerLock auto_lock(expected_thread_priority_lock_); |
| 533 EXPECT_EQ(expected_thread_priority_, | 537 EXPECT_EQ(expected_thread_priority_, |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 597 // OnMainEntry() and GetWork() are called. | 601 // OnMainEntry() and GetWork() are called. |
| 598 worker->WakeUp(); | 602 worker->WakeUp(); |
| 599 delegate_raw->WaitForPriorityVerifiedInGetWork(); | 603 delegate_raw->WaitForPriorityVerifiedInGetWork(); |
| 600 | 604 |
| 601 worker->JoinForTesting(); | 605 worker->JoinForTesting(); |
| 602 } | 606 } |
| 603 | 607 |
| 604 } // namespace | 608 } // namespace |
| 605 } // namespace internal | 609 } // namespace internal |
| 606 } // namespace base | 610 } // namespace base |
| OLD | NEW |