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 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
100 public: | 98 public: |
101 // |did_run|, if provided, will be signaled when Run() fires. | 99 // |did_run|, if provided, will be signaled when Run() fires. |
102 explicit OneShotTimerTester( | 100 explicit OneShotTimerTester( |
103 WaitableEvent* did_run = nullptr, | 101 WaitableEvent* did_run = nullptr, |
104 const TimeDelta& delay = TimeDelta::FromMilliseconds(10)) | 102 const TimeDelta& delay = TimeDelta::FromMilliseconds(10)) |
105 : OneShotTimerTesterBase(did_run, delay), | 103 : OneShotTimerTesterBase(did_run, delay), |
106 quit_closure_(run_loop_.QuitClosure()) {} | 104 quit_closure_(run_loop_.QuitClosure()) {} |
107 | 105 |
108 ~OneShotTimerTester() override = default; | 106 ~OneShotTimerTester() override = default; |
109 | 107 |
110 void SetTaskRunner(scoped_refptr<SingleThreadTaskRunner> task_runner) { | 108 void SetTaskRunner(scoped_refptr<SequencedTaskRunner> task_runner) { |
111 timer_->SetTaskRunner(std::move(task_runner)); | 109 timer_->SetTaskRunner(std::move(task_runner)); |
112 | 110 |
113 // Run() will be invoked on |task_runner| but |run_loop_|'s QuitClosure | 111 // Run() will be invoked on |task_runner| but |run_loop_|'s QuitClosure |
114 // needs to run on this thread (where the MessageLoop lives). | 112 // needs to run on this thread (where the MessageLoop lives). |
115 quit_closure_ = | 113 quit_closure_ = Bind(IgnoreResult(&SequencedTaskRunner::PostTask), |
116 Bind(IgnoreResult(&SingleThreadTaskRunner::PostTask), | 114 SequencedTaskRunnerHandle::Get(), FROM_HERE, |
117 ThreadTaskRunnerHandle::Get(), FROM_HERE, run_loop_.QuitClosure()); | 115 run_loop_.QuitClosure()); |
118 } | 116 } |
119 | 117 |
120 // Blocks until Run() executes and confirms that Run() didn't fire before | 118 // Blocks until Run() executes and confirms that Run() didn't fire before |
121 // |delay_| expired. | 119 // |delay_| expired. |
122 void WaitAndConfirmTimerFiredAfterDelay() { | 120 void WaitAndConfirmTimerFiredAfterDelay() { |
123 run_loop_.Run(); | 121 run_loop_.Run(); |
124 | 122 |
125 EXPECT_NE(TimeTicks(), started_time()); | 123 EXPECT_NE(TimeTicks(), started_time()); |
126 EXPECT_GE(TimeTicks::Now() - started_time(), delay()); | 124 EXPECT_GE(TimeTicks::Now() - started_time(), delay()); |
127 } | 125 } |
(...skipping 488 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
616 false); | 614 false); |
617 EXPECT_FALSE(timer.IsRunning()); | 615 EXPECT_FALSE(timer.IsRunning()); |
618 timer.Reset(); | 616 timer.Reset(); |
619 EXPECT_TRUE(timer.IsRunning()); | 617 EXPECT_TRUE(timer.IsRunning()); |
620 timer.Stop(); | 618 timer.Stop(); |
621 EXPECT_FALSE(timer.IsRunning()); | 619 EXPECT_FALSE(timer.IsRunning()); |
622 timer.Reset(); | 620 timer.Reset(); |
623 EXPECT_TRUE(timer.IsRunning()); | 621 EXPECT_TRUE(timer.IsRunning()); |
624 } | 622 } |
625 | 623 |
| 624 //----------------------------------------------------------------------------- |
| 625 |
626 namespace { | 626 namespace { |
627 | 627 |
628 bool g_callback_happened1 = false; | 628 bool g_callback_happened1 = false; |
629 bool g_callback_happened2 = false; | 629 bool g_callback_happened2 = false; |
630 | 630 |
631 void ClearAllCallbackHappened() { | 631 void ClearAllCallbackHappened() { |
632 g_callback_happened1 = false; | 632 g_callback_happened1 = false; |
633 g_callback_happened2 = false; | 633 g_callback_happened2 = false; |
634 } | 634 } |
635 | 635 |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
669 timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), | 669 timer.Start(FROM_HERE, TimeDelta::FromMilliseconds(10), |
670 Bind(&SetCallbackHappened1)); | 670 Bind(&SetCallbackHappened1)); |
671 timer.Reset(); | 671 timer.Reset(); |
672 // Since Reset happened before task ran, the user_task must not be cleared: | 672 // Since Reset happened before task ran, the user_task must not be cleared: |
673 ASSERT_FALSE(timer.user_task().is_null()); | 673 ASSERT_FALSE(timer.user_task().is_null()); |
674 RunLoop().Run(); | 674 RunLoop().Run(); |
675 EXPECT_TRUE(g_callback_happened1); | 675 EXPECT_TRUE(g_callback_happened1); |
676 } | 676 } |
677 } | 677 } |
678 | 678 |
| 679 namespace { |
| 680 |
| 681 const size_t kNumWorkerThreads = 3; |
| 682 |
| 683 // Fixture for tests requiring a worker pool. Includes a WaitableEvent so |
| 684 // that cases may Wait() on one thread and Signal() (explicitly, or implicitly |
| 685 // via helper methods) on another. |
| 686 class TimerSequenceTest : public testing::Test { |
| 687 public: |
| 688 TimerSequenceTest() |
| 689 : event_(WaitableEvent::ResetPolicy::AUTOMATIC, |
| 690 WaitableEvent::InitialState::NOT_SIGNALED) {} |
| 691 |
| 692 void SetUp() override { |
| 693 pool1_owner_.reset( |
| 694 new SequencedWorkerPoolOwner(kNumWorkerThreads, "test1")); |
| 695 pool2_owner_.reset( |
| 696 new SequencedWorkerPoolOwner(kNumWorkerThreads, "test2")); |
| 697 } |
| 698 |
| 699 // Block until Signal() is called on another thread. |
| 700 void Wait() { event_.Wait(); } |
| 701 |
| 702 void Signal() { event_.Signal(); } |
| 703 |
| 704 // Helper to augment a task with a subsequent call to Signal(). |
| 705 Closure TaskWithSignal(const Closure& task) { |
| 706 return Bind(&TimerSequenceTest::RunTaskAndSignal, Unretained(this), task); |
| 707 } |
| 708 |
| 709 // Create the timer. |
| 710 void CreateTimer() { timer_.reset(new OneShotTimer); } |
| 711 |
| 712 // Schedule an event on the timer. |
| 713 void StartTimer(TimeDelta delay, const Closure& task) { |
| 714 timer_->Start(FROM_HERE, delay, task); |
| 715 } |
| 716 |
| 717 void SetTaskRunnerForTimer(scoped_refptr<SequencedTaskRunner> task_runner) { |
| 718 timer_->SetTaskRunner(std::move(task_runner)); |
| 719 } |
| 720 |
| 721 // Tell the timer to abandon the task. |
| 722 void AbandonTask() { |
| 723 EXPECT_TRUE(timer_->IsRunning()); |
| 724 // Reset() to call Timer::AbandonScheduledTask() |
| 725 timer_->Reset(); |
| 726 EXPECT_TRUE(timer_->IsRunning()); |
| 727 timer_->Stop(); |
| 728 EXPECT_FALSE(timer_->IsRunning()); |
| 729 } |
| 730 |
| 731 static void VerifyAffinity(const SequencedTaskRunner* task_runner) { |
| 732 EXPECT_TRUE(task_runner->RunsTasksOnCurrentThread()); |
| 733 } |
| 734 |
| 735 // Delete the timer. |
| 736 void DeleteTimer() { timer_.reset(); } |
| 737 |
| 738 protected: |
| 739 const scoped_refptr<SequencedWorkerPool>& pool1() { |
| 740 return pool1_owner_->pool(); |
| 741 } |
| 742 const scoped_refptr<SequencedWorkerPool>& pool2() { |
| 743 return pool2_owner_->pool(); |
| 744 } |
| 745 |
| 746 private: |
| 747 void RunTaskAndSignal(const Closure& task) { |
| 748 task.Run(); |
| 749 Signal(); |
| 750 } |
| 751 |
| 752 WaitableEvent event_; |
| 753 |
| 754 MessageLoop message_loop_; |
| 755 std::unique_ptr<SequencedWorkerPoolOwner> pool1_owner_; |
| 756 std::unique_ptr<SequencedWorkerPoolOwner> pool2_owner_; |
| 757 |
| 758 std::unique_ptr<OneShotTimer> timer_; |
| 759 |
| 760 DISALLOW_COPY_AND_ASSIGN(TimerSequenceTest); |
| 761 }; |
| 762 |
| 763 } // namespace |
| 764 |
| 765 TEST_F(TimerSequenceTest, OneShotTimerTaskOnPoolThread) { |
| 766 scoped_refptr<SequencedTaskRunner> task_runner = |
| 767 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); |
| 768 |
| 769 // Timer is created on this thread. |
| 770 CreateTimer(); |
| 771 |
| 772 // Task will execute on a pool thread. |
| 773 SetTaskRunnerForTimer(task_runner); |
| 774 StartTimer(TimeDelta::FromMilliseconds(1), |
| 775 Bind(&TimerSequenceTest::Signal, Unretained(this))); |
| 776 Wait(); |
| 777 |
| 778 // Timer will be destroyed on this thread. |
| 779 DeleteTimer(); |
| 780 } |
| 781 |
| 782 TEST_F(TimerSequenceTest, OneShotTimerUsedOnPoolThread) { |
| 783 scoped_refptr<SequencedTaskRunner> task_runner = |
| 784 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); |
| 785 |
| 786 // Timer is created on this thread. |
| 787 CreateTimer(); |
| 788 |
| 789 // Task will be scheduled from a pool thread. |
| 790 task_runner->PostTask( |
| 791 FROM_HERE, Bind(&TimerSequenceTest::StartTimer, Unretained(this), |
| 792 TimeDelta::FromMilliseconds(1), |
| 793 Bind(&TimerSequenceTest::Signal, Unretained(this)))); |
| 794 Wait(); |
| 795 |
| 796 // Timer must be destroyed on pool thread, too. |
| 797 task_runner->PostTask( |
| 798 FROM_HERE, |
| 799 TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this)))); |
| 800 Wait(); |
| 801 } |
| 802 |
| 803 TEST_F(TimerSequenceTest, OneShotTimerTwoPoolsAbandonTask) { |
| 804 scoped_refptr<SequencedTaskRunner> task_runner1 = |
| 805 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); |
| 806 scoped_refptr<SequencedTaskRunner> task_runner2 = |
| 807 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken()); |
| 808 |
| 809 // Create timer on pool #1. |
| 810 task_runner1->PostTask( |
| 811 FROM_HERE, |
| 812 TaskWithSignal(Bind(&TimerSequenceTest::CreateTimer, Unretained(this)))); |
| 813 Wait(); |
| 814 |
| 815 // And tell it to execute on a different pool (#2). |
| 816 task_runner1->PostTask( |
| 817 FROM_HERE, TaskWithSignal(Bind(&TimerSequenceTest::SetTaskRunnerForTimer, |
| 818 Unretained(this), task_runner2))); |
| 819 Wait(); |
| 820 |
| 821 // Task will be scheduled from pool #1. |
| 822 task_runner1->PostTask(FROM_HERE, |
| 823 Bind(&TimerSequenceTest::StartTimer, Unretained(this), |
| 824 TimeDelta::FromHours(1), Bind(&DoNothing))); |
| 825 |
| 826 // Abandon task - must be called from scheduling pool (#1). |
| 827 task_runner1->PostTask( |
| 828 FROM_HERE, |
| 829 TaskWithSignal(Bind(&TimerSequenceTest::AbandonTask, Unretained(this)))); |
| 830 Wait(); |
| 831 |
| 832 // Timer must be destroyed on the pool it was scheduled from (#1). |
| 833 task_runner1->PostTask( |
| 834 FROM_HERE, |
| 835 TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this)))); |
| 836 Wait(); |
| 837 } |
| 838 |
| 839 TEST_F(TimerSequenceTest, OneShotTimerUsedAndTaskedOnDifferentPools) { |
| 840 scoped_refptr<SequencedTaskRunner> task_runner1 = |
| 841 pool1()->GetSequencedTaskRunner(pool1()->GetSequenceToken()); |
| 842 scoped_refptr<SequencedTaskRunner> task_runner2 = |
| 843 pool2()->GetSequencedTaskRunner(pool2()->GetSequenceToken()); |
| 844 |
| 845 // Create timer on pool #1. |
| 846 task_runner1->PostTask( |
| 847 FROM_HERE, |
| 848 TaskWithSignal(Bind(&TimerSequenceTest::CreateTimer, Unretained(this)))); |
| 849 Wait(); |
| 850 |
| 851 // And tell it to execute on a different pool (#2). |
| 852 task_runner1->PostTask( |
| 853 FROM_HERE, TaskWithSignal(Bind(&TimerSequenceTest::SetTaskRunnerForTimer, |
| 854 Unretained(this), task_runner2))); |
| 855 Wait(); |
| 856 |
| 857 // Task will be scheduled from pool #1. |
| 858 task_runner1->PostTask( |
| 859 FROM_HERE, Bind(&TimerSequenceTest::StartTimer, Unretained(this), |
| 860 TimeDelta::FromMilliseconds(1), |
| 861 TaskWithSignal(Bind(&TimerSequenceTest::VerifyAffinity, |
| 862 Unretained(task_runner2.get()))))); |
| 863 |
| 864 Wait(); |
| 865 |
| 866 // Timer must be destroyed on the pool it was scheduled from (#1). |
| 867 task_runner1->PostTask( |
| 868 FROM_HERE, |
| 869 TaskWithSignal(Bind(&TimerSequenceTest::DeleteTimer, Unretained(this)))); |
| 870 Wait(); |
| 871 } |
| 872 |
679 } // namespace base | 873 } // namespace base |
OLD | NEW |