00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include <stdio.h>
00013 #include <sys/time.h>
00014 #include <assert.h>
00015 #include <string.h>
00016 #include <stdlib.h>
00017 #include <list>
00018 using std::list;
00019 #include "artdaq/TransferPlugins/detail/Timeout.hh"
00020 #include "artdaq/DAQdata/Globals.hh"
00021 #include "artdaq-core/Utilities/TimeUtils.hh"
00022
00023
00024
00025 #if 0
00026 Timeout::timeoutspec::timeoutspec()
00027 : desc(), tag(), function()
00028 , ts(), period()
00029 , missed_periods(), check()
00030 { TRACE( 18, "Timeout::timeoutspec ctor this=%p", this );
00031 }
00032 Timeout::timeoutspec::timeoutspec( const timeoutspec & other )
00033 : desc(other.desc), tag(other.tag), function(other.function)
00034 , ts(other.ts), period(other.period)
00035 , missed_periods(other.missed_periods), check(other.check)
00036 { TRACE( 18, "Timeout::timeoutspec copy ctor" );
00037 }
00038 Timeout::timeoutspec & Timeout::timeoutspec::operator=( const Timeout::timeoutspec & other )
00039 { TRACE( 18, "Timeout::timeoutspec copy assignment (operator=) other.desc="+other.desc );
00040 desc = other.desc;
00041 tag=other.tag;
00042 function=other.function;
00043 ts=other.ts;
00044 period=other.period;
00045 missed_periods=other.missed_periods;
00046 check=other.check;
00047 return *this;
00048 }
00049 #endif
00050
00051
00052 Timeout::Timeout(int max_tmos)
00053 : tmospecs_(max_tmos)
00054 {
00055 TRACE( 16, "Timeout ctor" );
00056 timeoutlist_init();
00057 }
00058
00059
00060 void
00061 Timeout::add_periodic(const char* desc, void* tag, std::function<void()>& function
00062 , uint64_t period_us
00063 , uint64_t start_us)
00064 {
00065 timeoutspec tmo;
00066 tmo.desc = desc;
00067 tmo.tag = tag;
00068 tmo.function = function;
00069 tmo.tmo_tod_us = start_us ? start_us : artdaq::TimeUtils::gettimeofday_us() + period_us;
00070 tmo.period_us = period_us;
00071 tmo.check = tmo.missed_periods = 0;
00072 copy_in_timeout(tmo);
00073 }
00074
00075 void
00076 Timeout::add_periodic(const char* desc, void* tag, std::function<void()>& function
00077 , int rel_ms)
00078 {
00079 timeoutspec tmo;
00080 tmo.desc = desc;
00081 tmo.tag = tag;
00082 tmo.function = function;
00083 tmo.period_us = rel_ms * 1000;
00084 tmo.tmo_tod_us = artdaq::TimeUtils::gettimeofday_us() + tmo.period_us;
00085 tmo.check = tmo.missed_periods = 0;
00086 copy_in_timeout(tmo);
00087 }
00088
00089 void
00090 Timeout::add_periodic(const char* desc
00091 , uint64_t period_us
00092 , uint64_t start_us)
00093 {
00094 TRACE( 19, "add_periodic - desc="+std::string(desc)+" period_us=%lu start_us=%lu"
00095 , period_us, start_us );
00096 timeoutspec tmo;
00097 tmo.desc = desc;
00098 tmo.tag = 0;
00099 tmo.function = 0;
00100 tmo.tmo_tod_us = start_us;
00101 tmo.period_us = period_us;
00102 tmo.missed_periods = tmo.check = 0;
00103 copy_in_timeout(tmo);
00104 }
00105
00106 void
00107 Timeout::add_relative(const char* desc, void* tag, std::function<void()>& function
00108 , int rel_ms)
00109 {
00110 timeoutspec tmo;
00111 tmo.desc = desc;
00112 tmo.tag = tag;
00113 tmo.function = function;
00114 tmo.tmo_tod_us = artdaq::TimeUtils::gettimeofday_us() + rel_ms * 1000;
00115 tmo.period_us = 0;
00116 tmo.missed_periods = tmo.check = 0;
00117 copy_in_timeout(tmo);
00118 }
00119
00120 void
00121 Timeout::add_relative(std::string desc
00122 , int rel_ms)
00123 {
00124 timeoutspec tmo;
00125 tmo.desc = desc.c_str();
00126 tmo.tag = 0;
00127 tmo.function = 0;
00128 tmo.period_us = 0;
00129 tmo.tmo_tod_us = artdaq::TimeUtils::gettimeofday_us() + rel_ms * 1000;
00130 tmo.missed_periods = tmo.check = 0;
00131 copy_in_timeout(tmo);
00132 }
00133
00134 int
00135 Timeout::get_next_expired_timeout(std::string& desc, void** tag, std::function<void()>& function
00136 , uint64_t* tmo_tod_us)
00137 {
00138 int skipped = 0;
00139 timeoutspec tmo;
00140 TRACE( 15, "get_next_expired_timeout b4 get_clear_next_expired_timeout" );
00141 skipped = get_clear_next_expired_timeout(tmo, artdaq::TimeUtils::gettimeofday_us());
00142 if (skipped == -1)
00143 {
00144 TRACE( 18, "get_next_expired_timeout - get_clear_next_expired_timeout returned false" );
00145 desc = std::string("");
00146 }
00147 else
00148 {
00149 desc = tmo.desc;
00150 *tag = tmo.tag;
00151 function = tmo.function;
00152 *tmo_tod_us = tmo.tmo_tod_us;
00153 }
00154 return (skipped);
00155 }
00156
00157 void
00158 Timeout::get_next_timeout_delay(int64_t* delay_us)
00159 {
00160 std::unique_lock<std::mutex> ulock(lock_mutex_);
00161 size_t active_time_size = active_time_.size();
00162 if (active_time_size == 0)
00163 {
00164 TRACE( 17, "get_next_timeout_delay active_.size() == 0" );
00165 *delay_us = -1;
00166 }
00167 else
00168 {
00169 TRACE( 17, "get_next_timeout_delay active_.size() != 0 %lu",active_time_size );
00170 uint64_t tod_us = artdaq::TimeUtils::gettimeofday_us();
00171 timeoutspec* tmo = &tmospecs_[(*(active_time_.begin())).second];
00172 *delay_us = tmo->tmo_tod_us - tod_us;
00173 if (*delay_us < 0)
00174 *delay_us = 0;
00175 }
00176 }
00177
00178 int
00179 Timeout::get_next_timeout_msdly()
00180 {
00181 int64_t delay_us;
00182 int tmo;
00183 get_next_timeout_delay(&delay_us);
00184 if (delay_us == -1)
00185 {
00186 tmo = -1;
00187 }
00188 else
00189 {
00190 tmo = delay_us / 1000;
00191 }
00192 return (tmo);
00193 }
00194
00195
00196 bool
00197 Timeout::is_consistent()
00198 {
00199 std::map<uint64_t, size_t>::iterator itactive;
00200 std::list<size_t>::iterator itfree;
00201 for (unsigned ii = 0; ii < tmospecs_.size(); ++ii)
00202 tmospecs_[ii].check = 1;
00203 for (itactive = active_time_.begin(); itactive != active_time_.end(); ++itactive)
00204 tmospecs_[(*itactive).second].check--;
00205 for (itfree = free_.begin(); itfree != free_.end(); ++itfree)
00206 tmospecs_[*itfree].check--;
00207 for (unsigned ii = 0; ii < tmospecs_.size(); ++ii)
00208 if (tmospecs_[ii].check != 0) return false;
00209 return (true);
00210 }
00211
00212 void
00213 Timeout::timeoutlist_init()
00214 {
00215 size_t list_sz = tmospecs_.size();
00216 for (size_t ii = 0; ii < list_sz; ++ii)
00217 {
00218 free_.push_front(ii);
00219 }
00220 }
00221
00222
00223 int Timeout::get_clear_next_expired_timeout(timeoutspec& tmo
00224 , uint64_t tod_now_us)
00225 {
00226 int skipped = 0;
00227 if (active_time_.size() == 0)
00228 {
00229 TRACE( 17, "get_clear_next_expired_timeout - nothing to get/clear!" );
00230 return (false);
00231 }
00232 else
00233 {
00234 std::unique_lock<std::mutex> ulock(lock_mutex_);
00235 std::multimap<uint64_t, size_t>::iterator itfront = active_time_.begin();
00236 size_t idx = (*itfront).second;
00237 if (tmospecs_[idx].tmo_tod_us < tod_now_us)
00238 {
00239 tmo = tmospecs_[idx];
00240 TRACE( 17, "get_clear_next_expired_timeout - clearing tag=%p desc="+tmo.desc+" period=%lu idx=%lu"
00241 , tmo.tag, tmo.period_us, idx );
00242
00243 active_time_.erase(itfront);
00244
00245
00246 if (tmo.period_us)
00247 {
00248
00249 int64_t delta_us;
00250 uint64_t period_us = tmo.period_us;
00251 delta_us = tod_now_us - tmo.tmo_tod_us;
00252 skipped = delta_us / period_us;
00253 assert( skipped >= 0 );
00254 tmo.missed_periods += skipped;
00255
00256
00257 period_us += period_us * skipped;
00258 tmospecs_[idx].tmo_tod_us += period_us;
00259 active_time_.insert(std::pair<uint64_t, size_t>(tmospecs_[idx].tmo_tod_us, idx));
00260 TRACE( 18
00261 ,"get_clear_next_expired_timeout - periodic timeout desc="+tmo.desc
00262 +" period_us=%lu delta_us=%lu skipped=%d next tmo at:%lu"
00263 , period_us, delta_us, skipped, tmospecs_[idx].tmo_tod_us );
00264 }
00265 else
00266 {
00267
00268 std::unordered_multimap<std::string, size_t>::iterator i2;
00269 i2 = active_desc_.equal_range(tmospecs_[idx].desc).first;
00270 while (1)
00271 {
00272 if (i2->second == idx)
00273 break;
00274 ++i2;
00275 }
00276 active_desc_.erase(i2);
00277 free_.push_front(idx);
00278 }
00279 }
00280 else
00281 {
00282 TRACE( 17, "get_clear_next_expired_timeout - front %lu NOT before ts_now %lu - not clearing!"
00283 , tmospecs_[idx].tmo_tod_us, tod_now_us );
00284 return (-1);
00285 }
00286 }
00287 return true;
00288 }
00289
00290
00291 void Timeout::copy_in_timeout(const char* desc, uint64_t period_us, uint64_t start_us)
00292 {
00293 TRACE( 18, "copy_in_timeout desc="+std::string(desc) );
00294 timeoutspec tos;
00295 tos.desc = desc;
00296 tos.tag = NULL;
00297 tos.function = 0;
00298 tos.period_us = period_us;
00299 tos.tmo_tod_us = start_us;
00300 tos.missed_periods = tos.check = 0;
00301 copy_in_timeout(tos);
00302 }
00303
00304 void
00305 Timeout::copy_in_timeout(timeoutspec& tmo)
00306 {
00307
00308 assert( free_.size() );
00309
00310
00311 std::unique_lock<std::mutex> ulock(lock_mutex_);
00312 size_t idx = free_.front();
00313 free_.pop_front();
00314 tmospecs_[idx] = tmo;
00315 TRACE( 20, "copy_in_timeout timeoutspec desc="+tmo.desc );
00316 active_time_.insert(std::pair<uint64_t, size_t>(tmo.tmo_tod_us, idx));
00317 active_desc_.insert(std::pair<std::string, size_t>(tmo.desc, idx));
00318 }
00319
00320 bool
00321 Timeout::cancel_timeout(void* tag
00322 , std::string desc)
00323 {
00324 bool retsts = false;
00325 std::unordered_multimap<std::string, size_t>::iterator ii, ee;
00326 std::unique_lock<std::mutex> ulock(lock_mutex_);
00327 auto pairOfIters = active_desc_.equal_range(desc);
00328 ii = pairOfIters.first;
00329 ee = pairOfIters.second;
00330 for (; ii != ee && ii->first.compare(desc) == 0; ++ii)
00331 {
00332 size_t idx = ii->second;
00333 if (tmospecs_[idx].tag == tag)
00334 {
00335
00336 retsts = true;
00337 uint64_t tmo_tod_us = tmospecs_[idx].tmo_tod_us;
00338
00339
00340 std::multimap<uint64_t, size_t>::iterator i2;
00341 i2 = active_time_.equal_range(tmo_tod_us).first;
00342 while (1)
00343 {
00344 if (i2->second == idx)
00345 break;
00346 ++i2;
00347 }
00348
00349 active_desc_.erase(ii);
00350 active_time_.erase(i2);
00351 free_.push_front(idx);
00352 break;
00353 }
00354 }
00355 TRACE( 22, "cancel_timeout returning %d", retsts );
00356 return retsts;
00357 }
00358
00359 void
00360 Timeout::list_active_time()
00361 {
00362 std::map<uint64_t, size_t>::iterator ii = active_time_.begin(), ee = active_time_.end();
00363 for (; ii != ee; ++ii)
00364 {
00365 TRACE( 3, "list_active_time %lu desc="+tmospecs_[(*ii).second].desc, (*ii).first );
00366 }
00367 }