diff options
author | darin@google.com <darin@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-28 20:50:12 +0000 |
---|---|---|
committer | darin@google.com <darin@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-08-28 20:50:12 +0000 |
commit | aeab57ea8560065d6c513fcd46bb43e1bfbfd7a6 (patch) | |
tree | a63f2d36e86361d5c27122a6d6ef4098b755d7d9 /base | |
parent | e115558691eb08608fad56bb32f40265fdfa4ac5 (diff) | |
download | chromium_src-aeab57ea8560065d6c513fcd46bb43e1bfbfd7a6.zip chromium_src-aeab57ea8560065d6c513fcd46bb43e1bfbfd7a6.tar.gz chromium_src-aeab57ea8560065d6c513fcd46bb43e1bfbfd7a6.tar.bz2 |
Simplify OneShotTimer and RepeatingTimer. Fix up all consumers.
Major changes:
OneShotTimer and RepeatingTimer become template classes that no longer require
a Task or a Timer object. They just use PostDelayedTask. Under the hood that
still uses a Timer object.
The API is much simpler for consumers as they now no longer need to worry about
allocating a Task or managing the lifetime of the object pointer held by the
Task.
I added some new unit tests to timer_unittest.cc to cover the API.
I preserved the old TimerManager / Timer API for now, but I plan to soon kill
it.
R=brettw
BUG=1346553
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1502 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/idle_timer.cc | 36 | ||||
-rw-r--r-- | base/idle_timer.h | 72 | ||||
-rw-r--r-- | base/idletimer_unittest.cc | 22 | ||||
-rw-r--r-- | base/message_loop.h | 6 | ||||
-rw-r--r-- | base/task.h | 6 | ||||
-rw-r--r-- | base/timer.cc | 44 | ||||
-rw-r--r-- | base/timer.h | 206 | ||||
-rw-r--r-- | base/timer_unittest.cc | 135 |
8 files changed, 372 insertions, 155 deletions
diff --git a/base/idle_timer.cc b/base/idle_timer.cc index 39b9bd4..ad29b2c 100644 --- a/base/idle_timer.cc +++ b/base/idle_timer.cc @@ -2,35 +2,34 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <windows.h> - #include "base/idle_timer.h" #include "base/message_loop.h" #include "base/time.h" -IdleTimerTask::IdleTimerTask(TimeDelta idle_time, bool repeat) - : idle_interval_(idle_time), - repeat_(repeat), - get_last_input_info_fn_(GetLastInputInfo) { +namespace base { + +IdleTimer::IdleTimer(TimeDelta idle_time, bool repeat) + : idle_interval_(idle_time), + repeat_(repeat), + get_last_input_info_fn_(GetLastInputInfo) { DCHECK_EQ(MessageLoop::TYPE_UI, MessageLoop::current()->type()) << "Requires a thread that processes Windows UI events"; } -IdleTimerTask::~IdleTimerTask() { +IdleTimer::~IdleTimer() { Stop(); } -void IdleTimerTask::Start() { - DCHECK(!timer_.get()); +void IdleTimer::Start() { StartTimer(); } -void IdleTimerTask::Stop() { - timer_.reset(); +void IdleTimer::Stop() { + timer_.Stop(); } -void IdleTimerTask::Run() { +void IdleTimer::Run() { // Verify we can fire the idle timer. if (TimeUntilIdle().InMilliseconds() <= 0) { OnIdle(); @@ -40,17 +39,15 @@ void IdleTimerTask::Run() { StartTimer(); // Restart the timer for next run. } -void IdleTimerTask::StartTimer() { - DCHECK(timer_ == NULL); +void IdleTimer::StartTimer() { + DCHECK(!timer_.IsRunning()); TimeDelta delay = TimeUntilIdle(); if (delay.InMilliseconds() < 0) delay = TimeDelta(); - timer_.reset(new OneShotTimer(delay)); - timer_->set_unowned_task(this); - timer_->Start(); + timer_.Start(delay, this, &IdleTimer::Run); } -TimeDelta IdleTimerTask::CurrentIdleTime() { +TimeDelta IdleTimer::CurrentIdleTime() { // TODO(mbelshe): This is windows-specific code. LASTINPUTINFO info; info.cbSize = sizeof(info); @@ -68,7 +65,7 @@ TimeDelta IdleTimerTask::CurrentIdleTime() { return TimeDelta::FromMilliseconds(0); } -TimeDelta IdleTimerTask::TimeUntilIdle() { +TimeDelta IdleTimer::TimeUntilIdle() { TimeDelta time_since_last_fire = Time::Now() - last_time_fired_; TimeDelta current_idle_time = CurrentIdleTime(); if (current_idle_time > time_since_last_fire) { @@ -79,3 +76,4 @@ TimeDelta IdleTimerTask::TimeUntilIdle() { return idle_interval_ - current_idle_time; } +} // namespace base diff --git a/base/idle_timer.h b/base/idle_timer.h index ec3d628..7b9446e 100644 --- a/base/idle_timer.h +++ b/base/idle_timer.h @@ -2,57 +2,58 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef BASE_IDLE_TIMER_H__ -#define BASE_IDLE_TIMER_H__ - -#include <windows.h> - -#include "base/basictypes.h" -#include "base/task.h" -#include "base/timer.h" - -// IdleTimer is a recurring Timer task which runs only when the system is idle. +// IdleTimer is a recurring Timer which runs only when the system is idle. // System Idle time is defined as not having any user keyboard or mouse // activity for some period of time. Because the timer is user dependant, it // is possible for the timer to never fire. - // -// Usage should be for low-priority tasks, and may look like this: +// Usage should be for low-priority work, and may look like this: // -// class MyIdleTimerTask : public IdleTimerTask { +// class MyIdleTimer : public IdleTimer { // public: -// // This task will run after 5 seconds of idle time -// // and not more often than once per minute. -// MyIdleTimerTask() : IdleTimerTask(5, 60) {}; +// // This timer will run repeatedly after 5 seconds of idle time +// MyIdleTimer() : IdleTimer(TimeDelta::FromSeconds(5), true) {}; // virtual void OnIdle() { do something }; // } // -// MyIdleTimerTask *task = new MyIdleTimerTask(); -// task->Start(); +// MyIdleTimer *timer = new MyIdleTimer(); +// timer->Start(); +// +// // As with all Timers, the caller must dispose the object. +// delete timer; // Will Stop the timer and cleanup. // -// // As with all TimerTasks, the caller must dispose the object. -// delete task; // Will Stop the timer and cleanup the task. +// NOTE: An IdleTimer can only be used on a thread that processes UI events. +// Such a thread should be running a MessageLoopForUI. -class TimerManager; +#ifndef BASE_IDLE_TIMER_H_ +#define BASE_IDLE_TIMER_H_ + +#include <windows.h> + +#include "base/basictypes.h" +#include "base/task.h" +#include "base/timer.h" + +namespace base { // Function prototype for GetLastInputInfo. typedef BOOL (__stdcall *GetLastInputInfoFunction)(PLASTINPUTINFO plii); -class IdleTimerTask : public Task { +class IdleTimer { public: - // Create an IdleTimerTask. - // idle_time: idle time required before this task can run. + // Create an IdleTimer. + // idle_time: idle time required before this timer can run. // repeat: true if the timer should fire multiple times per idle, // false to fire once per idle. - IdleTimerTask(TimeDelta idle_time, bool repeat); + IdleTimer(TimeDelta idle_time, bool repeat); - // On destruction, the IdleTimerTask will Stop itself and delete the Task. - virtual ~IdleTimerTask(); + // On destruction, the IdleTimer will Stop itself. + virtual ~IdleTimer(); - // Start the IdleTimerTask. + // Start the IdleTimer. void Start(); - // Stop the IdleTimertask. + // Stop the IdleTimer. void Stop(); // The method to run when the timer elapses. @@ -61,12 +62,12 @@ class IdleTimerTask : public Task { protected: // Override the GetLastInputInfo function. void set_last_input_info_fn(GetLastInputInfoFunction function) { - get_last_input_info_fn_ = function; + get_last_input_info_fn_ = function; } private: - // This task's run method. - virtual void Run(); + // Called when timer_ expires. + void Run(); // Start the timer. void StartTimer(); @@ -81,10 +82,13 @@ class IdleTimerTask : public Task { bool repeat_; Time last_time_fired_; // The last time the idle timer fired. // will be 0 until the timer fires the first time. - scoped_ptr<OneShotTimer> timer_; + OneShotTimer<IdleTimer> timer_; GetLastInputInfoFunction get_last_input_info_fn_; + + DISALLOW_COPY_AND_ASSIGN(IdleTimer); }; -#endif // BASE_IDLE_TIMER_H__ +} // namespace base +#endif // BASE_IDLE_TIMER_H_ diff --git a/base/idletimer_unittest.cc b/base/idletimer_unittest.cc index ea53854..1e2baa9 100644 --- a/base/idletimer_unittest.cc +++ b/base/idletimer_unittest.cc @@ -6,12 +6,14 @@ #include "base/message_loop.h" #include "testing/gtest/include/gtest/gtest.h" +using base::IdleTimer; + namespace { - class IdleTimerTest : public testing::Test { - private: - // IdleTimer requires a UI message loop on the current thread. - MessageLoopForUI message_loop_; - }; + +class IdleTimerTest : public testing::Test { + private: + // IdleTimer requires a UI message loop on the current thread. + MessageLoopForUI message_loop_; }; // We Mock the GetLastInputInfo function to return @@ -25,12 +27,12 @@ BOOL __stdcall MockGetLastInputInfoFunction(PLASTINPUTINFO plii) { } // TestIdle task fires after 100ms of idle time. -class TestIdleTask : public IdleTimerTask { +class TestIdleTask : public IdleTimer { public: TestIdleTask(bool repeat) - : IdleTimerTask(TimeDelta::FromMilliseconds(100), repeat), - idle_counter_(0) { - set_last_input_info_fn(MockGetLastInputInfoFunction); + : IdleTimer(TimeDelta::FromMilliseconds(100), repeat), + idle_counter_(0) { + set_last_input_info_fn(MockGetLastInputInfoFunction); } int get_idle_counter() { return idle_counter_; } @@ -61,6 +63,8 @@ class ResetIdleTask : public Task { } }; +} // namespace + /////////////////////////////////////////////////////////////////////////////// // NoRepeat tests: // A non-repeating idle timer will fire once on idle, and diff --git a/base/message_loop.h b/base/message_loop.h index b4e84e6..efdb5d7 100644 --- a/base/message_loop.h +++ b/base/message_loop.h @@ -200,7 +200,7 @@ class MessageLoop : public base::MessagePump::Delegate { } // Returns the TimerManager object for the current thread. - TimerManager* timer_manager() { return &timer_manager_; } + base::TimerManager* timer_manager() { return &timer_manager_; } // Enables or disables the recursive task processing. This happens in the case // of recursive message loops. Some unwanted message loop may occurs when @@ -231,7 +231,7 @@ class MessageLoop : public base::MessagePump::Delegate { //---------------------------------------------------------------------------- protected: - friend class TimerManager; // So it can call DidChangeNextTimerExpiry + friend class base::TimerManager; // So it can call DidChangeNextTimerExpiry struct RunState { // Used to count how many Run() invocations are on the stack. @@ -405,7 +405,7 @@ class MessageLoop : public base::MessagePump::Delegate { Type type_; - TimerManager timer_manager_; + base::TimerManager timer_manager_; // A list of tasks that need to be processed by this instance. Note that this // queue is only accessed (push/pop) by our current thread. diff --git a/base/task.h b/base/task.h index b609a1e..42277d4 100644 --- a/base/task.h +++ b/base/task.h @@ -14,6 +14,10 @@ #include "base/tracked.h" #include "base/tuple.h" +namespace base { +class TimerManager; +} + //------------------------------------------------------------------------------ // Base class of Task, where we store info to help MessageLoop handle PostTask() // elements of Task processing. @@ -56,7 +60,7 @@ class TaskBase : public tracked_objects::Tracked { } private: - friend class TimerManager; // To check is_owned_by_message_loop(). + friend class base::TimerManager; // To check is_owned_by_message_loop(). friend class MessageLoop; // To maintain posted_task_delay(). // Access methods used ONLY by friends in MessageLoop and TimerManager diff --git a/base/timer.cc b/base/timer.cc index 1ee52d4..09a13f6 100644 --- a/base/timer.cc +++ b/base/timer.cc @@ -14,9 +14,11 @@ #include "base/message_loop.h" #include "base/task.h" +namespace base { + // A sequence number for all allocated times (used to break ties when // comparing times in the TimerManager, and assure FIFO execution sequence). -static base::AtomicSequenceNumber timer_id_counter_; +static AtomicSequenceNumber timer_id_counter_; //----------------------------------------------------------------------------- // Timer @@ -199,36 +201,22 @@ void TimerManager::DidChangeNextTimer() { } //----------------------------------------------------------------------------- -// SimpleTimer - -SimpleTimer::SimpleTimer(TimeDelta delay, Task* task, bool repeating) - : timer_(static_cast<int>(delay.InMilliseconds()), task, repeating), - owns_task_(true) { -} - -SimpleTimer::~SimpleTimer() { - Stop(); - - if (owns_task_) - delete timer_.task(); -} - -void SimpleTimer::Start() { - DCHECK(timer_.task()); - timer_.Reset(); - MessageLoop::current()->timer_manager()->StartTimer(&timer_); -} +// BaseTimer_Helper -void SimpleTimer::Stop() { - MessageLoop::current()->timer_manager()->StopTimer(&timer_); +void BaseTimer_Helper::OrphanDelayedTask() { + if (delayed_task_) { + delayed_task_->timer_ = NULL; + delayed_task_ = NULL; + } } -bool SimpleTimer::IsRunning() const { - return MessageLoop::current()->timer_manager()->IsTimerRunning(&timer_); -} +void BaseTimer_Helper::InitiateDelayedTask(TimerTask* timer_task) { + OrphanDelayedTask(); -void SimpleTimer::Reset() { - DCHECK(timer_.task()); - MessageLoop::current()->timer_manager()->ResetTimer(&timer_); + delayed_task_ = timer_task; + delayed_task_->timer_ = this; + MessageLoop::current()->PostDelayedTask( + FROM_HERE, timer_task, static_cast<int>(delay_.InMilliseconds())); } +} // namespace base diff --git a/base/timer.h b/base/timer.h index 9b7c726..a78af31 100644 --- a/base/timer.h +++ b/base/timer.h @@ -2,6 +2,45 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// OneShotTimer and RepeatingTimer provide a simple timer API. As the names +// suggest, OneShotTimer calls you back once after a time delay expires. +// RepeatingTimer on the other hand calls you back periodically with the +// prescribed time interval. +// +// OneShotTimer and RepeatingTimer both cancel the timer when they go out of +// scope, which makes it easy to ensure that you do not get called when your +// object has gone out of scope. Just instantiate a OneShotTimer or +// RepeatingTimer as a member variable of the class for which you wish to +// receive timer events. +// +// Sample RepeatingTimer usage: +// +// class MyClass { +// public: +// void StartDoingStuff() { +// timer_.Start(TimeDelta::FromSeconds(1), this, &MyClass::DoStuff); +// } +// void StopDoingStuff() { +// timer_.Stop(); +// } +// private: +// void DoStuff() { +// // This method is called every second to do stuff. +// ... +// } +// base::RepeatingTimer<MyClass> timer_; +// }; +// +// Both OneShotTimer and RepeatingTimer also support a Reset method, which +// allows you to easily defer the timer event until the timer delay passes once +// again. So, in the above example, if 0.5 seconds have already passed, +// calling Reset on timer_ would postpone DoStuff by another 1 second. In +// other words, Reset is shorthand for calling Stop and then Start again with +// the same arguments. +// +// NOTE: The older TimerManager / Timer API is deprecated. New code should +// use OneShotTimer or RepeatingTimer. + #ifndef BASE_TIMER_H_ #define BASE_TIMER_H_ @@ -9,6 +48,7 @@ #include <vector> #include "base/basictypes.h" +#include "base/task.h" #include "base/time.h" //----------------------------------------------------------------------------- @@ -21,11 +61,15 @@ //----------------------------------------------------------------------------- class MessageLoop; + +namespace base { + class TimerManager; -class Task; //----------------------------------------------------------------------------- // The core timer object. Use TimerManager to create and control timers. +// +// NOTE: This class is DEPRECATED. Do not use! class Timer { public: Timer(int delay, Task* task, bool repeating); @@ -77,6 +121,8 @@ class Timer { //----------------------------------------------------------------------------- // Used to implement TimerPQueue +// +// NOTE: This class is DEPRECATED. Do not use! class TimerComparison { public: bool operator() (const Timer* t1, const Timer* t2) const { @@ -101,6 +147,8 @@ class TimerComparison { // // Terminology: The "pending" timer is the timer at the top of the queue, // i.e. the timer whose task needs to be Run next. +// +// NOTE: This class is DEPRECATED. Do not use! class TimerPQueue : public std::priority_queue<Timer*, std::vector<Timer*>, TimerComparison> { public: @@ -122,6 +170,8 @@ class TimerPQueue : // // NOTE: TimerManager is not thread safe. You cannot set timers onto a thread // other than your own. +// +// NOTE: This class is DEPRECATED. Do not use! class TimerManager { public: explicit TimerManager(MessageLoop* message_loop); @@ -189,89 +239,123 @@ class TimerManager { }; //----------------------------------------------------------------------------- -// A simple wrapper for the Timer / TimerManager API. This is a helper class. -// Use OneShotTimer or RepeatingTimer instead. -class SimpleTimer { +// This class is an implementation detail of OneShotTimer and RepeatingTimer. +// Please do not use this class directly. +// +// This class exists to share code between BaseTimer<T> template instantiations. +// +class BaseTimer_Helper { public: // Stops the timer. - ~SimpleTimer(); - - // Call this method to explicitly start the timer. This is a no-op if the - // timer is already running. - void Start(); - - // Call this method to explicitly stop the timer. This is a no-op if the - // timer is not running. - void Stop(); + ~BaseTimer_Helper() { + OrphanDelayedTask(); + } // Returns true if the timer is running (i.e., not stopped). - bool IsRunning() const; - - // Short-hand for calling Stop and then Start. - void Reset(); - - // Get/Set the task to be run when this timer expires. NOTE: The caller of - // set_task must be careful to ensure that the old task is properly deleted. - Task* task() const { return timer_.task(); } - void set_task(Task* task) { - timer_.set_task(task); - owns_task_ = true; + bool IsRunning() const { + return delayed_task_ != NULL; } - // Sets the task, but marks it so it shouldn't be deleted by the SimpleTimer. - void set_unowned_task(Task* task) { - timer_.set_task(task); - owns_task_ = false; + protected: + BaseTimer_Helper(bool repeating) + : delayed_task_(NULL), repeating_(repeating) { } - protected: - SimpleTimer(TimeDelta delay, Task* task, bool repeating); + // We have access to the timer_ member so we can orphan this task. + class TimerTask : public Task { + public: + BaseTimer_Helper* timer_; + }; - private: - Timer timer_; + // Used to orphan delayed_task_ so that when it runs it does nothing. + void OrphanDelayedTask(); + + // Used to initiated a new delayed task. This has the side-effect of + // orphaning delayed_task_ if it is non-null. + void InitiateDelayedTask(TimerTask* timer_task); - // Whether we need to clean up the Task* object for this Timer when - // we are deallocated. Defaults to true. - bool owns_task_; + TimerTask* delayed_task_; + TimeDelta delay_; + bool repeating_; - DISALLOW_COPY_AND_ASSIGN(SimpleTimer); + DISALLOW_COPY_AND_ASSIGN(BaseTimer_Helper); }; //----------------------------------------------------------------------------- -// A simple, one-shot timer. The task is run after the specified delay once -// the Start method is called. The task is deleted when the timer object is -// destroyed. -class OneShotTimer : public SimpleTimer { +// This class is an implementation detail of OneShotTimer and RepeatingTimer. +// Please do not use this class directly. +template <class Receiver> +class BaseTimer : public BaseTimer_Helper { public: + typedef void (Receiver::*ReceiverMethod)(); + // The task must be set using set_task before calling Start. - explicit OneShotTimer(TimeDelta delay) - : SimpleTimer(delay, NULL, false) { + BaseTimer(bool repeating) + : BaseTimer_Helper(repeating), receiver_(NULL), receiver_method_(NULL) { } - // If task is null, then it must be set using set_task before calling Start. - OneShotTimer(TimeDelta delay, Task* task) - : SimpleTimer(delay, task, false) { + + // Call this method to start the timer. It is an error to call this method + // while the timer is already running. + void Start(TimeDelta delay, Receiver* receiver, ReceiverMethod method) { + DCHECK(!IsRunning()); + delay_ = delay; + receiver_ = receiver; + receiver_method_ = method; + InitiateDelayedTask(new TimerTask()); + } + + // Call this method to stop the timer. It is a no-op if the timer is not + // running. + void Stop() { + receiver_ = NULL; + receiver_method_ = NULL; + OrphanDelayedTask(); } + + // Call this method to reset the timer delay of an already running timer. + void Reset() { + DCHECK(IsRunning()); + OrphanDelayedTask(); + InitiateDelayedTask(new TimerTask()); + } + private: - DISALLOW_COPY_AND_ASSIGN(OneShotTimer); + class TimerTask : public BaseTimer_Helper::TimerTask { + public: + virtual void Run() { + if (!timer_) // timer_ is null if we were orphaned. + return; + BaseTimer<Receiver>* self = static_cast<BaseTimer<Receiver>*>(timer_); + if (self->repeating_) + self->Reset(); + DispatchToMethod(self->receiver_, self->receiver_method_, Tuple0()); + } + }; + + Receiver* receiver_; + ReceiverMethod receiver_method_; }; //----------------------------------------------------------------------------- -// A simple, repeating timer. The task is run at the specified interval once -// the Start method is called. The task is deleted when the timer object is -// destroyed. -class RepeatingTimer : public SimpleTimer { +// A simple, one-shot timer. See usage notes at the top of the file. +template <class Receiver> +class OneShotTimer : public BaseTimer<Receiver> { public: - // The task must be set using set_task before calling Start. - explicit RepeatingTimer(TimeDelta interval) - : SimpleTimer(interval, NULL, true) { - } - // If task is null, then it must be set using set_task before calling Start. - RepeatingTimer(TimeDelta interval, Task* task) - : SimpleTimer(interval, task, true) { - } - private: - DISALLOW_COPY_AND_ASSIGN(RepeatingTimer); + OneShotTimer() : BaseTimer<Receiver>(false) {} }; -#endif // BASE_TIMER_H_ +//----------------------------------------------------------------------------- +// A simple, repeating timer. See usage notes at the top of the file. +template <class Receiver> +class RepeatingTimer : public BaseTimer<Receiver> { + public: + RepeatingTimer() : BaseTimer<Receiver>(true) {} +}; + +} // namespace base +// TODO(darin): b/1346553: Remove these once Timer and TimerManager are unused. +using base::Timer; +using base::TimerManager; + +#endif // BASE_TIMER_H_ diff --git a/base/timer_unittest.cc b/base/timer_unittest.cc index 1d1a964..9b251b2 100644 --- a/base/timer_unittest.cc +++ b/base/timer_unittest.cc @@ -7,6 +7,8 @@ #include "base/timer.h" #include "testing/gtest/include/gtest/gtest.h" +using base::TimerComparison; + namespace { class TimerTest : public testing::Test {}; @@ -322,6 +324,115 @@ void RunTest_FifoOrder(MessageLoop::Type message_loop_type) { EXPECT_GT(new_id, last_id); } +namespace { + +class OneShotTimerTester { + public: + OneShotTimerTester(bool* did_run) : did_run_(did_run) { + } + void Start() { + timer_.Start(TimeDelta::FromMilliseconds(10), this, + &OneShotTimerTester::Run); + } + private: + void Run() { + *did_run_ = true; + MessageLoop::current()->Quit(); + } + bool* did_run_; + base::OneShotTimer<OneShotTimerTester> timer_; +}; + +class RepeatingTimerTester { + public: + RepeatingTimerTester(bool* did_run) : did_run_(did_run), counter_(10) { + } + void Start() { + timer_.Start(TimeDelta::FromMilliseconds(10), this, + &RepeatingTimerTester::Run); + } + private: + void Run() { + if (--counter_ == 0) { + *did_run_ = true; + MessageLoop::current()->Quit(); + } + } + bool* did_run_; + int counter_; + base::RepeatingTimer<RepeatingTimerTester> timer_; +}; + +} // namespace + +void RunTest_OneShotTimer(MessageLoop::Type message_loop_type) { + MessageLoop loop(message_loop_type); + + bool did_run = false; + OneShotTimerTester f(&did_run); + f.Start(); + + MessageLoop::current()->Run(); + + EXPECT_TRUE(did_run); +} + +void RunTest_OneShotTimer_Cancel(MessageLoop::Type message_loop_type) { + MessageLoop loop(message_loop_type); + + bool did_run_a = false; + OneShotTimerTester* a = new OneShotTimerTester(&did_run_a); + + // This should run before the timer expires. + MessageLoop::current()->DeleteSoon(FROM_HERE, a); + + // Now start the timer. + a->Start(); + + bool did_run_b = false; + OneShotTimerTester b(&did_run_b); + b.Start(); + + MessageLoop::current()->Run(); + + EXPECT_FALSE(did_run_a); + EXPECT_TRUE(did_run_b); +} + +void RunTest_RepeatingTimer(MessageLoop::Type message_loop_type) { + MessageLoop loop(message_loop_type); + + bool did_run = false; + RepeatingTimerTester f(&did_run); + f.Start(); + + MessageLoop::current()->Run(); + + EXPECT_TRUE(did_run); +} + +void RunTest_RepeatingTimer_Cancel(MessageLoop::Type message_loop_type) { + MessageLoop loop(message_loop_type); + + bool did_run_a = false; + RepeatingTimerTester* a = new RepeatingTimerTester(&did_run_a); + + // This should run before the timer expires. + MessageLoop::current()->DeleteSoon(FROM_HERE, a); + + // Now start the timer. + a->Start(); + + bool did_run_b = false; + RepeatingTimerTester b(&did_run_b); + b.Start(); + + MessageLoop::current()->Run(); + + EXPECT_FALSE(did_run_a); + EXPECT_TRUE(did_run_b); +} + } // namespace //----------------------------------------------------------------------------- @@ -363,3 +474,27 @@ TEST(TimerTest, FifoOrder) { RunTest_FifoOrder(MessageLoop::TYPE_UI); RunTest_FifoOrder(MessageLoop::TYPE_IO); } + +TEST(TimerTest, OneShotTimer) { + RunTest_OneShotTimer(MessageLoop::TYPE_DEFAULT); + RunTest_OneShotTimer(MessageLoop::TYPE_UI); + RunTest_OneShotTimer(MessageLoop::TYPE_IO); +} + +TEST(TimerTest, OneShotTimer_Cancel) { + RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_DEFAULT); + RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_UI); + RunTest_OneShotTimer_Cancel(MessageLoop::TYPE_IO); +} + +TEST(TimerTest, RepeatingTimer) { + RunTest_RepeatingTimer(MessageLoop::TYPE_DEFAULT); + RunTest_RepeatingTimer(MessageLoop::TYPE_UI); + RunTest_RepeatingTimer(MessageLoop::TYPE_IO); +} + +TEST(TimerTest, RepeatingTimer_Cancel) { + RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_DEFAULT); + RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_UI); + RunTest_RepeatingTimer_Cancel(MessageLoop::TYPE_IO); +} |