LCOV - code coverage report
Current view: top level - ipc/chromium/src/base - timer.h (source / functions) Hit Total Coverage
Test: output.info Lines: 0 50 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 34 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13