| Index: base/task_scheduler/scheduler_worker_thread_unittest.cc
|
| diff --git a/base/task_scheduler/scheduler_worker_thread_unittest.cc b/base/task_scheduler/scheduler_worker_thread_unittest.cc
|
| index 88d9b23c8f2a5199d45245cd67a10df4752a12e5..18710b7f322c6d699131054e07784bf0a1fd50a7 100644
|
| --- a/base/task_scheduler/scheduler_worker_thread_unittest.cc
|
| +++ b/base/task_scheduler/scheduler_worker_thread_unittest.cc
|
| @@ -41,7 +41,8 @@ class TaskSchedulerWorkerThreadTest : public testing::TestWithParam<size_t> {
|
| worker_thread_ = SchedulerWorkerThread::Create(
|
| ThreadPriority::NORMAL,
|
| WrapUnique(new TestSchedulerWorkerThreadDelegate(this)),
|
| - &task_tracker_);
|
| + &task_tracker_,
|
| + SchedulerWorkerThread::InitialWorkerState::ALIVE);
|
| ASSERT_TRUE(worker_thread_);
|
| worker_thread_set_.Signal();
|
| main_entry_called_.Wait();
|
| @@ -172,6 +173,10 @@ class TaskSchedulerWorkerThreadTest : public testing::TestWithParam<size_t> {
|
| return TimeDelta::Max();
|
| }
|
|
|
| + bool CanDetach(SchedulerWorkerThread* worker_thread) override {
|
| + return false;
|
| + }
|
| +
|
| private:
|
| TaskSchedulerWorkerThreadTest* outer_;
|
| };
|
| @@ -286,6 +291,137 @@ INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence,
|
| TaskSchedulerWorkerThreadTest,
|
| ::testing::Values(2));
|
|
|
| +namespace {
|
| +
|
| +class ControllableDetachDelegate : public SchedulerWorkerThread::Delegate {
|
| + public:
|
| + ControllableDetachDelegate()
|
| + : work_requested_(false),
|
| + can_detach_(false),
|
| + work_processed_(WaitableEvent::ResetPolicy::MANUAL,
|
| + WaitableEvent::InitialState::NOT_SIGNALED),
|
| + detach_requested_(WaitableEvent::ResetPolicy::MANUAL,
|
| + WaitableEvent::InitialState::NOT_SIGNALED) {}
|
| +
|
| + ~ControllableDetachDelegate() override = default;
|
| +
|
| + // SchedulerWorkerThread::Delegate:
|
| + void OnMainEntry(SchedulerWorkerThread* worker_thread) override {}
|
| +
|
| + scoped_refptr<Sequence> GetWork(SchedulerWorkerThread* worker_thread)
|
| + override {
|
| + if (work_requested_)
|
| + return nullptr;
|
| +
|
| + work_requested_ = true;
|
| + scoped_refptr<Sequence> sequence(new Sequence);
|
| + std::unique_ptr<Task> task(new Task(
|
| + FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&work_processed_)),
|
| + TaskTraits(), TimeDelta()));
|
| + sequence->PushTask(std::move(task));
|
| + return sequence;
|
| + }
|
| +
|
| + void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override {
|
| + NOTREACHED() <<
|
| + "GetWork() never returns a sequence so there's nothing to reenqueue.";
|
| + }
|
| +
|
| + TimeDelta GetSleepTimeout() override {
|
| + return TimeDelta::Max();
|
| + }
|
| +
|
| + bool CanDetach(SchedulerWorkerThread* worker_thread) override {
|
| + detach_requested_.Signal();
|
| + return can_detach_;
|
| + }
|
| +
|
| + void WaitForWorkToRun() {
|
| + work_processed_.Wait();
|
| + }
|
| +
|
| + void WaitForDetachRequest() {
|
| + detach_requested_.Wait();
|
| + }
|
| +
|
| + void ResetAll() {
|
| + work_requested_ = false;
|
| + work_processed_.Reset();
|
| + detach_requested_.Reset();
|
| + }
|
| +
|
| + void set_can_detach(bool can_detach) { can_detach_ = can_detach; }
|
| +
|
| + private:
|
| + bool work_requested_;
|
| + bool can_detach_;
|
| + WaitableEvent work_processed_;
|
| + WaitableEvent detach_requested_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate);
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +TEST(TaskSchedulerWorkerThreadTest, WorkerDetaches) {
|
| + TaskTracker task_tracker;
|
| + // Will be owned by SchedulerWorkerThread.
|
| + ControllableDetachDelegate* delegate = new ControllableDetachDelegate;
|
| + delegate->set_can_detach(true);
|
| + std::unique_ptr<SchedulerWorkerThread> worker_thread =
|
| + SchedulerWorkerThread::Create(
|
| + ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker,
|
| + SchedulerWorkerThread::InitialWorkerState::ALIVE);
|
| + worker_thread->WakeUp();
|
| + delegate->WaitForWorkToRun();
|
| + delegate->WaitForDetachRequest();
|
| + // Sleep to give a chance for the detach to happen. A yield is too short.
|
| + PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
|
| + ASSERT_FALSE(worker_thread->WorkerAliveForTesting());
|
| +}
|
| +
|
| +TEST(TaskSchedulerWorkerThreadTest, WorkerDetachesAndWakes) {
|
| + TaskTracker task_tracker;
|
| + // Will be owned by SchedulerWorkerThread.
|
| + ControllableDetachDelegate* delegate = new ControllableDetachDelegate;
|
| + delegate->set_can_detach(true);
|
| + std::unique_ptr<SchedulerWorkerThread> worker_thread =
|
| + SchedulerWorkerThread::Create(
|
| + ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker,
|
| + SchedulerWorkerThread::InitialWorkerState::ALIVE);
|
| + worker_thread->WakeUp();
|
| + delegate->WaitForWorkToRun();
|
| + delegate->WaitForDetachRequest();
|
| + // Sleep to give a chance for the detach to happen. A yield is too short.
|
| + PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
|
| + ASSERT_FALSE(worker_thread->WorkerAliveForTesting());
|
| +
|
| + delegate->ResetAll();
|
| + delegate->set_can_detach(false);
|
| + worker_thread->WakeUp();
|
| + delegate->WaitForWorkToRun();
|
| + delegate->WaitForDetachRequest();
|
| + PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
|
| + ASSERT_TRUE(worker_thread->WorkerAliveForTesting());
|
| + worker_thread->JoinForTesting();
|
| +}
|
| +
|
| +TEST(TaskSchedulerWorkerThreadTest, CreateDetached) {
|
| + TaskTracker task_tracker;
|
| + // Will be owned by SchedulerWorkerThread.
|
| + ControllableDetachDelegate* delegate = new ControllableDetachDelegate;
|
| + std::unique_ptr<SchedulerWorkerThread> worker_thread =
|
| + SchedulerWorkerThread::Create(
|
| + ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker,
|
| + SchedulerWorkerThread::InitialWorkerState::DETACHED);
|
| + ASSERT_FALSE(worker_thread->WorkerAliveForTesting());
|
| + worker_thread->WakeUp();
|
| + delegate->WaitForWorkToRun();
|
| + delegate->WaitForDetachRequest();
|
| + ASSERT_TRUE(worker_thread->WorkerAliveForTesting());
|
| + worker_thread->JoinForTesting();
|
| +}
|
| +
|
| } // namespace
|
| } // namespace internal
|
| } // namespace base
|
|
|