blob: 9b7c726089ca3a9516f8f40376fc5eddbf02dccb [file] [log] [blame]
license.botf003cfe2008-08-24 09:55:55 +09001// 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.commit3f4a7322008-07-27 06:49:38 +09004
5#ifndef BASE_TIMER_H_
6#define BASE_TIMER_H_
7
initial.commit3f4a7322008-07-27 06:49:38 +09008#include <queue>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/time.h"
13
darin@google.comee6fa722008-08-13 08:25:43 +090014//-----------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +090015// Timer/TimerManager are objects designed to help setting timers.
16// Goals of TimerManager:
darin@google.comee6fa722008-08-13 08:25:43 +090017// - have only one system timer for all app timer functionality
initial.commit3f4a7322008-07-27 06:49:38 +090018// - 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.comee6fa722008-08-13 08:25:43 +090021//-----------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +090022
darin@google.comee6fa722008-08-13 08:25:43 +090023class MessageLoop;
initial.commit3f4a7322008-07-27 06:49:38 +090024class TimerManager;
25class Task;
initial.commit3f4a7322008-07-27 06:49:38 +090026
darin@google.comee6fa722008-08-13 08:25:43 +090027//-----------------------------------------------------------------------------
28// The core timer object. Use TimerManager to create and control timers.
initial.commit3f4a7322008-07-27 06:49:38 +090029class Timer {
30 public:
31 Timer(int delay, Task* task, bool repeating);
32
darin@google.comee6fa722008-08-13 08:25:43 +090033 // The task to be run when the timer fires.
initial.commit3f4a7322008-07-27 06:49:38 +090034 Task* task() const { return task_; }
35 void set_task(Task* task) { task_ = task; }
36
darin@google.comee6fa722008-08-13 08:25:43 +090037 // Returns the absolute time at which the timer should fire.
initial.commit3f4a7322008-07-27 06:49:38 +090038 const Time &fire_time() const { return fire_time_; }
39
darin@google.comee6fa722008-08-13 08:25:43 +090040 // A repeating timer is a timer that is automatically scheduled to fire again
41 // after it fires.
initial.commit3f4a7322008-07-27 06:49:38 +090042 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.comee6fa722008-08-13 08:25:43 +090048 // A unique identifier for this timer.
initial.commit3f4a7322008-07-27 06:49:38 +090049 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.commit3f4a7322008-07-27 06:49:38 +090058 // The task that is run when this timer fires.
59 Task* task_;
60
61 // Timer delay in milliseconds.
62 int delay_;
63
darin@google.comee6fa722008-08-13 08:25:43 +090064 // A monotonically increasing timer id. Used for ordering two timers which
65 // have the same timestamp in a FIFO manner.
initial.commit3f4a7322008-07-27 06:49:38 +090066 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.comee6fa722008-08-13 08:25:43 +090075 DISALLOW_COPY_AND_ASSIGN(Timer);
initial.commit3f4a7322008-07-27 06:49:38 +090076};
77
darin@google.comee6fa722008-08-13 08:25:43 +090078//-----------------------------------------------------------------------------
79// Used to implement TimerPQueue
initial.commit3f4a7322008-07-27 06:49:38 +090080class 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.comee6fa722008-08-13 08:25:43 +090098//-----------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +090099// 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.comee6fa722008-08-13 08:25:43 +0900104class TimerPQueue :
105 public std::priority_queue<Timer*, std::vector<Timer*>, TimerComparison> {
initial.commit3f4a7322008-07-27 06:49:38 +0900106 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.comee6fa722008-08-13 08:25:43 +0900114//-----------------------------------------------------------------------------
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.commit3f4a7322008-07-27 06:49:38 +0900122//
darin@google.comee6fa722008-08-13 08:25:43 +0900123// NOTE: TimerManager is not thread safe. You cannot set timers onto a thread
124// other than your own.
initial.commit3f4a7322008-07-27 06:49:38 +0900125class TimerManager {
126 public:
darin@google.comee6fa722008-08-13 08:25:43 +0900127 explicit TimerManager(MessageLoop* message_loop);
initial.commit3f4a7322008-07-27 06:49:38 +0900128 ~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.commit3f4a7322008-07-27 06:49:38 +0900134 // 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.com6393bed2008-08-20 15:30:58 +0900152 // 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.commit3f4a7322008-07-27 06:49:38 +0900156
initial.commit3f4a7322008-07-27 06:49:38 +0900157#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.com38100322008-08-07 06:27:02 +0900163#endif // UNIT_TEST
initial.commit3f4a7322008-07-27 06:49:38 +0900164
darin@google.comee6fa722008-08-13 08:25:43 +0900165 bool use_broken_delay() const {
166 return use_broken_delay_;
167 }
168
initial.commit3f4a7322008-07-27 06:49:38 +0900169 protected:
170 // Peek at the timer which will fire soonest.
171 Timer* PeekTopTimer();
172
173 private:
darin@google.comee6fa722008-08-13 08:25:43 +0900174 void DidChangeNextTimer();
initial.commit3f4a7322008-07-27 06:49:38 +0900175
darin@google.comee6fa722008-08-13 08:25:43 +0900176 // 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.com38100322008-08-07 06:27:02 +0900180
initial.commit3f4a7322008-07-27 06:49:38 +0900181 TimerPQueue timers_;
182
183 bool use_broken_delay_;
184
initial.commit3f4a7322008-07-27 06:49:38 +0900185 // A lazily cached copy of MessageLoop::current.
186 MessageLoop* message_loop_;
187
darin@google.comee6fa722008-08-13 08:25:43 +0900188 DISALLOW_COPY_AND_ASSIGN(TimerManager);
initial.commit3f4a7322008-07-27 06:49:38 +0900189};
190
darin@google.comee6fa722008-08-13 08:25:43 +0900191//-----------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900192// A simple wrapper for the Timer / TimerManager API. This is a helper class.
193// Use OneShotTimer or RepeatingTimer instead.
194class 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.comee6fa722008-08-13 08:25:43 +0900237 DISALLOW_COPY_AND_ASSIGN(SimpleTimer);
initial.commit3f4a7322008-07-27 06:49:38 +0900238};
239
darin@google.comee6fa722008-08-13 08:25:43 +0900240//-----------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900241// 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.
244class 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.comee6fa722008-08-13 08:25:43 +0900255 DISALLOW_COPY_AND_ASSIGN(OneShotTimer);
initial.commit3f4a7322008-07-27 06:49:38 +0900256};
257
darin@google.comee6fa722008-08-13 08:25:43 +0900258//-----------------------------------------------------------------------------
initial.commit3f4a7322008-07-27 06:49:38 +0900259// 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.
262class 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.comee6fa722008-08-13 08:25:43 +0900273 DISALLOW_COPY_AND_ASSIGN(RepeatingTimer);
initial.commit3f4a7322008-07-27 06:49:38 +0900274};
275
276#endif // BASE_TIMER_H_
license.botf003cfe2008-08-24 09:55:55 +0900277