diff options
28 files changed, 469 insertions, 259 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); +} diff --git a/chrome/browser/browser.cc b/chrome/browser/browser.cc index 2be43a7..38fb2bb 100644 --- a/chrome/browser/browser.cc +++ b/chrome/browser/browser.cc @@ -89,11 +89,11 @@ class ReducePluginsWorkingSetTask : public Task { // A browser task to run when the user is not using the browser. // In our case, we're trying to be nice to the operating system and release // memory not in use. -class BrowserIdleTask : public IdleTimerTask { +class BrowserIdleTimer : public base::IdleTimer { public: - BrowserIdleTask() - : IdleTimerTask( - TimeDelta::FromSeconds(kBrowserReleaseMemoryInterval), false) { + BrowserIdleTimer() + : base::IdleTimer(TimeDelta::FromSeconds(kBrowserReleaseMemoryInterval), + false) { } virtual void OnIdle() { @@ -197,7 +197,7 @@ Browser::Browser(const gfx::Rect& initial_bounds, toolbar_model_(this), type_(type), app_name_(app_name), - idle_task_(new BrowserIdleTask()) { + idle_task_(new BrowserIdleTimer()) { tabstrip_model_.AddObserver(this); CommandLine parsed_command_line; diff --git a/chrome/browser/browser.h b/chrome/browser/browser.h index 67c0938..f500972 100644 --- a/chrome/browser/browser.h +++ b/chrome/browser/browser.h @@ -17,7 +17,7 @@ #include "chrome/common/notification_service.h" #include "chrome/common/pref_member.h" -class BrowserIdleTask; +class BrowserIdleTimer; class BrowserWindow; class DebuggerWindow; class GoButton; @@ -617,7 +617,7 @@ class Browser : public TabStripModelDelegate, scoped_refptr<SelectFileDialog> select_file_dialog_; // The browser idle task helps cleanup unused memory resources when idle. - scoped_ptr<BrowserIdleTask> idle_task_; + scoped_ptr<BrowserIdleTimer> idle_task_; // Keep track of the encoding auto detect pref. BooleanPrefMember encoding_auto_detect_; diff --git a/chrome/browser/download_file.h b/chrome/browser/download_file.h index b995281..f9c6e91 100644 --- a/chrome/browser/download_file.h +++ b/chrome/browser/download_file.h @@ -57,9 +57,12 @@ class GURL; class MessageLoop; class ResourceDispatcherHost; class Task; -class Timer; class URLRequestContext; +namespace base { +class Timer; +} + // DownloadBuffer -------------------------------------------------------------- // This container is created and populated on the io_thread, and passed to the @@ -240,7 +243,7 @@ class DownloadFileManager // Throttle updates to the UI thread. Task* update_task_; - Timer* update_timer_; + base::Timer* update_timer_; // The MessageLoop that the DownloadManagers live on. MessageLoop* ui_loop_; diff --git a/chrome/browser/download_tab_view.h b/chrome/browser/download_tab_view.h index 59eebe5..346a903 100644 --- a/chrome/browser/download_tab_view.h +++ b/chrome/browser/download_tab_view.h @@ -21,7 +21,10 @@ class DownloadTabView; class SkBitmap; class Task; + +namespace base { class Timer; +} class DownloadItemTabView : public ChromeViews::View, public ChromeViews::LinkController { @@ -170,7 +173,7 @@ class DownloadTabView : public ChromeViews::View, OrderedDownloads downloads_; // Progress animations - Timer* progress_timer_; + base::Timer* progress_timer_; Task* progress_task_; // Since this view manages the progress animation timers for all the floating diff --git a/chrome/browser/profile.h b/chrome/browser/profile.h index 282354e..e4057c6 100644 --- a/chrome/browser/profile.h +++ b/chrome/browser/profile.h @@ -29,11 +29,14 @@ class SpellChecker; class TabRestoreService; class TemplateURLFetcher; class TemplateURLModel; -class Timer; class URLRequestContext; class VisitedLinkMaster; class WebDataService; +namespace base { +class Timer; +} + class Profile { public: @@ -340,7 +343,7 @@ class ProfileImpl : public Profile { ProfileControllerSet controllers_; - Timer* create_session_service_timer_; + base::Timer* create_session_service_timer_; CreateSessionServiceTask create_session_service_task_; scoped_ptr<OffTheRecordProfileImpl> off_the_record_profile_; diff --git a/chrome/browser/resource_dispatcher_host.cc b/chrome/browser/resource_dispatcher_host.cc index 4b3c5f0..ae3ef20 100644 --- a/chrome/browser/resource_dispatcher_host.cc +++ b/chrome/browser/resource_dispatcher_host.cc @@ -270,10 +270,7 @@ class ResourceDispatcherHost::DownloadEventHandler save_as_(save_as), buffer_(new DownloadBuffer), rdh_(rdh), - is_paused_(false), - pause_timer_(TimeDelta::FromMilliseconds(kThrottleTimeMs)) { - pause_timer_.set_task( - NewRunnableMethod(this, &DownloadEventHandler::CheckWriteProgress)); + is_paused_(false) { } // Not needed, as this event handler ought to be the final resource. @@ -344,7 +341,7 @@ class ResourceDispatcherHost::DownloadEventHandler // We schedule a pause outside of the read loop if there is too much file // writing work to do. if (buffer_->contents.size() > kLoadsToWrite) - pause_timer_.Start(); + StartPauseTimer(); return true; } @@ -389,7 +386,7 @@ class ResourceDispatcherHost::DownloadEventHandler // We'll come back later and see if it's okay to unpause the request. if (should_pause) - pause_timer_.Start(); + StartPauseTimer(); if (is_paused_ != should_pause) { rdh_->PauseRequest(global_id_.render_process_host_id, @@ -400,6 +397,11 @@ class ResourceDispatcherHost::DownloadEventHandler } private: + void StartPauseTimer() { + pause_timer_.Start(TimeDelta::FromMilliseconds(kThrottleTimeMs), this, + &DownloadEventHandler::CheckWriteProgress); + } + int download_id_; ResourceDispatcherHost::GlobalRequestID global_id_; int render_view_id_; @@ -413,7 +415,7 @@ class ResourceDispatcherHost::DownloadEventHandler DownloadBuffer* buffer_; ResourceDispatcherHost* rdh_; bool is_paused_; - OneShotTimer pause_timer_; + base::OneShotTimer<DownloadEventHandler> pause_timer_; static const int kReadBufSize = 32768; // bytes static const int kLoadsToWrite = 100; // number of data buffers queued @@ -1231,8 +1233,6 @@ class ResourceDispatcherHost::SaveFileEventHandler ResourceDispatcherHost::ResourceDispatcherHost(MessageLoop* io_loop) : ui_loop_(MessageLoop::current()), io_loop_(io_loop), - update_load_states_timer_( - TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec)), download_file_manager_(new DownloadFileManager(ui_loop_, this)), save_file_manager_(new SaveFileManager(ui_loop_, io_loop, this)), safe_browsing_(new SafeBrowsingService), @@ -1240,8 +1240,6 @@ ResourceDispatcherHost::ResourceDispatcherHost(MessageLoop* io_loop) plugin_service_(PluginService::GetInstance()), method_runner_(this), is_shutdown_(false) { - update_load_states_timer_.set_task(method_runner_.NewRunnableMethod( - &ResourceDispatcherHost::UpdateLoadStates)); } ResourceDispatcherHost::~ResourceDispatcherHost() { @@ -1889,7 +1887,11 @@ void ResourceDispatcherHost::BeginRequestInternal(URLRequest* request, request->Start(); // Make sure we have the load state monitor running - update_load_states_timer_.Start(); + if (!update_load_states_timer_.IsRunning()) { + update_load_states_timer_.Start( + TimeDelta::FromMilliseconds(kUpdateLoadStatesIntervalMsec), + this, &ResourceDispatcherHost::UpdateLoadStates); + } } // This test mirrors the decision that WebKit makes in diff --git a/chrome/browser/resource_dispatcher_host.h b/chrome/browser/resource_dispatcher_host.h index 2205ff6..db94fcd 100644 --- a/chrome/browser/resource_dispatcher_host.h +++ b/chrome/browser/resource_dispatcher_host.h @@ -444,7 +444,7 @@ class ResourceDispatcherHost : public URLRequest::Delegate { // A timer that periodically calls UpdateLoadStates while pending_requests_ // is not empty. - RepeatingTimer update_load_states_timer_; + base::RepeatingTimer<ResourceDispatcherHost> update_load_states_timer_; // We own the download file writing thread and manager scoped_refptr<DownloadFileManager> download_file_manager_; diff --git a/chrome/browser/save_file_manager.h b/chrome/browser/save_file_manager.h index 84397b9..23631e0 100644 --- a/chrome/browser/save_file_manager.h +++ b/chrome/browser/save_file_manager.h @@ -73,7 +73,6 @@ class SavePackage; class MessageLoop; class ResourceDispatcherHost; class Task; -class Timer; class URLRequestContext; class SaveFileManager diff --git a/chrome/browser/session_service.h b/chrome/browser/session_service.h index 3f7548f..9d75707 100644 --- a/chrome/browser/session_service.h +++ b/chrome/browser/session_service.h @@ -24,7 +24,6 @@ class NavigationController; class NavigationEntry; class Profile; class TabContents; -class Timer; class SessionBackend; class SessionCommand; diff --git a/chrome/browser/task_manager.h b/chrome/browser/task_manager.h index f7ab4f4..a84917c 100644 --- a/chrome/browser/task_manager.h +++ b/chrome/browser/task_manager.h @@ -22,10 +22,13 @@ class TaskManager; class TaskManagerContents; class TaskManagerTableModel; class TaskManagerWindow; -class Timer; struct BytesReadParam; +namespace base { +class Timer; +} + namespace ChromeViews { class View; class Window; @@ -260,7 +263,7 @@ class TaskManagerTableModel : public ChromeViews::GroupTableModel, // The timer controlling the updates of the information. The timer is // allocated every time the task manager is shown and deleted when it is // hidden/closed. - Timer* timer_; + base::Timer* timer_; scoped_ptr<Task> update_task_; MessageLoop* ui_loop_; diff --git a/chrome/common/animation.cc b/chrome/common/animation.cc index b4b4ba6..d407ccc 100644 --- a/chrome/common/animation.cc +++ b/chrome/common/animation.cc @@ -14,9 +14,7 @@ Animation::Animation(int frame_rate, iteration_count_(0), current_iteration_(0), state_(0.0), - delegate_(delegate), - timer_(TimeDelta::FromMilliseconds(timer_interval_)) { - timer_.set_unowned_task(this); + delegate_(delegate) { } Animation::Animation(int duration, @@ -29,9 +27,7 @@ Animation::Animation(int duration, iteration_count_(0), current_iteration_(0), state_(0.0), - delegate_(delegate), - timer_(TimeDelta::FromMilliseconds(timer_interval_)) { - timer_.set_unowned_task(this); + delegate_(delegate) { SetDuration(duration); } @@ -50,7 +46,8 @@ double Animation::GetCurrentValue() const { void Animation::Start() { if (!animating_) { - timer_.Start(); + timer_.Start(TimeDelta::FromMilliseconds(timer_interval_), this, + &Animation::Run); animating_ = true; if (delegate_) @@ -87,6 +84,17 @@ bool Animation::IsAnimating() { return animating_; } +void Animation::SetDuration(int duration) { + duration_ = duration; + if (duration_ < timer_interval_) + duration_ = timer_interval_; + iteration_count_ = duration_ / timer_interval_; + + // Changing the number of iterations forces us to reset the + // animation to the first iteration. + current_iteration_ = 0; +} + void Animation::Run() { state_ = static_cast<double>(++current_iteration_) / iteration_count_; @@ -101,17 +109,6 @@ void Animation::Run() { Stop(); } -void Animation::SetDuration(int duration) { - duration_ = duration; - if (duration_ < timer_interval_) - duration_ = timer_interval_; - iteration_count_ = duration_ / timer_interval_; - - // Changing the number of iterations forces us to reset the - // animation to the first iteration. - current_iteration_ = 0; -} - int Animation::CalculateInterval(int frame_rate) { int timer_interval = 1000 / frame_rate; if (timer_interval < 10) diff --git a/chrome/common/animation.h b/chrome/common/animation.h index 3505fe6..657512a 100644 --- a/chrome/common/animation.h +++ b/chrome/common/animation.h @@ -6,7 +6,6 @@ #ifndef CHROME_COMMON_ANIMATION_H__ #define CHROME_COMMON_ANIMATION_H__ -#include "base/task.h" #include "base/timer.h" class Animation; @@ -48,7 +47,7 @@ class AnimationDelegate { // initialization specific to the subclass, and then call |Start|. The // animation uses the current thread's message loop. // -class Animation : public Task { +class Animation { public: // Initializes everything except the duration. // @@ -86,14 +85,14 @@ class Animation : public Task { // Return whether this animation is animating. bool IsAnimating(); - // The animation's Task::Run implementation - virtual void Run(); - // Changes the length of the animation. This resets the current // state of the animation to the beginning. void SetDuration(int duration); protected: + // Called when the animation's timer expires. + void Run(); + // Calculates the timer interval from the constructor list. int CalculateInterval(int frame_rate); @@ -111,7 +110,7 @@ class Animation : public Task { AnimationDelegate* delegate_; - RepeatingTimer timer_; + base::RepeatingTimer<Animation> timer_; DISALLOW_EVIL_CONSTRUCTORS(Animation); }; diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc index af11413..8d91e58 100644 --- a/chrome/renderer/render_view.cc +++ b/chrome/renderer/render_view.cc @@ -140,7 +140,6 @@ RenderView::RenderView() last_page_id_sent_to_browser_(-1), last_indexed_page_id_(-1), method_factory_(this), - nav_state_sync_timer_(kDelayForNavigationSync), opened_by_user_gesture_(true), enable_dom_automation_(false), enable_dom_ui_bindings_(false), @@ -153,8 +152,6 @@ RenderView::RenderView() disable_popup_blocking_(false), has_unload_listener_(false) { resource_dispatcher_ = new ResourceDispatcher(this); - nav_state_sync_timer_.set_task( - method_factory_.NewRunnableMethod(&RenderView::SyncNavigationState)); #ifdef CHROME_PERSONALIZATION personalization_ = Personalization::CreateRendererPersonalization(); #endif @@ -2190,7 +2187,9 @@ int RenderView::GetHistoryForwardListCount() { } void RenderView::OnNavStateChanged(WebView* webview) { - nav_state_sync_timer_.Start(); + if (!nav_state_sync_timer_.IsRunning()) + nav_state_sync_timer_.Start(kDelayForNavigationSync, this, + &RenderView::SyncNavigationState); } void RenderView::SetTooltipText(WebView* webview, diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h index 6ac8f0c..f4afb8f 100644 --- a/chrome/renderer/render_view.h +++ b/chrome/renderer/render_view.h @@ -574,7 +574,7 @@ class RenderView : public RenderWidget, public WebViewDelegate, ScopedRunnableMethodFactory<RenderView> method_factory_; // Timer used to delay the updating of nav state (see SyncNavigationState). - OneShotTimer nav_state_sync_timer_; + base::OneShotTimer<RenderView> nav_state_sync_timer_; typedef std::vector<WebPluginDelegateProxy*> PluginDelegateList; PluginDelegateList plugin_delegates_; diff --git a/chrome/views/throbber.h b/chrome/views/throbber.h index d7e298c..812cae1 100644 --- a/chrome/views/throbber.h +++ b/chrome/views/throbber.h @@ -12,7 +12,10 @@ #include "chrome/views/view.h" class SkBitmap; + +namespace base { class Timer; +} namespace ChromeViews { @@ -49,7 +52,7 @@ class Throbber : public ChromeViews::View, DWORD last_time_recorded_; SkBitmap* frames_; int frame_time_ms_; - Timer* timer_; + base::Timer* timer_; DISALLOW_EVIL_CONSTRUCTORS(Throbber); }; diff --git a/net/base/client_socket_pool.cc b/net/base/client_socket_pool.cc index fcf812e..2fb6703 100644 --- a/net/base/client_socket_pool.cc +++ b/net/base/client_socket_pool.cc @@ -19,19 +19,14 @@ const int kCleanupInterval = 5; namespace net { ClientSocketPool::ClientSocketPool(int max_sockets_per_group) - : timer_(TimeDelta::FromSeconds(kCleanupInterval)), - idle_socket_count_(0), + : idle_socket_count_(0), max_sockets_per_group_(max_sockets_per_group) { - timer_.set_task(this); } ClientSocketPool::~ClientSocketPool() { - timer_.set_task(NULL); - // Clean up any idle sockets. Assert that we have no remaining active sockets // or pending requests. They should have all been cleaned up prior to the // manager being destroyed. - CloseIdleSockets(); DCHECK(group_map_.empty()); } @@ -134,7 +129,8 @@ void ClientSocketPool::MaybeCloseIdleSockets( void ClientSocketPool::IncrementIdleCount() { if (++idle_socket_count_ == 1) - timer_.Start(); + timer_.Start(TimeDelta::FromSeconds(kCleanupInterval), this, + &ClientSocketPool::DoTimeout); } void ClientSocketPool::DecrementIdleCount() { @@ -177,7 +173,7 @@ void ClientSocketPool::DoReleaseSocket(const std::string& group_name, } } -void ClientSocketPool::Run() { +void ClientSocketPool::DoTimeout() { MaybeCloseIdleSockets(true); } diff --git a/net/base/client_socket_pool.h b/net/base/client_socket_pool.h index 99e4936..4b89705 100644 --- a/net/base/client_socket_pool.h +++ b/net/base/client_socket_pool.h @@ -25,8 +25,7 @@ class ClientSocketHandle; // not responsible for allocating the associated ClientSocket objects. The // consumer must do so if it gets a scoped_ptr<ClientSocket> with a null value. // -class ClientSocketPool : public base::RefCounted<ClientSocketPool>, - public Task { +class ClientSocketPool : public base::RefCounted<ClientSocketPool> { public: explicit ClientSocketPool(int max_sockets_per_group); @@ -85,9 +84,9 @@ class ClientSocketPool : public base::RefCounted<ClientSocketPool>, // Called via PostTask by ReleaseSocket. void DoReleaseSocket(const std::string& group_name, ClientSocketPtr* ptr); - // Task implementation. This method scans the idle sockets checking to see - // if any have been disconnected. - virtual void Run(); + // Called when timer_ fires. This method scans the idle sockets checking to + // see if any have been disconnected. + void DoTimeout(); // A Request is allocated per call to RequestSocket that results in // ERR_IO_PENDING. @@ -109,13 +108,15 @@ class ClientSocketPool : public base::RefCounted<ClientSocketPool>, GroupMap group_map_; // Timer used to periodically prune sockets that have been disconnected. - RepeatingTimer timer_; + base::RepeatingTimer<ClientSocketPool> timer_; // The total number of idle sockets in the system. int idle_socket_count_; // The maximum number of sockets kept per group. int max_sockets_per_group_; + + DISALLOW_COPY_AND_ASSIGN(ClientSocketPool); }; } // namespace net diff --git a/net/disk_cache/backend_impl.cc b/net/disk_cache/backend_impl.cc index 18025a1..7deb343 100644 --- a/net/disk_cache/backend_impl.cc +++ b/net/disk_cache/backend_impl.cc @@ -132,23 +132,10 @@ bool DelayedCacheCleanup(const std::wstring& full_path) { return true; } -// ------------------------------------------------------------------------ - -class TimerTask : public Task { - public: - explicit TimerTask(disk_cache::BackendImpl* backend) : backend_(backend) {} - ~TimerTask() {} - - virtual void Run() { - backend_->OnStatsTimer(); - } - - private: - disk_cache::BackendImpl* backend_; -}; - } // namespace +// ------------------------------------------------------------------------ + namespace disk_cache { // If the initialization of the cache fails, and force is true, we will discard @@ -201,10 +188,8 @@ bool BackendImpl::Init() { if (!restarted_) { // Create a recurrent timer of 30 secs. int timer_delay = unit_test_ ? 1000 : 30000; - TimerTask* task = new TimerTask(this); - timer_task_ = task; - timer_ = MessageLoop::current()->timer_manager()->StartTimer(timer_delay, - task, true); + timer_.Start(TimeDelta::FromMilliseconds(timer_delay), this, + &BackendImpl::OnStatsTimer); } init_ = true; @@ -238,9 +223,7 @@ BackendImpl::~BackendImpl() { if (!init_) return; - MessageLoop::current()->timer_manager()->StopTimer(timer_); - delete timer_; - delete timer_task_; + timer_.Stop(); WaitForPendingIO(&num_pending_io_); DCHECK(!num_refs_); diff --git a/net/disk_cache/backend_impl.h b/net/disk_cache/backend_impl.h index 04a228d..7a39238 100644 --- a/net/disk_cache/backend_impl.h +++ b/net/disk_cache/backend_impl.h @@ -7,14 +7,13 @@ #ifndef NET_DISK_CACHE_BACKEND_IMPL_H__ #define NET_DISK_CACHE_BACKEND_IMPL_H__ +#include "base/timer.h" #include "net/disk_cache/block_files.h" #include "net/disk_cache/disk_cache.h" #include "net/disk_cache/rankings.h" #include "net/disk_cache/stats.h" #include "net/disk_cache/trace.h" -class Timer; - namespace disk_cache { // This class implements the Backend interface. An object of this @@ -176,8 +175,7 @@ class BackendImpl : public Backend { bool disabled_; Stats stats_; // Usage statistcs. - Task* timer_task_; - Timer* timer_; // Usage timer. + base::RepeatingTimer<BackendImpl> timer_; // Usage timer. TraceObject trace_object_; // Inits and destroys internal tracing. DISALLOW_EVIL_CONSTRUCTORS(BackendImpl); diff --git a/net/disk_cache/stress_cache.cc b/net/disk_cache/stress_cache.cc index 10058f0..864309a 100644 --- a/net/disk_cache/stress_cache.cc +++ b/net/disk_cache/stress_cache.cc @@ -143,6 +143,9 @@ class CrashTask : public Task { ~CrashTask() {} virtual void Run() { + // Keep trying to run. + RunSoon(MessageLoop::current()); + if (g_crashing) return; @@ -151,6 +154,12 @@ class CrashTask : public Task { TerminateProcess(GetCurrentProcess(), kExpectedCrash); } } + + static void RunSoon(MessageLoop* target_loop) { + int task_delay = 10000; // 10 seconds + CrashTask* task = new CrashTask(); + target_loop->PostDelayedTask(FROM_HERE, task, task_delay); + } }; // We leak everything here :) @@ -159,11 +168,7 @@ bool StartCrashThread() { if (!thread->Start()) return false; - // Create a recurrent timer of 10 secs. - int timer_delay = 10000; - CrashTask* task = new CrashTask(); - thread->message_loop()->timer_manager()->StartTimer(timer_delay, task, true); - + CrashTask::RunSoon(thread->message_loop()); return true; } |