YARP
Yet Another Robot Platform
Timer.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2020 Istituto Italiano di Tecnologia (IIT)
3  * All rights reserved.
4  *
5  * This software may be modified and distributed under the terms of the
6  * BSD-3-Clause license. See the accompanying LICENSE file for details.
7  */
8 
9 #include <yarp/os/Timer.h>
10 
11 #include <yarp/os/PeriodicThread.h>
12 #include <yarp/os/Time.h>
13 
14 #include <cmath>
15 #include <map>
16 #include <mutex>
17 #include <utility>
18 
19 using namespace yarp::os;
20 
21 //disclaimer: the following inheritance little madness is for avoiding critical copy and paste code and
22 //avoiding data inconsistence(example: RateThread::GetIterations() and runTimes)
23 
25 {
26 protected:
27  yarp::os::YarpTimerEvent getEventNow(unsigned int iteration);
28 
29  bool runTimer(unsigned int iteration, YarpTimerEvent event);
30 
31 public:
33 
34 #ifndef YARP_NO_DEPRECATED // since YARP 3.3
38  TimerCallback call,
39  yarp::os::Mutex* mutex) :
40  m_settings(sett),
41  m_callback(std::move(call)),
42  m_old_mutex(mutex)
43  {
44  }
46 #endif // YARP_NO_DEPRECATED
47 
49  TimerCallback call,
50  std::mutex* mutex = nullptr) :
51  m_settings(sett),
52  m_callback(std::move(call)),
53  m_mutex(mutex)
54  {
55  }
56 
57  virtual ~PrivateImpl() = default;
58 
59  virtual bool startTimer() = 0;
60 
61  virtual void stopTimer() = 0;
62 
63  virtual bool stepTimer() = 0;
64 
65  virtual bool timerIsRunning() = 0;
66 
67 
70  double m_startStamp{0.0};
71  double m_lastReal{0.0};
72  std::mutex* m_mutex{nullptr};
73 #ifndef YARP_NO_DEPRECATED // since YARP 3.3
78 #endif // YARP_NO_DEPRECATED
79 };
80 
82 {
83 public:
84 
85 #ifndef YARP_NO_DEPRECATED // since YARP 3.3
88  MonoThreadTimer(const TimerSettings& sett,
89  const TimerCallback& call,
90  yarp::os::Mutex* mutex);
92 #endif // YARP_NO_DEPRECATED
93 
94  MonoThreadTimer(const TimerSettings& sett,
95  const TimerCallback& call,
96  std::mutex* mutex = nullptr);
97 
98  ~MonoThreadTimer() override;
99  bool m_active{false};
100  unsigned int m_runTimes{1};
101  size_t m_id{(size_t)-1};
102 
104  {
105  return PrivateImpl::getEventNow(m_runTimes);
106  }
107 
108  bool startTimer() override
109  {
110  m_startStamp = yarp::os::Time::now();
111  m_active = true;
112  return true;
113  }
114 
115  void stopTimer() override
116  {
117  m_active = false;
118  }
119 
120  bool stepTimer() override
121  {
122  return step(getEventNow(), true);
123  }
124 
125  virtual bool step(YarpTimerEvent event, bool singleStep)
126  {
127  bool m_active = runTimer(m_runTimes, event);
128  if (!singleStep) {
129  m_runTimes++;
130  }
131  return m_active;
132  }
133 
134  bool timerIsRunning() override
135  {
136  return m_active;
137  }
138 };
139 
140 double gcd(double a, double b)
141 {
142  if (a < b) {
143  return gcd(b, a);
144  }
145 
146  // base case
147  if (fabs(b) < 0.001) {
148  return a;
149  } else {
150  return (gcd(b, a - floor(a / b) * b));
151  }
152 }
153 
155 {
156  std::mutex mu;
157  std::map<size_t, MonoThreadTimer*> timers;
158  TimerSingleton() :
159  PeriodicThread(10)
160  {
161  }
162 
163  void run() override;
164 
165  ~TimerSingleton() override
166  {
167  stop();
168  }
169 
170 public:
171  //reminder: int c++11 static variables'inside function are guaranteed to be lazy initialized and atomic
172  static TimerSingleton& self()
173  {
174  static TimerSingleton instance;
175  return instance;
176  }
177 
179  {
180  if (timers.size()) {
181  setPeriod(gcd(getPeriod(), t->m_settings.period));
182  } else {
183  setPeriod(t->m_settings.period);
184  }
185  mu.lock();
186  timers[timers.size()] = t;
187  mu.unlock();
188 
189  return timers.size() - 1;
190  }
191 
192  void removeTimer(size_t id)
193  {
194  mu.lock();
195  timers.erase(id);
196  mu.unlock();
197  if (!timers.size()) {
198  return;
199  }
200 
201  double new_gcd = timers.begin()->second->m_settings.period;
202  for (auto& i : timers) {
203  new_gcd = gcd(new_gcd, i.second->m_settings.period);
204  }
205  setPeriod(new_gcd);
206  }
207 
208  size_t getTimerCount()
209  {
210  return timers.size();
211  }
212 };
213 
214 #ifndef YARP_NO_DEPRECATED // since YARP 3.3
218  const TimerCallback& call,
219  yarp::os::Mutex* mutex) :
220  PrivateImpl(sett, call, mutex)
221 {
222  TimerSingleton& singlInstance = TimerSingleton::self();
223  m_id = singlInstance.addTimer(this);
224  if (!singlInstance.isRunning()) {
225  singlInstance.start();
226  }
227 }
229 #endif // YARP_NO_DEPRECATED
230 
232  const TimerCallback& call,
233  std::mutex* mutex) :
234  PrivateImpl(sett, call, mutex)
235 {
236  TimerSingleton& singlInstance = TimerSingleton::self();
237  m_id = singlInstance.addTimer(this);
238  if (!singlInstance.isRunning()) {
239  singlInstance.start();
240  }
241 }
242 
244 {
245  TimerSingleton& singlInstance = TimerSingleton::self();
246  singlInstance.removeTimer(m_id);
247  if (singlInstance.getTimerCount() == 0) {
248  singlInstance.stop();
249  }
250 }
251 
252 void TimerSingleton::run()
253 {
254  mu.lock();
255  for (auto t : timers) {
256  MonoThreadTimer& timer = *t.second;
257  YarpTimerEvent tEvent = timer.getEventNow();
258  if (timer.m_active && tEvent.currentReal > tEvent.currentExpected) {
259  timer.m_active = timer.step(tEvent, false);
260  timer.m_lastReal = tEvent.currentReal;
261  }
262  }
263  mu.unlock();
264 }
265 
269 {
271  void run() override;
272  bool threadInit() override;
273  bool singleStep{false};
274 
275 public:
276 #ifndef YARP_NO_DEPRECATED // since YARP 3.3
280  const TimerCallback& call,
281  yarp::os::Mutex* mutex) :
282  PrivateImpl(sett, call, mutex),
283  PeriodicThread(sett.period)
284  {
285  }
287 #endif // YARP_NO_DEPRECATED
288 
290  const TimerCallback& call,
291  std::mutex* mutex = nullptr) :
292  PrivateImpl(sett, call, mutex),
293  PeriodicThread(sett.period)
294  {
295  }
296 
297  ~ThreadedTimer() override
298  {
299  stop();
300  }
301 
302  bool startTimer() override
303  {
306  return start();
307  }
308 
309  bool stepTimer() override
310  {
311  singleStep = true;
312  step();
313  return true;
314  }
315 
316  void stopTimer() override
317  {
318  return askToStop();
319  }
320 
321  bool timerIsRunning() override
322  {
323  return isRunning();
324  }
325 };
326 
327 bool ThreadedTimer::threadInit()
328 {
330  return true;
331 }
332 
333 #ifndef YARP_NO_DEPRECATED // since YARP 3.3
336 //the newThread parameter is not in the settings for it to be unmutable and only checked by the constructor
337 Timer::Timer(const TimerSettings& settings, const TimerCallback& callback, bool newThread, Mutex* mutex) :
338  //added cast for incompatible operand error
339  impl(newThread ? dynamic_cast<PrivateImpl*>(new ThreadedTimer(settings, callback, mutex))
340  : dynamic_cast<PrivateImpl*>(new MonoThreadTimer(settings, callback, mutex)))
341 {
342 }
344 #endif // YARP_NO_DEPRECATED
345 
346 //the newThread parameter is not in the settings for it to be unmutable and only checked by the constructor
347 Timer::Timer(const TimerSettings& settings, const TimerCallback& callback, bool newThread, std::mutex* mutex) :
348  //added cast for incompatible operand error
349  impl(newThread ? dynamic_cast<PrivateImpl*>(new ThreadedTimer(settings, callback, mutex))
350  : dynamic_cast<PrivateImpl*>(new MonoThreadTimer(settings, callback, mutex)))
351 {
352 }
353 
355 {
356 
357  return impl->startTimer();
358 }
359 
361 {
362  return impl->stepTimer();
363 }
364 
366 {
367  impl->stopTimer();
368 }
369 
371 {
372  YarpTimerEvent event;
373 
375  event.currentExpected = m_startStamp + iteration * m_settings.period;
376  event.lastExpected = event.currentExpected - m_settings.period;
377  event.lastReal = m_lastReal;
378  event.lastDuration = event.currentReal - m_lastReal;
379  event.runCount = iteration;
380  return event;
381 }
382 
383 bool yarp::os::Timer::PrivateImpl::runTimer(unsigned int iteration, YarpTimerEvent event)
384 {
385  if (m_mutex != nullptr) {
386  m_mutex->lock();
387  }
388 
389 #ifndef YARP_NO_DEPRECATED // since YARP 3.3
390  if (m_old_mutex != nullptr) {
391  m_old_mutex->lock();
392  }
393 #endif // YARP_NO_DEPRECATED
394 
395  bool ret = m_callback(event);
396 
397 #ifndef YARP_NO_DEPRECATED // since YARP 3.3
398  if (m_old_mutex != nullptr) {
399  m_old_mutex->unlock();
400  }
401 #endif // YARP_NO_DEPRECATED
402 
403  if (m_mutex != nullptr) {
404  m_mutex->unlock();
405  }
406 
407  if (!ret) {
408  return false;
409  }
410 
411  m_lastReal = event.currentReal;
412 
413  double timerAge = (yarp::os::Time::now() - m_startStamp);
414 
415  //totalRunCount == 0 ----> infinite run count. follows the run count of the timer
416  bool stop(m_settings.totalRunCount != 0 && m_settings.totalRunCount <= iteration);
417 
418  //totalTime == 0 ----> infinite time. follows the age check for the timer
419  stop |= m_settings.totalTime > 0.00001 && (m_settings.totalTime - timerAge) < m_settings.tolerance;
420 
421  return !stop;
422 }
423 
424 void ThreadedTimer::run()
425 {
426  if (getIterations() == 0 && !singleStep) {
427  return;
428  }
429  singleStep = false;
430  YarpTimerEvent event = getEventNow(this->getIterations());
431  if (!runTimer(this->getIterations(), event)) {
432  askToStop();
433  }
434 }
435 
436 void Timer::setSettings(const TimerSettings& settings)
437 {
438  impl->m_settings = settings;
439 }
440 
442 {
443  return impl->m_settings;
444 }
445 
447 {
448  return impl->timerIsRunning();
449 }
450 
452 {
453  delete impl;
454 }
float t
bool ret
double gcd(double a, double b)
Definition: Timer.cpp:140
void stopTimer() override
Definition: Timer.cpp:115
MonoThreadTimer(const TimerSettings &sett, const TimerCallback &call, yarp::os::Mutex *mutex)
Definition: Timer.cpp:217
~MonoThreadTimer() override
Definition: Timer.cpp:243
virtual yarp::os::YarpTimerEvent getEventNow()
Definition: Timer.cpp:103
bool stepTimer() override
Definition: Timer.cpp:120
size_t m_id
Definition: Timer.cpp:101
virtual bool step(YarpTimerEvent event, bool singleStep)
Definition: Timer.cpp:125
bool m_active
Definition: Timer.cpp:99
bool startTimer() override
Definition: Timer.cpp:108
bool timerIsRunning() override
Definition: Timer.cpp:134
void stopTimer() override
Definition: Timer.cpp:316
ThreadedTimer(const TimerSettings &sett, const TimerCallback &call, std::mutex *mutex=nullptr)
Definition: Timer.cpp:289
bool stepTimer() override
Definition: Timer.cpp:309
~ThreadedTimer() override
Definition: Timer.cpp:297
bool startTimer() override
Definition: Timer.cpp:302
ThreadedTimer(const TimerSettings &sett, const TimerCallback &call, yarp::os::Mutex *mutex)
Definition: Timer.cpp:279
bool timerIsRunning() override
Definition: Timer.cpp:321
static TimerSingleton & self()
Definition: Timer.cpp:172
void removeTimer(size_t id)
Definition: Timer.cpp:192
size_t addTimer(MonoThreadTimer *t)
Definition: Timer.cpp:178
size_t getTimerCount()
Definition: Timer.cpp:208
Basic wrapper for mutual exclusion.
Definition: Mutex.h:35
An abstraction for a periodic thread.
bool setPeriod(double period)
Set the (new) period of the thread.
bool isRunning() const
Returns true when the thread is started, false otherwise.
void askToStop()
Stop the thread.
bool start()
Call this to start the thread.
void step()
Call this to "step" the thread rather than starting it.
void stop()
Call this to stop the thread, this call blocks until the thread is terminated (and releaseThread() ca...
TimerCallback m_callback
Definition: Timer.cpp:69
yarp::os::YarpTimerEvent getEventNow(unsigned int iteration)
Definition: Timer.cpp:370
virtual bool startTimer()=0
yarp::os::Mutex * m_old_mutex
Definition: Timer.cpp:76
bool runTimer(unsigned int iteration, YarpTimerEvent event)
Definition: Timer.cpp:383
PrivateImpl(const TimerSettings &sett, TimerCallback call, std::mutex *mutex=nullptr)
Definition: Timer.cpp:48
virtual ~PrivateImpl()=default
virtual void stopTimer()=0
virtual bool timerIsRunning()=0
TimerSettings m_settings
Definition: Timer.cpp:68
virtual bool stepTimer()=0
yarp::os::Timer::TimerCallback TimerCallback
Definition: Timer.cpp:32
PrivateImpl(const TimerSettings &sett, TimerCallback call, yarp::os::Mutex *mutex)
Definition: Timer.cpp:37
virtual ~Timer()
Definition: Timer.cpp:451
void setSettings(const yarp::os::TimerSettings &settings)
setSettings
Definition: Timer.cpp:436
virtual bool isRunning()
Definition: Timer.cpp:446
virtual bool start()
Definition: Timer.cpp:354
virtual void stop()
Definition: Timer.cpp:365
const yarp::os::TimerSettings getSettings()
getSettings
Definition: Timer.cpp:441
virtual bool step()
Definition: Timer.cpp:360
Timer(const Timer &)=delete
std::function< bool(const yarp::os::YarpTimerEvent &)> TimerCallback
Definition: Timer.h:109
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition: Time.cpp:124
An interface to the operating system, including Port based communication.
double currentReal
currentReal When the current callback is actually being called
Definition: Timer.h:47
double currentExpected
currentExpected this is when the current callback should have been called
Definition: Timer.h:42
#define YARP_WARNING_POP
Ends a temporary alteration of the enabled warnings.
Definition: system.h:335
#define YARP_WARNING_PUSH
Starts a temporary alteration of the enabled warnings.
Definition: system.h:334
#define YARP_DISABLE_DEPRECATED_WARNING
Disable deprecated warnings in the following code.
Definition: system.h:336