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