LCOV - code coverage report
Current view: top level - artdaq/TransferPlugins/detail - Timeout.cc (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 0.0 % 192 0
Test Date: 2025-09-04 00:45:34 Functions: 0.0 % 30 0

            Line data    Source code
       1              : //  This file (Timer.cxx) was created by Ron Rechenmacher <ron@fnal.gov> on
       2              : //  Sep 28, 2009. "TERMS AND CONDITIONS" governing this file are in the README
       3              : //  or COPYING file. If you do not have such a file, one can be obtained by
       4              : //  contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000.
       5              : //  $RCSfile: Timeout.cxx,v $
       6              : //  rev="$Revision: 1.13 $$Date: 2016/10/12 21:00:13 $";
       7              : /*
       8              :     g++ -Wall -g -std=c++0x -c Timeout.cxx
       9              : OR
      10              :     g++ -Wall -g -std=c++0x -shared -fPIC -o Timeout.so Timeout.cxx -lrt
      11              : */
      12              : 
      13              : #define TRACE_NAME "Timeout"
      14              : #include "TRACE/tracemf.h"
      15              : 
      16              : #include "artdaq/TransferPlugins/detail/Timeout.hh"
      17              : 
      18              : #include "artdaq-core/Utilities/TimeUtils.hh"
      19              : 
      20              : #include <sys/time.h> /* struct timeval */
      21              : #include <cassert>    /* assert */
      22              : #include <cstdio>     // printf
      23              : #include <cstdlib>    // exit
      24              : #include <cstring>    /* strcmp */
      25              : #include <list>
      26              : using std::list;
      27              : 
      28              : // public:
      29              : 
      30              : #if 0
      31              : Timeout::timeoutspec::timeoutspec()
      32              :         : desc(), tag(), function()
      33              :         , ts(), period()
      34              :         , missed_periods(), check()
      35              : {
      36              :         TLOG(TLVL_DEBUG + 38) << "Timeout::timeoutspec ctor this=" << this;
      37              : }
      38              : Timeout::timeoutspec::timeoutspec(const timeoutspec & other)
      39              :         : desc(other.desc), tag(other.tag), function(other.function)
      40              :         , ts(other.ts), period(other.period)
      41              :         , missed_periods(other.missed_periods), check(other.check)
      42              : {
      43              :         TLOG(TLVL_DEBUG + 38) << "Timeout::timeoutspec copy ctor";
      44              : }
      45              : Timeout::timeoutspec & Timeout::timeoutspec::operator=(const Timeout::timeoutspec & other)
      46              : {
      47              :         TLOG(TLVL_DEBUG + 38) << "Timeout::timeoutspec copy assignment (operator= other.desc=" << other.desc << ")";
      48              :         desc = other.desc;
      49              :         tag = other.tag;
      50              :         function = other.function;
      51              :         ts = other.ts;
      52              :         period = other.period;
      53              :         missed_periods = other.missed_periods;
      54              :         check = other.check;
      55              :         return *this;
      56              : }
      57              : #endif
      58              : 
      59            0 : Timeout::Timeout(int max_tmos)
      60            0 :     : tmospecs_(max_tmos)
      61              : {
      62            0 :         TLOG(TLVL_DEBUG + 36) << "Timeout ctor";
      63            0 :         timeoutlist_init();
      64            0 : }
      65              : 
      66            0 : void Timeout::add_periodic(const char* desc, void* tag, std::function<void()>& function, uint64_t period_us, uint64_t start_us)
      67              : {
      68            0 :         timeoutspec tmo;
      69            0 :         tmo.desc = desc;
      70            0 :         tmo.tag = tag;
      71            0 :         tmo.function = function;
      72            0 :         tmo.tmo_tod_us = start_us != 0u ? start_us : artdaq::TimeUtils::gettimeofday_us() + period_us;
      73            0 :         tmo.period_us = period_us;
      74            0 :         tmo.check = tmo.missed_periods = 0;
      75            0 :         copy_in_timeout(tmo);
      76            0 : }  // add_periodic
      77              : 
      78            0 : void Timeout::add_periodic(const char* desc, void* tag, std::function<void()>& function, int rel_ms)
      79              : {
      80            0 :         timeoutspec tmo;
      81            0 :         tmo.desc = desc;
      82            0 :         tmo.tag = tag;
      83            0 :         tmo.function = function;
      84            0 :         tmo.period_us = rel_ms * 1000;
      85            0 :         tmo.tmo_tod_us = artdaq::TimeUtils::gettimeofday_us() + tmo.period_us;
      86            0 :         tmo.check = tmo.missed_periods = 0;
      87            0 :         copy_in_timeout(tmo);
      88            0 : }  // add_periodic
      89              : 
      90            0 : void Timeout::add_periodic(const char* desc, uint64_t period_us, uint64_t start_us)
      91              : {
      92            0 :         TLOG(TLVL_DEBUG + 39) << "add_periodic - desc=" << desc << " period_us=" << period_us << " start_us=" << start_us;
      93            0 :         timeoutspec tmo;
      94            0 :         tmo.desc = desc;
      95            0 :         tmo.tag = nullptr;
      96            0 :         tmo.function = nullptr;
      97            0 :         tmo.tmo_tod_us = start_us;
      98            0 :         tmo.period_us = period_us;
      99            0 :         tmo.missed_periods = tmo.check = 0;
     100            0 :         copy_in_timeout(tmo);
     101            0 : }  // add_periodic
     102              : 
     103            0 : void Timeout::add_relative(const char* desc, void* tag, std::function<void()>& function, int rel_ms)
     104              : {
     105            0 :         timeoutspec tmo;
     106            0 :         tmo.desc = desc;
     107            0 :         tmo.tag = tag;
     108            0 :         tmo.function = function;
     109            0 :         tmo.tmo_tod_us = artdaq::TimeUtils::gettimeofday_us() + rel_ms * 1000;
     110            0 :         tmo.period_us = 0;
     111            0 :         tmo.missed_periods = tmo.check = 0;
     112            0 :         copy_in_timeout(tmo);
     113            0 : }  // add_periodic
     114              : 
     115            0 : void Timeout::add_relative(const std::string& desc, int rel_ms)
     116              : {
     117            0 :         timeoutspec tmo;
     118            0 :         tmo.desc = desc;
     119            0 :         tmo.tag = nullptr;
     120            0 :         tmo.function = nullptr;
     121            0 :         tmo.period_us = 0;
     122            0 :         tmo.tmo_tod_us = artdaq::TimeUtils::gettimeofday_us() + rel_ms * 1000;
     123            0 :         tmo.missed_periods = tmo.check = 0;
     124            0 :         copy_in_timeout(tmo);
     125            0 : }  // add_periodic
     126              : 
     127              : int  // tmo_tod_us is an output
     128            0 : Timeout::get_next_expired_timeout(std::string& desc, void** tag, std::function<void()>& function, uint64_t* tmo_tod_us)
     129              : {
     130            0 :         int skipped = 0;
     131            0 :         timeoutspec tmo;
     132            0 :         TLOG(TLVL_DEBUG + 38) << "get_next_expired_timeout b4 get_clear_next_expired_timeout";
     133            0 :         skipped = get_clear_next_expired_timeout(tmo, artdaq::TimeUtils::gettimeofday_us());
     134            0 :         if (skipped == -1)
     135              :         {
     136            0 :                 TLOG(TLVL_DEBUG + 38) << "get_next_expired_timeout - get_clear_next_expired_timeout returned false";
     137            0 :                 desc = std::string("");  // 2 ways to check for none timed out
     138              :         }
     139              :         else
     140              :         {
     141            0 :                 desc = tmo.desc;
     142            0 :                 *tag = tmo.tag;
     143            0 :                 function = tmo.function;
     144            0 :                 *tmo_tod_us = tmo.tmo_tod_us;
     145              :         }
     146            0 :         return (skipped);
     147            0 : }  // get_next_expired_timeout
     148              : 
     149            0 : void Timeout::get_next_timeout_delay(int64_t* delay_us)
     150              : {
     151            0 :         std::unique_lock<std::mutex> ulock(lock_mutex_);
     152            0 :         size_t active_time_size = active_time_.size();
     153            0 :         if (active_time_size == 0)
     154              :         {
     155            0 :                 TLOG(TLVL_DEBUG + 37) << "get_next_timeout_delay active_.size() == 0";
     156            0 :                 *delay_us = -1;  // usually means a very very long time
     157              :         }
     158              :         else
     159              :         {
     160            0 :                 TLOG(TLVL_DEBUG + 37) << "get_next_timeout_delay active_.size() != 0: " << active_time_size;
     161            0 :                 uint64_t tod_us = artdaq::TimeUtils::gettimeofday_us();
     162            0 :                 timeoutspec* tmo = &tmospecs_[(*(active_time_.begin())).second];
     163            0 :                 *delay_us = tmo->tmo_tod_us - tod_us;
     164            0 :                 if (*delay_us < 0)
     165              :                 {
     166            0 :                         *delay_us = 0;
     167              :                 }
     168              :         }
     169            0 : }  // get_next_timeout_delay
     170              : 
     171            0 : int Timeout::get_next_timeout_msdly()
     172              : {
     173              :         int64_t delay_us;
     174              :         int tmo;
     175            0 :         get_next_timeout_delay(&delay_us);
     176            0 :         if (delay_us == -1)
     177              :         {
     178            0 :                 tmo = -1;
     179              :         }
     180              :         else
     181              :         {  // NOTE THE + 1 b/c of integer division and/or system HZ resolution
     182            0 :                 tmo = delay_us / 1000;
     183              :         }
     184            0 :         return (tmo);
     185              : }  // get_next_timeout_msdly
     186              : 
     187            0 : bool Timeout::is_consistent()
     188              : {
     189            0 :         std::map<uint64_t, size_t>::iterator itactive;
     190            0 :         std::list<size_t>::iterator itfree;
     191            0 :         for (auto& tmospec : tmospecs_)
     192              :         {
     193            0 :                 tmospec.check = 1;
     194              :         }
     195            0 :         for (itactive = active_time_.begin(); itactive != active_time_.end(); ++itactive)
     196              :         {
     197            0 :                 tmospecs_[(*itactive).second].check--;
     198              :         }
     199            0 :         for (itfree = free_.begin(); itfree != free_.end(); ++itfree)
     200              :         {
     201            0 :                 tmospecs_[*itfree].check--;
     202              :         }
     203            0 :         for (auto& tmospec : tmospecs_)
     204              :         {
     205            0 :                 if (tmospec.check != 0)
     206              :                 {
     207            0 :                         return false;
     208              :                 }
     209              :         }
     210            0 :         return (true);
     211              : }
     212              : 
     213            0 : void Timeout::timeoutlist_init()
     214              : {
     215            0 :         size_t list_sz = tmospecs_.size();
     216            0 :         for (size_t ii = 0; ii < list_sz; ++ii)
     217              :         {  // bzero( &tmospecs_[list_sz], sizeof(tmospecs_[0]) );
     218            0 :                 free_.push_front(ii);
     219              :         }
     220            0 : }
     221              : 
     222            0 : int Timeout::get_clear_next_expired_timeout(timeoutspec& tmo, uint64_t tod_now_us)
     223              : {
     224            0 :         int skipped = 0;
     225            0 :         if (active_time_.empty())
     226              :         {
     227            0 :                 TLOG(TLVL_DEBUG + 37) << "get_clear_next_expired_timeout - nothing to get/clear!";
     228            0 :                 return static_cast<int>(false);
     229              :         }
     230              : 
     231            0 :         std::unique_lock<std::mutex> ulock(lock_mutex_);
     232            0 :         auto itfront = active_time_.begin();
     233            0 :         size_t idx = (*itfront).second;
     234            0 :         if (tmospecs_[idx].tmo_tod_us < tod_now_us)
     235              :         {
     236            0 :                 tmo = tmospecs_[idx];
     237            0 :                 TLOG(TLVL_DEBUG + 37) << "get_clear_next_expired_timeout - clearing tag=" << tmo.tag << " desc=" << tmo.desc << " period=" << tmo.period_us << " idx=" << idx;
     238              : 
     239            0 :                 active_time_.erase(itfront);
     240              :                 // now, be effecient -- if periodic, add back at new time, else
     241              :                 // find/erase active_desc_ with same idx and free
     242            0 :                 if (tmo.period_us != 0u)
     243              :                 {
     244              :                         // PERIODIC
     245              :                         int64_t delta_us;
     246            0 :                         uint64_t period_us = tmo.period_us;
     247            0 :                         delta_us = tod_now_us - tmo.tmo_tod_us;
     248            0 :                         skipped = delta_us / period_us;
     249            0 :                         assert(skipped >= 0);
     250            0 :                         tmo.missed_periods += skipped;
     251              : 
     252              :                         /* now fast forward over skipped */
     253            0 :                         period_us += period_us * skipped;
     254            0 :                         tmospecs_[idx].tmo_tod_us += period_us;
     255            0 :                         active_time_.insert(std::pair<uint64_t, size_t>(tmospecs_[idx].tmo_tod_us, idx));
     256            0 :                         TLOG(TLVL_DEBUG + 38) << "get_clear_next_expired_timeout - periodic timeout desc=" << tmo.desc
     257            0 :                                               << " period_us=" << period_us << " delta_us=" << delta_us
     258            0 :                                               << " skipped=" << skipped << " next tmo at:" << tmospecs_[idx].tmo_tod_us;
     259              :                 }
     260              :                 else
     261              :                 {
     262              :                         // find active_desc_ with same idx
     263            0 :                         std::unordered_multimap<std::string, size_t>::iterator i2;
     264            0 :                         i2 = active_desc_.equal_range(tmospecs_[idx].desc).first;
     265              :                         while (true)
     266              :                         {  // see also in cancel_timeout below
     267            0 :                                 if (i2->second == idx)
     268              :                                 {
     269            0 :                                         break;
     270              :                                 }
     271            0 :                                 ++i2;
     272              :                         }
     273            0 :                         active_desc_.erase(i2);
     274            0 :                         free_.push_front(idx);
     275              :                 }
     276              :         }
     277              :         else
     278              :         {
     279            0 :                 TLOG(TLVL_DEBUG + 37) << "get_clear_next_expired_timeout - front " << tmospecs_[idx].tmo_tod_us << " NOT before ts_now " << tod_now_us << " - not clearing!";
     280            0 :                 return (-1);
     281              :         }
     282              : 
     283            0 :         return 1;
     284            0 : }  // get_clear_next_expired_timeout
     285              : 
     286              : // this doesn't do anything (function undefined)
     287            0 : void Timeout::copy_in_timeout(const char* desc, uint64_t period_us, uint64_t start_us)
     288              : {
     289            0 :         TLOG(TLVL_DEBUG + 38) << "copy_in_timeout desc=" + std::string(desc);
     290            0 :         timeoutspec tos;
     291            0 :         tos.desc = desc;
     292            0 :         tos.tag = nullptr;
     293            0 :         tos.function = nullptr;
     294            0 :         tos.period_us = period_us;
     295            0 :         tos.tmo_tod_us = start_us;
     296            0 :         tos.missed_periods = tos.check = 0;
     297            0 :         copy_in_timeout(tos);
     298            0 : }
     299              : 
     300            0 : void Timeout::copy_in_timeout(timeoutspec& tmo)
     301              : {
     302              :         // check for at least one empty entry
     303            0 :         assert(free_.size());
     304              : 
     305              :         // get/fill-in free tmospec
     306            0 :         std::unique_lock<std::mutex> ulock(lock_mutex_);
     307            0 :         size_t idx = free_.front();
     308            0 :         free_.pop_front();
     309            0 :         tmospecs_[idx] = tmo;
     310            0 :         TLOG(TLVL_DEBUG + 40) << "copy_in_timeout timeoutspec desc=" + tmo.desc;
     311            0 :         active_time_.insert(std::pair<uint64_t, size_t>(tmo.tmo_tod_us, idx));
     312            0 :         active_desc_.insert(std::pair<std::string, size_t>(tmo.desc, idx));
     313            0 : }
     314              : 
     315            0 : bool Timeout::cancel_timeout(void* tag, const std::string& desc)
     316              : {
     317            0 :         bool retsts = false;
     318            0 :         std::unordered_multimap<std::string, size_t>::iterator ii, ee;
     319            0 :         std::unique_lock<std::mutex> ulock(lock_mutex_);
     320            0 :         auto pairOfIters = active_desc_.equal_range(desc);
     321            0 :         ii = pairOfIters.first;
     322            0 :         ee = pairOfIters.second;
     323            0 :         for (; ii != ee && ii->first == desc; ++ii)
     324              :         {
     325            0 :                 size_t idx = ii->second;
     326            0 :                 if (tmospecs_[idx].tag == tag)
     327              :                 {
     328              :                         // found a match
     329            0 :                         retsts = true;
     330            0 :                         uint64_t tmo_tod_us = tmospecs_[idx].tmo_tod_us;
     331              : 
     332              :                         // now make sure to find the active_time_ with the same idx
     333            0 :                         std::multimap<uint64_t, size_t>::iterator i2;
     334            0 :                         i2 = active_time_.equal_range(tmo_tod_us).first;
     335              :                         while (true)
     336              :                         {  // see also in get_clear_next_expired_timeout above
     337            0 :                                 if (i2->second == idx)
     338              :                                 {
     339            0 :                                         break;
     340              :                                 }
     341            0 :                                 ++i2;
     342              :                         }
     343              : 
     344            0 :                         active_desc_.erase(ii);
     345            0 :                         active_time_.erase(i2);
     346            0 :                         free_.push_front(idx);
     347            0 :                         break;
     348              :                 }
     349              :         }
     350            0 :         TLOG(TLVL_DEBUG + 42) << "cancel_timeout returning " << retsts;
     351            0 :         return retsts;
     352            0 : }  // cancel_timeout
     353              : 
     354            0 : void Timeout::list_active_time()
     355              : {
     356            0 :         auto ii = active_time_.begin(), ee = active_time_.end();
     357            0 :         for (; ii != ee; ++ii)
     358              :         {
     359            0 :                 TLOG(TLVL_DEBUG + 32) << "list_active_time " << (*ii).first << " desc=" << tmospecs_[(*ii).second].desc;
     360              :         }
     361            0 : }
        

Generated by: LCOV version 2.0-1