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