license.bot | f003cfe | 2008-08-24 09:55:55 +0900 | [diff] [blame^] | 1 | // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 4 | |
| 5 | #ifndef BASE_TIMER_H_ |
| 6 | #define BASE_TIMER_H_ |
| 7 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 8 | #include <queue> |
| 9 | #include <vector> |
| 10 | |
| 11 | #include "base/basictypes.h" |
| 12 | #include "base/time.h" |
| 13 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 14 | //----------------------------------------------------------------------------- |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 15 | // Timer/TimerManager are objects designed to help setting timers. |
| 16 | // Goals of TimerManager: |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 17 | // - have only one system timer for all app timer functionality |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 18 | // - work around bugs with timers firing arbitrarily earlier than specified |
| 19 | // - provide the ability to run timers even if the application is in a |
| 20 | // windows modal app loop. |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 21 | //----------------------------------------------------------------------------- |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 22 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 23 | class MessageLoop; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 24 | class TimerManager; |
| 25 | class Task; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 26 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 27 | //----------------------------------------------------------------------------- |
| 28 | // The core timer object. Use TimerManager to create and control timers. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 29 | class Timer { |
| 30 | public: |
| 31 | Timer(int delay, Task* task, bool repeating); |
| 32 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 33 | // The task to be run when the timer fires. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 34 | Task* task() const { return task_; } |
| 35 | void set_task(Task* task) { task_ = task; } |
| 36 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 37 | // Returns the absolute time at which the timer should fire. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 38 | const Time &fire_time() const { return fire_time_; } |
| 39 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 40 | // A repeating timer is a timer that is automatically scheduled to fire again |
| 41 | // after it fires. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 42 | bool repeating() const { return repeating_; } |
| 43 | |
| 44 | // Update (or fill in) creation_time_, and calculate future fire_time_ based |
| 45 | // on current time plus delay_. |
| 46 | void Reset(); |
| 47 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 48 | // A unique identifier for this timer. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 49 | int id() const { return timer_id_; } |
| 50 | |
| 51 | protected: |
| 52 | // Protected (rather than private) so that we can access from unit tests. |
| 53 | |
| 54 | // The time when the timer should fire. |
| 55 | Time fire_time_; |
| 56 | |
| 57 | private: |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 58 | // The task that is run when this timer fires. |
| 59 | Task* task_; |
| 60 | |
| 61 | // Timer delay in milliseconds. |
| 62 | int delay_; |
| 63 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 64 | // A monotonically increasing timer id. Used for ordering two timers which |
| 65 | // have the same timestamp in a FIFO manner. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 66 | int timer_id_; |
| 67 | |
| 68 | // Whether or not this timer repeats. |
| 69 | const bool repeating_; |
| 70 | |
| 71 | // The tick count when the timer was "created". (i.e. when its current |
| 72 | // iteration started.) |
| 73 | Time creation_time_; |
| 74 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 75 | DISALLOW_COPY_AND_ASSIGN(Timer); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 76 | }; |
| 77 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 78 | //----------------------------------------------------------------------------- |
| 79 | // Used to implement TimerPQueue |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 80 | class TimerComparison { |
| 81 | public: |
| 82 | bool operator() (const Timer* t1, const Timer* t2) const { |
| 83 | const Time& f1 = t1->fire_time(); |
| 84 | const Time& f2 = t2->fire_time(); |
| 85 | // If the two timers have the same delay, revert to using |
| 86 | // the timer_id to maintain FIFO ordering. |
| 87 | if (f1 == f2) { |
| 88 | // Gracefully handle wrap as we try to return (t1->id() > t2->id()); |
| 89 | int delta = t1->id() - t2->id(); |
| 90 | // Assuming the delta is smaller than 2**31, we'll always get the right |
| 91 | // answer (in terms of sign of delta). |
| 92 | return delta > 0; |
| 93 | } |
| 94 | return f1 > f2; |
| 95 | } |
| 96 | }; |
| 97 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 98 | //----------------------------------------------------------------------------- |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 99 | // Subclass priority_queue to provide convenient access to removal from this |
| 100 | // list. |
| 101 | // |
| 102 | // Terminology: The "pending" timer is the timer at the top of the queue, |
| 103 | // i.e. the timer whose task needs to be Run next. |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 104 | class TimerPQueue : |
| 105 | public std::priority_queue<Timer*, std::vector<Timer*>, TimerComparison> { |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 106 | public: |
| 107 | // Removes |timer| from the queue. |
| 108 | void RemoveTimer(Timer* timer); |
| 109 | |
| 110 | // Returns true if the queue contains |timer|. |
| 111 | bool ContainsTimer(const Timer* timer) const; |
| 112 | }; |
| 113 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 114 | //----------------------------------------------------------------------------- |
| 115 | // There is one TimerManager per thread, owned by the MessageLoop. Timers can |
| 116 | // either be fired by the MessageLoop from within its run loop or via a system |
| 117 | // timer event that the MesssageLoop constructs. The advantage of the former |
| 118 | // is that we can make timers fire significantly faster than the granularity |
| 119 | // provided by the system. The advantage of a system timer is that modal |
| 120 | // message loops which don't run our MessageLoop code will still be able to |
| 121 | // process system timer events. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 122 | // |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 123 | // NOTE: TimerManager is not thread safe. You cannot set timers onto a thread |
| 124 | // other than your own. |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 125 | class TimerManager { |
| 126 | public: |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 127 | explicit TimerManager(MessageLoop* message_loop); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 128 | ~TimerManager(); |
| 129 | |
| 130 | // Create and start a new timer. |task| is owned by the caller, as is the |
| 131 | // timer object that is returned. |
| 132 | Timer* StartTimer(int delay, Task* task, bool repeating); |
| 133 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 134 | // Starts a timer. This is a no-op if the timer is already started. |
| 135 | void StartTimer(Timer* timer); |
| 136 | |
| 137 | // Stop a timer. This is a no-op if the timer is already stopped. |
| 138 | void StopTimer(Timer* timer); |
| 139 | |
| 140 | // Reset an existing timer, which may or may not be currently in the queue of |
| 141 | // upcoming timers. The timer's parameters are unchanged; it simply begins |
| 142 | // counting down again as if it was just created. |
| 143 | void ResetTimer(Timer* timer); |
| 144 | |
| 145 | // Returns true if |timer| is in the queue of upcoming timers. |
| 146 | bool IsTimerRunning(const Timer* timer) const; |
| 147 | |
| 148 | // Run some small number of timers. |
| 149 | // Returns true if it runs a task, false otherwise. |
| 150 | bool RunSomePendingTimers(); |
| 151 | |
darin@google.com | 6393bed | 2008-08-20 15:30:58 +0900 | [diff] [blame] | 152 | // The absolute time at which the next timer is to fire. If there is not a |
| 153 | // next timer to run, then the is_null property of the returned Time object |
| 154 | // will be true. NOTE: This could be a time in the past! |
| 155 | Time GetNextFireTime() const; |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 156 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 157 | #ifdef UNIT_TEST |
| 158 | // For testing only, used to simulate broken early-firing WM_TIMER |
| 159 | // notifications by setting arbitrarily small delays in SetTimer. |
| 160 | void set_use_broken_delay(bool use_broken_delay) { |
| 161 | use_broken_delay_ = use_broken_delay; |
| 162 | } |
darin@google.com | 3810032 | 2008-08-07 06:27:02 +0900 | [diff] [blame] | 163 | #endif // UNIT_TEST |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 164 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 165 | bool use_broken_delay() const { |
| 166 | return use_broken_delay_; |
| 167 | } |
| 168 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 169 | protected: |
| 170 | // Peek at the timer which will fire soonest. |
| 171 | Timer* PeekTopTimer(); |
| 172 | |
| 173 | private: |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 174 | void DidChangeNextTimer(); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 175 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 176 | // A cached value that indicates the time when we think the next timer is to |
| 177 | // fire. We use this to determine if we should call DidChangeNextTimerExpiry |
| 178 | // on the MessageLoop. |
| 179 | Time next_timer_expiry_; |
darin@google.com | 3810032 | 2008-08-07 06:27:02 +0900 | [diff] [blame] | 180 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 181 | TimerPQueue timers_; |
| 182 | |
| 183 | bool use_broken_delay_; |
| 184 | |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 185 | // A lazily cached copy of MessageLoop::current. |
| 186 | MessageLoop* message_loop_; |
| 187 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 188 | DISALLOW_COPY_AND_ASSIGN(TimerManager); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 189 | }; |
| 190 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 191 | //----------------------------------------------------------------------------- |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 192 | // A simple wrapper for the Timer / TimerManager API. This is a helper class. |
| 193 | // Use OneShotTimer or RepeatingTimer instead. |
| 194 | class SimpleTimer { |
| 195 | public: |
| 196 | // Stops the timer. |
| 197 | ~SimpleTimer(); |
| 198 | |
| 199 | // Call this method to explicitly start the timer. This is a no-op if the |
| 200 | // timer is already running. |
| 201 | void Start(); |
| 202 | |
| 203 | // Call this method to explicitly stop the timer. This is a no-op if the |
| 204 | // timer is not running. |
| 205 | void Stop(); |
| 206 | |
| 207 | // Returns true if the timer is running (i.e., not stopped). |
| 208 | bool IsRunning() const; |
| 209 | |
| 210 | // Short-hand for calling Stop and then Start. |
| 211 | void Reset(); |
| 212 | |
| 213 | // Get/Set the task to be run when this timer expires. NOTE: The caller of |
| 214 | // set_task must be careful to ensure that the old task is properly deleted. |
| 215 | Task* task() const { return timer_.task(); } |
| 216 | void set_task(Task* task) { |
| 217 | timer_.set_task(task); |
| 218 | owns_task_ = true; |
| 219 | } |
| 220 | |
| 221 | // Sets the task, but marks it so it shouldn't be deleted by the SimpleTimer. |
| 222 | void set_unowned_task(Task* task) { |
| 223 | timer_.set_task(task); |
| 224 | owns_task_ = false; |
| 225 | } |
| 226 | |
| 227 | protected: |
| 228 | SimpleTimer(TimeDelta delay, Task* task, bool repeating); |
| 229 | |
| 230 | private: |
| 231 | Timer timer_; |
| 232 | |
| 233 | // Whether we need to clean up the Task* object for this Timer when |
| 234 | // we are deallocated. Defaults to true. |
| 235 | bool owns_task_; |
| 236 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 237 | DISALLOW_COPY_AND_ASSIGN(SimpleTimer); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 238 | }; |
| 239 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 240 | //----------------------------------------------------------------------------- |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 241 | // A simple, one-shot timer. The task is run after the specified delay once |
| 242 | // the Start method is called. The task is deleted when the timer object is |
| 243 | // destroyed. |
| 244 | class OneShotTimer : public SimpleTimer { |
| 245 | public: |
| 246 | // The task must be set using set_task before calling Start. |
| 247 | explicit OneShotTimer(TimeDelta delay) |
| 248 | : SimpleTimer(delay, NULL, false) { |
| 249 | } |
| 250 | // If task is null, then it must be set using set_task before calling Start. |
| 251 | OneShotTimer(TimeDelta delay, Task* task) |
| 252 | : SimpleTimer(delay, task, false) { |
| 253 | } |
| 254 | private: |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 255 | DISALLOW_COPY_AND_ASSIGN(OneShotTimer); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 256 | }; |
| 257 | |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 258 | //----------------------------------------------------------------------------- |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 259 | // A simple, repeating timer. The task is run at the specified interval once |
| 260 | // the Start method is called. The task is deleted when the timer object is |
| 261 | // destroyed. |
| 262 | class RepeatingTimer : public SimpleTimer { |
| 263 | public: |
| 264 | // The task must be set using set_task before calling Start. |
| 265 | explicit RepeatingTimer(TimeDelta interval) |
| 266 | : SimpleTimer(interval, NULL, true) { |
| 267 | } |
| 268 | // If task is null, then it must be set using set_task before calling Start. |
| 269 | RepeatingTimer(TimeDelta interval, Task* task) |
| 270 | : SimpleTimer(interval, task, true) { |
| 271 | } |
| 272 | private: |
darin@google.com | ee6fa72 | 2008-08-13 08:25:43 +0900 | [diff] [blame] | 273 | DISALLOW_COPY_AND_ASSIGN(RepeatingTimer); |
initial.commit | 3f4a732 | 2008-07-27 06:49:38 +0900 | [diff] [blame] | 274 | }; |
| 275 | |
| 276 | #endif // BASE_TIMER_H_ |
license.bot | f003cfe | 2008-08-24 09:55:55 +0900 | [diff] [blame^] | 277 | |