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