LCOV - code coverage report
Current view: top level - root/contrail/src/contrail-common/base - timer.h (source / functions) Hit Total Coverage
Test: OpenSDN C/C++ coverage (all TARGET_SET jobs) Lines: 38 46 82.6 %
Date: 2026-08-03 02:19:58 Functions: 11 14 78.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
       3             :  */
       4             : 
       5             : //  Timer implementation using ASIO and Task infrastructure.
       6             : //  Registers an ASIO timer. On ASIO timer expiry, a task will be created to
       7             : //  run the timer. Supports user specified task-id.
       8             : //
       9             : //  Operations supported
      10             : //  - Create a timer by allocating an object of type Timer
      11             : //  - Start a timer
      12             : //    If a timer is already running, it is a no op. In order to auto-restart
      13             : //    a timer, return 'tru'e from timer callback, false otherwise
      14             : //
      15             : //    There can be atmost one "Task" outstanding for the timer.
      16             : //
      17             : //  - Cancel a timer
      18             : //    Cancels a running timer. Both ASIO registerations and task spawned will
      19             : //    be cancelled.
      20             : //
      21             : //    If timer is already fired, "Cancel" api will fail and return 'false'
      22             : //
      23             : //  - Delete a timer
      24             : //    Cancels the timer and triggers deletion of the timer. Application should
      25             : //    not access the timer after its deleted
      26             : //
      27             : //  Concurrency aspects:
      28             : //  - Timer is allocated by application
      29             : //  - Applications must call TimerManager::DeleteTimer() to delete the timer
      30             : //  - All operations on timer are protected by mutex
      31             : //  - When timer is running, it can have references from ASIO and Task.
      32             : //    Timer class will keep of reference from ASIO and Task. Timer will
      33             : //    be deleted when both the references go away. (via intrusive pointer)
      34             : //
      35             : 
      36             : #ifndef TIMER_H_
      37             : #define TIMER_H_
      38             : 
      39             : #include <atomic>
      40             : #include <mutex>
      41             : #include <set>
      42             : 
      43             : #include <boost/asio/placeholders.hpp>
      44             : #include <boost/bind/bind.hpp>
      45             : #include <boost/intrusive_ptr.hpp>
      46             : #include <boost/scoped_ptr.hpp>
      47             : #include <boost/function.hpp>
      48             : #include <boost/asio.hpp>
      49             : #include <boost/system/error_code.hpp>
      50             : 
      51             : #include <base/task.h>
      52             : 
      53             : using namespace boost::placeholders;
      54             : 
      55             : class TimerImpl;
      56             : 
      57             : class Timer {
      58             : private:
      59             :     // Task used to fire the timer
      60             :     class TimerTask;
      61             : 
      62             : public:
      63             :     typedef boost::function<bool(void)> Handler;
      64             :     typedef boost::function<void(std::string, std::string, std::string)>
      65             :         ErrorHandler;
      66             : 
      67             :     Timer(boost::asio::io_context &service, const std::string &name,
      68             :           int task_id, int task_instance, bool delete_on_completion = false);
      69             :     virtual ~Timer();
      70             : 
      71             :     // Start a timer
      72             :     // If timer already started, try cancelling and restart
      73             :     //
      74             :     // Timer callback routine handler should return true to start the timer
      75             :     // again, false otherwise
      76             :     //
      77             :     // XXX Timer cannot be Start()ed from timer callback routine itself.
      78             :     // Return true from the callback in order to post the timer again. This
      79             :     // would use the same time, the timer was initially started with
      80             :     //
      81             :     bool Start(int time, Handler handler, ErrorHandler error_handler = NULL);
      82             : 
      83             :     //Can be called only from callback
      84             :     bool Reschedule(int time);
      85             : 
      86             :     // Cancel a running timer
      87             :     bool Cancel();
      88             : 
      89       93535 :     bool running() const {
      90       93535 :         std::scoped_lock lock(mutex_);
      91       93539 :         return (state_ == Running);
      92       93539 :     }
      93             : 
      94      336465 :     bool fired() const {
      95      336465 :         std::scoped_lock lock(mutex_);
      96      336465 :         return (state_ == Fired);
      97      336465 :     }
      98             : 
      99          16 :     int time() const {
     100          16 :         return time_;
     101             :     }
     102             : 
     103       22887 :     bool cancelled() const {
     104       22887 :         std::scoped_lock lock(mutex_);
     105       22895 :         return (state_ == Cancelled);
     106       22892 :     }
     107             : 
     108           0 :     bool Idle() const {
     109           0 :         std::scoped_lock lock(mutex_);
     110           0 :         return (state_ == Cancelled || state_ == Init);
     111           0 :     }
     112             : 
     113           0 :     bool IsDeleteOnCompletion() const {
     114           0 :         return delete_on_completion_;
     115             :     }
     116             : 
     117             :     int64_t GetElapsedTime() const;
     118             : 
     119             :     // Only for state machine test
     120             :     // XXX: Don't use in production code
     121         516 :     void Fire() {
     122         516 :         std::scoped_lock lock(mutex_);
     123         516 :         if (handler_ && !handler_.empty()) {
     124         508 :             SetState(Fired);
     125         508 :             handler_();
     126         508 :             SetState(Init);
     127             :         }
     128         516 :     }
     129             : 
     130           0 :     virtual std::string Description() {
     131           0 :         return name_;
     132             :     }
     133             : private:
     134             :     friend class TimerManager;
     135             :     friend class TimerTest;
     136             : 
     137             :     friend void intrusive_ptr_add_ref(Timer *timer);
     138             :     friend void intrusive_ptr_release(Timer *timer);
     139             :     typedef boost::intrusive_ptr<Timer> TimerPtr;
     140             : 
     141             :     enum TimerState {
     142             :         Init            = 0,
     143             :         Running         = 1,
     144             :         Fired           = 2,
     145             :         Cancelled       = 3,
     146             :     };
     147             : 
     148             :     // ASIO callback on timer expiry. Start a task to serve the timer
     149             :     void StartTimerTask(TimerPtr reference,
     150             :                         int time, uint32_t seq_no,
     151             :                         const boost::system::error_code &ec);
     152             : 
     153    10123193 :     void SetState(TimerState s) { state_ = s; }
     154       24816 :     static int GetTimerInstanceId() { return -1; }
     155       24816 :     static int GetTimerTaskId() {
     156             :         static int timer_task_id = -1;
     157             : 
     158       24816 :         if (timer_task_id == -1) {
     159          79 :             TaskScheduler *scheduler = TaskScheduler::GetInstance();
     160          79 :             timer_task_id = scheduler->GetTaskId("timer::TimerTask");
     161             :         }
     162       24816 :         return timer_task_id;
     163             :     }
     164             : 
     165             :     boost::scoped_ptr<TimerImpl> impl_;
     166             :     std::string name_;
     167             :     Handler handler_;
     168             :     ErrorHandler error_handler_;
     169             :     mutable std::mutex mutex_;
     170             :     TimerState state_;
     171             :     TimerTask *timer_task_;
     172             :     int time_;
     173             :     int task_id_;
     174             :     int task_instance_;
     175             :     uint32_t seq_no_;
     176             :     bool delete_on_completion_;
     177             :     std::atomic<int> refcount_;
     178             : };
     179             : 
     180    51974511 : inline void intrusive_ptr_add_ref(Timer *timer) {
     181    51974511 :     timer->refcount_++;
     182    51986432 : }
     183             : 
     184    51980769 : inline void intrusive_ptr_release(Timer *timer) {
     185    51980769 :     int prev = timer->refcount_.fetch_sub(1);
     186    51980769 :     if (prev == 1) {
     187      376965 :         delete timer;
     188             :     }
     189    51980768 : }
     190             : 
     191             : //
     192             : // TimerManager is the place holder for all the Timer objects
     193             : // instantiated in the life time of a process
     194             : //
     195             : // Timer objects are help in TimerSet until all the cleanup is complete
     196             : // and only then should they be deleted via DeleteTimer() API
     197             : //
     198             : // Since Timer objects are also held by boost::asio routines, they are
     199             : // protected using intrusive pointers
     200             : //
     201             : // This is similar to how TcpSession objects are managed via TcpSessionPtr
     202             : //
     203             : class TimerManager {
     204             : public:
     205             :     static Timer *CreateTimer(boost::asio::io_context &service,
     206             :                               const std::string &name,
     207             :                               int task_id = Timer::GetTimerTaskId(),
     208             :                               int task_instance = Timer::GetTimerInstanceId(),
     209             :                               bool delete_on_completion = false);
     210             :     static bool DeleteTimer(Timer *Timer);
     211             : 
     212             : private:
     213             :     friend class TimerTest;
     214             : 
     215             :     typedef boost::intrusive_ptr<Timer> TimerPtr;
     216             :     struct TimerPtrCmp {
     217     7205566 :         bool operator()(const TimerPtr &lhs,
     218             :                         const TimerPtr &rhs) const {
     219     7205566 :             return lhs.get() < rhs.get();
     220             :         }
     221             :     };
     222             :     typedef std::set<TimerPtr, TimerPtrCmp> TimerSet;
     223             :     static void AddTimer(Timer *Timer);
     224             : 
     225             :     static std::mutex mutex_;
     226             :     static TimerSet timer_ref_;
     227             : };
     228             : 
     229             : #endif /* TIMER_H_ */

Generated by: LCOV version 1.14