$treeview $search $mathjax $extrastylesheet
artdaq
v3_04_01
$projectbrief
|
$projectbrief
|
$searchbox |
00001 // This file (Timer.cxx) was created by Ron Rechenmacher <ron@fnal.gov> on 00002 // Sep 28, 2009. "TERMS AND CONDITIONS" governing this file are in the README 00003 // or COPYING file. If you do not have such a file, one can be obtained by 00004 // contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000. 00005 // $RCSfile: Timeout.cxx,v $ 00006 // rev="$Revision: 1.13 $$Date: 2016/10/12 21:00:13 $"; 00007 /* 00008 g++ -Wall -g -std=c++0x -c Timeout.cxx 00009 OR 00010 g++ -Wall -g -std=c++0x -shared -fPIC -o Timeout.so Timeout.cxx -lrt 00011 */ 00012 00013 #define TRACE_NAME "Timeout" 00014 00015 #include <stdio.h> // printf 00016 #include <sys/time.h> /* struct timeval */ 00017 #include <assert.h> /* assert */ 00018 #include <string.h> /* strcmp */ 00019 #include <stdlib.h> // exit 00020 #include <list> 00021 using std::list; 00022 #include "artdaq/TransferPlugins/detail/Timeout.hh" 00023 #include "artdaq/DAQdata/Globals.hh" // TRACE 00024 #include "artdaq-core/Utilities/TimeUtils.hh" 00025 00026 // public: 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 } // add_periodic 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 } // add_periodic 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 } // add_periodic 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 } // add_periodic 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 } // add_periodic 00138 00139 int // tmo_tod_us is an output 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(""); // 2 ways to check for none timed out 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 } // get_next_expired_timeout 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; // usually means a very very long time 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 } // get_next_timeout_delay 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 { // NOTE THE + 1 b/c of integer division and/or system HZ resolution 00195 tmo = delay_us / 1000; 00196 } 00197 return (tmo); 00198 } // get_next_timeout_msdly 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 { //bzero( &tmospecs_[list_sz], sizeof(tmospecs_[0]) ); 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 // now, be effecient -- if periodic, add back at new time, else 00249 // find/erase active_desc_ with same idx and free 00250 if (tmo.period_us) 00251 { 00252 // PERIODIC 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 /* now fast forward over skipped */ 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 // find active_desc_ with same idx 00271 std::unordered_multimap<std::string, size_t>::iterator i2; 00272 i2 = active_desc_.equal_range(tmospecs_[idx].desc).first; 00273 while (1) 00274 { // see also in cancel_timeout below 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 } // get_clear_next_expired_timeout 00291 00292 // this doesn't do anything (function undefined) 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 // check for at least one empty entry 00310 assert(free_.size()); 00311 00312 // get/fill-in free tmospec 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 // found a match 00338 retsts = true; 00339 uint64_t tmo_tod_us = tmospecs_[idx].tmo_tod_us; 00340 00341 // now make sure to find the active_time_ with the same idx 00342 std::multimap<uint64_t, size_t>::iterator i2; 00343 i2 = active_time_.equal_range(tmo_tod_us).first; 00344 while (1) 00345 { // see also in get_clear_next_expired_timeout above 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 } // cancel_timeout 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 }