blob: c23f725f48a95480b3122a6c12da5d2dbafd5cd0 [file] [log] [blame]
// 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 <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 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 MessageLoop;
class TimerManager;
class Task;
//-----------------------------------------------------------------------------
// The core timer object. Use TimerManager to create and control timers.
class Timer {
public:
Timer(int delay, Task* task, bool repeating);
// The task to be run when the timer fires.
Task* task() const { return task_; }
void set_task(Task* task) { task_ = task; }
// Returns the time in msec relative to now that the timer should fire.
int GetCurrentDelay() const;
// Returns the absolute time at which the timer should fire.
const Time &fire_time() const { return fire_time_; }
// A repeating timer is a timer that is automatically scheduled to fire again
// after it fires.
bool repeating() const { return repeating_; }
// Update (or fill in) creation_time_, and calculate future fire_time_ based
// on current time plus delay_.
void Reset();
// A unique identifier for this timer.
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:
// 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_COPY_AND_ASSIGN(Timer);
};
//-----------------------------------------------------------------------------
// Used to implement TimerPQueue
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 by the MessageLoop from within its run loop or via a system
// timer event that the MesssageLoop constructs. The advantage of the former
// is that we can make timers fire significantly faster than the granularity
// provided by the system. The advantage of a system timer is that modal
// message loops which don't run our MessageLoop code will still be able to
// process system timer events.
//
// NOTE: TimerManager is not thread safe. You cannot set timers onto a thread
// other than your own.
class TimerManager {
public:
explicit TimerManager(MessageLoop* message_loop);
~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);
// 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();
#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 // UNIT_TEST
bool use_broken_delay() const {
return use_broken_delay_;
}
protected:
// Peek at the timer which will fire soonest.
Timer* PeekTopTimer();
private:
void DidChangeNextTimer();
// A cached value that indicates the time when we think the next timer is to
// fire. We use this to determine if we should call DidChangeNextTimerExpiry
// on the MessageLoop.
Time next_timer_expiry_;
TimerPQueue timers_;
bool use_broken_delay_;
// A lazily cached copy of MessageLoop::current.
MessageLoop* message_loop_;
DISALLOW_COPY_AND_ASSIGN(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_COPY_AND_ASSIGN(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_COPY_AND_ASSIGN(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_COPY_AND_ASSIGN(RepeatingTimer);
};
#endif // BASE_TIMER_H_