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 |