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 }
yarp::os::Timer::PrivateImpl::stepTimer
virtual bool stepTimer()=0
YARP_WARNING_PUSH
#define YARP_WARNING_PUSH
Starts a temporary alteration of the enabled warnings.
Definition: system.h:334
MonoThreadTimer::MonoThreadTimer
MonoThreadTimer(const TimerSettings &sett, const TimerCallback &call, yarp::os::Mutex *mutex)
Definition: Timer.cpp:217
ThreadedTimer::startTimer
bool startTimer() override
Definition: Timer.cpp:302
yarp::os::TimerSettings::period
double period
Definition: Timer.h:100
yarp::os::Timer::stop
virtual void stop()
Definition: Timer.cpp:365
t
float t
Definition: FfmpegWriter.cpp:74
yarp::os::Timer::Timer
Timer(const Timer &)=delete
yarp::os::Timer::PrivateImpl::~PrivateImpl
virtual ~PrivateImpl()=default
yarp::os::Timer::PrivateImpl::PrivateImpl
PrivateImpl(const TimerSettings &sett, TimerCallback call, yarp::os::Mutex *mutex)
Definition: Timer.cpp:37
ThreadedTimer::stepTimer
bool stepTimer() override
Definition: Timer.cpp:309
MonoThreadTimer::m_id
size_t m_id
Definition: Timer.cpp:101
yarp::os::Timer::setSettings
void setSettings(const yarp::os::TimerSettings &settings)
setSettings
Definition: Timer.cpp:436
yarp::os::Timer::PrivateImpl::stopTimer
virtual void stopTimer()=0
MonoThreadTimer::startTimer
bool startTimer() override
Definition: Timer.cpp:108
ThreadedTimer
Definition: Timer.cpp:269
yarp::os::Timer::PrivateImpl::startTimer
virtual bool startTimer()=0
MonoThreadTimer::m_active
bool m_active
Definition: Timer.cpp:99
yarp::os::Timer::PrivateImpl::m_settings
TimerSettings m_settings
Definition: Timer.cpp:68
ret
bool ret
Definition: ImplementAxisInfo.cpp:72
yarp::os::Timer::PrivateImpl::m_startStamp
double m_startStamp
Definition: Timer.cpp:70
MonoThreadTimer::stopTimer
void stopTimer() override
Definition: Timer.cpp:115
yarp::os::PeriodicThread::isRunning
bool isRunning() const
Returns true when the thread is started, false otherwise.
Definition: PeriodicThread.cpp:316
yarp::os::Time::now
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition: Time.cpp:124
TimerSingleton::addTimer
size_t addTimer(MonoThreadTimer *t)
Definition: Timer.cpp:178
yarp::os::YarpTimerEvent
Definition: Timer.h:27
MonoThreadTimer::stepTimer
bool stepTimer() override
Definition: Timer.cpp:120
yarp::os::Timer::start
virtual bool start()
Definition: Timer.cpp:354
MonoThreadTimer::getEventNow
virtual yarp::os::YarpTimerEvent getEventNow()
Definition: Timer.cpp:103
yarp::os::Timer::getSettings
const yarp::os::TimerSettings getSettings()
getSettings
Definition: Timer.cpp:441
MonoThreadTimer
Definition: Timer.cpp:82
ThreadedTimer::~ThreadedTimer
~ThreadedTimer() override
Definition: Timer.cpp:297
yarp::os::Timer::PrivateImpl
Definition: Timer.cpp:25
yarp::os::Timer::PrivateImpl::TimerCallback
yarp::os::Timer::TimerCallback TimerCallback
Definition: Timer.cpp:32
Timer.h
yarp::os::Timer::step
virtual bool step()
Definition: Timer.cpp:360
ThreadedTimer::ThreadedTimer
ThreadedTimer(const TimerSettings &sett, const TimerCallback &call, yarp::os::Mutex *mutex)
Definition: Timer.cpp:279
yarp::os::PeriodicThread::start
bool start()
Call this to start the thread.
Definition: PeriodicThread.cpp:311
yarp::os::Timer::PrivateImpl::m_callback
TimerCallback m_callback
Definition: Timer.cpp:69
yarp::os::PeriodicThread::setPeriod
bool setPeriod(double period)
Set the (new) period of the thread.
Definition: PeriodicThread.cpp:281
yarp::os::Timer::TimerCallback
std::function< bool(const yarp::os::YarpTimerEvent &)> TimerCallback
Definition: Timer.h:109
MonoThreadTimer::timerIsRunning
bool timerIsRunning() override
Definition: Timer.cpp:134
yarp::os::YarpTimerEvent::currentReal
double currentReal
currentReal When the current callback is actually being called
Definition: Timer.h:47
TimerSingleton::removeTimer
void removeTimer(size_t id)
Definition: Timer.cpp:192
yarp::os::PeriodicThread
An abstraction for a periodic thread.
Definition: PeriodicThread.h:25
yarp::os::Timer::~Timer
virtual ~Timer()
Definition: Timer.cpp:451
yarp::os::Timer::PrivateImpl::PrivateImpl
PrivateImpl(const TimerSettings &sett, TimerCallback call, std::mutex *mutex=nullptr)
Definition: Timer.cpp:48
yarp::os::Timer::PrivateImpl::m_old_mutex
yarp::os::Mutex * m_old_mutex
Definition: Timer.cpp:76
YARP_WARNING_POP
#define YARP_WARNING_POP
Ends a temporary alteration of the enabled warnings.
Definition: system.h:335
PeriodicThread.h
ThreadedTimer::stopTimer
void stopTimer() override
Definition: Timer.cpp:316
TimerSingleton::getTimerCount
size_t getTimerCount()
Definition: Timer.cpp:208
yarp::os::Timer::isRunning
virtual bool isRunning()
Definition: Timer.cpp:446
yarp::os::YarpTimerEvent::currentExpected
double currentExpected
currentExpected this is when the current callback should have been called
Definition: Timer.h:42
gcd
double gcd(double a, double b)
Definition: Timer.cpp:140
yarp::os::PeriodicThread::askToStop
void askToStop()
Stop the thread.
Definition: PeriodicThread.cpp:301
TimerSingleton::self
static TimerSingleton & self()
Definition: Timer.cpp:172
yarp::os
An interface to the operating system, including Port based communication.
Definition: AbstractCarrier.h:17
yarp::os::Timer::PrivateImpl::runTimer
bool runTimer(unsigned int iteration, YarpTimerEvent event)
Definition: Timer.cpp:383
yarp::os::Timer::PrivateImpl::m_lastReal
double m_lastReal
Definition: Timer.cpp:71
TimerSingleton
Definition: Timer.cpp:155
yarp::os::Timer::PrivateImpl::timerIsRunning
virtual bool timerIsRunning()=0
yarp::os::PeriodicThread::stop
void stop()
Call this to stop the thread, this call blocks until the thread is terminated (and releaseThread() ca...
Definition: PeriodicThread.cpp:296
Time.h
yarp::os::Mutex
Basic wrapper for mutual exclusion.
Definition: Mutex.h:35
yarp::os::PeriodicThread::step
void step()
Call this to "step" the thread rather than starting it.
Definition: PeriodicThread.cpp:306
yarp::os::TimerSettings
Definition: Timer.h:61
yarp::os::Timer::PrivateImpl::getEventNow
yarp::os::YarpTimerEvent getEventNow(unsigned int iteration)
Definition: Timer.cpp:370
YARP_DISABLE_DEPRECATED_WARNING
#define YARP_DISABLE_DEPRECATED_WARNING
Disable deprecated warnings in the following code.
Definition: system.h:336
ThreadedTimer::ThreadedTimer
ThreadedTimer(const TimerSettings &sett, const TimerCallback &call, std::mutex *mutex=nullptr)
Definition: Timer.cpp:289
yarp::os::Timer::PrivateImpl::m_mutex
std::mutex * m_mutex
Definition: Timer.cpp:72
MonoThreadTimer::~MonoThreadTimer
~MonoThreadTimer() override
Definition: Timer.cpp:243
ThreadedTimer::timerIsRunning
bool timerIsRunning() override
Definition: Timer.cpp:321
MonoThreadTimer::step
virtual bool step(YarpTimerEvent event, bool singleStep)
Definition: Timer.cpp:125