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-11-09 02:10:49 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             :  * Copyright Contributors to the OpenSDN project
       4             :  */
       5             : 
       6             : #include "base/timer.h"
       7             : #include "base/timer_impl.h"
       8             : 
       9             : class Timer::TimerTask : public Task {
      10             : public:
      11       59081 :     TimerTask(TimerPtr timer, boost::system::error_code ec)
      12       59081 :         : Task(timer->task_id_, timer->task_instance_), timer_(timer), ec_(ec) {
      13       59081 :     }
      14             : 
      15      118162 :     virtual ~TimerTask() {
      16      118162 :     }
      17             : 
      18             :     // Invokes user callback.
      19             :     // Timer could have been cancelled or delete when task was enqueued
      20       58921 :     virtual bool Run() {
      21             :         {
      22       58921 :             std::unique_lock<std::mutex> lock(timer_->mutex_);
      23             : 
      24             :             // cancelled task .. ignore
      25       58926 :             if (task_cancelled()) {
      26             :                 // Cancelled timer's task releases the ownership of the timer
      27           2 :                 lock.unlock();
      28           2 :                 timer_ = NULL;
      29           2 :                 return true;
      30             :             }
      31             : 
      32             :             // Conditions to invoke user callback met. Fire it
      33       58900 :             timer_->SetState(Timer::Fired);
      34       58904 :         }
      35             : 
      36       58924 :         bool restart = false;
      37             : 
      38             :         // TODO: Is this error needed by user?
      39       58924 :         if (ec_ && !timer_->error_handler_.empty()) {
      40           0 :             timer_->error_handler_(timer_->name_,
      41           0 :                                    std::string(ec_.category().name()),
      42           0 :                                    ec_.message());
      43             :         } else {
      44       58910 :             restart = timer_->handler_();
      45             :         }
      46             : 
      47       58928 :         OnTaskCancel();
      48             : 
      49       58922 :         if (restart) {
      50       67161 :             timer_->Start(timer_->time_, timer_->handler_,
      51       33597 :                           timer_->error_handler_);
      52       25315 :         } else if (timer_->delete_on_completion_) {
      53         165 :             TimerManager::DeleteTimer(timer_.get());
      54             :         }
      55       58957 :         return true;
      56             :     }
      57             : 
      58             :     // Task Cancelled/Destroyed when it was Fired.
      59       58915 :     void OnTaskCancel() {
      60       58915 :         if (!timer_) {
      61           2 :             return;
      62             :         }
      63       58907 :         std::scoped_lock lock(timer_->mutex_);
      64             : 
      65       58896 :         if (timer_->timer_task_ != this) {
      66           0 :             assert(!timer_->timer_task_);
      67             :         }
      68             : 
      69       58874 :         timer_->timer_task_ = NULL;
      70       58859 :         timer_->SetState(Timer::Init);
      71       58840 :     }
      72             : 
      73           0 :     virtual std::string Description() const {
      74           0 :         return timer_->Description();
      75             :     }
      76             : 
      77             : private:
      78             :     TimerPtr timer_;
      79             :     boost::system::error_code ec_;
      80             :     DISALLOW_COPY_AND_ASSIGN(TimerTask);
      81             : };
      82             : 
      83      379719 : Timer::Timer(boost::asio::io_context &service, const std::string &name,
      84      379719 :           int task_id, int task_instance, bool delete_on_completion)
      85      379719 :         : impl_(new TimerImpl(service)),
      86      379717 :           name_(name),
      87      379715 :           handler_(NULL),
      88      379715 :           error_handler_(NULL),
      89      379715 :           state_(Init),
      90      379715 :           timer_task_(NULL),
      91      379715 :           time_(0),
      92      379715 :           task_id_(task_id),
      93      379715 :           task_instance_(task_instance),
      94      379715 :           seq_no_(0),
      95      759434 :           delete_on_completion_(delete_on_completion) {
      96      379715 :     refcount_ = 0;
      97      379718 : }
      98             : 
      99      756596 : Timer::~Timer() {
     100      378298 :     assert(state_ != Running && state_ != Fired);
     101      756596 : }
     102             : 
     103             : //
     104             : // Start a timer
     105             : //
     106             : // If the timer is already running, return silently
     107             : //
     108     4683050 : bool Timer::Start(int time, Handler handler, ErrorHandler error_handler) {
     109     4683050 :     std::scoped_lock lock(mutex_);
     110             : 
     111     4683268 :     if (time < 0) {
     112         138 :         return true;
     113             :     }
     114             : 
     115     4683130 :     if (state_ == Running || state_ == Fired) {
     116      174725 :         return true;
     117             :     }
     118             : 
     119             :     // Restart the timer
     120     4508405 :     time_ = time;
     121     4508405 :     handler_ = handler;
     122     4507768 :     seq_no_++;
     123     4507768 :     error_handler_ = error_handler;
     124     4507556 :     boost::system::error_code ec;
     125     4507556 :     impl_->expires_from_now(time, ec);
     126     4508397 :     if (ec) {
     127           0 :         return false;
     128             :     }
     129             : 
     130     4508374 :     SetState(Running);
     131     9016729 :     impl_->async_wait(
     132     9016799 :         boost::bind(&Timer::StartTimerTask, this, TimerPtr(this),
     133             :                     time, seq_no_, boost::asio::placeholders::error));
     134     4508494 :     return true;
     135     4683357 : }
     136             : 
     137       10702 : bool Timer::Reschedule(int time)
     138             : {
     139       10702 :     if (state_ != Fired)
     140         183 :         return false;
     141             : 
     142       10519 :     if (time < 0)
     143           0 :         return false;
     144             : 
     145       10519 :     time_ = time;
     146       10519 :     return true;
     147             : }
     148             : 
     149             : // Cancel a running timer
     150     5371422 : bool Timer::Cancel() {
     151     5371422 :     std::scoped_lock lock(mutex_);
     152             : 
     153             :     // A fired timer cannot be cancelled
     154     5371432 :     if (state_ == Fired) {
     155        4815 :         return false;
     156             :     }
     157             : 
     158             :     // Cancel Task. If Task cancel succeeds, there will be no callback.
     159             :     // Reset TaskRef if call succeeds.
     160     5366617 :     if (timer_task_) {
     161             :         TaskScheduler::CancelReturnCode rc =
     162         122 :             TaskScheduler::GetInstance()->Cancel(timer_task_);
     163         122 :         assert(rc != TaskScheduler::FAILED);
     164         122 :         timer_task_ = NULL;
     165             :     }
     166             : 
     167     5366617 :     SetState(Cancelled);
     168     5366566 :     return true;
     169     5371381 : }
     170             : 
     171             : // ASIO callback on timer expiry. Start a task to serve the timer
     172     4429100 : void Timer::StartTimerTask(TimerPtr reference, int time, uint32_t seq_no,
     173             :                            const boost::system::error_code &ec) {
     174     4429100 :     std::scoped_lock lock(mutex_);
     175             : 
     176     4429100 :     if (state_ == Cancelled) {
     177       25791 :         return;
     178             :     }
     179             : 
     180             :     // If timer was cancelled, no callback is invoked
     181     4403309 :     if (ec && ec.value() == boost::asio::error::operation_aborted) {
     182     4344228 :         return;
     183             :     }
     184             : 
     185             :     // Timer could have fired for previous run. Validate the seq_no_
     186       59081 :     if (seq_no_ != seq_no) {
     187           0 :         return;
     188             :     }
     189             :     // Start a task and add Task reference.
     190       59081 :     assert(timer_task_ == NULL);
     191       59081 :     timer_task_ = new TimerTask(reference, ec);
     192       59081 :     TaskScheduler::GetInstance()->Enqueue(timer_task_);
     193     4429100 : }
     194             : 
     195             : //
     196             : // TimerManager class routines
     197             : //
     198             : TimerManager::TimerSet TimerManager::timer_ref_;
     199             : std::mutex TimerManager::mutex_;
     200             : 
     201      379718 : Timer *TimerManager::CreateTimer(
     202             :             boost::asio::io_context &service, const std::string &name,
     203             :             int task_id, int task_instance, bool delete_on_completion) {
     204             :     Timer *timer = new Timer(service, name, task_id, task_instance,
     205      379718 :                              delete_on_completion);
     206      379717 :     AddTimer(timer);
     207      379719 :     return timer;
     208             : }
     209             : 
     210      379717 : void TimerManager::AddTimer(Timer *timer) {
     211      379717 :     std::scoped_lock lock(mutex_);
     212      379719 :     timer_ref_.insert(TimerPtr(timer));
     213             : 
     214      759438 :     return;
     215      379719 : }
     216             : 
     217             : //
     218             : // Delete a timer object from the data base, by removing the intrusive
     219             : // reference. If any other objects has a reference to this timer such as
     220             : // boost::asio, the timer object deletion is automatically deferred
     221             : //
     222      374118 : bool TimerManager::DeleteTimer(Timer *timer) {
     223      374118 :     if (!timer || timer->fired()) return false;
     224             : 
     225      362350 :     if (!timer->Cancel() && timer->IsDeleteOnCompletion())
     226           0 :         return false;
     227             : 
     228      362350 :     std::scoped_lock lock(mutex_);
     229      362350 :     timer_ref_.erase(TimerPtr(timer));
     230             : 
     231      362350 :     return true;
     232      362350 : }
     233             : 
     234             : // Get timer's already elapsed time in milliseconds.
     235         729 : int64_t Timer::GetElapsedTime() const {
     236         729 :     std::scoped_lock lock(mutex_);
     237             :     int64_t elapsed;
     238             : 
     239             : #if __cplusplus >= 201103L
     240         729 :     elapsed = std::chrono::nanoseconds(impl_->expires_from_now()).count();
     241             : #else
     242             :     elapsed = boost::chrono::nanoseconds(impl_->expires_from_now()).count();
     243             : #endif
     244             : 
     245         729 :     elapsed = time_ - elapsed / 1000000; // Convert nanoseconds to milliseconds.
     246         729 :     if (elapsed < 0)
     247           0 :         elapsed = 0;
     248         729 :     return elapsed;
     249         729 : }

Generated by: LCOV version 1.14