artdaq  v3_00_03
Timeout.cc
1 // This file (Timer.cxx) was created by Ron Rechenmacher <ron@fnal.gov> on
2 // Sep 28, 2009. "TERMS AND CONDITIONS" governing this file are in the README
3 // or COPYING file. If you do not have such a file, one can be obtained by
4 // contacting Ron or Fermi Lab in Batavia IL, 60510, phone: 630-840-3000.
5 // $RCSfile: Timeout.cxx,v $
6 // rev="$Revision: 1.13 $$Date: 2016/10/12 21:00:13 $";
7 /*
8  g++ -Wall -g -std=c++0x -c Timeout.cxx
9 OR
10  g++ -Wall -g -std=c++0x -shared -fPIC -o Timeout.so Timeout.cxx -lrt
11 */
12 #include <stdio.h> // printf
13 #include <sys/time.h> /* struct timeval */
14 #include <assert.h> /* assert */
15 #include <string.h> /* strcmp */
16 #include <stdlib.h> // exit
17 #include <list>
18 using std::list;
19 #include "artdaq/TransferPlugins/detail/Timeout.hh"
20 #include "artdaq/DAQdata/Globals.hh" // TRACE
21 #include "artdaq-core/Utilities/TimeUtils.hh"
22 
23 // public:
24 
25 #if 0
26 Timeout::timeoutspec::timeoutspec()
27  : desc(), tag(), function()
28  , ts(), period()
29  , missed_periods(), check()
30 { TRACE( 18, "Timeout::timeoutspec ctor this=%p", this );
31 }
32 Timeout::timeoutspec::timeoutspec( const timeoutspec & other )
33  : desc(other.desc), tag(other.tag), function(other.function)
34  , ts(other.ts), period(other.period)
35  , missed_periods(other.missed_periods), check(other.check)
36 { TRACE( 18, "Timeout::timeoutspec copy ctor" );
37 }
38 Timeout::timeoutspec & Timeout::timeoutspec::operator=( const Timeout::timeoutspec & other )
39 { TRACE( 18, "Timeout::timeoutspec copy assignment (operator=) other.desc="+other.desc );
40  desc = other.desc;
41  tag=other.tag;
42  function=other.function;
43  ts=other.ts;
44  period=other.period;
46  check=other.check;
47  return *this;
48 }
49 #endif
50 
51 
52 Timeout::Timeout(int max_tmos)
53  : tmospecs_(max_tmos)
54 {
55  TRACE( 16, "Timeout ctor" );
56  timeoutlist_init();
57 }
58 
59 
60 void
61 Timeout::add_periodic(const char* desc, void* tag, std::function<void()>& function
62  , uint64_t period_us
63  , uint64_t start_us)
64 {
65  timeoutspec tmo;
66  tmo.desc = desc;
67  tmo.tag = tag;
68  tmo.function = function;
69  tmo.tmo_tod_us = start_us ? start_us : artdaq::TimeUtils::gettimeofday_us() + period_us;
70  tmo.period_us = period_us;
71  tmo.check = tmo.missed_periods = 0;
72  copy_in_timeout(tmo);
73 } // add_periodic
74 
75 void
76 Timeout::add_periodic(const char* desc, void* tag, std::function<void()>& function
77  , int rel_ms)
78 {
79  timeoutspec tmo;
80  tmo.desc = desc;
81  tmo.tag = tag;
82  tmo.function = function;
83  tmo.period_us = rel_ms * 1000;
84  tmo.tmo_tod_us = artdaq::TimeUtils::gettimeofday_us() + tmo.period_us;
85  tmo.check = tmo.missed_periods = 0;
86  copy_in_timeout(tmo);
87 } // add_periodic
88 
89 void
90 Timeout::add_periodic(const char* desc
91  , uint64_t period_us
92  , uint64_t start_us)
93 {
94  TRACE( 19, "add_periodic - desc="+std::string(desc)+" period_us=%lu start_us=%lu"
95  , period_us, start_us );
96  timeoutspec tmo;
97  tmo.desc = desc;
98  tmo.tag = 0;
99  tmo.function = 0;
100  tmo.tmo_tod_us = start_us;
101  tmo.period_us = period_us;
102  tmo.missed_periods = tmo.check = 0;
103  copy_in_timeout(tmo);
104 } // add_periodic
105 
106 void
107 Timeout::add_relative(const char* desc, void* tag, std::function<void()>& function
108  , int rel_ms)
109 {
110  timeoutspec tmo;
111  tmo.desc = desc;
112  tmo.tag = tag;
113  tmo.function = function;
114  tmo.tmo_tod_us = artdaq::TimeUtils::gettimeofday_us() + rel_ms * 1000;
115  tmo.period_us = 0;
116  tmo.missed_periods = tmo.check = 0;
117  copy_in_timeout(tmo);
118 } // add_periodic
119 
120 void
121 Timeout::add_relative(std::string desc
122  , int rel_ms)
123 {
124  timeoutspec tmo;
125  tmo.desc = desc.c_str();
126  tmo.tag = 0;
127  tmo.function = 0;
128  tmo.period_us = 0;
129  tmo.tmo_tod_us = artdaq::TimeUtils::gettimeofday_us() + rel_ms * 1000;
130  tmo.missed_periods = tmo.check = 0;
131  copy_in_timeout(tmo);
132 } // add_periodic
133 
134 int // tmo_tod_us is an output
135 Timeout::get_next_expired_timeout(std::string& desc, void** tag, std::function<void()>& function
136  , uint64_t* tmo_tod_us)
137 {
138  int skipped = 0;
139  timeoutspec tmo;
140  TRACE( 15, "get_next_expired_timeout b4 get_clear_next_expired_timeout" );
141  skipped = get_clear_next_expired_timeout(tmo, artdaq::TimeUtils::gettimeofday_us());
142  if (skipped == -1)
143  {
144  TRACE( 18, "get_next_expired_timeout - get_clear_next_expired_timeout returned false" );
145  desc = std::string(""); // 2 ways to check for none timed out
146  }
147  else
148  {
149  desc = tmo.desc;
150  *tag = tmo.tag;
151  function = tmo.function;
152  *tmo_tod_us = tmo.tmo_tod_us;
153  }
154  return (skipped);
155 } // get_next_expired_timeout
156 
157 void
159 {
160  std::unique_lock<std::mutex> ulock(lock_mutex_);
161  size_t active_time_size = active_time_.size();
162  if (active_time_size == 0)
163  {
164  TRACE( 17, "get_next_timeout_delay active_.size() == 0" );
165  *delay_us = -1; // usually means a very very long time
166  }
167  else
168  {
169  TRACE( 17, "get_next_timeout_delay active_.size() != 0 %lu",active_time_size );
170  uint64_t tod_us = artdaq::TimeUtils::gettimeofday_us();
171  timeoutspec* tmo = &tmospecs_[(*(active_time_.begin())).second];
172  *delay_us = tmo->tmo_tod_us - tod_us;
173  if (*delay_us < 0)
174  *delay_us = 0;
175  }
176 } // get_next_timeout_delay
177 
178 int
180 {
181  int64_t delay_us;
182  int tmo;
183  get_next_timeout_delay(&delay_us);
184  if (delay_us == -1)
185  {
186  tmo = -1;
187  }
188  else
189  { // NOTE THE + 1 b/c of integer division and/or system HZ resolution
190  tmo = delay_us / 1000;
191  }
192  return (tmo);
193 } // get_next_timeout_msdly
194 
195 
196 bool
198 {
199  std::map<uint64_t, size_t>::iterator itactive;
200  std::list<size_t>::iterator itfree;
201  for (unsigned ii = 0; ii < tmospecs_.size(); ++ii)
202  tmospecs_[ii].check = 1;
203  for (itactive = active_time_.begin(); itactive != active_time_.end(); ++itactive)
204  tmospecs_[(*itactive).second].check--;
205  for (itfree = free_.begin(); itfree != free_.end(); ++itfree)
206  tmospecs_[*itfree].check--;
207  for (unsigned ii = 0; ii < tmospecs_.size(); ++ii)
208  if (tmospecs_[ii].check != 0) return false;
209  return (true);
210 }
211 
212 void
213 Timeout::timeoutlist_init()
214 {
215  size_t list_sz = tmospecs_.size();
216  for (size_t ii = 0; ii < list_sz; ++ii)
217  { //bzero( &tmospecs_[list_sz], sizeof(tmospecs_[0]) );
218  free_.push_front(ii);
219  }
220 }
221 
222 
223 int Timeout::get_clear_next_expired_timeout(timeoutspec& tmo
224  , uint64_t tod_now_us)
225 {
226  int skipped = 0;
227  if (active_time_.size() == 0)
228  {
229  TRACE( 17, "get_clear_next_expired_timeout - nothing to get/clear!" );
230  return (false);
231  }
232  else
233  {
234  std::unique_lock<std::mutex> ulock(lock_mutex_);
235  std::multimap<uint64_t, size_t>::iterator itfront = active_time_.begin();
236  size_t idx = (*itfront).second;
237  if (tmospecs_[idx].tmo_tod_us < tod_now_us)
238  {
239  tmo = tmospecs_[idx];
240  TRACE( 17, "get_clear_next_expired_timeout - clearing tag=%p desc="+tmo.desc+" period=%lu idx=%lu"
241  , tmo.tag, tmo.period_us, idx );
242 
243  active_time_.erase(itfront);
244  // now, be effecient -- if periodic, add back at new time, else
245  // find/erase active_desc_ with same idx and free
246  if (tmo.period_us)
247  {
248  // PERIODIC
249  int64_t delta_us;
250  uint64_t period_us = tmo.period_us;
251  delta_us = tod_now_us - tmo.tmo_tod_us;
252  skipped = delta_us / period_us;
253  assert( skipped >= 0 );
254  tmo.missed_periods += skipped;
255 
256  /* now fast forward over skipped */
257  period_us += period_us * skipped;
258  tmospecs_[idx].tmo_tod_us += period_us;
259  active_time_.insert(std::pair<uint64_t, size_t>(tmospecs_[idx].tmo_tod_us, idx));
260  TRACE( 18
261  ,"get_clear_next_expired_timeout - periodic timeout desc="+tmo.desc
262  +" period_us=%lu delta_us=%lu skipped=%d next tmo at:%lu"
263  , period_us, delta_us, skipped, tmospecs_[idx].tmo_tod_us );
264  }
265  else
266  {
267  // find active_desc_ with same idx
268  std::unordered_multimap<std::string, size_t>::iterator i2;
269  i2 = active_desc_.equal_range(tmospecs_[idx].desc).first;
270  while (1)
271  { // see also in cancel_timeout below
272  if (i2->second == idx)
273  break;
274  ++i2;
275  }
276  active_desc_.erase(i2);
277  free_.push_front(idx);
278  }
279  }
280  else
281  {
282  TRACE( 17, "get_clear_next_expired_timeout - front %lu NOT before ts_now %lu - not clearing!"
283  , tmospecs_[idx].tmo_tod_us, tod_now_us );
284  return (-1);
285  }
286  }
287  return true;
288 } // get_clear_next_expired_timeout
289 
290 // this doesn't do anything (function undefined)
291 void Timeout::copy_in_timeout(const char* desc, uint64_t period_us, uint64_t start_us)
292 {
293  TRACE( 18, "copy_in_timeout desc="+std::string(desc) );
294  timeoutspec tos;
295  tos.desc = desc;
296  tos.tag = NULL;
297  tos.function = 0;
298  tos.period_us = period_us;
299  tos.tmo_tod_us = start_us;
300  tos.missed_periods = tos.check = 0;
301  copy_in_timeout(tos);
302 }
303 
304 void
305 Timeout::copy_in_timeout(timeoutspec& tmo)
306 {
307  // check for at least one empty entry
308  assert( free_.size() );
309 
310  // get/fill-in free tmospec
311  std::unique_lock<std::mutex> ulock(lock_mutex_);
312  size_t idx = free_.front();
313  free_.pop_front();
314  tmospecs_[idx] = tmo;
315  TRACE( 20, "copy_in_timeout timeoutspec desc="+tmo.desc );
316  active_time_.insert(std::pair<uint64_t, size_t>(tmo.tmo_tod_us, idx));
317  active_desc_.insert(std::pair<std::string, size_t>(tmo.desc, idx));
318 }
319 
320 bool
322  , std::string desc)
323 {
324  bool retsts = false;
325  std::unordered_multimap<std::string, size_t>::iterator ii, ee;
326  std::unique_lock<std::mutex> ulock(lock_mutex_);
327  auto pairOfIters = active_desc_.equal_range(desc);
328  ii = pairOfIters.first;
329  ee = pairOfIters.second;
330  for (; ii != ee && ii->first.compare(desc) == 0; ++ii)
331  {
332  size_t idx = ii->second;
333  if (tmospecs_[idx].tag == tag)
334  {
335  // found a match
336  retsts = true;
337  uint64_t tmo_tod_us = tmospecs_[idx].tmo_tod_us;
338 
339  // now make sure to find the active_time_ with the same idx
340  std::multimap<uint64_t, size_t>::iterator i2;
341  i2 = active_time_.equal_range(tmo_tod_us).first;
342  while (1)
343  { // see also in get_clear_next_expired_timeout above
344  if (i2->second == idx)
345  break;
346  ++i2;
347  }
348 
349  active_desc_.erase(ii);
350  active_time_.erase(i2);
351  free_.push_front(idx);
352  break;
353  }
354  }
355  TRACE( 22, "cancel_timeout returning %d", retsts );
356  return retsts;
357 } // cancel_timeout
358 
359 void
361 {
362  std::map<uint64_t, size_t>::iterator ii = active_time_.begin(), ee = active_time_.end();
363  for (; ii != ee; ++ii)
364  {
365  TRACE( 3, "list_active_time %lu desc="+tmospecs_[(*ii).second].desc, (*ii).first );
366  }
367 }
void copy_in_timeout(const char *desc, uint64_t period_us, uint64_t start_us=0)
Add a timeout with the given parameters.
Definition: Timeout.cc:291
void add_relative(const char *desc, void *tag, std::function< void()> &function, int rel_ms)
Add a periodic timeout to the Timeout container.
Definition: Timeout.cc:107
void * tag
could be file descriptor (fd)
Definition: Timeout.hh:36
std::function< void()> function
Function to execute at Timeout.
Definition: Timeout.hh:37
uint64_t tmo_tod_us
When the function should be executed (gettimeofday, microseconds)
Definition: Timeout.hh:38
int get_next_timeout_msdly()
Get the amount to wait for the next timeout to occur.
Definition: Timeout.cc:179
int check
Check the timeoutspec.
Definition: Timeout.hh:41
int missed_periods
Number of periods that passed while the function was executing.
Definition: Timeout.hh:40
void get_next_timeout_delay(int64_t *delay_us)
Get the amount to wait for the next timeout to occur.
Definition: Timeout.cc:158
uint64_t period_us
0 if not periodic
Definition: Timeout.hh:39
Specification for a Timeout function.
Definition: Timeout.hh:28
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.
Definition: Timeout.cc:135
bool is_consistent()
Run a consistency check on all confiugured timeouts.
Definition: Timeout.cc:197
std::string desc
Description of the Timeout function.
Definition: Timeout.hh:35
bool cancel_timeout(void *tag, std::string desc)
Cancel the timeout having the given description and tag.
Definition: Timeout.cc:321
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.
Definition: Timeout.cc:61
Timeout(int max_tmos=100)
Construct a Timeout object.
Definition: Timeout.cc:52
void list_active_time()
TRACE all active timeouts.
Definition: Timeout.cc:360