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

Generated by: LCOV version 1.14