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