YARP
Yet Another Robot Platform
 
Loading...
Searching...
No Matches
Timer.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2006-2021 Istituto Italiano di Tecnologia (IIT)
3 * SPDX-License-Identifier: BSD-3-Clause
4 */
5
6#include <yarp/os/Timer.h>
7
9#include <yarp/os/Time.h>
10
11#include <cmath>
12#include <map>
13#include <mutex>
14#include <utility>
15
16using namespace yarp::os;
17
18//disclaimer: the following inheritance little madness is for avoiding critical copy and paste code and
19//avoiding data inconsistence(example: RateThread::GetIterations() and runTimes)
20
22{
23protected:
25
26 bool runTimer(unsigned int iteration, YarpTimerEvent event);
27
28public:
30
32 TimerCallback call,
33 std::mutex* mutex = nullptr) :
35 m_callback(std::move(call)),
36 m_mutex(mutex)
37 {
38 }
39
40 virtual ~PrivateImpl() = default;
41
42 virtual bool startTimer() = 0;
43
44 virtual void stopTimer() = 0;
45
46 virtual bool stepTimer() = 0;
47
48 virtual bool timerIsRunning() = 0;
49
50
53 double m_startStamp{0.0};
54 double m_lastReal{0.0};
55 std::mutex* m_mutex{nullptr};
56};
57
59{
60public:
61
63 const TimerCallback& call,
64 std::mutex* mutex = nullptr);
65
66 ~MonoThreadTimer() override;
67 bool m_active{false};
68 unsigned int m_runTimes{1};
69 size_t m_id{(size_t)-1};
70
72 {
73 return PrivateImpl::getEventNow(m_runTimes);
74 }
75
76 bool startTimer() override
77 {
79 m_active = true;
80 return true;
81 }
82
83 void stopTimer() override
84 {
85 m_active = false;
86 }
87
88 bool stepTimer() override
89 {
90 return step(getEventNow(), true);
91 }
92
93 virtual bool step(YarpTimerEvent event, bool singleStep)
94 {
95 bool m_active = runTimer(m_runTimes, event);
96 if (!singleStep) {
97 m_runTimes++;
98 }
99 return m_active;
100 }
101
102 bool timerIsRunning() override
103 {
104 return m_active;
105 }
106};
107
108double gcd(double a, double b)
109{
110 if (a < b) {
111 return gcd(b, a);
112 }
113
114 // base case
115 if (fabs(b) < 0.001) {
116 return a;
117 } else {
118 return (gcd(b, a - floor(a / b) * b));
119 }
120}
121
123{
124 std::mutex mu;
125 std::map<size_t, MonoThreadTimer*> timers;
128 {
129 }
130
131 void run() override;
132
133 ~TimerSingleton() override
134 {
135 stop();
136 }
137
138public:
139 //reminder: int c++11 static variables'inside function are guaranteed to be lazy initialized and atomic
141 {
142 static TimerSingleton instance;
143 return instance;
144 }
145
147 {
148 if (timers.size()) {
150 } else {
152 }
153 mu.lock();
154 timers[timers.size()] = t;
155 mu.unlock();
156
157 return timers.size() - 1;
158 }
159
160 void removeTimer(size_t id)
161 {
162 mu.lock();
163 timers.erase(id);
164 mu.unlock();
165 if (!timers.size()) {
166 return;
167 }
168
169 double new_gcd = timers.begin()->second->m_settings.period;
170 for (auto& i : timers) {
171 new_gcd = gcd(new_gcd, i.second->m_settings.period);
172 }
174 }
175
177 {
178 return timers.size();
179 }
180};
181
183 const TimerCallback& call,
184 std::mutex* mutex) :
185 PrivateImpl(sett, call, mutex)
186{
188 m_id = singlInstance.addTimer(this);
189 if (!singlInstance.isRunning()) {
190 singlInstance.start();
191 }
192}
193
195{
197 singlInstance.removeTimer(m_id);
198 if (singlInstance.getTimerCount() == 0) {
199 singlInstance.stop();
200 }
201}
202
203void TimerSingleton::run()
204{
205 mu.lock();
206 for (auto t : timers) {
207 MonoThreadTimer& timer = *t.second;
208 YarpTimerEvent tEvent = timer.getEventNow();
209 if (timer.m_active && tEvent.currentReal > tEvent.currentExpected) {
210 timer.m_active = timer.step(tEvent, false);
211 timer.m_lastReal = tEvent.currentReal;
212 }
213 }
214 mu.unlock();
215}
216
220{
221 using TimerCallback = yarp::os::Timer::TimerCallback;
222 void run() override;
223 bool threadInit() override;
224 bool singleStep{false};
225
226public:
228 const TimerCallback& call,
229 std::mutex* mutex = nullptr) :
230 PrivateImpl(sett, call, mutex),
231 PeriodicThread(sett.period)
232 {
233 }
234
235 ~ThreadedTimer() override
236 {
237 stop();
238 }
239
240 bool startTimer() override
241 {
244 return start();
245 }
246
247 bool stepTimer() override
248 {
249 singleStep = true;
250 step();
251 return true;
252 }
253
254 void stopTimer() override
255 {
256 return askToStop();
257 }
258
259 bool timerIsRunning() override
260 {
261 return isRunning();
262 }
263};
264
265bool ThreadedTimer::threadInit()
266{
268 return true;
269}
270
271//the newThread parameter is not in the settings for it to be unmutable and only checked by the constructor
272Timer::Timer(const TimerSettings& settings, const TimerCallback& callback, bool newThread, std::mutex* mutex) :
273 //added cast for incompatible operand error
274 impl(newThread ? dynamic_cast<PrivateImpl*>(new ThreadedTimer(settings, callback, mutex))
275 : dynamic_cast<PrivateImpl*>(new MonoThreadTimer(settings, callback, mutex)))
276{
277}
278
280{
281
282 return impl->startTimer();
283}
284
286{
287 return impl->stepTimer();
288}
289
291{
292 impl->stopTimer();
293}
294
296{
297 YarpTimerEvent event;
298
300 event.currentExpected = m_startStamp + iteration * m_settings.period;
301 event.lastExpected = event.currentExpected - m_settings.period;
302 event.lastReal = m_lastReal;
303 event.lastDuration = event.currentReal - m_lastReal;
304 event.runCount = iteration;
305 return event;
306}
307
309{
310 if (m_mutex != nullptr) {
311 m_mutex->lock();
312 }
313
314 bool ret = m_callback(event);
315
316 if (m_mutex != nullptr) {
317 m_mutex->unlock();
318 }
319
320 if (!ret) {
321 return false;
322 }
323
324 m_lastReal = event.currentReal;
325
326 double timerAge = (yarp::os::Time::now() - m_startStamp);
327
328 //totalRunCount == 0 ----> infinite run count. follows the run count of the timer
329 bool stop(m_settings.totalRunCount != 0 && m_settings.totalRunCount <= iteration);
330
331 //totalTime == 0 ----> infinite time. follows the age check for the timer
332 stop |= m_settings.totalTime > 0.00001 && (m_settings.totalTime - timerAge) < m_settings.tolerance;
333
334 return !stop;
335}
336
337void ThreadedTimer::run()
338{
339 if (getIterations() == 0 && !singleStep) {
340 return;
341 }
342 singleStep = false;
343 YarpTimerEvent event = getEventNow(this->getIterations());
344 if (!runTimer(this->getIterations(), event)) {
345 askToStop();
346 }
347}
348
350{
351 impl->m_settings = settings;
352}
353
355{
356 return impl->m_settings;
357}
358
360{
361 return impl->timerIsRunning();
362}
363
365{
366 delete impl;
367}
size_t size_t
bool ret
double gcd(double a, double b)
Definition Timer.cpp:108
void stopTimer() override
Definition Timer.cpp:83
~MonoThreadTimer() override
Definition Timer.cpp:194
virtual yarp::os::YarpTimerEvent getEventNow()
Definition Timer.cpp:71
bool stepTimer() override
Definition Timer.cpp:88
size_t m_id
Definition Timer.cpp:69
MonoThreadTimer(const TimerSettings &sett, const TimerCallback &call, std::mutex *mutex=nullptr)
Definition Timer.cpp:182
virtual bool step(YarpTimerEvent event, bool singleStep)
Definition Timer.cpp:93
unsigned int m_runTimes
Definition Timer.cpp:68
bool startTimer() override
Definition Timer.cpp:76
bool timerIsRunning() override
Definition Timer.cpp:102
void stopTimer() override
Definition Timer.cpp:254
ThreadedTimer(const TimerSettings &sett, const TimerCallback &call, std::mutex *mutex=nullptr)
Definition Timer.cpp:227
bool stepTimer() override
Definition Timer.cpp:247
~ThreadedTimer() override
Definition Timer.cpp:235
bool startTimer() override
Definition Timer.cpp:240
bool timerIsRunning() override
Definition Timer.cpp:259
static TimerSingleton & self()
Definition Timer.cpp:140
void removeTimer(size_t id)
Definition Timer.cpp:160
size_t addTimer(MonoThreadTimer *t)
Definition Timer.cpp:146
size_t getTimerCount()
Definition Timer.cpp:176
A mini-server for performing network communication in the background.
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.
double getPeriod() const
Return the current period of the thread.
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:52
yarp::os::YarpTimerEvent getEventNow(unsigned int iteration)
Definition Timer.cpp:295
virtual bool startTimer()=0
bool runTimer(unsigned int iteration, YarpTimerEvent event)
Definition Timer.cpp:308
PrivateImpl(const TimerSettings &sett, TimerCallback call, std::mutex *mutex=nullptr)
Definition Timer.cpp:31
virtual ~PrivateImpl()=default
virtual void stopTimer()=0
virtual bool timerIsRunning()=0
TimerSettings m_settings
Definition Timer.cpp:51
virtual bool stepTimer()=0
yarp::os::Timer::TimerCallback TimerCallback
Definition Timer.cpp:29
virtual ~Timer()
Definition Timer.cpp:364
void setSettings(const yarp::os::TimerSettings &settings)
setSettings
Definition Timer.cpp:349
virtual bool isRunning()
Definition Timer.cpp:359
virtual bool start()
Definition Timer.cpp:279
virtual void stop()
Definition Timer.cpp:290
const yarp::os::TimerSettings getSettings()
getSettings
Definition Timer.cpp:354
virtual bool step()
Definition Timer.cpp:285
Timer(const Timer &)=delete
std::function< bool(const yarp::os::YarpTimerEvent &)> TimerCallback
Definition Timer.h:99
STL namespace.
double now()
Return the current time in seconds, relative to an arbitrary starting point.
Definition Time.cpp:121
An interface to the operating system, including Port based communication.
double currentReal
currentReal When the current callback is actually being called
Definition Timer.h:37