summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authordarin@google.com <darin@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-28 20:50:12 +0000
committerdarin@google.com <darin@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-08-28 20:50:12 +0000
commitaeab57ea8560065d6c513fcd46bb43e1bfbfd7a6 (patch)
treea63f2d36e86361d5c27122a6d6ef4098b755d7d9 /base
parente115558691eb08608fad56bb32f40265fdfa4ac5 (diff)
downloadchromium_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.cc36
-rw-r--r--base/idle_timer.h72
-rw-r--r--base/idletimer_unittest.cc22
-rw-r--r--base/message_loop.h6
-rw-r--r--base/task.h6
-rw-r--r--base/timer.cc44
-rw-r--r--base/timer.h206
-rw-r--r--base/timer_unittest.cc135
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);
+}