ipc/chromium/src/base/timer.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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

mercurial