13 #define TRACE_NAME "Timeout"
14 #include "TRACE/tracemf.h"
16 #include "artdaq/TransferPlugins/detail/Timeout.hh"
18 #include "artdaq-core/Utilities/TimeUtils.hh"
31 Timeout::timeoutspec::timeoutspec()
32 : desc(), tag(), function()
34 , missed_periods(), check()
36 TLOG(TLVL_DEBUG + 38) <<
"Timeout::timeoutspec ctor this=" <<
this;
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)
43 TLOG(TLVL_DEBUG + 38) <<
"Timeout::timeoutspec copy ctor";
47 TLOG(TLVL_DEBUG + 38) <<
"Timeout::timeoutspec copy assignment (operator= other.desc=" << other.
desc <<
")";
52 period = other.period;
62 TLOG(TLVL_DEBUG + 36) <<
"Timeout ctor";
66 void Timeout::add_periodic(
const char* desc,
void* tag, std::function<
void()>&
function, uint64_t period_us, uint64_t start_us)
72 tmo.
tmo_tod_us = start_us != 0u ? start_us : artdaq::TimeUtils::gettimeofday_us() + period_us;
92 TLOG(TLVL_DEBUG + 39) <<
"add_periodic - desc=" << desc <<
" period_us=" << period_us <<
" start_us=" << start_us;
109 tmo.
tmo_tod_us = artdaq::TimeUtils::gettimeofday_us() + rel_ms * 1000;
122 tmo.
tmo_tod_us = artdaq::TimeUtils::gettimeofday_us() + rel_ms * 1000;
132 TLOG(TLVL_DEBUG + 38) <<
"get_next_expired_timeout b4 get_clear_next_expired_timeout";
133 skipped = get_clear_next_expired_timeout(tmo, artdaq::TimeUtils::gettimeofday_us());
136 TLOG(TLVL_DEBUG + 38) <<
"get_next_expired_timeout - get_clear_next_expired_timeout returned false";
137 desc = std::string(
"");
151 std::unique_lock<std::mutex> ulock(lock_mutex_);
152 size_t active_time_size = active_time_.size();
153 if (active_time_size == 0)
155 TLOG(TLVL_DEBUG + 37) <<
"get_next_timeout_delay active_.size() == 0";
160 TLOG(TLVL_DEBUG + 37) <<
"get_next_timeout_delay active_.size() != 0: " << active_time_size;
161 uint64_t tod_us = artdaq::TimeUtils::gettimeofday_us();
162 timeoutspec* tmo = &tmospecs_[(*(active_time_.begin())).second];
182 tmo = delay_us / 1000;
189 std::map<uint64_t, size_t>::iterator itactive;
190 std::list<size_t>::iterator itfree;
191 for (
auto& tmospec : tmospecs_)
195 for (itactive = active_time_.begin(); itactive != active_time_.end(); ++itactive)
197 tmospecs_[(*itactive).second].check--;
199 for (itfree = free_.begin(); itfree != free_.end(); ++itfree)
201 tmospecs_[*itfree].check--;
203 for (
auto& tmospec : tmospecs_)
205 if (tmospec.check != 0)
213 void Timeout::timeoutlist_init()
215 size_t list_sz = tmospecs_.size();
216 for (
size_t ii = 0; ii < list_sz; ++ii)
218 free_.push_front(ii);
222 int Timeout::get_clear_next_expired_timeout(timeoutspec& tmo, uint64_t tod_now_us)
225 if (active_time_.empty())
227 TLOG(TLVL_DEBUG + 37) <<
"get_clear_next_expired_timeout - nothing to get/clear!";
228 return static_cast<int>(
false);
231 std::unique_lock<std::mutex> ulock(lock_mutex_);
232 auto itfront = active_time_.begin();
233 size_t idx = (*itfront).second;
234 if (tmospecs_[idx].tmo_tod_us < tod_now_us)
236 tmo = tmospecs_[idx];
237 TLOG(TLVL_DEBUG + 37) <<
"get_clear_next_expired_timeout - clearing tag=" << tmo.tag <<
" desc=" << tmo.desc <<
" period=" << tmo.period_us <<
" idx=" << idx;
239 active_time_.erase(itfront);
242 if (tmo.period_us != 0u)
246 uint64_t period_us = tmo.period_us;
247 delta_us = tod_now_us - tmo.tmo_tod_us;
248 skipped = delta_us / period_us;
249 assert(skipped >= 0);
250 tmo.missed_periods += skipped;
253 period_us += period_us * skipped;
254 tmospecs_[idx].tmo_tod_us += period_us;
255 active_time_.insert(std::pair<uint64_t, size_t>(tmospecs_[idx].tmo_tod_us, idx));
256 TLOG(TLVL_DEBUG + 38) <<
"get_clear_next_expired_timeout - periodic timeout desc=" << tmo.desc
257 <<
" period_us=" << period_us <<
" delta_us=" << delta_us
258 <<
" skipped=" << skipped <<
" next tmo at:" << tmospecs_[idx].tmo_tod_us;
263 std::unordered_multimap<std::string, size_t>::iterator i2;
264 i2 = active_desc_.equal_range(tmospecs_[idx].desc).first;
267 if (i2->second == idx)
273 active_desc_.erase(i2);
274 free_.push_front(idx);
279 TLOG(TLVL_DEBUG + 37) <<
"get_clear_next_expired_timeout - front " << tmospecs_[idx].tmo_tod_us <<
" NOT before ts_now " << tod_now_us <<
" - not clearing!";
289 TLOG(TLVL_DEBUG + 38) <<
"copy_in_timeout desc=" + std::string(desc);
303 assert(free_.size());
306 std::unique_lock<std::mutex> ulock(lock_mutex_);
307 size_t idx = free_.front();
309 tmospecs_[idx] = tmo;
310 TLOG(TLVL_DEBUG + 40) <<
"copy_in_timeout timeoutspec desc=" + tmo.desc;
311 active_time_.insert(std::pair<uint64_t, size_t>(tmo.tmo_tod_us, idx));
312 active_desc_.insert(std::pair<std::string, size_t>(tmo.desc, idx));
318 std::unordered_multimap<std::string, size_t>::iterator ii, ee;
319 std::unique_lock<std::mutex> ulock(lock_mutex_);
320 auto pairOfIters = active_desc_.equal_range(desc);
321 ii = pairOfIters.first;
322 ee = pairOfIters.second;
323 for (; ii != ee && ii->first == desc; ++ii)
325 size_t idx = ii->second;
326 if (tmospecs_[idx].tag == tag)
330 uint64_t tmo_tod_us = tmospecs_[idx].tmo_tod_us;
333 std::multimap<uint64_t, size_t>::iterator i2;
334 i2 = active_time_.equal_range(tmo_tod_us).first;
337 if (i2->second == idx)
344 active_desc_.erase(ii);
345 active_time_.erase(i2);
346 free_.push_front(idx);
350 TLOG(TLVL_DEBUG + 42) <<
"cancel_timeout returning " << retsts;
356 auto ii = active_time_.begin(), ee = active_time_.end();
357 for (; ii != ee; ++ii)
359 TLOG(TLVL_DEBUG + 32) <<
"list_active_time " << (*ii).first <<
" desc=" << tmospecs_[(*ii).second].desc;
void copy_in_timeout(const char *desc, uint64_t period_us, uint64_t start_us=0)
Add a timeout with the given parameters.
void add_relative(const char *desc, void *tag, std::function< void()> &function, int rel_ms)
Add a periodic timeout to the Timeout container.
void * tag
could be file descriptor (fd)
std::function< void()> function
Function to execute at Timeout.
uint64_t tmo_tod_us
When the function should be executed (gettimeofday, microseconds)
int get_next_timeout_msdly()
Get the amount to wait for the next timeout to occur.
int check
Check the timeoutspec.
int missed_periods
Number of periods that passed while the function was executing.
void get_next_timeout_delay(int64_t *delay_us)
Get the amount to wait for the next timeout to occur.
uint64_t period_us
0 if not periodic
bool cancel_timeout(void *tag, const std::string &desc)
Cancel the timeout having the given description and tag.
Specification for a Timeout function.
int get_next_expired_timeout(std::string &desc, void **tag, std::function< void()> &function, uint64_t *tmo_tod_us)
Get a timeout that has expired.
bool is_consistent()
Run a consistency check on all confiugured timeouts.
std::string desc
Description of the Timeout function.
void add_periodic(const char *desc, void *tag, std::function< void()> &function, uint64_t period_us, uint64_t start_us=0)
Add a periodic timeout to the Timeout container.
Timeout(int max_tmos=100)
Construct a Timeout object.
void list_active_time()
TRACE all active timeouts.