Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(42)

Side by Side Diff: base/timer/timer_unittest.cc

Issue 2491613004: Make base::Timer sequence-friendly. (Closed)
Patch Set: add back commented out DCHECK in Stop() Created 3 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/timer/timer.cc ('k') | build/sanitizers/tsan_suppressions.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
OLDNEW
« no previous file with comments | « base/timer/timer.cc ('k') | build/sanitizers/tsan_suppressions.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698