1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 2c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Use of this source code is governed by a BSD-style license that can be 3c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// found in the LICENSE file. 4c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 5c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// OneShotTimer and RepeatingTimer provide a simple timer API. As the names 6c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// suggest, OneShotTimer calls you back once after a time delay expires. 7c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// RepeatingTimer on the other hand calls you back periodically with the 8c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// prescribed time interval. 9c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 10c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// OneShotTimer and RepeatingTimer both cancel the timer when they go out of 11c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// scope, which makes it easy to ensure that you do not get called when your 12c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// object has gone out of scope. Just instantiate a OneShotTimer or 13c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// RepeatingTimer as a member variable of the class for which you wish to 14c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// receive timer events. 15c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 16c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Sample RepeatingTimer usage: 17c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 18c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// class MyClass { 19c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// public: 20c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// void StartDoingStuff() { 21c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// timer_.Start(TimeDelta::FromSeconds(1), this, &MyClass::DoStuff); 22c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// } 23c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// void StopDoingStuff() { 24c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// timer_.Stop(); 25c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// } 26c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// private: 27c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// void DoStuff() { 28c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// // This method is called every second to do stuff. 29c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// ... 30c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// } 31c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// base::RepeatingTimer<MyClass> timer_; 32c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// }; 33c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 34c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Both OneShotTimer and RepeatingTimer also support a Reset method, which 35c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// allows you to easily defer the timer event until the timer delay passes once 36c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// again. So, in the above example, if 0.5 seconds have already passed, 37c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// calling Reset on timer_ would postpone DoStuff by another 1 second. In 38c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// other words, Reset is shorthand for calling Stop and then Start again with 39c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// the same arguments. 40c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 41c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#ifndef BASE_TIMER_H_ 42c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#define BASE_TIMER_H_ 433345a6884c488ff3a535c2c9acdd33d74b37e311Iain Merrick#pragma once 44c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 45c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// IMPORTANT: If you change timer code, make sure that all tests (including 46c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// disabled ones) from timer_unittests.cc pass locally. Some are disabled 47c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// because they're flaky on the buildbot, but when you run them locally you 48c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// should be able to tell the difference. 49c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 50ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/base_api.h" 51c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/logging.h" 52c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/task.h" 53c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#include "base/time.h" 54c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 55c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass MessageLoop; 56c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 57c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottnamespace base { 58c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 59c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//----------------------------------------------------------------------------- 60c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// This class is an implementation detail of OneShotTimer and RepeatingTimer. 61c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Please do not use this class directly. 62c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 63c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// This class exists to share code between BaseTimer<T> template instantiations. 64c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 65ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsenclass BASE_API BaseTimer_Helper { 66c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 67c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Stops the timer. 68c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ~BaseTimer_Helper() { 69c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott OrphanDelayedTask(); 70c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 71c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 72c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Returns true if the timer is running (i.e., not stopped). 73c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott bool IsRunning() const { 74c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return delayed_task_ != NULL; 75c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 76c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 77c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Returns the current delay for this timer. May only call this method when 78c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // the timer is running! 79c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TimeDelta GetCurrentDelay() const { 80c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(IsRunning()); 81c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return delayed_task_->delay_; 82c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 83c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 84c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott protected: 85c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott BaseTimer_Helper() : delayed_task_(NULL) {} 86c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 87c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We have access to the timer_ member so we can orphan this task. 88c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott class TimerTask : public Task { 89c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 90c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott explicit TimerTask(TimeDelta delay) : timer_(NULL), delay_(delay) { 91c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 92c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott virtual ~TimerTask() {} 93c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott BaseTimer_Helper* timer_; 94c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TimeDelta delay_; 95c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott }; 96c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 97c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Used to orphan delayed_task_ so that when it runs it does nothing. 98c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void OrphanDelayedTask(); 99c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 100c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Used to initiated a new delayed task. This has the side-effect of 101c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // orphaning delayed_task_ if it is non-null. 102c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void InitiateDelayedTask(TimerTask* timer_task); 103c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 104c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TimerTask* delayed_task_; 105c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 106c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DISALLOW_COPY_AND_ASSIGN(BaseTimer_Helper); 107c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 108c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 109c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//----------------------------------------------------------------------------- 110c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// This class is an implementation detail of OneShotTimer and RepeatingTimer. 111c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Please do not use this class directly. 112c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttemplate <class Receiver, bool kIsRepeating> 113c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass BaseTimer : public BaseTimer_Helper { 114c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 115c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott typedef void (Receiver::*ReceiverMethod)(); 116c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 117c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Call this method to start the timer. It is an error to call this method 118c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // while the timer is already running. 119c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void Start(TimeDelta delay, Receiver* receiver, ReceiverMethod method) { 120c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(!IsRunning()); 121c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott InitiateDelayedTask(new TimerTask(delay, receiver, method)); 122c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 123c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 124c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Call this method to stop the timer. It is a no-op if the timer is not 125c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // running. 126c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void Stop() { 127c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott OrphanDelayedTask(); 128c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 129c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 130c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Call this method to reset the timer delay of an already running timer. 131c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void Reset() { 132c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(IsRunning()); 133c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott InitiateDelayedTask(static_cast<TimerTask*>(delayed_task_)->Clone()); 134c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 135c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 136c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private: 137c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott typedef BaseTimer<Receiver, kIsRepeating> SelfType; 138c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 139c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott class TimerTask : public BaseTimer_Helper::TimerTask { 140c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 141c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TimerTask(TimeDelta delay, Receiver* receiver, ReceiverMethod method) 142c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : BaseTimer_Helper::TimerTask(delay), 143c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott receiver_(receiver), 144c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott method_(method) { 145c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 146c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 147c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott virtual ~TimerTask() { 148c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // This task may be getting cleared because the MessageLoop has been 149c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // destructed. If so, don't leave the Timer with a dangling pointer 150c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // to this now-defunct task. 151c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ClearBaseTimer(); 152c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 153c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 154c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott virtual void Run() { 155c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (!timer_) // timer_ is null if we were orphaned. 156c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 157c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (kIsRepeating) 158c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ResetBaseTimer(); 159c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott else 160c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ClearBaseTimer(); 161c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DispatchToMethod(receiver_, method_, Tuple0()); 162c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 163c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 164c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott TimerTask* Clone() const { 165c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return new TimerTask(delay_, receiver_, method_); 166c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 167c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 168c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private: 169c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Inform the Base that the timer is no longer active. 170c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void ClearBaseTimer() { 171c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (timer_) { 172c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SelfType* self = static_cast<SelfType*>(timer_); 173c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // It is possible that the Timer has already been reset, and that this 174c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Task is old. So, if the Timer points to a different task, assume 175c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // that the Timer has already taken care of properly setting the task. 176c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (self->delayed_task_ == this) 177c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott self->delayed_task_ = NULL; 178c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // By now the delayed_task_ in the Timer does not point to us anymore. 179c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // We should reset our own timer_ because the Timer can not do this 180c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // for us in its destructor. 181c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott timer_ = NULL; 182c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 183c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 184c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 185c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // Inform the Base that we're resetting the timer. 186c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void ResetBaseTimer() { 187c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(timer_); 188c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DCHECK(kIsRepeating); 189c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott SelfType* self = static_cast<SelfType*>(timer_); 190c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott self->Reset(); 191c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 192c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 193c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Receiver* receiver_; 194c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott ReceiverMethod method_; 195c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott }; 196c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 197c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 198c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//----------------------------------------------------------------------------- 199c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// A simple, one-shot timer. See usage notes at the top of the file. 200c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttemplate <class Receiver> 201c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass OneShotTimer : public BaseTimer<Receiver, false> {}; 202c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 203c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//----------------------------------------------------------------------------- 204c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// A simple, repeating timer. See usage notes at the top of the file. 205c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttemplate <class Receiver> 206c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass RepeatingTimer : public BaseTimer<Receiver, true> {}; 207c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 208c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott//----------------------------------------------------------------------------- 209c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// A Delay timer is like The Button from Lost. Once started, you have to keep 210c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// calling Reset otherwise it will call the given method in the MessageLoop 211c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// thread. 212c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 213c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// Once created, it is inactive until Reset is called. Once |delay| seconds have 214c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// passed since the last call to Reset, the callback is made. Once the callback 215c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// has been made, it's inactive until Reset is called again. 216c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// 217c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// If destroyed, the timeout is canceled and will not occur even if already 218c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott// inflight. 219c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scotttemplate <class Receiver> 220c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scottclass DelayTimer { 221c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott public: 222c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott typedef void (Receiver::*ReceiverMethod)(); 223c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 224c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DelayTimer(TimeDelta delay, Receiver* receiver, ReceiverMethod method) 225c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott : receiver_(receiver), 226c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott method_(method), 227c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott delay_(delay) { 228c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 229c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 230c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void Reset() { 231c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DelayFor(delay_); 232c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 233c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 234c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott private: 235c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void DelayFor(TimeDelta delay) { 236ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen trigger_time_ = TimeTicks::Now() + delay; 237c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 238c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If we already have a timer that will expire at or before the given delay, 239c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // then we have nothing more to do now. 240c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (timer_.IsRunning() && timer_.GetCurrentDelay() <= delay) 241c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 242c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 243c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // The timer isn't running, or will expire too late, so restart it. 244c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott timer_.Stop(); 245c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott timer_.Start(delay, this, &DelayTimer<Receiver>::Check); 246c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 247c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 248c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott void Check() { 249c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (trigger_time_.is_null()) 250c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 251c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 252c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott // If we have not waited long enough, then wait some more. 253ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen const TimeTicks now = TimeTicks::Now(); 254c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott if (now < trigger_time_) { 255c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott DelayFor(trigger_time_ - now); 256c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott return; 257c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 258c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 259c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott (receiver_->*method_)(); 260c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott } 261c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 262c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott Receiver *const receiver_; 263c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const ReceiverMethod method_; 264c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott const TimeDelta delay_; 265c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 266c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott OneShotTimer<DelayTimer<Receiver> > timer_; 267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen TimeTicks trigger_time_; 268c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott}; 269c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 270c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott} // namespace base 271c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott 272c7f5f8508d98d5952d42ed7648c2a8f30a4da156Patrick Scott#endif // BASE_TIMER_H_ 273