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/memory/ref_counted.h" | 16 #include "base/memory/ref_counted.h" |
17 #include "base/message_loop/message_loop.h" | 17 #include "base/message_loop/message_loop.h" |
18 #include "base/run_loop.h" | 18 #include "base/run_loop.h" |
19 #include "base/sequenced_task_runner.h" | 19 #include "base/sequenced_task_runner.h" |
20 #include "base/single_thread_task_runner.h" | |
21 #include "base/synchronization/waitable_event.h" | 20 #include "base/synchronization/waitable_event.h" |
22 #include "base/test/sequenced_worker_pool_owner.h" | 21 #include "base/test/sequenced_worker_pool_owner.h" |
23 #include "base/test/test_mock_time_task_runner.h" | 22 #include "base/test/test_mock_time_task_runner.h" |
24 #include "base/threading/platform_thread.h" | 23 #include "base/threading/platform_thread.h" |
25 #include "base/threading/sequenced_task_runner_handle.h" | 24 #include "base/threading/sequenced_task_runner_handle.h" |
26 #include "base/threading/thread.h" | 25 #include "base/threading/thread.h" |
27 #include "base/threading/thread_task_runner_handle.h" | |
28 #include "base/time/tick_clock.h" | 26 #include "base/time/tick_clock.h" |
29 #include "base/time/time.h" | 27 #include "base/time/time.h" |
30 #include "build/build_config.h" | 28 #include "build/build_config.h" |
31 #include "testing/gtest/include/gtest/gtest.h" | 29 #include "testing/gtest/include/gtest/gtest.h" |
32 | 30 |
33 namespace base { | 31 namespace base { |
34 | 32 |
35 namespace { | 33 namespace { |
36 | 34 |
37 // The message loops on which each timer should be tested. | 35 // The message loops on which each timer should be tested. |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
101 public: | 99 public: |
102 // |did_run|, if provided, will be signaled when Run() fires. | 100 // |did_run|, if provided, will be signaled when Run() fires. |
103 explicit OneShotTimerTester( | 101 explicit OneShotTimerTester( |
104 WaitableEvent* did_run = nullptr, | 102 WaitableEvent* did_run = nullptr, |
105 const TimeDelta& delay = TimeDelta::FromMilliseconds(10)) | 103 const TimeDelta& delay = TimeDelta::FromMilliseconds(10)) |
106 : OneShotTimerTesterBase(did_run, delay), | 104 : OneShotTimerTesterBase(did_run, delay), |
107 quit_closure_(run_loop_.QuitClosure()) {} | 105 quit_closure_(run_loop_.QuitClosure()) {} |
108 | 106 |
109 ~OneShotTimerTester() override = default; | 107 ~OneShotTimerTester() override = default; |
110 | 108 |
111 void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) { | 109 void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) { |
112 timer_->SetTaskRunner(std::move(task_runner)); | 110 timer_->SetTaskRunner(std::move(task_runner)); |
113 | 111 |
114 // Run() will be invoked on |task_runner| but |run_loop_|'s QuitClosure | 112 // Run() will be invoked on |task_runner| but |run_loop_|'s QuitClosure |
115 // needs to run on this thread (where the MessageLoop lives). | 113 // needs to run on this thread (where the MessageLoop lives). |
116 quit_closure_ = | 114 quit_closure_ = Bind(IgnoreResult(&SequencedTaskRunner::PostTask), |
117 Bind(IgnoreResult(&SingleThreadTaskRunner::PostTask), | 115 SequencedTaskRunnerHandle::Get(), FROM_HERE, |
118 ThreadTaskRunnerHandle::Get(), FROM_HERE, run_loop_.QuitClosure()); | 116 run_loop_.QuitClosure()); |
119 } | 117 } |
120 | 118 |
121 // Blocks until Run() executes and confirms that Run() didn't fire before | 119 // Blocks until Run() executes and confirms that Run() didn't fire before |
122 // |delay_| expired. | 120 // |delay_| expired. |
123 void WaitAndConfirmTimerFiredAfterDelay() { | 121 void WaitAndConfirmTimerFiredAfterDelay() { |
124 run_loop_.Run(); | 122 run_loop_.Run(); |
125 | 123 |
126 EXPECT_NE(TimeTicks(), started_time()); | 124 EXPECT_NE(TimeTicks(), started_time()); |
127 EXPECT_GE(TimeTicks::Now() - started_time(), delay()); | 125 EXPECT_GE(TimeTicks::Now() - started_time(), delay()); |
128 } | 126 } |
(...skipping 532 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
661 false); | 659 false); |
662 EXPECT_FALSE(timer.IsRunning()); | 660 EXPECT_FALSE(timer.IsRunning()); |
663 timer.Reset(); | 661 timer.Reset(); |
664 EXPECT_TRUE(timer.IsRunning()); | 662 EXPECT_TRUE(timer.IsRunning()); |
665 timer.Stop(); | 663 timer.Stop(); |
666 EXPECT_FALSE(timer.IsRunning()); | 664 EXPECT_FALSE(timer.IsRunning()); |
667 timer.Reset(); | 665 timer.Reset(); |
668 EXPECT_TRUE(timer.IsRunning()); | 666 EXPECT_TRUE(timer.IsRunning()); |
669 } | 667 } |
670 | 668 |
| 669 //----------------------------------------------------------------------------- |
| 670 |
671 namespace { | 671 namespace { |
672 | 672 |
673 bool g_callback_happened1 = false; | 673 bool g_callback_happened1 = false; |
674 bool g_callback_happened2 = false; | 674 bool g_callback_happened2 = false; |
675 | 675 |
676 void ClearAllCallbackHappened() { | 676 void ClearAllCallbackHappened() { |
677 g_callback_happened1 = false; | 677 g_callback_happened1 = false; |
678 g_callback_happened2 = false; | 678 g_callback_happened2 = false; |
679 } | 679 } |
680 | 680 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
714 timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), | 714 timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), |
715 Bind(&SetCallbackHappened1)); | 715 Bind(&SetCallbackHappened1)); |
716 timer.Reset(); | 716 timer.Reset(); |
717 // Since Reset happened before task ran, the user_task must not be cleared: | 717 // Since Reset happened before task ran, the user_task must not be cleared: |
718 ASSERT_FALSE(timer.user_task().is_null()); | 718 ASSERT_FALSE(timer.user_task().is_null()); |
719 RunLoop().Run(); | 719 RunLoop().Run(); |
720 EXPECT_TRUE(g_callback_happened1); | 720 EXPECT_TRUE(g_callback_happened1); |
721 } | 721 } |
722 } | 722 } |
723 | 723 |
| 724 namespace { |
| 725 |
| 726 const size_t kNumWorkerThreads = 3; |
| 727 |
| 728 // Fixture for tests requiring a worker pool. Includes a WaitableEvent so |
| 729 // that cases may Wait() on one thread and Signal() (explicitly, or implicitly |
| 730 // via helper methods) on another. |
| 731 class TimerSequenceTest : public testing::Test { |
| 732 public: |
| 733 TimerSequenceTest() |
| 734 : event_(WaitableEvent::ResetPolicy::AUTOMATIC, |
| 735 WaitableEvent::InitialState::NOT_SIGNALED) {} |
| 736 |
| 737 void SetUp() override { |
| 738 pool1_owner_.reset( |
| 739 new SequencedWorkerPoolOwner(kNumWorkerThreads, "test1")); |
| 740 pool2_owner_.reset( |
| 741 new SequencedWorkerPoolOwner(kNumWorkerThreads, "test2")); |
| 742 } |
| 743 |
| 744 // Block until Signal() is called on another thread. |
| 745 void Wait() { event_.Wait(); } |
| 746 |
| 747 void Signal() { event_.Signal(); } |
| 748 |
| 749 // Helper to augment a task with a subsequent call to Signal(). |
| 750 Closure TaskWithSignal(const Closure& task) { |
| 751 return Bind(&TimerSequenceTest::RunTaskAndSignal, Unretained(this), task); |
| 752 } |
| 753 |
| 754 // Create the timer. |
| 755 void CreateTimer() { timer_.reset(new OneShotTimer); } |
| 756 |
| 757 // Schedule an event on the timer. |
| 758 void StartTimer(TimeDelta delay, const Closure& task) { |
| 759 timer_->Start(FROM_HERE, delay, task); |
| 760 } |
| 761 |
| 762 void SetTaskRunnerForTimer(scoped_refptr<SequencedTaskRunner> task_runner) { |
| 763 timer_->SetTaskRunner(std::move(task_runner)); |
| 764 } |
| 765 |
| 766 // Tell the timer to abandon the task. |
| 767 void AbandonTask() { |
| 768 EXPECT_TRUE(timer_->IsRunning()); |
| 769 // Reset() to call Timer::AbandonScheduledTask() |
| 770 timer_->Reset(); |
| 771 EXPECT_TRUE(timer_->IsRunning()); |
| 772 timer_->Stop(); |
| 773 EXPECT_FALSE(timer_->IsRunning()); |
| 774 } |
| 775 |
| 776 static void VerifyAffinity(const SequencedTaskRunner* task_runner) { |
| 777 EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread()); |
| 778 } |
| 779 |
| 780 // Delete the timer. |
| 781 void DeleteTimer() { timer_.reset(); } |
| 782 |
| 783 protected: |
| 784 const scoped_refptr<SequencedWorkerPool>& pool1() { |
| 785 return pool1_owner_->pool(); |
| 786 } |
| 787 const scoped_refptr<SequencedWorkerPool>& pool2() { |
| 788 return pool2_owner_->pool(); |
| 789 } |
| 790 |
| 791 private: |
| 792 void RunTaskAndSignal(const Closure& task) { |
| 793 task.Run(); |
| 794 Signal(); |
| 795 } |
| 796 |
| 797 WaitableEvent event_; |
| 798 |
| 799 MessageLoop message_loop_; |
| 800 std::unique_ptr<SequencedWorkerPoolOwner> pool1_owner_; |
| 801 std::unique_ptr<SequencedWorkerPoolOwner> pool2_owner_; |
| 802 |
| 803 std::unique_ptr<OneShotTimer> timer_; |
| 804 |
| 805 DISALLOW_COPY_AND_ASSIGN(TimerSequenceTest); |
| 806 }; |
| 807 |
| 808 } // namespace |
| 809 |
| 810 TEST_F(TimerSequenceTest, OneShotTimerTaskOnPoolThread) { |
| 811 scoped_refptr<SequencedTaskRunner> task_runner = |
| 812 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); |
| 813 |
| 814 base::RunLoop run_loop_; |
| 815 |
| 816 // Timer is created on this thread. |
| 817 CreateTimer(); |
| 818 |
| 819 // Task will execute on a pool thread. |
| 820 SetTaskRunnerForTimer(task_runner); |
| 821 StartTimer(TimeDelta::FromMilliseconds(1), |
| 822 Bind(IgnoreResult(&SequencedTaskRunner::PostTask), |
| 823 SequencedTaskRunnerHandle::Get(), FROM_HERE, |
| 824 run_loop_.QuitClosure())); |
| 825 |
| 826 // Spin the loop so that the delayed task fires on it, which will forward it |
| 827 // to |task_runner|. And since the Timer's task is one that posts back to this |
| 828 // MessageLoop to quit, we finally unblock. |
| 829 run_loop_.Run(); |
| 830 |
| 831 // Timer will be destroyed on this thread. |
| 832 DeleteTimer(); |
| 833 } |
| 834 |
| 835 TEST_F(TimerSequenceTest, OneShotTimerUsedOnPoolThread) { |
| 836 scoped_refptr<SequencedTaskRunner> task_runner = |
| 837 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); |
| 838 |
| 839 // Timer is created on this thread. |
| 840 CreateTimer(); |
| 841 |
| 842 // Task will be scheduled from a pool thread. |
| 843 task_runner->PostTask( |
| 844 FROM_HERE, Bind(&TimerSequenceTest::StartTimer, Unretained(this), |
| 845 TimeDelta::FromMilliseconds(1), |
| 846 Bind(&TimerSequenceTest::Signal, Unretained(this)))); |
| 847 Wait(); |
| 848 |
| 849 // Timer must be destroyed on pool thread, too. |
| 850 task_runner->PostTask( |
| 851 FROM_HERE, |
| 852 TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this)))); |
| 853 Wait(); |
| 854 } |
| 855 |
| 856 TEST_F(TimerSequenceTest, OneShotTimerTwoPoolsAbandonTask) { |
| 857 scoped_refptr<SequencedTaskRunner> task_runner1 = |
| 858 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); |
| 859 scoped_refptr<SequencedTaskRunner> task_runner2 = |
| 860 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken()); |
| 861 |
| 862 // Create timer on pool #1. |
| 863 task_runner1->PostTask( |
| 864 FROM_HERE, |
| 865 TaskWithSignal(Bind(&TimerSequenceTest::CreateTimer, Unretained(this)))); |
| 866 Wait(); |
| 867 |
| 868 // And tell it to execute on a different pool (#2). |
| 869 task_runner1->PostTask( |
| 870 FROM_HERE, TaskWithSignal(Bind(&TimerSequenceTest::SetTaskRunnerForTimer, |
| 871 Unretained(this), task_runner2))); |
| 872 Wait(); |
| 873 |
| 874 // Task will be scheduled from pool #1. |
| 875 task_runner1->PostTask(FROM_HERE, |
| 876 Bind(&TimerSequenceTest::StartTimer, Unretained(this), |
| 877 TimeDelta::FromHours(1), Bind(&DoNothing))); |
| 878 |
| 879 // Abandon task - must be called from scheduling pool (#1). |
| 880 task_runner1->PostTask( |
| 881 FROM_HERE, |
| 882 TaskWithSignal(Bind(&TimerSequenceTest::AbandonTask, Unretained(this)))); |
| 883 Wait(); |
| 884 |
| 885 // Timer must be destroyed on the pool it was scheduled from (#1). |
| 886 task_runner1->PostTask( |
| 887 FROM_HERE, |
| 888 TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this)))); |
| 889 Wait(); |
| 890 } |
| 891 |
| 892 TEST_F(TimerSequenceTest, OneShotTimerUsedAndTaskedOnDifferentPools) { |
| 893 scoped_refptr<SequencedTaskRunner> task_runner1 = |
| 894 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); |
| 895 scoped_refptr<SequencedTaskRunner> task_runner2 = |
| 896 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken()); |
| 897 |
| 898 // Create timer on pool #1. |
| 899 task_runner1->PostTask( |
| 900 FROM_HERE, |
| 901 TaskWithSignal(Bind(&TimerSequenceTest::CreateTimer, Unretained(this)))); |
| 902 Wait(); |
| 903 |
| 904 // And tell it to execute on a different pool (#2). |
| 905 task_runner1->PostTask( |
| 906 FROM_HERE, TaskWithSignal(Bind(&TimerSequenceTest::SetTaskRunnerForTimer, |
| 907 Unretained(this), task_runner2))); |
| 908 Wait(); |
| 909 |
| 910 // Task will be scheduled from pool #1. |
| 911 task_runner1->PostTask( |
| 912 FROM_HERE, Bind(&TimerSequenceTest::StartTimer, Unretained(this), |
| 913 TimeDelta::FromMilliseconds(1), |
| 914 TaskWithSignal(Bind(&TimerSequenceTest::VerifyAffinity, |
| 915 Unretained(task_runner2.get()))))); |
| 916 |
| 917 Wait(); |
| 918 |
| 919 // Timer must be destroyed on the pool it was scheduled from (#1). |
| 920 task_runner1->PostTask( |
| 921 FROM_HERE, |
| 922 TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this)))); |
| 923 Wait(); |
| 924 } |
| 925 |
724 } // namespace base | 926 } // namespace base |
OLD | NEW |