| Index: base/task_scheduler/scheduler_worker_unittest.cc
|
| diff --git a/base/task_scheduler/scheduler_worker_unittest.cc b/base/task_scheduler/scheduler_worker_unittest.cc
|
| index a776d7a18e6b09360fd0804cac531231540bc9ff..437bbedfdb5472dd74a6e45def138c4667dee6b9 100644
|
| --- a/base/task_scheduler/scheduler_worker_unittest.cc
|
| +++ b/base/task_scheduler/scheduler_worker_unittest.cc
|
| @@ -41,7 +41,8 @@ class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> {
|
| worker_ = SchedulerWorker::Create(
|
| ThreadPriority::NORMAL,
|
| WrapUnique(new TestSchedulerWorkerDelegate(this)),
|
| - &task_tracker_);
|
| + &task_tracker_,
|
| + SchedulerWorker::InitialState::ALIVE);
|
| ASSERT_TRUE(worker_);
|
| worker_set_.Signal();
|
| main_entry_called_.Wait();
|
| @@ -171,6 +172,10 @@ class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> {
|
| return TimeDelta::Max();
|
| }
|
|
|
| + bool CanDetach(SchedulerWorker* worker) override {
|
| + return false;
|
| + }
|
| +
|
| private:
|
| TaskSchedulerWorkerTest* outer_;
|
| };
|
| @@ -285,6 +290,137 @@ INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence,
|
| TaskSchedulerWorkerTest,
|
| ::testing::Values(2));
|
|
|
| +namespace {
|
| +
|
| +class ControllableDetachDelegate : public SchedulerWorker::Delegate {
|
| + public:
|
| + ControllableDetachDelegate()
|
| + : work_processed_(WaitableEvent::ResetPolicy::MANUAL,
|
| + WaitableEvent::InitialState::NOT_SIGNALED),
|
| + detach_requested_(WaitableEvent::ResetPolicy::MANUAL,
|
| + WaitableEvent::InitialState::NOT_SIGNALED) {}
|
| +
|
| + ~ControllableDetachDelegate() override = default;
|
| +
|
| + // SchedulerWorker::Delegate:
|
| + void OnMainEntry(SchedulerWorker* worker) override {}
|
| +
|
| + scoped_refptr<Sequence> GetWork(SchedulerWorker* worker)
|
| + override {
|
| + // Sends one item of work to signal |work_processed_|. On subsequent calls,
|
| + // sends 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 {
|
| + ADD_FAILURE() <<
|
| + "GetWork() returns a sequence of one, so there's nothing to reenqueue.";
|
| + }
|
| +
|
| + TimeDelta GetSleepTimeout() override {
|
| + return TimeDelta::Max();
|
| + }
|
| +
|
| + bool CanDetach(SchedulerWorker* worker) 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(TaskSchedulerWorkerTest, WorkerDetaches) {
|
| + TaskTracker task_tracker;
|
| + // Will be owned by SchedulerWorker.
|
| + ControllableDetachDelegate* delegate = new ControllableDetachDelegate;
|
| + delegate->set_can_detach(true);
|
| + std::unique_ptr<SchedulerWorker> worker =
|
| + SchedulerWorker::Create(
|
| + ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker,
|
| + SchedulerWorker::InitialState::ALIVE);
|
| + worker->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->ThreadAliveForTesting());
|
| +}
|
| +
|
| +TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) {
|
| + TaskTracker task_tracker;
|
| + // Will be owned by SchedulerWorker.
|
| + ControllableDetachDelegate* delegate = new ControllableDetachDelegate;
|
| + delegate->set_can_detach(true);
|
| + std::unique_ptr<SchedulerWorker> worker =
|
| + SchedulerWorker::Create(
|
| + ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker,
|
| + SchedulerWorker::InitialState::ALIVE);
|
| + worker->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->ThreadAliveForTesting());
|
| +
|
| + delegate->ResetState();
|
| + delegate->set_can_detach(false);
|
| + worker->WakeUp();
|
| + delegate->WaitForWorkToRun();
|
| + delegate->WaitForDetachRequest();
|
| + PlatformThread::Sleep(TimeDelta::FromMilliseconds(50));
|
| + ASSERT_TRUE(worker->ThreadAliveForTesting());
|
| + worker->JoinForTesting();
|
| +}
|
| +
|
| +TEST(TaskSchedulerWorkerTest, CreateDetached) {
|
| + TaskTracker task_tracker;
|
| + // Will be owned by SchedulerWorker.
|
| + ControllableDetachDelegate* delegate = new ControllableDetachDelegate;
|
| + std::unique_ptr<SchedulerWorker> worker =
|
| + SchedulerWorker::Create(
|
| + ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker,
|
| + SchedulerWorker::InitialState::DETACHED);
|
| + ASSERT_FALSE(worker->ThreadAliveForTesting());
|
| + worker->WakeUp();
|
| + delegate->WaitForWorkToRun();
|
| + delegate->WaitForDetachRequest();
|
| + ASSERT_TRUE(worker->ThreadAliveForTesting());
|
| + worker->JoinForTesting();
|
| +}
|
| +
|
| } // namespace
|
| } // namespace internal
|
| } // namespace base
|
|
|