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