summaryrefslogtreecommitdiffstats
path: root/base/timer.h
blob: 32adbf1743826f055227cff88beb3619433ab279 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// OneShotTimer and RepeatingTimer provide a simple timer API.  As the names
// suggest, OneShotTimer calls you back once after a time delay expires.
// RepeatingTimer on the other hand calls you back periodically with the
// prescribed time interval.
//
// OneShotTimer and RepeatingTimer both cancel the timer when they go out of
// scope, which makes it easy to ensure that you do not get called when your
// object has gone out of scope.  Just instantiate a OneShotTimer or
// RepeatingTimer as a member variable of the class for which you wish to
// receive timer events.
//
// Sample RepeatingTimer usage:
//
//   class MyClass {
//    public:
//     void StartDoingStuff() {
//       timer_.Start(TimeDelta::FromSeconds(1), this, &MyClass::DoStuff);
//     }
//     void StopDoingStuff() {
//       timer_.Stop();
//     }
//    private:
//     void DoStuff() {
//       // This method is called every second to do stuff.
//       ...
//     }
//     base::RepeatingTimer<MyClass> timer_;
//   };
//
// Both OneShotTimer and RepeatingTimer also support a Reset method, which
// allows you to easily defer the timer event until the timer delay passes once
// again.  So, in the above example, if 0.5 seconds have already passed,
// calling Reset on timer_ would postpone DoStuff by another 1 second.  In
// other words, Reset is shorthand for calling Stop and then Start again with
// the same arguments.

#ifndef BASE_TIMER_H_
#define BASE_TIMER_H_

#include "base/task.h"
#include "base/time.h"

class MessageLoop;

namespace base {

//-----------------------------------------------------------------------------
// This class is an implementation detail of OneShotTimer and RepeatingTimer.
// Please do not use this class directly.
//
// This class exists to share code between BaseTimer<T> template instantiations.
//
class BaseTimer_Helper {
 public:
  // Stops the timer.
  ~BaseTimer_Helper() {
    OrphanDelayedTask();
  }

  // Returns true if the timer is running (i.e., not stopped).
  bool IsRunning() const {
    return delayed_task_ != NULL;
  }

 protected:
  BaseTimer_Helper() : delayed_task_(NULL) {}

  // We have access to the timer_ member so we can orphan this task.
  class TimerTask : public Task {
   public:
    TimerTask(TimeDelta delay) : delay_(delay) {
      // timer_ is set in InitiateDelayedTask.
    }
    BaseTimer_Helper* timer_;
    TimeDelta delay_;
  };

  // Used to orphan delayed_task_ so that when it runs it does nothing.
  void OrphanDelayedTask();
  
  // Used to initiated a new delayed task.  This has the side-effect of
  // orphaning delayed_task_ if it is non-null.
  void InitiateDelayedTask(TimerTask* timer_task);

  TimerTask* delayed_task_;

  DISALLOW_COPY_AND_ASSIGN(BaseTimer_Helper);
};

//-----------------------------------------------------------------------------
// This class is an implementation detail of OneShotTimer and RepeatingTimer.
// Please do not use this class directly.
template <class Receiver, bool kIsRepeating>
class BaseTimer : public BaseTimer_Helper {
 public:
  typedef void (Receiver::*ReceiverMethod)();

  // Call this method to start the timer.  It is an error to call this method
  // while the timer is already running.
  void Start(TimeDelta delay, Receiver* receiver, ReceiverMethod method) {
    DCHECK(!IsRunning());
    InitiateDelayedTask(new TimerTask(delay, receiver, method));
  }

  // Call this method to stop the timer.  It is a no-op if the timer is not
  // running.
  void Stop() {
    OrphanDelayedTask();
  }

  // Call this method to reset the timer delay of an already running timer.
  void Reset() {
    DCHECK(IsRunning());
    InitiateDelayedTask(static_cast<TimerTask*>(delayed_task_)->Clone());
  }

 private:
  typedef BaseTimer<Receiver, kIsRepeating> SelfType;
  
  class TimerTask : public BaseTimer_Helper::TimerTask {
   public:
    TimerTask(TimeDelta delay, Receiver* receiver, ReceiverMethod method)
        : BaseTimer_Helper::TimerTask(delay),
          receiver_(receiver),
          method_(method) {
    }
    virtual void Run() {
      if (!timer_)  // timer_ is null if we were orphaned.
        return;
      SelfType* self = static_cast<SelfType*>(timer_);
      if (kIsRepeating) {
        self->Reset();
      } else {
        self->delayed_task_ = NULL;
      }
      DispatchToMethod(receiver_, method_, Tuple0());
    }
    TimerTask* Clone() const {
      return new TimerTask(delay_, receiver_, method_);
    }
   private:
    Receiver* receiver_;
    ReceiverMethod method_;
  };
};

//-----------------------------------------------------------------------------
// A simple, one-shot timer.  See usage notes at the top of the file.
template <class Receiver>
class OneShotTimer : public BaseTimer<Receiver, false> {};

//-----------------------------------------------------------------------------
// A simple, repeating timer.  See usage notes at the top of the file.
template <class Receiver>
class RepeatingTimer : public BaseTimer<Receiver, true> {};

}  // namespace base

#endif  // BASE_TIMER_H_