summaryrefslogtreecommitdiffstats
path: root/base/timer.h
diff options
context:
space:
mode:
Diffstat (limited to 'base/timer.h')
-rw-r--r--base/timer.h320
1 files changed, 320 insertions, 0 deletions
diff --git a/base/timer.h b/base/timer.h
new file mode 100644
index 0000000..39eb313
--- /dev/null
+++ b/base/timer.h
@@ -0,0 +1,320 @@
+// Copyright 2008, Google Inc.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following disclaimer
+// in the documentation and/or other materials provided with the
+// distribution.
+// * Neither the name of Google Inc. nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef BASE_TIMER_H_
+#define BASE_TIMER_H_
+
+#include <math.h>
+#include <windows.h>
+
+#include <queue>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/time.h"
+
+// Timer/TimerManager are objects designed to help setting timers.
+// Goals of TimerManager:
+// - have only one Windows system timer for all app timer functionality
+// - work around bugs with timers firing arbitrarily earlier than specified
+// - provide the ability to run timers even if the application is in a
+// windows modal app loop.
+
+class TimerManager;
+class Task;
+class MessageLoop;
+
+class Timer {
+ public:
+ Timer(int delay, Task* task, bool repeating);
+
+ Task* task() const { return task_; }
+ void set_task(Task* task) { task_ = task; }
+
+ int current_delay() const {
+ // Be careful here. Timers have a precision of microseconds,
+ // but this API is in milliseconds. If there are 5.5ms left,
+ // should the delay be 5 or 6? It should be 6 to avoid timers
+ // firing early. Implement ceiling by adding 999us prior to
+ // conversion to ms.
+ double delay = ceil((fire_time_ - Time::Now()).InMillisecondsF());
+ return static_cast<int>(delay);
+ }
+
+ const Time &fire_time() const { return fire_time_; }
+
+ bool repeating() const { return repeating_; }
+
+ // Update (or fill in) creation_time_, and calculate future fire_time_ based
+ // on current time plus delay_.
+ void Reset();
+
+ int id() const { return timer_id_; }
+
+ protected:
+ // Protected (rather than private) so that we can access from unit tests.
+
+ // The time when the timer should fire.
+ Time fire_time_;
+
+ private:
+ // A sequence number for all allocated times (used to break ties when
+ // comparing times in the TimerManager, and assure FIFO execution sequence).
+ static int32 timer_id_counter_;
+
+ // The task that is run when this timer fires.
+ Task* task_;
+
+ // Timer delay in milliseconds.
+ int delay_;
+
+ // A monotonically increasing timer id. Used
+ // for ordering two timers which have the same
+ // timestamp in a FIFO manner.
+ int timer_id_;
+
+ // Whether or not this timer repeats.
+ const bool repeating_;
+
+ // The tick count when the timer was "created". (i.e. when its current
+ // iteration started.)
+ Time creation_time_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(Timer);
+};
+
+class TimerComparison {
+ public:
+ bool operator() (const Timer* t1, const Timer* t2) const {
+ const Time& f1 = t1->fire_time();
+ const Time& f2 = t2->fire_time();
+ // If the two timers have the same delay, revert to using
+ // the timer_id to maintain FIFO ordering.
+ if (f1 == f2) {
+ // Gracefully handle wrap as we try to return (t1->id() > t2->id());
+ int delta = t1->id() - t2->id();
+ // Assuming the delta is smaller than 2**31, we'll always get the right
+ // answer (in terms of sign of delta).
+ return delta > 0;
+ }
+ return f1 > f2;
+ }
+};
+
+// Subclass priority_queue to provide convenient access to removal from this
+// list.
+//
+// Terminology: The "pending" timer is the timer at the top of the queue,
+// i.e. the timer whose task needs to be Run next.
+class TimerPQueue : public std::priority_queue<Timer*,
+ std::vector<Timer*>,
+ TimerComparison> {
+ public:
+ // Removes |timer| from the queue.
+ void RemoveTimer(Timer* timer);
+
+ // Returns true if the queue contains |timer|.
+ bool ContainsTimer(const Timer* timer) const;
+};
+
+// There is one TimerManager per thread, owned by the MessageLoop.
+// Timers can either be fired directly by the MessageLoop, or by
+// SetTimer and a WM_TIMER message. The advantage of the former
+// is that we can make timers fire significantly faster than the 10ms
+// granularity provided by SetTimer(). The advantage of SetTimer()
+// is that modal message loops which don't run our MessageLoop
+// code will still be able to process WM_TIMER messages.
+//
+// Note: TimerManager is not thread safe. You cannot set timers
+// onto a thread other than your own.
+class TimerManager {
+ public:
+ TimerManager();
+ ~TimerManager();
+
+ // Create and start a new timer. |task| is owned by the caller, as is the
+ // timer object that is returned.
+ Timer* StartTimer(int delay, Task* task, bool repeating);
+
+ // Flag indicating whether the timer manager should use the OS
+ // timers or not. Default is true. MessageLoops which are not reliably
+ // called due to nested windows message loops should set this to
+ // true.
+ bool use_native_timers() { return use_native_timers_; }
+ void set_use_native_timers(bool value) { use_native_timers_ = value; }
+
+ // Starts a timer. This is a no-op if the timer is already started.
+ void StartTimer(Timer* timer);
+
+ // Stop a timer. This is a no-op if the timer is already stopped.
+ void StopTimer(Timer* timer);
+
+ // Reset an existing timer, which may or may not be currently in the queue of
+ // upcoming timers. The timer's parameters are unchanged; it simply begins
+ // counting down again as if it was just created.
+ void ResetTimer(Timer* timer);
+
+ // Returns true if |timer| is in the queue of upcoming timers.
+ bool IsTimerRunning(const Timer* timer) const;
+
+ // Run some small number of timers.
+ // Returns true if it runs a task, false otherwise.
+ bool RunSomePendingTimers();
+
+ // The number of milliseconds remaining until the pending timer (top of the
+ // pqueue) needs to be fired. Returns -1 if no timers are pending.
+ int GetCurrentDelay();
+
+ // A handler for WM_TIMER messages.
+ // If a task is not running currently, it runs some timer tasks (if there are
+ // some ready to fire), otherwise it just updates the WM_TIMER to be called
+ // again (hopefully when it is allowed to run a task).
+ int MessageWndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
+
+ // Return cached copy of MessageLoop::current().
+ MessageLoop* message_loop();
+
+#ifdef UNIT_TEST
+ // For testing only, used to simulate broken early-firing WM_TIMER
+ // notifications by setting arbitrarily small delays in SetTimer.
+ void set_use_broken_delay(bool use_broken_delay) {
+ use_broken_delay_ = use_broken_delay;
+ }
+#endif
+
+ protected:
+ // Peek at the timer which will fire soonest.
+ Timer* PeekTopTimer();
+
+ private:
+ // Update our Windows WM_TIMER to match our most immediately pending timer.
+ void UpdateWindowsWmTimer();
+
+ // Retrieve the Message Window that handles WM_TIMER messages from the
+ // system.
+ HWND GetMessageHWND();
+
+ TimerPQueue timers_;
+
+ bool use_broken_delay_;
+
+ HWND message_hwnd_;
+
+ // Flag to enable/disable use of native timers.
+ bool use_native_timers_;
+
+ // A lazily cached copy of MessageLoop::current.
+ MessageLoop* message_loop_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(TimerManager);
+};
+
+// A simple wrapper for the Timer / TimerManager API. This is a helper class.
+// Use OneShotTimer or RepeatingTimer instead.
+class SimpleTimer {
+ 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();
+
+ // 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;
+ }
+
+ // 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:
+ SimpleTimer(TimeDelta delay, Task* task, bool repeating);
+
+ private:
+ Timer timer_;
+
+ // Whether we need to clean up the Task* object for this Timer when
+ // we are deallocated. Defaults to true.
+ bool owns_task_;
+
+ DISALLOW_EVIL_CONSTRUCTORS(SimpleTimer);
+};
+
+// 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 {
+ public:
+ // The task must be set using set_task before calling Start.
+ explicit OneShotTimer(TimeDelta delay)
+ : SimpleTimer(delay, NULL, false) {
+ }
+ // If task is null, then it must be set using set_task before calling Start.
+ OneShotTimer(TimeDelta delay, Task* task)
+ : SimpleTimer(delay, task, false) {
+ }
+ private:
+ DISALLOW_EVIL_CONSTRUCTORS(OneShotTimer);
+};
+
+// 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 {
+ 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_EVIL_CONSTRUCTORS(RepeatingTimer);
+};
+
+#endif // BASE_TIMER_H_