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: 118 129 91.5 %
Date: 2026-09-07 02:14:47 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       60749 :     TimerTask(TimerPtr timer, boost::system::error_code ec)
      11       60749 :         : Task(timer->task_id_, timer->task_instance_), timer_(timer), ec_(ec) {
      12       60749 :     }
      13             : 
      14      121498 :     virtual ~TimerTask() {
      15      121498 :     }
      16             : 
      17             :     // Invokes user callback.
      18             :     // Timer could have been cancelled or delete when task was enqueued
      19       60514 :     virtual bool Run() {
      20             :         {
      21       60514 :             std::unique_lock<std::mutex> lock(timer_->mutex_);
      22             : 
      23             :             // cancelled task .. ignore
      24       60547 :             if (task_cancelled()) {
      25             :                 // Cancelled timer's task releases the ownership of the timer
      26           2 :                 lock.unlock();
      27           2 :                 timer_ = NULL;
      28           2 :                 return true;
      29             :             }
      30             : 
      31             :             // Conditions to invoke user callback met. Fire it
      32       60471 :             timer_->SetState(Timer::Fired);
      33       60501 :         }
      34             : 
      35       60550 :         bool restart = false;
      36             : 
      37             :         // TODO: Is this error needed by user?
      38       60550 :         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       60546 :             restart = timer_->handler_();
      44             :         }
      45             : 
      46       60577 :         OnTaskCancel();
      47             : 
      48       60498 :         if (restart) {
      49       69578 :             timer_->Start(timer_->time_, timer_->handler_,
      50       34841 :                           timer_->error_handler_);
      51       25629 :         } else if (timer_->delete_on_completion_) {
      52         164 :             TimerManager::DeleteTimer(timer_.get());
      53             :         }
      54       60619 :         return true;
      55             :     }
      56             : 
      57             :     // Task Cancelled/Destroyed when it was Fired.
      58       60568 :     void OnTaskCancel() {
      59       60568 :         if (!timer_) {
      60           2 :             return;
      61             :         }
      62       60532 :         std::scoped_lock lock(timer_->mutex_);
      63             : 
      64       60449 :         if (timer_->timer_task_ != this) {
      65           0 :             assert(!timer_->timer_task_);
      66             :         }
      67             : 
      68       60382 :         timer_->timer_task_ = NULL;
      69       60342 :         timer_->SetState(Timer::Init);
      70       60302 :     }
      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      378990 : Timer::Timer(boost::asio::io_context &service, const std::string &name,
      83      378990 :           int task_id, int task_instance, bool delete_on_completion)
      84      378990 :         : impl_(new TimerImpl(service)),
      85      378986 :           name_(name),
      86      378989 :           handler_(NULL),
      87      378989 :           error_handler_(NULL),
      88      378989 :           state_(Init),
      89      378989 :           timer_task_(NULL),
      90      378989 :           time_(0),
      91      378989 :           task_id_(task_id),
      92      378989 :           task_instance_(task_instance),
      93      378989 :           seq_no_(0),
      94      757979 :           delete_on_completion_(delete_on_completion) {
      95      378989 :     refcount_ = 0;
      96      378990 : }
      97             : 
      98      755128 : Timer::~Timer() {
      99      377564 :     assert(state_ != Running && state_ != Fired);
     100      755128 : }
     101             : 
     102             : //
     103             : // Start a timer
     104             : //
     105             : // If the timer is already running, return silently
     106             : //
     107     4727942 : bool Timer::Start(int time, Handler handler, ErrorHandler error_handler) {
     108     4727942 :     std::scoped_lock lock(mutex_);
     109             : 
     110     4728104 :     if (time < 0) {
     111         136 :         return true;
     112             :     }
     113             : 
     114     4727968 :     if (state_ == Running || state_ == Fired) {
     115      172510 :         return true;
     116             :     }
     117             : 
     118             :     // Restart the timer
     119     4555458 :     time_ = time;
     120     4555458 :     handler_ = handler;
     121     4554453 :     seq_no_++;
     122     4554453 :     error_handler_ = error_handler;
     123     4554222 :     boost::system::error_code ec;
     124     4554222 :     impl_->expires_from_now(time, ec);
     125     4555479 :     if (ec) {
     126           0 :         return false;
     127             :     }
     128             : 
     129     4555456 :     SetState(Running);
     130     9110923 :     impl_->async_wait(
     131     9111099 :         boost::bind(&Timer::StartTimerTask, this, TimerPtr(this),
     132             :                     time, seq_no_, boost::asio::placeholders::error));
     133     4555735 :     return true;
     134     4728381 : }
     135             : 
     136       11824 : bool Timer::Reschedule(int time)
     137             : {
     138       11824 :     if (state_ != Fired)
     139         183 :         return false;
     140             : 
     141       11641 :     if (time < 0)
     142           0 :         return false;
     143             : 
     144       11641 :     time_ = time;
     145       11641 :     return true;
     146             : }
     147             : 
     148             : // Cancel a running timer
     149     5420479 : bool Timer::Cancel() {
     150     5420479 :     std::scoped_lock lock(mutex_);
     151             : 
     152             :     // A fired timer cannot be cancelled
     153     5420458 :     if (state_ == Fired) {
     154        4843 :         return false;
     155             :     }
     156             : 
     157             :     // Cancel Task. If Task cancel succeeds, there will be no callback.
     158             :     // Reset TaskRef if call succeeds.
     159     5415615 :     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     5415615 :     SetState(Cancelled);
     167     5415531 :     return true;
     168     5420374 : }
     169             : 
     170             : // ASIO callback on timer expiry. Start a task to serve the timer
     171     4476978 : void Timer::StartTimerTask(TimerPtr reference, int time, uint32_t seq_no,
     172             :                            const boost::system::error_code &ec) {
     173     4476978 :     std::scoped_lock lock(mutex_);
     174             : 
     175     4476980 :     if (state_ == Cancelled) {
     176       26190 :         return;
     177             :     }
     178             : 
     179             :     // If timer was cancelled, no callback is invoked
     180     4450790 :     if (ec && ec.value() == boost::asio::error::operation_aborted) {
     181     4390041 :         return;
     182             :     }
     183             : 
     184             :     // Timer could have fired for previous run. Validate the seq_no_
     185       60749 :     if (seq_no_ != seq_no) {
     186           0 :         return;
     187             :     }
     188             :     // Start a task and add Task reference.
     189       60749 :     assert(timer_task_ == NULL);
     190       60749 :     timer_task_ = new TimerTask(reference, ec);
     191       60749 :     TaskScheduler::GetInstance()->Enqueue(timer_task_);
     192     4476980 : }
     193             : 
     194             : //
     195             : // TimerManager class routines
     196             : //
     197             : TimerManager::TimerSet TimerManager::timer_ref_;
     198             : std::mutex TimerManager::mutex_;
     199             : 
     200      378988 : 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      378988 :                              delete_on_completion);
     205      378988 :     AddTimer(timer);
     206      378990 :     return timer;
     207             : }
     208             : 
     209      378989 : void TimerManager::AddTimer(Timer *timer) {
     210      378989 :     std::scoped_lock lock(mutex_);
     211      378990 :     timer_ref_.insert(TimerPtr(timer));
     212             : 
     213      757980 :     return;
     214      378990 : }
     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      373386 : bool TimerManager::DeleteTimer(Timer *timer) {
     222      373386 :     if (!timer || timer->fired()) return false;
     223             : 
     224      361621 :     if (!timer->Cancel() && timer->IsDeleteOnCompletion())
     225           0 :         return false;
     226             : 
     227      361621 :     std::scoped_lock lock(mutex_);
     228      361621 :     timer_ref_.erase(TimerPtr(timer));
     229             : 
     230      361621 :     return true;
     231      361621 : }
     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