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..927f3e56ec41030a70775f16ef07852d03342e89 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::InitialState::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_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 { |
+ // Sends one item of work to signal work_processed_. On subsequent calls, |
gab
2016/06/13 19:23:06
|work_processed_|
robliao
2016/06/13 23:23:28
Done.
|
+ // send nullptr to indicate there's no more work to be done. |
+ 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() << |
gab
2016/06/13 19:23:06
Actually, in tests, prefer ADD_FAILURE() to NOTREA
robliao
2016/06/13 23:23:28
Done.
|
+ "GetWork() returns a sequence of one, 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 ResetState() { |
+ work_requested_ = false; |
+ work_processed_.Reset(); |
+ detach_requested_.Reset(); |
+ } |
+ |
+ void set_can_detach(bool can_detach) { can_detach_ = can_detach; } |
+ |
+ private: |
+ bool work_requested_ = false; |
+ bool can_detach_ = false; |
+ 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::InitialState::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::InitialState::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->ResetState(); |
+ delegate->set_can_detach(false); |
+ worker_thread->WakeUp(); |
+ delegate->WaitForWorkToRun(); |
+ delegate->WaitForDetachRequest(); |
+ PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); |
+ ASSERT_TRUE(worker_thread->WorkerAliveForTesting()); |
fdoray
2016/06/13 20:31:17
EXPECT_TRUE()
We want JoinForTesting() to run even
robliao
2016/06/13 23:23:28
This needs to be an ASSERT. There's no thread to j
|
+ 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::InitialState::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 |