OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/timer/timer.h" | 5 #include "base/timer/timer.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include <memory> | 9 #include <memory> |
10 | 10 |
11 #include "base/bind.h" | 11 #include "base/bind.h" |
12 #include "base/bind_helpers.h" | 12 #include "base/bind_helpers.h" |
13 #include "base/callback.h" | 13 #include "base/callback.h" |
14 #include "base/macros.h" | 14 #include "base/macros.h" |
15 #include "base/memory/ptr_util.h" | 15 #include "base/memory/ptr_util.h" |
16 #include "base/message_loop/message_loop.h" | 16 #include "base/message_loop/message_loop.h" |
17 #include "base/run_loop.h" | 17 #include "base/run_loop.h" |
18 #include "base/sequenced_task_runner.h" | 18 #include "base/sequenced_task_runner.h" |
19 #include "base/single_thread_task_runner.h" | |
20 #include "base/synchronization/waitable_event.h" | 19 #include "base/synchronization/waitable_event.h" |
21 #include "base/test/sequenced_worker_pool_owner.h" | 20 #include "base/test/sequenced_worker_pool_owner.h" |
22 #include "base/test/test_mock_time_task_runner.h" | 21 #include "base/test/test_mock_time_task_runner.h" |
23 #include "base/threading/platform_thread.h" | 22 #include "base/threading/platform_thread.h" |
24 #include "base/threading/sequenced_task_runner_handle.h" | 23 #include "base/threading/sequenced_task_runner_handle.h" |
25 #include "base/threading/thread.h" | 24 #include "base/threading/thread.h" |
26 #include "base/threading/thread_task_runner_handle.h" | |
27 #include "base/time/tick_clock.h" | 25 #include "base/time/tick_clock.h" |
28 #include "base/time/time.h" | 26 #include "base/time/time.h" |
29 #include "build/build_config.h" | 27 #include "build/build_config.h" |
30 #include "testing/gtest/include/gtest/gtest.h" | 28 #include "testing/gtest/include/gtest/gtest.h" |
31 | 29 |
32 namespace base { | 30 namespace base { |
33 | 31 |
34 namespace { | 32 namespace { |
35 | 33 |
36 // The message loops on which each timer should be tested. | 34 // The message loops on which each timer should be tested. |
(...skipping 22 matching lines...) Expand all Loading... |
59 // |did_run|, if provided, will be signaled when Run() fires. | 57 // |did_run|, if provided, will be signaled when Run() fires. |
60 explicit OneShotTimerTester( | 58 explicit OneShotTimerTester( |
61 WaitableEvent* did_run = nullptr, | 59 WaitableEvent* did_run = nullptr, |
62 const TimeDelta& delay = TimeDelta::FromMilliseconds(10)) | 60 const TimeDelta& delay = TimeDelta::FromMilliseconds(10)) |
63 : quit_closure_(run_loop_.QuitClosure()), | 61 : quit_closure_(run_loop_.QuitClosure()), |
64 did_run_(did_run), | 62 did_run_(did_run), |
65 delay_(delay) {} | 63 delay_(delay) {} |
66 | 64 |
67 virtual ~OneShotTimerTester() = default; | 65 virtual ~OneShotTimerTester() = default; |
68 | 66 |
69 void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) { | 67 void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) { |
70 timer_->SetTaskRunner(std::move(task_runner)); | 68 timer_->SetTaskRunner(std::move(task_runner)); |
71 | 69 |
72 // Run() will be invoked on |task_runner| but |run_loop_|'s QuitClosure | 70 // Run() will be invoked on |task_runner| but |run_loop_|'s QuitClosure |
73 // needs to run on this thread (where the MessageLoop lives). | 71 // needs to run on this thread (where the MessageLoop lives). |
74 quit_closure_ = | 72 quit_closure_ = Bind(IgnoreResult(&SingleThreadTaskRunner::PostTask), |
75 Bind(IgnoreResult(&SingleThreadTaskRunner::PostTask), | 73 SequencedTaskRunnerHandle::Get(), FROM_HERE, |
76 ThreadTaskRunnerHandle::Get(), FROM_HERE, run_loop_.QuitClosure()); | 74 run_loop_.QuitClosure()); |
77 } | 75 } |
78 | 76 |
79 void Start() { | 77 void Start() { |
80 started_time_ = TimeTicks::Now(); | 78 started_time_ = TimeTicks::Now(); |
81 timer_->Start(FROM_HERE, delay_, this, &OneShotTimerTester::Run); | 79 timer_->Start(FROM_HERE, delay_, this, &OneShotTimerTester::Run); |
82 } | 80 } |
83 | 81 |
84 // Blocks until Run() executes and confirms that Run() didn't fire before | 82 // Blocks until Run() executes and confirms that Run() didn't fire before |
85 // |delay_| expired. | 83 // |delay_| expired. |
86 void WaitAndConfirmTimerFiredAfterDelay() { | 84 void WaitAndConfirmTimerFiredAfterDelay() { |
(...skipping 557 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
644 timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), | 642 timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), |
645 Bind(&SetCallbackHappened1)); | 643 Bind(&SetCallbackHappened1)); |
646 timer.Reset(); | 644 timer.Reset(); |
647 // Since Reset happened before task ran, the user_task must not be cleared: | 645 // Since Reset happened before task ran, the user_task must not be cleared: |
648 ASSERT_FALSE(timer.user_task().is_null()); | 646 ASSERT_FALSE(timer.user_task().is_null()); |
649 RunLoop().Run(); | 647 RunLoop().Run(); |
650 EXPECT_TRUE(g_callback_happened1); | 648 EXPECT_TRUE(g_callback_happened1); |
651 } | 649 } |
652 } | 650 } |
653 | 651 |
| 652 namespace { |
| 653 |
| 654 const size_t kNumWorkerThreads = 3; |
| 655 |
| 656 // Fixture for tests requiring a worker pool. Includes a WaitableEvent so |
| 657 // that cases may Wait() on one thread and Signal() (explicitly, or implicitly |
| 658 // via helper methods) on another. |
| 659 class TimerSequenceTest : public testing::Test { |
| 660 public: |
| 661 TimerSequenceTest() |
| 662 : event_(WaitableEvent::ResetPolicy::AUTOMATIC, |
| 663 WaitableEvent::InitialState::NOT_SIGNALED) {} |
| 664 |
| 665 void SetUp() override { |
| 666 pool1_owner_.reset( |
| 667 new SequencedWorkerPoolOwner(kNumWorkerThreads, "test1")); |
| 668 pool2_owner_.reset( |
| 669 new SequencedWorkerPoolOwner(kNumWorkerThreads, "test2")); |
| 670 } |
| 671 |
| 672 // Block until Signal() is called on another thread. |
| 673 void Wait() { event_.Wait(); } |
| 674 |
| 675 void Signal() { event_.Signal(); } |
| 676 |
| 677 // Helper to augment a task with a subsequent call to Signal(). |
| 678 Closure TaskWithSignal(const Closure& task) { |
| 679 return Bind(&TimerSequenceTest::RunTaskAndSignal, Unretained(this), task); |
| 680 } |
| 681 |
| 682 // Create the timer. |
| 683 void CreateTimer() { timer_.reset(new OneShotTimer); } |
| 684 |
| 685 // Schedule an event on the timer. |
| 686 void StartTimer(TimeDelta delay, const Closure& task) { |
| 687 timer_->Start(FROM_HERE, delay, task); |
| 688 } |
| 689 |
| 690 void SetTaskRunnerForTimer(scoped_refptr<SequencedTaskRunner> task_runner) { |
| 691 timer_->SetTaskRunner(std::move(task_runner)); |
| 692 } |
| 693 |
| 694 // Tell the timer to abandon the task. |
| 695 void AbandonTask() { |
| 696 EXPECT_TRUE(timer_->IsRunning()); |
| 697 // Reset() to call Timer::AbandonScheduledTask() |
| 698 timer_->Reset(); |
| 699 EXPECT_TRUE(timer_->IsRunning()); |
| 700 timer_->Stop(); |
| 701 EXPECT_FALSE(timer_->IsRunning()); |
| 702 } |
| 703 |
| 704 static void VerifyAffinity(const SequencedTaskRunner* task_runner) { |
| 705 EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread()); |
| 706 } |
| 707 |
| 708 // Delete the timer. |
| 709 void DeleteTimer() { timer_.reset(); } |
| 710 |
| 711 protected: |
| 712 const scoped_refptr<SequencedWorkerPool>& pool1() { |
| 713 return pool1_owner_->pool(); |
| 714 } |
| 715 const scoped_refptr<SequencedWorkerPool>& pool2() { |
| 716 return pool2_owner_->pool(); |
| 717 } |
| 718 |
| 719 private: |
| 720 void RunTaskAndSignal(const Closure& task) { |
| 721 task.Run(); |
| 722 Signal(); |
| 723 } |
| 724 |
| 725 WaitableEvent event_; |
| 726 |
| 727 MessageLoop message_loop_; |
| 728 std::unique_ptr<SequencedWorkerPoolOwner> pool1_owner_; |
| 729 std::unique_ptr<SequencedWorkerPoolOwner> pool2_owner_; |
| 730 |
| 731 std::unique_ptr<OneShotTimer> timer_; |
| 732 |
| 733 DISALLOW_COPY_AND_ASSIGN(TimerSequenceTest); |
| 734 }; |
| 735 |
| 736 } // namespace |
| 737 |
| 738 TEST_F(TimerSequenceTest, OneShotTimerTaskOnPoolThread) { |
| 739 scoped_refptr<SequencedTaskRunner> task_runner = |
| 740 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); |
| 741 |
| 742 // Timer is created on this thread. |
| 743 CreateTimer(); |
| 744 |
| 745 // Task will execute on a pool thread. |
| 746 SetTaskRunnerForTimer(task_runner); |
| 747 StartTimer(TimeDelta::FromMilliseconds(1), |
| 748 Bind(&TimerSequenceTest::Signal, Unretained(this))); |
| 749 Wait(); |
| 750 |
| 751 // Timer will be destroyed on this thread. |
| 752 DeleteTimer(); |
| 753 } |
| 754 |
| 755 TEST_F(TimerSequenceTest, OneShotTimerUsedOnPoolThread) { |
| 756 scoped_refptr<SequencedTaskRunner> task_runner = |
| 757 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); |
| 758 |
| 759 // Timer is created on this thread. |
| 760 CreateTimer(); |
| 761 |
| 762 // Task will be scheduled from a pool thread. |
| 763 task_runner->PostTask( |
| 764 FROM_HERE, Bind(&TimerSequenceTest::StartTimer, Unretained(this), |
| 765 TimeDelta::FromMilliseconds(1), |
| 766 Bind(&TimerSequenceTest::Signal, Unretained(this)))); |
| 767 Wait(); |
| 768 |
| 769 // Timer must be destroyed on pool thread, too. |
| 770 task_runner->PostTask( |
| 771 FROM_HERE, |
| 772 TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this)))); |
| 773 Wait(); |
| 774 } |
| 775 |
| 776 TEST_F(TimerSequenceTest, OneShotTimerTwoPoolsAbandonTask) { |
| 777 scoped_refptr<SequencedTaskRunner> task_runner1 = |
| 778 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); |
| 779 scoped_refptr<SequencedTaskRunner> task_runner2 = |
| 780 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken()); |
| 781 |
| 782 // Create timer on pool #1. |
| 783 task_runner1->PostTask( |
| 784 FROM_HERE, |
| 785 TaskWithSignal(Bind(&TimerSequenceTest::CreateTimer, Unretained(this)))); |
| 786 Wait(); |
| 787 |
| 788 // And tell it to execute on a different pool (#2). |
| 789 task_runner1->PostTask( |
| 790 FROM_HERE, TaskWithSignal(Bind(&TimerSequenceTest::SetTaskRunnerForTimer, |
| 791 Unretained(this), task_runner2))); |
| 792 Wait(); |
| 793 |
| 794 // Task will be scheduled from pool #1. |
| 795 task_runner1->PostTask(FROM_HERE, |
| 796 Bind(&TimerSequenceTest::StartTimer, Unretained(this), |
| 797 TimeDelta::FromHours(1), Bind(&DoNothing))); |
| 798 |
| 799 // Abandon task - must be called from scheduling pool (#1). |
| 800 task_runner1->PostTask( |
| 801 FROM_HERE, |
| 802 TaskWithSignal(Bind(&TimerSequenceTest::AbandonTask, Unretained(this)))); |
| 803 Wait(); |
| 804 |
| 805 // Timer must be destroyed on the pool it was scheduled from (#1). |
| 806 task_runner1->PostTask( |
| 807 FROM_HERE, |
| 808 TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this)))); |
| 809 Wait(); |
| 810 } |
| 811 |
| 812 TEST_F(TimerSequenceTest, OneShotTimerUsedAndTaskedOnDifferentPools) { |
| 813 scoped_refptr<SequencedTaskRunner> task_runner1 = |
| 814 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); |
| 815 scoped_refptr<SequencedTaskRunner> task_runner2 = |
| 816 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken()); |
| 817 |
| 818 // Create timer on pool #1. |
| 819 task_runner1->PostTask( |
| 820 FROM_HERE, |
| 821 TaskWithSignal(Bind(&TimerSequenceTest::CreateTimer, Unretained(this)))); |
| 822 Wait(); |
| 823 |
| 824 // And tell it to execute on a different pool (#2). |
| 825 task_runner1->PostTask( |
| 826 FROM_HERE, TaskWithSignal(Bind(&TimerSequenceTest::SetTaskRunnerForTimer, |
| 827 Unretained(this), task_runner2))); |
| 828 Wait(); |
| 829 |
| 830 // Task will be scheduled from pool #1. |
| 831 task_runner1->PostTask( |
| 832 FROM_HERE, Bind(&TimerSequenceTest::StartTimer, Unretained(this), |
| 833 TimeDelta::FromMilliseconds(1), |
| 834 TaskWithSignal(Bind(&TimerSequenceTest::VerifyAffinity, |
| 835 Unretained(task_runner2.get()))))); |
| 836 |
| 837 Wait(); |
| 838 |
| 839 // Timer must be destroyed on the pool it was scheduled from (#1). |
| 840 task_runner1->PostTask( |
| 841 FROM_HERE, |
| 842 TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this)))); |
| 843 Wait(); |
| 844 } |
| 845 |
654 } // namespace base | 846 } // namespace base |
OLD | NEW |