OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/task_scheduler/scheduler_worker.h" | 5 #include "base/task_scheduler/scheduler_worker.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 #include <vector> | 10 #include <vector> |
(...skipping 23 matching lines...) Expand all Loading... |
34 namespace internal { | 34 namespace internal { |
35 namespace { | 35 namespace { |
36 | 36 |
37 const size_t kNumSequencesPerTest = 150; | 37 const size_t kNumSequencesPerTest = 150; |
38 | 38 |
39 class SchedulerWorkerDefaultDelegate : public SchedulerWorker::Delegate { | 39 class SchedulerWorkerDefaultDelegate : public SchedulerWorker::Delegate { |
40 public: | 40 public: |
41 SchedulerWorkerDefaultDelegate() = default; | 41 SchedulerWorkerDefaultDelegate() = default; |
42 | 42 |
43 // SchedulerWorker::Delegate: | 43 // SchedulerWorker::Delegate: |
44 void OnMainEntry(SchedulerWorker* worker, | 44 void OnMainEntry(SchedulerWorker* worker) override {} |
45 const TimeDelta& detach_duration) override {} | |
46 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { | 45 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { |
47 return nullptr; | 46 return nullptr; |
48 } | 47 } |
49 void DidRunTaskWithPriority(TaskPriority task_priority, | 48 void DidRunTaskWithPriority(TaskPriority task_priority, |
50 const TimeDelta& task_latency) override { | 49 const TimeDelta& task_latency) override { |
51 ADD_FAILURE() << "Unexpected call to DidRunTaskWithPriority()"; | 50 ADD_FAILURE() << "Unexpected call to DidRunTaskWithPriority()"; |
52 } | 51 } |
53 void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { | 52 void ReEnqueueSequence(scoped_refptr<Sequence> sequence) override { |
54 ADD_FAILURE() << "Unexpected call to ReEnqueueSequence()"; | 53 ADD_FAILURE() << "Unexpected call to ReEnqueueSequence()"; |
55 } | 54 } |
56 TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); } | 55 TimeDelta GetSleepTimeout() override { return TimeDelta::Max(); } |
57 bool CanDetach(SchedulerWorker* worker) override { return false; } | 56 bool CanDetach(SchedulerWorker* worker) override { return false; } |
| 57 void OnDetach() override { ADD_FAILURE() << "Unexpected call to OnDetach()"; } |
58 | 58 |
59 private: | 59 private: |
60 DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerDefaultDelegate); | 60 DISALLOW_COPY_AND_ASSIGN(SchedulerWorkerDefaultDelegate); |
61 }; | 61 }; |
62 | 62 |
63 // The test parameter is the number of Tasks per Sequence returned by GetWork(). | 63 // The test parameter is the number of Tasks per Sequence returned by GetWork(). |
64 class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> { | 64 class TaskSchedulerWorkerTest : public testing::TestWithParam<size_t> { |
65 protected: | 65 protected: |
66 TaskSchedulerWorkerTest() | 66 TaskSchedulerWorkerTest() |
67 : main_entry_called_(WaitableEvent::ResetPolicy::MANUAL, | 67 : main_entry_called_(WaitableEvent::ResetPolicy::MANUAL, |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 class TestSchedulerWorkerDelegate : public SchedulerWorkerDefaultDelegate { | 124 class TestSchedulerWorkerDelegate : public SchedulerWorkerDefaultDelegate { |
125 public: | 125 public: |
126 TestSchedulerWorkerDelegate(TaskSchedulerWorkerTest* outer) | 126 TestSchedulerWorkerDelegate(TaskSchedulerWorkerTest* outer) |
127 : outer_(outer) {} | 127 : outer_(outer) {} |
128 | 128 |
129 ~TestSchedulerWorkerDelegate() override { | 129 ~TestSchedulerWorkerDelegate() override { |
130 EXPECT_FALSE(IsCallToDidRunTaskWithPriorityExpected()); | 130 EXPECT_FALSE(IsCallToDidRunTaskWithPriorityExpected()); |
131 } | 131 } |
132 | 132 |
133 // SchedulerWorker::Delegate: | 133 // SchedulerWorker::Delegate: |
134 void OnMainEntry(SchedulerWorker* worker, | 134 void OnMainEntry(SchedulerWorker* worker) override { |
135 const TimeDelta& detach_duration) override { | |
136 outer_->worker_set_.Wait(); | 135 outer_->worker_set_.Wait(); |
137 EXPECT_EQ(outer_->worker_.get(), worker); | 136 EXPECT_EQ(outer_->worker_.get(), worker); |
138 EXPECT_FALSE(IsCallToDidRunTaskWithPriorityExpected()); | 137 EXPECT_FALSE(IsCallToDidRunTaskWithPriorityExpected()); |
139 | 138 |
140 // Without synchronization, OnMainEntry() could be called twice without | 139 // Without synchronization, OnMainEntry() could be called twice without |
141 // generating an error. | 140 // generating an error. |
142 AutoSchedulerLock auto_lock(outer_->lock_); | 141 AutoSchedulerLock auto_lock(outer_->lock_); |
143 EXPECT_FALSE(outer_->main_entry_called_.IsSignaled()); | 142 EXPECT_FALSE(outer_->main_entry_called_.IsSignaled()); |
144 outer_->main_entry_called_.Signal(); | 143 outer_->main_entry_called_.Signal(); |
145 } | 144 } |
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
356 | 355 |
357 namespace { | 356 namespace { |
358 | 357 |
359 class ControllableDetachDelegate : public SchedulerWorkerDefaultDelegate { | 358 class ControllableDetachDelegate : public SchedulerWorkerDefaultDelegate { |
360 public: | 359 public: |
361 ControllableDetachDelegate(TaskTracker* task_tracker) | 360 ControllableDetachDelegate(TaskTracker* task_tracker) |
362 : task_tracker_(task_tracker), | 361 : task_tracker_(task_tracker), |
363 work_processed_(WaitableEvent::ResetPolicy::MANUAL, | 362 work_processed_(WaitableEvent::ResetPolicy::MANUAL, |
364 WaitableEvent::InitialState::NOT_SIGNALED), | 363 WaitableEvent::InitialState::NOT_SIGNALED), |
365 detach_requested_(WaitableEvent::ResetPolicy::MANUAL, | 364 detach_requested_(WaitableEvent::ResetPolicy::MANUAL, |
366 WaitableEvent::InitialState::NOT_SIGNALED) { | 365 WaitableEvent::InitialState::NOT_SIGNALED), |
| 366 detached_(WaitableEvent::ResetPolicy::MANUAL, |
| 367 WaitableEvent::InitialState::NOT_SIGNALED) { |
367 EXPECT_TRUE(task_tracker_); | 368 EXPECT_TRUE(task_tracker_); |
368 } | 369 } |
369 | 370 |
370 ~ControllableDetachDelegate() override = default; | 371 ~ControllableDetachDelegate() override = default; |
371 | 372 |
372 // SchedulerWorker::Delegate: | 373 // SchedulerWorker::Delegate: |
373 MOCK_METHOD2(OnMainEntry, | 374 MOCK_METHOD1(OnMainEntry, void(SchedulerWorker* worker)); |
374 void(SchedulerWorker* worker, const TimeDelta& detach_duration)); | |
375 | 375 |
376 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) | 376 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) |
377 override { | 377 override { |
378 // Sends one item of work to signal |work_processed_|. On subsequent calls, | 378 // Sends one item of work to signal |work_processed_|. On subsequent calls, |
379 // sends nullptr to indicate there's no more work to be done. | 379 // sends nullptr to indicate there's no more work to be done. |
380 if (work_requested_) | 380 if (work_requested_) |
381 return nullptr; | 381 return nullptr; |
382 | 382 |
383 work_requested_ = true; | 383 work_requested_ = true; |
384 scoped_refptr<Sequence> sequence(new Sequence); | 384 scoped_refptr<Sequence> sequence(new Sequence); |
385 std::unique_ptr<Task> task(new Task( | 385 std::unique_ptr<Task> task(new Task( |
386 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&work_processed_)), | 386 FROM_HERE, Bind(&WaitableEvent::Signal, Unretained(&work_processed_)), |
387 TaskTraits(), TimeDelta())); | 387 TaskTraits(), TimeDelta())); |
388 EXPECT_TRUE(task_tracker_->WillPostTask(task.get())); | 388 EXPECT_TRUE(task_tracker_->WillPostTask(task.get())); |
389 sequence->PushTask(std::move(task)); | 389 sequence->PushTask(std::move(task)); |
390 return sequence; | 390 return sequence; |
391 } | 391 } |
392 | 392 |
393 void DidRunTaskWithPriority(TaskPriority task, | 393 void DidRunTaskWithPriority(TaskPriority task, |
394 const TimeDelta& task_latency) override {} | 394 const TimeDelta& task_latency) override {} |
395 | 395 |
396 bool CanDetach(SchedulerWorker* worker) override { | 396 bool CanDetach(SchedulerWorker* worker) override { |
397 detach_requested_.Signal(); | 397 detach_requested_.Signal(); |
398 return can_detach_; | 398 return can_detach_; |
399 } | 399 } |
400 | 400 |
| 401 void OnDetach() override { |
| 402 EXPECT_TRUE(can_detach_); |
| 403 EXPECT_TRUE(detach_requested_.IsSignaled()); |
| 404 detached_.Signal(); |
| 405 } |
| 406 |
401 void WaitForWorkToRun() { | 407 void WaitForWorkToRun() { |
402 work_processed_.Wait(); | 408 work_processed_.Wait(); |
403 } | 409 } |
404 | 410 |
405 void WaitForDetachRequest() { | 411 void WaitForDetachRequest() { |
406 detach_requested_.Wait(); | 412 detach_requested_.Wait(); |
407 } | 413 } |
408 | 414 |
| 415 void WaitForDetach() { detached_.Wait(); } |
| 416 |
409 void ResetState() { | 417 void ResetState() { |
410 work_requested_ = false; | 418 work_requested_ = false; |
411 work_processed_.Reset(); | 419 work_processed_.Reset(); |
412 detach_requested_.Reset(); | 420 detach_requested_.Reset(); |
413 } | 421 } |
414 | 422 |
415 void set_can_detach(bool can_detach) { can_detach_ = can_detach; } | 423 void set_can_detach(bool can_detach) { can_detach_ = can_detach; } |
416 | 424 |
417 private: | 425 private: |
418 TaskTracker* const task_tracker_; | 426 TaskTracker* const task_tracker_; |
419 bool work_requested_ = false; | 427 bool work_requested_ = false; |
420 bool can_detach_ = false; | 428 bool can_detach_ = false; |
421 WaitableEvent work_processed_; | 429 WaitableEvent work_processed_; |
422 WaitableEvent detach_requested_; | 430 WaitableEvent detach_requested_; |
| 431 WaitableEvent detached_; |
423 | 432 |
424 DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate); | 433 DISALLOW_COPY_AND_ASSIGN(ControllableDetachDelegate); |
425 }; | 434 }; |
426 | 435 |
427 } // namespace | 436 } // namespace |
428 | 437 |
429 TEST(TaskSchedulerWorkerTest, WorkerDetaches) { | 438 TEST(TaskSchedulerWorkerTest, WorkerDetaches) { |
430 TaskTracker task_tracker; | 439 TaskTracker task_tracker; |
431 // Will be owned by SchedulerWorker. | 440 // Will be owned by SchedulerWorker. |
432 ControllableDetachDelegate* delegate = | 441 ControllableDetachDelegate* delegate = |
433 new StrictMock<ControllableDetachDelegate>(&task_tracker); | 442 new StrictMock<ControllableDetachDelegate>(&task_tracker); |
434 delegate->set_can_detach(true); | 443 delegate->set_can_detach(true); |
435 EXPECT_CALL(*delegate, OnMainEntry(_, TimeDelta::Max())); | 444 EXPECT_CALL(*delegate, OnMainEntry(_)); |
436 std::unique_ptr<SchedulerWorker> worker = | 445 std::unique_ptr<SchedulerWorker> worker = |
437 SchedulerWorker::Create( | 446 SchedulerWorker::Create( |
438 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | 447 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, |
439 SchedulerWorker::InitialState::ALIVE); | 448 SchedulerWorker::InitialState::ALIVE); |
440 worker->WakeUp(); | 449 worker->WakeUp(); |
441 delegate->WaitForWorkToRun(); | 450 delegate->WaitForWorkToRun(); |
442 Mock::VerifyAndClear(delegate); | 451 Mock::VerifyAndClear(delegate); |
443 delegate->WaitForDetachRequest(); | 452 delegate->WaitForDetachRequest(); |
444 // Sleep to give a chance for the detach to happen. A yield is too short. | 453 delegate->WaitForDetach(); |
445 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | |
446 ASSERT_FALSE(worker->ThreadAliveForTesting()); | 454 ASSERT_FALSE(worker->ThreadAliveForTesting()); |
447 } | 455 } |
448 | 456 |
449 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) { | 457 TEST(TaskSchedulerWorkerTest, WorkerDetachesAndWakes) { |
450 TaskTracker task_tracker; | 458 TaskTracker task_tracker; |
451 // Will be owned by SchedulerWorker. | 459 // Will be owned by SchedulerWorker. |
452 ControllableDetachDelegate* delegate = | 460 ControllableDetachDelegate* delegate = |
453 new StrictMock<ControllableDetachDelegate>(&task_tracker); | 461 new StrictMock<ControllableDetachDelegate>(&task_tracker); |
454 delegate->set_can_detach(true); | 462 delegate->set_can_detach(true); |
455 EXPECT_CALL(*delegate, OnMainEntry(_, TimeDelta::Max())); | 463 EXPECT_CALL(*delegate, OnMainEntry(_)); |
456 std::unique_ptr<SchedulerWorker> worker = | 464 std::unique_ptr<SchedulerWorker> worker = |
457 SchedulerWorker::Create( | 465 SchedulerWorker::Create( |
458 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | 466 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, |
459 SchedulerWorker::InitialState::ALIVE); | 467 SchedulerWorker::InitialState::ALIVE); |
460 worker->WakeUp(); | 468 worker->WakeUp(); |
461 delegate->WaitForWorkToRun(); | 469 delegate->WaitForWorkToRun(); |
462 Mock::VerifyAndClear(delegate); | 470 Mock::VerifyAndClear(delegate); |
463 delegate->WaitForDetachRequest(); | 471 delegate->WaitForDetachRequest(); |
464 // Sleep to give a chance for the detach to happen. A yield is too short. | 472 delegate->WaitForDetach(); |
465 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | |
466 ASSERT_FALSE(worker->ThreadAliveForTesting()); | 473 ASSERT_FALSE(worker->ThreadAliveForTesting()); |
467 | 474 |
468 delegate->ResetState(); | 475 delegate->ResetState(); |
469 delegate->set_can_detach(false); | 476 delegate->set_can_detach(false); |
470 // When SchedulerWorker recreates its thread, expect OnMainEntry() to be | 477 // Expect OnMainEntry() to be called when SchedulerWorker recreates its |
471 // called with a detach duration which is not TimeDelta::Max(). | 478 // thread. |
472 EXPECT_CALL(*delegate, OnMainEntry(worker.get(), Ne(TimeDelta::Max()))); | 479 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); |
473 worker->WakeUp(); | 480 worker->WakeUp(); |
474 delegate->WaitForWorkToRun(); | 481 delegate->WaitForWorkToRun(); |
475 Mock::VerifyAndClear(delegate); | 482 Mock::VerifyAndClear(delegate); |
476 delegate->WaitForDetachRequest(); | 483 delegate->WaitForDetachRequest(); |
477 PlatformThread::Sleep(TimeDelta::FromMilliseconds(50)); | 484 delegate->WaitForDetach(); |
478 ASSERT_TRUE(worker->ThreadAliveForTesting()); | 485 ASSERT_TRUE(worker->ThreadAliveForTesting()); |
479 worker->JoinForTesting(); | 486 worker->JoinForTesting(); |
480 } | 487 } |
481 | 488 |
482 TEST(TaskSchedulerWorkerTest, CreateDetached) { | 489 TEST(TaskSchedulerWorkerTest, CreateDetached) { |
483 TaskTracker task_tracker; | 490 TaskTracker task_tracker; |
484 // Will be owned by SchedulerWorker. | 491 // Will be owned by SchedulerWorker. |
485 ControllableDetachDelegate* delegate = | 492 ControllableDetachDelegate* delegate = |
486 new StrictMock<ControllableDetachDelegate>(&task_tracker); | 493 new StrictMock<ControllableDetachDelegate>(&task_tracker); |
487 std::unique_ptr<SchedulerWorker> worker = | 494 std::unique_ptr<SchedulerWorker> worker = |
488 SchedulerWorker::Create( | 495 SchedulerWorker::Create( |
489 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, | 496 ThreadPriority::NORMAL, WrapUnique(delegate), &task_tracker, |
490 SchedulerWorker::InitialState::DETACHED); | 497 SchedulerWorker::InitialState::DETACHED); |
491 ASSERT_FALSE(worker->ThreadAliveForTesting()); | 498 ASSERT_FALSE(worker->ThreadAliveForTesting()); |
492 EXPECT_CALL(*delegate, OnMainEntry(worker.get(), TimeDelta::Max())); | 499 EXPECT_CALL(*delegate, OnMainEntry(worker.get())); |
493 worker->WakeUp(); | 500 worker->WakeUp(); |
494 delegate->WaitForWorkToRun(); | 501 delegate->WaitForWorkToRun(); |
495 Mock::VerifyAndClear(delegate); | 502 Mock::VerifyAndClear(delegate); |
496 delegate->WaitForDetachRequest(); | 503 delegate->WaitForDetachRequest(); |
497 ASSERT_TRUE(worker->ThreadAliveForTesting()); | 504 ASSERT_TRUE(worker->ThreadAliveForTesting()); |
498 worker->JoinForTesting(); | 505 worker->JoinForTesting(); |
499 } | 506 } |
500 | 507 |
501 namespace { | 508 namespace { |
502 | 509 |
503 class ExpectThreadPriorityDelegate : public SchedulerWorkerDefaultDelegate { | 510 class ExpectThreadPriorityDelegate : public SchedulerWorkerDefaultDelegate { |
504 public: | 511 public: |
505 ExpectThreadPriorityDelegate() | 512 ExpectThreadPriorityDelegate() |
506 : priority_verified_in_get_work_event_( | 513 : priority_verified_in_get_work_event_( |
507 WaitableEvent::ResetPolicy::AUTOMATIC, | 514 WaitableEvent::ResetPolicy::AUTOMATIC, |
508 WaitableEvent::InitialState::NOT_SIGNALED), | 515 WaitableEvent::InitialState::NOT_SIGNALED), |
509 expected_thread_priority_(ThreadPriority::BACKGROUND) {} | 516 expected_thread_priority_(ThreadPriority::BACKGROUND) {} |
510 | 517 |
511 void SetExpectedThreadPriority(ThreadPriority expected_thread_priority) { | 518 void SetExpectedThreadPriority(ThreadPriority expected_thread_priority) { |
512 expected_thread_priority_ = expected_thread_priority; | 519 expected_thread_priority_ = expected_thread_priority; |
513 } | 520 } |
514 | 521 |
515 void WaitForPriorityVerifiedInGetWork() { | 522 void WaitForPriorityVerifiedInGetWork() { |
516 priority_verified_in_get_work_event_.Wait(); | 523 priority_verified_in_get_work_event_.Wait(); |
517 } | 524 } |
518 | 525 |
519 // SchedulerWorker::Delegate: | 526 // SchedulerWorker::Delegate: |
520 void OnMainEntry(SchedulerWorker* worker, | 527 void OnMainEntry(SchedulerWorker* worker) override { VerifyThreadPriority(); } |
521 const TimeDelta& detach_duration) override { | |
522 VerifyThreadPriority(); | |
523 } | |
524 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { | 528 scoped_refptr<Sequence> GetWork(SchedulerWorker* worker) override { |
525 VerifyThreadPriority(); | 529 VerifyThreadPriority(); |
526 priority_verified_in_get_work_event_.Signal(); | 530 priority_verified_in_get_work_event_.Signal(); |
527 return nullptr; | 531 return nullptr; |
528 } | 532 } |
529 | 533 |
530 private: | 534 private: |
531 void VerifyThreadPriority() { | 535 void VerifyThreadPriority() { |
532 AutoSchedulerLock auto_lock(expected_thread_priority_lock_); | 536 AutoSchedulerLock auto_lock(expected_thread_priority_lock_); |
533 EXPECT_EQ(expected_thread_priority_, | 537 EXPECT_EQ(expected_thread_priority_, |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
597 // OnMainEntry() and GetWork() are called. | 601 // OnMainEntry() and GetWork() are called. |
598 worker->WakeUp(); | 602 worker->WakeUp(); |
599 delegate_raw->WaitForPriorityVerifiedInGetWork(); | 603 delegate_raw->WaitForPriorityVerifiedInGetWork(); |
600 | 604 |
601 worker->JoinForTesting(); | 605 worker->JoinForTesting(); |
602 } | 606 } |
603 | 607 |
604 } // namespace | 608 } // namespace |
605 } // namespace internal | 609 } // namespace internal |
606 } // namespace base | 610 } // namespace base |
OLD | NEW |