LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/base - timer.cc (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 114 129 88.4 %
Date: 2026-08-03 02:19:58 Functions: 16 17 94.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : #include "base/timer.h"
       6             : #include "base/timer_impl.h"
       7             : 
       8             : class Timer::TimerTask : public Task {
       9             : public:
      10       64864 :     TimerTask(TimerPtr timer, boost::system::error_code ec)
      11       64864 :         : Task(timer->task_id_, timer->task_instance_), timer_(timer), ec_(ec) {
      12       64864 :     }
      13             : 
      14      129728 :     virtual ~TimerTask() {
      15      129728 :     }
      16             : 
      17             :     // Invokes user callback.
      18             :     // Timer could have been cancelled or delete when task was enqueued
      19       64682 :     virtual bool Run() {
      20             :         {
      21       64682 :             std::unique_lock<std::mutex> lock(timer_->mutex_);
      22             : 
      23             :             // cancelled task .. ignore
      24       64694 :             if (task_cancelled()) {
      25             :                 // Cancelled timer's task releases the ownership of the timer
      26           0 :                 lock.unlock();
      27           0 :                 timer_ = NULL;
      28           0 :                 return true;
      29             :             }
      30             : 
      31             :             // Conditions to invoke user callback met. Fire it
      32       64620 :             timer_->SetState(Timer::Fired);
      33       64609 :         }
      34             : 
      35       64720 :         bool restart = false;
      36             : 
      37             :         // TODO: Is this error needed by user?
      38       64720 :         if (ec_ && !timer_->error_handler_.empty()) {
      39           0 :             timer_->error_handler_(timer_->name_,
      40           0 :                                    std::string(ec_.category().name()),
      41           0 :                                    ec_.message());
      42             :         } else {
      43       64694 :             restart = timer_->handler_();
      44             :         }
      45             : 
      46       64691 :         OnTaskCancel();
      47             : 
      48       64669 :         if (restart) {
      49       72572 :             timer_->Start(timer_->time_, timer_->handler_,
      50       36300 :                           timer_->error_handler_);
      51       28340 :         } else if (timer_->delete_on_completion_) {
      52         164 :             TimerManager::DeleteTimer(timer_.get());
      53             :         }
      54       64744 :         return true;
      55             :     }
      56             : 
      57             :     // Task Cancelled/Destroyed when it was Fired.
      58       64703 :     void OnTaskCancel() {
      59       64703 :         if (!timer_) {
      60           0 :             return;
      61             :         }
      62       64679 :         std::scoped_lock lock(timer_->mutex_);
      63             : 
      64       64640 :         if (timer_->timer_task_ != this) {
      65           0 :             assert(!timer_->timer_task_);
      66             :         }
      67             : 
      68       64593 :         timer_->timer_task_ = NULL;
      69       64567 :         timer_->SetState(Timer::Init);
      70       64538 :     }
      71             : 
      72           0 :     virtual std::string Description() const {
      73           0 :         return timer_->Description();
      74             :     }
      75             : 
      76             : private:
      77             :     TimerPtr timer_;
      78             :     boost::system::error_code ec_;
      79             :     DISALLOW_COPY_AND_ASSIGN(TimerTask);
      80             : };
      81             : 
      82      378382 : Timer::Timer(boost::asio::io_context &service, const std::string &name,
      83      378382 :           int task_id, int task_instance, bool delete_on_completion)
      84      378383 :         : impl_(new TimerImpl(service)),
      85      378382 :           name_(name),
      86      378383 :           handler_(NULL),
      87      378383 :           error_handler_(NULL),
      88      378383 :           state_(Init),
      89      378383 :           timer_task_(NULL),
      90      378383 :           time_(0),
      91      378383 :           task_id_(task_id),
      92      378383 :           task_instance_(task_instance),
      93      378383 :           seq_no_(0),
      94      756765 :           delete_on_completion_(delete_on_completion) {
      95      378383 :     refcount_ = 0;
      96      378384 : }
      97             : 
      98      753930 : Timer::~Timer() {
      99      376965 :     assert(state_ != Running && state_ != Fired);
     100      753930 : }
     101             : 
     102             : //
     103             : // Start a timer
     104             : //
     105             : // If the timer is already running, return silently
     106             : //
     107     4836280 : bool Timer::Start(int time, Handler handler, ErrorHandler error_handler) {
     108     4836280 :     std::scoped_lock lock(mutex_);
     109             : 
     110     4836464 :     if (time < 0) {
     111         136 :         return true;
     112             :     }
     113             : 
     114     4836328 :     if (state_ == Running || state_ == Fired) {
     115      175173 :         return true;
     116             :     }
     117             : 
     118             :     // Restart the timer
     119     4661155 :     time_ = time;
     120     4661155 :     handler_ = handler;
     121     4660386 :     seq_no_++;
     122     4660386 :     error_handler_ = error_handler;
     123     4660232 :     boost::system::error_code ec;
     124     4660232 :     impl_->expires_from_now(time, ec);
     125     4661195 :     if (ec) {
     126           0 :         return false;
     127             :     }
     128             : 
     129     4661166 :     SetState(Running);
     130     9322313 :     impl_->async_wait(
     131     9322443 :         boost::bind(&Timer::StartTimerTask, this, TimerPtr(this),
     132             :                     time, seq_no_, boost::asio::placeholders::error));
     133     4661382 :     return true;
     134     4836691 : }
     135             : 
     136       14044 : bool Timer::Reschedule(int time)
     137             : {
     138       14044 :     if (state_ != Fired)
     139         183 :         return false;
     140             : 
     141       13861 :     if (time < 0)
     142           0 :         return false;
     143             : 
     144       13861 :     time_ = time;
     145       13861 :     return true;
     146             : }
     147             : 
     148             : // Cancel a running timer
     149     5546740 : bool Timer::Cancel() {
     150     5546740 :     std::scoped_lock lock(mutex_);
     151             : 
     152             :     // A fired timer cannot be cancelled
     153     5546764 :     if (state_ == Fired) {
     154        5109 :         return false;
     155             :     }
     156             : 
     157             :     // Cancel Task. If Task cancel succeeds, there will be no callback.
     158             :     // Reset TaskRef if call succeeds.
     159     5541655 :     if (timer_task_) {
     160             :         TaskScheduler::CancelReturnCode rc =
     161         118 :             TaskScheduler::GetInstance()->Cancel(timer_task_);
     162         118 :         assert(rc != TaskScheduler::FAILED);
     163         118 :         timer_task_ = NULL;
     164             :     }
     165             : 
     166     5541655 :     SetState(Cancelled);
     167     5541572 :     return true;
     168     5546681 : }
     169             : 
     170             : // ASIO callback on timer expiry. Start a task to serve the timer
     171     4583463 : void Timer::StartTimerTask(TimerPtr reference, int time, uint32_t seq_no,
     172             :                            const boost::system::error_code &ec) {
     173     4583463 :     std::scoped_lock lock(mutex_);
     174             : 
     175     4583463 :     if (state_ == Cancelled) {
     176       26916 :         return;
     177             :     }
     178             : 
     179             :     // If timer was cancelled, no callback is invoked
     180     4556547 :     if (ec && ec.value() == boost::asio::error::operation_aborted) {
     181     4491683 :         return;
     182             :     }
     183             : 
     184             :     // Timer could have fired for previous run. Validate the seq_no_
     185       64864 :     if (seq_no_ != seq_no) {
     186           0 :         return;
     187             :     }
     188             :     // Start a task and add Task reference.
     189       64864 :     assert(timer_task_ == NULL);
     190       64864 :     timer_task_ = new TimerTask(reference, ec);
     191       64864 :     TaskScheduler::GetInstance()->Enqueue(timer_task_);
     192     4583463 : }
     193             : 
     194             : //
     195             : // TimerManager class routines
     196             : //
     197             : TimerManager::TimerSet TimerManager::timer_ref_;
     198             : std::mutex TimerManager::mutex_;
     199             : 
     200      378382 : Timer *TimerManager::CreateTimer(
     201             :             boost::asio::io_context &service, const std::string &name,
     202             :             int task_id, int task_instance, bool delete_on_completion) {
     203             :     Timer *timer = new Timer(service, name, task_id, task_instance,
     204      378382 :                              delete_on_completion);
     205      378384 :     AddTimer(timer);
     206      378384 :     return timer;
     207             : }
     208             : 
     209      378384 : void TimerManager::AddTimer(Timer *timer) {
     210      378384 :     std::scoped_lock lock(mutex_);
     211      378384 :     timer_ref_.insert(TimerPtr(timer));
     212             : 
     213      756768 :     return;
     214      378384 : }
     215             : 
     216             : //
     217             : // Delete a timer object from the data base, by removing the intrusive
     218             : // reference. If any other objects has a reference to this timer such as
     219             : // boost::asio, the timer object deletion is automatically deferred
     220             : //
     221      372782 : bool TimerManager::DeleteTimer(Timer *timer) {
     222      372782 :     if (!timer || timer->fired()) return false;
     223             : 
     224      361015 :     if (!timer->Cancel() && timer->IsDeleteOnCompletion())
     225           0 :         return false;
     226             : 
     227      361015 :     std::scoped_lock lock(mutex_);
     228      361015 :     timer_ref_.erase(TimerPtr(timer));
     229             : 
     230      361015 :     return true;
     231      361015 : }
     232             : 
     233             : // Get timer's already elapsed time in milliseconds.
     234         730 : int64_t Timer::GetElapsedTime() const {
     235         730 :     std::scoped_lock lock(mutex_);
     236             :     int64_t elapsed;
     237             : 
     238             : #if __cplusplus >= 201103L
     239         730 :     elapsed = std::chrono::nanoseconds(impl_->expires_from_now()).count();
     240             : #else
     241             :     elapsed = boost::chrono::nanoseconds(impl_->expires_from_now()).count();
     242             : #endif
     243             : 
     244         730 :     elapsed = time_ - elapsed / 1000000; // Convert nanoseconds to milliseconds.
     245         730 :     if (elapsed < 0)
     246           0 :         elapsed = 0;
     247         730 :     return elapsed;
     248         730 : }

Generated by: LCOV version 1.14