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-10-26 01:57:03 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       58962 :     TimerTask(TimerPtr timer, boost::system::error_code ec)
      11       58962 :         : Task(timer->task_id_, timer->task_instance_), timer_(timer), ec_(ec) {
      12       58962 :     }
      13             : 
      14      117924 :     virtual ~TimerTask() {
      15      117924 :     }
      16             : 
      17             :     // Invokes user callback.
      18             :     // Timer could have been cancelled or delete when task was enqueued
      19       58739 :     virtual bool Run() {
      20             :         {
      21       58739 :             std::unique_lock<std::mutex> lock(timer_->mutex_);
      22             : 
      23             :             // cancelled task .. ignore
      24       58791 :             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       58778 :             timer_->SetState(Timer::Fired);
      33       58778 :         }
      34             : 
      35       58791 :         bool restart = false;
      36             : 
      37             :         // TODO: Is this error needed by user?
      38       58791 :         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       58770 :             restart = timer_->handler_();
      44             :         }
      45             : 
      46       58804 :         OnTaskCancel();
      47             : 
      48       58763 :         if (restart) {
      49       66227 :             timer_->Start(timer_->time_, timer_->handler_,
      50       33135 :                           timer_->error_handler_);
      51       25614 :         } else if (timer_->delete_on_completion_) {
      52         163 :             TimerManager::DeleteTimer(timer_.get());
      53             :         }
      54       58833 :         return true;
      55             :     }
      56             : 
      57             :     // Task Cancelled/Destroyed when it was Fired.
      58       58790 :     void OnTaskCancel() {
      59       58790 :         if (!timer_) {
      60           0 :             return;
      61             :         }
      62       58764 :         std::scoped_lock lock(timer_->mutex_);
      63             : 
      64       58756 :         if (timer_->timer_task_ != this) {
      65           0 :             assert(!timer_->timer_task_);
      66             :         }
      67             : 
      68       58722 :         timer_->timer_task_ = NULL;
      69       58701 :         timer_->SetState(Timer::Init);
      70       58659 :     }
      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      378814 : Timer::Timer(boost::asio::io_context &service, const std::string &name,
      83      378814 :           int task_id, int task_instance, bool delete_on_completion)
      84      378814 :         : impl_(new TimerImpl(service)),
      85      378812 :           name_(name),
      86      378809 :           handler_(NULL),
      87      378808 :           error_handler_(NULL),
      88      378808 :           state_(Init),
      89      378808 :           timer_task_(NULL),
      90      378808 :           time_(0),
      91      378808 :           task_id_(task_id),
      92      378808 :           task_instance_(task_instance),
      93      378808 :           seq_no_(0),
      94      757622 :           delete_on_completion_(delete_on_completion) {
      95      378808 :     refcount_ = 0;
      96      378814 : }
      97             : 
      98      754772 : Timer::~Timer() {
      99      377386 :     assert(state_ != Running && state_ != Fired);
     100      754772 : }
     101             : 
     102             : //
     103             : // Start a timer
     104             : //
     105             : // If the timer is already running, return silently
     106             : //
     107     4760565 : bool Timer::Start(int time, Handler handler, ErrorHandler error_handler) {
     108     4760565 :     std::scoped_lock lock(mutex_);
     109             : 
     110     4760756 :     if (time < 0) {
     111         138 :         return true;
     112             :     }
     113             : 
     114     4760618 :     if (state_ == Running || state_ == Fired) {
     115      174566 :         return true;
     116             :     }
     117             : 
     118             :     // Restart the timer
     119     4586052 :     time_ = time;
     120     4586052 :     handler_ = handler;
     121     4585381 :     seq_no_++;
     122     4585381 :     error_handler_ = error_handler;
     123     4585221 :     boost::system::error_code ec;
     124     4585221 :     impl_->expires_from_now(time, ec);
     125     4586102 :     if (ec) {
     126           0 :         return false;
     127             :     }
     128             : 
     129     4586086 :     SetState(Running);
     130     9172172 :     impl_->async_wait(
     131     9172229 :         boost::bind(&Timer::StartTimerTask, this, TimerPtr(this),
     132             :                     time, seq_no_, boost::asio::placeholders::error));
     133     4586186 :     return true;
     134     4760890 : }
     135             : 
     136       11223 : bool Timer::Reschedule(int time)
     137             : {
     138       11223 :     if (state_ != Fired)
     139         183 :         return false;
     140             : 
     141       11040 :     if (time < 0)
     142           0 :         return false;
     143             : 
     144       11040 :     time_ = time;
     145       11040 :     return true;
     146             : }
     147             : 
     148             : // Cancel a running timer
     149     5452326 : bool Timer::Cancel() {
     150     5452326 :     std::scoped_lock lock(mutex_);
     151             : 
     152             :     // A fired timer cannot be cancelled
     153     5452346 :     if (state_ == Fired) {
     154        4525 :         return false;
     155             :     }
     156             : 
     157             :     // Cancel Task. If Task cancel succeeds, there will be no callback.
     158             :     // Reset TaskRef if call succeeds.
     159     5447821 :     if (timer_task_) {
     160             :         TaskScheduler::CancelReturnCode rc =
     161         127 :             TaskScheduler::GetInstance()->Cancel(timer_task_);
     162         127 :         assert(rc != TaskScheduler::FAILED);
     163         127 :         timer_task_ = NULL;
     164             :     }
     165             : 
     166     5447821 :     SetState(Cancelled);
     167     5447771 :     return true;
     168     5452296 : }
     169             : 
     170             : // ASIO callback on timer expiry. Start a task to serve the timer
     171     4506732 : void Timer::StartTimerTask(TimerPtr reference, int time, uint32_t seq_no,
     172             :                            const boost::system::error_code &ec) {
     173     4506732 :     std::scoped_lock lock(mutex_);
     174             : 
     175     4506733 :     if (state_ == Cancelled) {
     176       24594 :         return;
     177             :     }
     178             : 
     179             :     // If timer was cancelled, no callback is invoked
     180     4482139 :     if (ec && ec.value() == boost::asio::error::operation_aborted) {
     181     4423177 :         return;
     182             :     }
     183             : 
     184             :     // Timer could have fired for previous run. Validate the seq_no_
     185       58962 :     if (seq_no_ != seq_no) {
     186           0 :         return;
     187             :     }
     188             :     // Start a task and add Task reference.
     189       58962 :     assert(timer_task_ == NULL);
     190       58962 :     timer_task_ = new TimerTask(reference, ec);
     191       58962 :     TaskScheduler::GetInstance()->Enqueue(timer_task_);
     192     4506733 : }
     193             : 
     194             : //
     195             : // TimerManager class routines
     196             : //
     197             : TimerManager::TimerSet TimerManager::timer_ref_;
     198             : std::mutex TimerManager::mutex_;
     199             : 
     200      378814 : 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      378814 :                              delete_on_completion);
     205      378814 :     AddTimer(timer);
     206      378814 :     return timer;
     207             : }
     208             : 
     209      378814 : void TimerManager::AddTimer(Timer *timer) {
     210      378814 :     std::scoped_lock lock(mutex_);
     211      378814 :     timer_ref_.insert(TimerPtr(timer));
     212             : 
     213      757628 :     return;
     214      378814 : }
     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      373208 : bool TimerManager::DeleteTimer(Timer *timer) {
     222      373208 :     if (!timer || timer->fired()) return false;
     223             : 
     224      361445 :     if (!timer->Cancel() && timer->IsDeleteOnCompletion())
     225           0 :         return false;
     226             : 
     227      361445 :     std::scoped_lock lock(mutex_);
     228      361445 :     timer_ref_.erase(TimerPtr(timer));
     229             : 
     230      361445 :     return true;
     231      361445 : }
     232             : 
     233             : // Get timer's already elapsed time in milliseconds.
     234         727 : int64_t Timer::GetElapsedTime() const {
     235         727 :     std::scoped_lock lock(mutex_);
     236             :     int64_t elapsed;
     237             : 
     238             : #if __cplusplus >= 201103L
     239         727 :     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         727 :     elapsed = time_ - elapsed / 1000000; // Convert nanoseconds to milliseconds.
     245         727 :     if (elapsed < 0)
     246           0 :         elapsed = 0;
     247         727 :     return elapsed;
     248         727 : }

Generated by: LCOV version 1.14