| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "base/task_scheduler/scheduler_worker.h" | |
| 6 | |
| 7 #include <stddef.h> | |
| 8 | |
| 9 #include <memory> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/bind.h" | |
| 13 #include "base/bind_helpers.h" | |
| 14 #include "base/macros.h" | |
| 15 #include "base/memory/ptr_util.h" | |
| 16 #include "base/synchronization/condition_variable.h" | |
| 17 #include "base/synchronization/waitable_event.h" | |
| 18 #include "base/task_scheduler/scheduler_lock.h" | |
| 19 #include "base/task_scheduler/sequence.h" | |
| 20 #include "base/task_scheduler/task.h" | |
| 21 #include "base/task_scheduler/task_tracker.h" | |
| 22 #include "base/threading/platform_thread.h" | |
| 23 #include "base/time/time.h" | |
| 24 #include "build/build_config.h" | |
| 25 #include "testing/gmock/include/gmock/gmock.h" | |
| 26 #include "testing/gtest/include/gtest/gtest.h" | |
| 27 | |
| 28 using testing::_; | |
| 29 using testing::Mock; | |
| 30 using testing::Ne; | |
| 31 using testing::StrictMock; | |
| 32 | |
| 33 namespace base { | |
| 34 namespace internal { | |
| 35 namespace { | |
| 36 | |
| 37 const size_t kNumSequencesPerTest = 150; | |
| 38 | |
| 39 class SchedulerWorkerDefaultDelegate : public SchedulerWorker::Delegate { | |
| 40 public: | |
| 41 SchedulerWorkerDefaultDelegate() = default; | |
| 42 | |
| 43 // SchedulerWorker::Delegate: | |
| 44 void OnMainEntry(SchedulerWorker* worker, const TimeDelta& detach_duration) ov
erride {} | |
| 45 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { return nul
lptr; } | |
| 46 void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { | |
| 47 ADD_FAILURE() << "Unexpected call to ReEnqueueSequence()"; | |
| 48 } | |
| 49 TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); } | |
| 50 bool CanDetach(SchedulerWorker* worker) override { return false; } | |
| 51 | |
| 52 private: | |
| 53 DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerDefaultDelegate); | |
| 54 }; | |
| 55 | |
| 56 // The test parameter is the number of Tasks per Sequence returned by GetWork(). | |
| 57 class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> { | |
| 58 protected: | |
| 59 TaskSchedulerWorkerTest() | |
| 60 : main_entry_called_(WaitableEvent::ResetPolicy::MANUAL, | |
| 61 WaitableEvent::InitialState::NOT_SIGNALED), | |
| 62 num_get_work_cv_(lock_.CreateConditionVariable()), | |
| 63 worker_set_(WaitableEvent::ResetPolicy::MANUAL, | |
| 64 WaitableEvent::InitialState::NOT_SIGNALED) {} | |
| 65 | |
| 66 void SetUp() override { | |
| 67 worker_ = SchedulerWorker::Create( | |
| 68 ThreadPriority::NORMAL, | |
| 69 WrapUnique(new TestSchedulerWorkerDelegate(this)), | |
| 70 &task_tracker_, | |
| 71 SchedulerWorker::InitialState::ALIVE); | |
| 72 ASSERT_TRUE(worker_); | |
| 73 worker_set_.Signal(); | |
| 74 main_entry_called_.Wait(); | |
| 75 } | |
| 76 | |
| 77 void TearDown() override { | |
| 78 worker_->JoinForTesting(); | |
| 79 } | |
| 80 | |
| 81 size_t TasksPerSequence() const { return GetParam(); } | |
| 82 | |
| 83 // Wait until GetWork() has been called |num_get_work| times. | |
| 84 void WaitForNumGetWork(size_t num_get_work) { | |
| 85 AutoSchedulerLock auto_lock(lock_); | |
| 86 while (num_get_work_ < num_get_work) | |
| 87 num_get_work_cv_->Wait(); | |
| 88 } | |
| 89 | |
| 90 void SetMaxGetWork(size_t max_get_work) { | |
| 91 AutoSchedulerLock auto_lock(lock_); | |
| 92 max_get_work_ = max_get_work; | |
| 93 } | |
| 94 | |
| 95 void SetNumSequencesToCreate(size_t num_sequences_to_create) { | |
| 96 AutoSchedulerLock auto_lock(lock_); | |
| 97 EXPECT_EQ(0U, num_sequences_to_create_); | |
| 98 num_sequences_to_create_ = num_sequences_to_create; | |
| 99 } | |
| 100 | |
| 101 size_t NumRunTasks() { | |
| 102 AutoSchedulerLock auto_lock(lock_); | |
| 103 return num_run_tasks_; | |
| 104 } | |
| 105 | |
| 106 std::vector<scoped_refptr<Sequence>> CreatedSequences() { | |
| 107 AutoSchedulerLock auto_lock(lock_); | |
| 108 return created_sequences_; | |
| 109 } | |
| 110 | |
| 111 std::vector<scoped_refptr<Sequence>> EnqueuedSequences() { | |
| 112 AutoSchedulerLock auto_lock(lock_); | |
| 113 return re_enqueued_sequences_; | |
| 114 } | |
| 115 | |
| 116 std::unique_ptr<SchedulerWorker> worker_; | |
| 117 | |
| 118 private: | |
| 119 class TestSchedulerWorkerDelegate : public SchedulerWorkerDefaultDelegate { | |
| 120 public: | |
| 121 TestSchedulerWorkerDelegate(TaskSchedulerWorkerTest* outer) | |
| 122 : outer_(outer) {} | |
| 123 | |
| 124 // SchedulerWorker::Delegate: | |
| 125 void OnMainEntry(SchedulerWorker* worker, | |
| 126 const TimeDelta& detach_duration) override { | |
| 127 outer_->worker_set_.Wait(); | |
| 128 EXPECT_EQ(outer_->worker_.get(), worker); | |
| 129 | |
| 130 // Without synchronization, OnMainEntry() could be called twice without | |
| 131 // generating an error. | |
| 132 AutoSchedulerLock auto_lock(outer_->lock_); | |
| 133 EXPECT_FALSE(outer_->main_entry_called_.IsSignaled()); | |
| 134 outer_->main_entry_called_.Signal(); | |
| 135 } | |
| 136 | |
| 137 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { | |
| 138 EXPECT_EQ(outer_->worker_.get(), worker); | |
| 139 | |
| 140 { | |
| 141 AutoSchedulerLock auto_lock(outer_->lock_); | |
| 142 | |
| 143 // Increment the number of times that this method has been called. | |
| 144 ++outer_->num_get_work_; | |
| 145 outer_->num_get_work_cv_->Signal(); | |
| 146 | |
| 147 // Verify that this method isn't called more times than expected. | |
| 148 EXPECT_LE(outer_->num_get_work_, outer_->max_get_work_); | |
| 149 | |
| 150 // Check if a Sequence should be returned. | |
| 151 if (outer_->num_sequences_to_create_ == 0) | |
| 152 return nullptr; | |
| 153 --outer_->num_sequences_to_create_; | |
| 154 } | |
| 155 | |
| 156 // Create a Sequence with TasksPerSequence() Tasks. | |
| 157 scoped_refptr<Sequence> sequence(new Sequence); | |
| 158 for (size_t i = 0; i < outer_->TasksPerSequence(); ++i) { | |
| 159 std::unique_ptr<Task> task(new Task( | |
| 160 FROM_HERE, Bind(&TaskSchedulerWorkerTest::RunTaskCallback, | |
| 161 Unretained(outer_)), | |
| 162 TaskTraits(), TimeDelta())); | |
| 163 EXPECT_TRUE(outer_->task_tracker_.WillPostTask(task.get())); | |
| 164 sequence->PushTask(std::move(task)); | |
| 165 } | |
| 166 | |
| 167 { | |
| 168 // Add the Sequence to the vector of created Sequences. | |
| 169 AutoSchedulerLock auto_lock(outer_->lock_); | |
| 170 outer_->created_sequences_.push_back(sequence); | |
| 171 } | |
| 172 | |
| 173 return sequence; | |
| 174 } | |
| 175 | |
| 176 // This override verifies that |sequence| contains the expected number of | |
| 177 // Tasks and adds it to |enqueued_sequences_|. Unlike a normal | |
| 178 // EnqueueSequence implementation, it doesn't reinsert |sequence| into a | |
| 179 // queue for further execution. | |
| 180 void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { | |
| 181 EXPECT_GT(outer_->TasksPerSequence(), 1U); | |
| 182 | |
| 183 // Verify that |sequence| contains TasksPerSequence() - 1 Tasks. | |
| 184 for (size_t i = 0; i < outer_->TasksPerSequence() - 1; ++i) { | |
| 185 EXPECT_TRUE(sequence->PeekTask()); | |
| 186 sequence->PopTask(); | |
| 187 } | |
| 188 EXPECT_FALSE(sequence->PeekTask()); | |
| 189 | |
| 190 // Add |sequence| to |re_enqueued_sequences_|. | |
| 191 AutoSchedulerLock auto_lock(outer_->lock_); | |
| 192 outer_->re_enqueued_sequences_.push_back(std::move(sequence)); | |
| 193 EXPECT_LE(outer_->re_enqueued_sequences_.size(), | |
| 194 outer_->created_sequences_.size()); | |
| 195 } | |
| 196 | |
| 197 private: | |
| 198 TaskSchedulerWorkerTest* outer_; | |
| 199 }; | |
| 200 | |
| 201 void RunTaskCallback() { | |
| 202 AutoSchedulerLock auto_lock(lock_); | |
| 203 ++num_run_tasks_; | |
| 204 EXPECT_LE(num_run_tasks_, created_sequences_.size()); | |
| 205 } | |
| 206 | |
| 207 TaskTracker task_tracker_; | |
| 208 | |
| 209 // Synchronizes access to all members below. | |
| 210 mutable SchedulerLock lock_; | |
| 211 | |
| 212 // Signaled once OnMainEntry() has been called. | |
| 213 WaitableEvent main_entry_called_; | |
| 214 | |
| 215 // Number of Sequences that should be created by GetWork(). When this | |
| 216 // is 0, GetWork() returns nullptr. | |
| 217 size_t num_sequences_to_create_ = 0; | |
| 218 | |
| 219 // Number of times that GetWork() has been called. | |
| 220 size_t num_get_work_ = 0; | |
| 221 | |
| 222 // Maximum number of times that GetWork() can be called. | |
| 223 size_t max_get_work_ = 0; | |
| 224 | |
| 225 // Condition variable signaled when |num_get_work_| is incremented. | |
| 226 std::unique_ptr<ConditionVariable> num_get_work_cv_; | |
| 227 | |
| 228 // Sequences created by GetWork(). | |
| 229 std::vector<scoped_refptr<Sequence>> created_sequences_; | |
| 230 | |
| 231 // Sequences passed to EnqueueSequence(). | |
| 232 std::vector<scoped_refptr<Sequence>> re_enqueued_sequences_; | |
| 233 | |
| 234 // Number of times that RunTaskCallback() has been called. | |
| 235 size_t num_run_tasks_ = 0; | |
| 236 | |
| 237 // Signaled after |worker_| is set. | |
| 238 WaitableEvent worker_set_; | |
| 239 | |
| 240 DISALLOW_COPY_AND_ASSIGN(TaskSchedulerWorkerTest); | |
| 241 }; | |
| 242 | |
| 243 // Verify that when GetWork() continuously returns Sequences, all Tasks in these | |
| 244 // Sequences run successfully. The test wakes up the SchedulerWorker once. | |
| 245 TEST_P(TaskSchedulerWorkerTest, ContinuousWork) { | |
| 246 // Set GetWork() to return |kNumSequencesPerTest| Sequences before starting to | |
| 247 // return nullptr. | |
| 248 SetNumSequencesToCreate(kNumSequencesPerTest); | |
| 249 | |
| 250 // Expect |kNumSequencesPerTest| calls to GetWork() in which it returns a | |
| 251 // Sequence and one call in which its returns nullptr. | |
| 252 const size_t kExpectedNumGetWork = kNumSequencesPerTest + 1; | |
| 253 SetMaxGetWork(kExpectedNumGetWork); | |
| 254 | |
| 255 // Wake up |worker_| and wait until GetWork() has been invoked the | |
| 256 // expected amount of times. | |
| 257 worker_->WakeUp(); | |
| 258 WaitForNumGetWork(kExpectedNumGetWork); | |
| 259 | |
| 260 // All tasks should have run. | |
| 261 EXPECT_EQ(kNumSequencesPerTest, NumRunTasks()); | |
| 262 | |
| 263 // If Sequences returned by GetWork() contain more than one Task, they aren't | |
| 264 // empty after the worker pops Tasks from them and thus should be returned to | |
| 265 // EnqueueSequence(). | |
| 266 if (TasksPerSequence() > 1) | |
| 267 EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); | |
| 268 else | |
| 269 EXPECT_TRUE(EnqueuedSequences().empty()); | |
| 270 } | |
| 271 | |
| 272 // Verify that when GetWork() alternates between returning a Sequence and | |
| 273 // returning nullptr, all Tasks in the returned Sequences run successfully. The | |
| 274 // test wakes up the SchedulerWorker once for each Sequence. | |
| 275 TEST_P(TaskSchedulerWorkerTest, IntermittentWork) { | |
| 276 for (size_t i = 0; i < kNumSequencesPerTest; ++i) { | |
| 277 // Set GetWork() to return 1 Sequence before starting to return | |
| 278 // nullptr. | |
| 279 SetNumSequencesToCreate(1); | |
| 280 | |
| 281 // Expect |i + 1| calls to GetWork() in which it returns a Sequence and | |
| 282 // |i + 1| calls in which it returns nullptr. | |
| 283 const size_t expected_num_get_work = 2 * (i + 1); | |
| 284 SetMaxGetWork(expected_num_get_work); | |
| 285 | |
| 286 // Wake up |worker_| and wait until GetWork() has been invoked | |
| 287 // the expected amount of times. | |
| 288 worker_->WakeUp(); | |
| 289 WaitForNumGetWork(expected_num_get_work); | |
| 290 | |
| 291 // The Task should have run | |
| 292 EXPECT_EQ(i + 1, NumRunTasks()); | |
| 293 | |
| 294 // If Sequences returned by GetWork() contain more than one Task, they | |
| 295 // aren't empty after the worker pops Tasks from them and thus should be | |
| 296 // returned to EnqueueSequence(). | |
| 297 if (TasksPerSequence() > 1) | |
| 298 EXPECT_EQ(CreatedSequences(), EnqueuedSequences()); | |
| 299 else | |
| 300 EXPECT_TRUE(EnqueuedSequences().empty()); | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 INSTANTIATE_TEST_CASE_P(OneTaskPerSequence, | |
| 305 TaskSchedulerWorkerTest, | |
| 306 ::testing::Values(1)); | |
| 307 INSTANTIATE_TEST_CASE_P(TwoTasksPerSequence, | |
| 308 TaskSchedulerWorkerTest, | |
| 309 ::testing::Values(2)); | |
| 310 | |
| 311 namespace { | |
| 312 | |
| 313 class ControllableDetachDelegate : public SchedulerWorkerDefaultDelegate { | |
| 314 public: | |
| 315 ControllableDetachDelegate() | |
| 316 : work_processed_(WaitableEvent::ResetPolicy::MANUAL, | |
| 317 WaitableEvent::InitialState::NOT_SIGNALED), | |
| 318 detach_requested_(WaitableEvent::ResetPolicy::MANUAL, | |
| 319 WaitableEvent::InitialState::NOT_SIGNALED) {} | |
| 320 | |
| 321 ~ControllableDetachDelegate() override = default; | |
| 322 | |
| 323 // SchedulerWorker::Delegate: | |
| 324 MOCK_METHOD2(OnMainEntry, | |
| 325 void(SchedulerWorker* worker, const TimeDelta& detach_duration)); | |
| 326 | |
| 327 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) | |
| 328 override { | |
| 329 // Sends one item of work to signal |work_processed_|. On subsequent calls, | |
| 330 // sends nullptr to indicate there's no more work to be done. | |
| 331 if (work_requested_) | |
| 332 return nullptr; | |
| 333 | |
| 334 work_requested_ = true; | |
| 335 scoped_refptr<Sequence> sequence(new Sequence); | |
| 336 std::unique_ptr<Task> task(new Task( | |
| 337 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&work_processed_)), | |
| 338 TaskTraits(), TimeDelta())); | |
| 339 sequence->PushTask(std::move(task)); | |
| 340 return sequence; | |
| 341 } | |
| 342 | |
| 343 bool CanDetach(SchedulerWorker* worker) override { | |
| 344 detach_requested_.Signal(); | |
| 345 return can_detach_; | |
| 346 } | |
| 347 | |
| 348 void WaitForWorkToRun() { | |
| 349 work_processed_.Wait(); | |
| 350 } | |
| 351 | |
| 352 void WaitForDetachRequest() { | |
| 353 detach_requested_.Wait(); | |
| 354 } | |
| 355 | |
| 356 void ResetState() { | |
| 357 work_requested_ = false; | |
| 358 work_processed_.Reset(); | |
| 359 detach_requested_.Reset(); | |
| 360 } | |
| 361 | |
| 362 void set_can_detach(bool can_detach) { can_detach_ = can_detach; } | |
| 363 | |
| 364 private: | |
| 365 bool work_requested_ = false; | |
| 366 bool can_detach_ = false; | |
| 367 WaitableEvent work_processed_; | |
| 368 WaitableEvent detach_requested_; | |
| 369 | |
| 370 DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate); | |
| 371 }; | |
| 372 | |
| 373 } // namespace | |
| 374 | |
| 375 TEST(TaskSchedulerWorkerTest, WorkerDetaches) { | |
| 376 TaskTracker task_tracker; | |
| 377 // Will be owned by SchedulerWorker. | |
| 378 ControllableDetachDelegate* delegate = | |
| 379 new StrictMock<ControllableDetachDelegate>; | |
| 380 delegate->set_can_detach(true); | |
| 381 EXPECT_CALL(*delegate, OnMainEntry(_, TimeDelta::Max())); | |
| 382 std::unique_ptr<SchedulerWorker> worker = | |
| 383 SchedulerWorker::Create( | |
| 384 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | |
| 385 SchedulerWorker::InitialState::ALIVE); | |
| 386 worker->WakeUp(); | |
| 387 delegate->WaitForWorkToRun(); | |
| 388 Mock::VerifyAndClear(delegate); | |
| 389 delegate->WaitForDetachRequest(); | |
| 390 // Sleep to give a chance for the detach to happen. A yield is too short. | |
| 391 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | |
| 392 ASSERT_FALSE(worker->ThreadAliveForTesting()); | |
| 393 } | |
| 394 | |
| 395 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) { | |
| 396 TaskTracker task_tracker; | |
| 397 // Will be owned by SchedulerWorker. | |
| 398 ControllableDetachDelegate* delegate = | |
| 399 new StrictMock<ControllableDetachDelegate>; | |
| 400 delegate->set_can_detach(true); | |
| 401 EXPECT_CALL(*delegate, OnMainEntry(_, TimeDelta::Max())); | |
| 402 std::unique_ptr<SchedulerWorker> worker = | |
| 403 SchedulerWorker::Create( | |
| 404 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | |
| 405 SchedulerWorker::InitialState::ALIVE); | |
| 406 worker->WakeUp(); | |
| 407 delegate->WaitForWorkToRun(); | |
| 408 Mock::VerifyAndClear(delegate); | |
| 409 delegate->WaitForDetachRequest(); | |
| 410 // Sleep to give a chance for the detach to happen. A yield is too short. | |
| 411 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | |
| 412 ASSERT_FALSE(worker->ThreadAliveForTesting()); | |
| 413 | |
| 414 delegate->ResetState(); | |
| 415 delegate->set_can_detach(false); | |
| 416 // When SchedulerWorker recreates its thread, expect OnMainEntry() to be | |
| 417 // called with a detach duration which is not TimeDelta::Max(). | |
| 418 EXPECT_CALL(*delegate, OnMainEntry(worker.get(), Ne(TimeDelta::Max()))); | |
| 419 worker->WakeUp(); | |
| 420 delegate->WaitForWorkToRun(); | |
| 421 Mock::VerifyAndClear(delegate); | |
| 422 delegate->WaitForDetachRequest(); | |
| 423 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | |
| 424 ASSERT_TRUE(worker->ThreadAliveForTesting()); | |
| 425 worker->JoinForTesting(); | |
| 426 } | |
| 427 | |
| 428 TEST(TaskSchedulerWorkerTest, CreateDetached) { | |
| 429 TaskTracker task_tracker; | |
| 430 // Will be owned by SchedulerWorker. | |
| 431 ControllableDetachDelegate* delegate = | |
| 432 new StrictMock<ControllableDetachDelegate>; | |
| 433 std::unique_ptr<SchedulerWorker> worker = | |
| 434 SchedulerWorker::Create( | |
| 435 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | |
| 436 SchedulerWorker::InitialState::DETACHED); | |
| 437 ASSERT_FALSE(worker->ThreadAliveForTesting()); | |
| 438 EXPECT_CALL(*delegate, OnMainEntry(worker.get(), TimeDelta::Max())); | |
| 439 worker->WakeUp(); | |
| 440 delegate->WaitForWorkToRun(); | |
| 441 Mock::VerifyAndClear(delegate); | |
| 442 delegate->WaitForDetachRequest(); | |
| 443 ASSERT_TRUE(worker->ThreadAliveForTesting()); | |
| 444 worker->JoinForTesting(); | |
| 445 } | |
| 446 | |
| 447 namespace { | |
| 448 | |
| 449 class ExpectThreadPriorityDelegate : public SchedulerWorkerDefaultDelegate { | |
| 450 public: | |
| 451 ExpectThreadPriorityDelegate() | |
| 452 : priority_verified_in_get_work_event_( | |
| 453 WaitableEvent::ResetPolicy::AUTOMATIC, | |
| 454 WaitableEvent::InitialState::NOT_SIGNALED), | |
| 455 expected_thread_priority_(ThreadPriority::BACKGROUND) {} | |
| 456 | |
| 457 void SetExpectedThreadPriority(ThreadPriority expected_thread_priority) { | |
| 458 expected_thread_priority_ = expected_thread_priority; | |
| 459 } | |
| 460 | |
| 461 void WaitForPriorityVerifiedInGetWork() { | |
| 462 priority_verified_in_get_work_event_.Wait(); | |
| 463 } | |
| 464 | |
| 465 // SchedulerWorker::Delegate: | |
| 466 void OnMainEntry(SchedulerWorker* worker, | |
| 467 const TimeDelta& detach_duration) override { | |
| 468 VerifyThreadPriority(); | |
| 469 } | |
| 470 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { | |
| 471 VerifyThreadPriority(); | |
| 472 priority_verified_in_get_work_event_.Signal(); | |
| 473 return nullptr; | |
| 474 } | |
| 475 | |
| 476 private: | |
| 477 void VerifyThreadPriority() { | |
| 478 AutoSchedulerLock auto_lock(expected_thread_priority_lock_); | |
| 479 EXPECT_EQ(expected_thread_priority_, | |
| 480 PlatformThread::GetCurrentThreadPriority()); | |
| 481 } | |
| 482 | |
| 483 // Signaled after GetWork() has verified the priority of the worker thread. | |
| 484 WaitableEvent priority_verified_in_get_work_event_; | |
| 485 | |
| 486 // Synchronizes access to |expected_thread_priority_|. | |
| 487 SchedulerLock expected_thread_priority_lock_; | |
| 488 | |
| 489 // Expected thread priority for the next call to OnMainEntry() or GetWork(). | |
| 490 ThreadPriority expected_thread_priority_; | |
| 491 | |
| 492 DISALLOW_COPY_AND_ASSIGN(ExpectThreadPriorityDelegate); | |
| 493 }; | |
| 494 | |
| 495 } // namespace | |
| 496 | |
| 497 TEST(TaskSchedulerWorkerTest, BumpPriorityOfAliveThreadDuringShutdown) { | |
| 498 TaskTracker task_tracker; | |
| 499 | |
| 500 std::unique_ptr<ExpectThreadPriorityDelegate> delegate( | |
| 501 new ExpectThreadPriorityDelegate); | |
| 502 ExpectThreadPriorityDelegate* delegate_raw = delegate.get(); | |
| 503 delegate_raw->SetExpectedThreadPriority( | |
| 504 PlatformThread::CanIncreaseCurrentThreadPriority() | |
| 505 ? ThreadPriority::BACKGROUND | |
| 506 : ThreadPriority::NORMAL); | |
| 507 | |
| 508 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create( | |
| 509 ThreadPriority::BACKGROUND, std::move(delegate), &task_tracker, | |
| 510 SchedulerWorker::InitialState::ALIVE); | |
| 511 | |
| 512 // Verify that the initial thread priority is BACKGROUND (or NORMAL if thread | |
| 513 // priority can't be increased). | |
| 514 worker->WakeUp(); | |
| 515 delegate_raw->WaitForPriorityVerifiedInGetWork(); | |
| 516 | |
| 517 // Verify that the thread priority is bumped to NORMAL during shutdown. | |
| 518 delegate_raw->SetExpectedThreadPriority(ThreadPriority::NORMAL); | |
| 519 task_tracker.SetHasShutdownStartedForTesting(); | |
| 520 worker->WakeUp(); | |
| 521 delegate_raw->WaitForPriorityVerifiedInGetWork(); | |
| 522 | |
| 523 worker->JoinForTesting(); | |
| 524 } | |
| 525 | |
| 526 TEST(TaskSchedulerWorkerTest, BumpPriorityOfDetachedThreadDuringShutdown) { | |
| 527 TaskTracker task_tracker; | |
| 528 | |
| 529 std::unique_ptr<ExpectThreadPriorityDelegate> delegate( | |
| 530 new ExpectThreadPriorityDelegate); | |
| 531 ExpectThreadPriorityDelegate* delegate_raw = delegate.get(); | |
| 532 delegate_raw->SetExpectedThreadPriority(ThreadPriority::NORMAL); | |
| 533 | |
| 534 // Create a DETACHED thread. | |
| 535 std::unique_ptr<SchedulerWorker> worker = SchedulerWorker::Create( | |
| 536 ThreadPriority::BACKGROUND, std::move(delegate), &task_tracker, | |
| 537 SchedulerWorker::InitialState::DETACHED); | |
| 538 | |
| 539 // Pretend that shutdown has started. | |
| 540 task_tracker.SetHasShutdownStartedForTesting(); | |
| 541 | |
| 542 // Wake up the thread and verify that its priority is NORMAL when | |
| 543 // OnMainEntry() and GetWork() are called. | |
| 544 worker->WakeUp(); | |
| 545 delegate_raw->WaitForPriorityVerifiedInGetWork(); | |
| 546 | |
| 547 worker->JoinForTesting(); | |
| 548 } | |
| 549 | |
| 550 } // namespace | |
| 551 } // namespace internal | |
| 552 } // namespace base | |
| OLD | NEW |