Orocos Real-Time Toolkit  2.8.3
Timer.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: FMTC Tue Mar 11 21:49:25 CET 2008 Timer.cpp
3 
4  Timer.cpp - description
5  -------------------
6  begin : Tue March 11 2008
7  copyright : (C) 2008 FMTC
8  email : peter.soetens@fmtc.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * Lesser General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 
39 #include "Timer.hpp"
40 #include "MutexLock.hpp"
41 #include "../Activity.hpp"
42 #include "../Logger.hpp"
43 #include "../os/fosi.h"
44 #include <limits>
45 
46 namespace RTT {
47  using namespace base;
48  using namespace os;
49 
51  mdo_quit = false;
52  // only start if non periodic.
53  return this->getThread()->getPeriod() == 0;
54  }
55  void Timer::finalize() {}
56 
57  void Timer::step() {
58  // no implementation for periodic execution.
59  }
60 
61  void Timer::loop()
62  {
63  // This code is executed from mThread's thread
64  while (!mdo_quit) {
65  Time wake_up_time;
66  TimerId next_timer_id = 0;
67 
68  // Select next timer.
69  int ret = 0;
70  {// This scope is for MutexLock.
71  // find wake_up_time
72  // check timers queue.
73  MutexLock locker(mmutex);
74  wake_up_time = std::numeric_limits<Time>::max();
75  for (TimerIds::iterator it = mtimers.begin(); it != mtimers.end(); ++it) {
76  if ( it->expires != 0 && it->expires < wake_up_time ) {
77  wake_up_time = it->expires;
78  next_timer_id = it - mtimers.begin();
79  }
80  }
81 
82  // Wait
83  if ( wake_up_time == std::numeric_limits<Time>::max() )
84  ret = mcond.wait( mmutex ); // case of no timers
85  else if ( wake_up_time > rtos_get_time_ns() )
86  ret = mcond.wait_until( mmutex, wake_up_time ); // case of running timers
87  else
88  ret = -1; // case of timer overrun.
89  }// MutexLock
90 
91  // Timeout handling
92  if (ret == -1) {
93  // a timer expired
94  // expires: reset/reprogram the timer that expired:
95  {
96  MutexLock locker(mmutex);
97  // detect corner case for resize:
98  if ( next_timer_id < int(mtimers.size()) ) {
99  // now clear or reprogram it.
100  TimerIds::iterator tim = mtimers.begin() + next_timer_id;
101  if ( tim->period ) {
102  // periodic timer
103  tim->expires += tim->period;
104  } else {
105  // aperiodic timer
106  tim->expires = 0;
107  }
108  }
109  }
110 
111  // Second: notify waiting threads
112  {// This scope is for MutexLock.
113  MutexLock locker(mmutex);
114  mtimers[next_timer_id].expired.broadcast();
115  }// MutexLock
116 
117  // Third: send the timeout signal and allow (within the callback)
118  // to reprogram the timer.
119  // If we would expires call timeout(), the code above would overwrite
120  // user settings.
121  timeout( next_timer_id );
122  }
123  }
124  }
125 
127  {
128  mdo_quit = true;
129  mcond.broadcast();
130  // kill all timers to abort all threads blocking in waitFor()
131  for (TimerId i = 0; i < (int) mtimers.size(); ++i) {
132  killTimer(i);
133  }
134  return true;
135  }
136 
137  Timer::Timer(TimerId max_timers, int scheduler, int priority)
138  : mThread(0), mdo_quit(false)
139  {
140  mtimers.resize(max_timers);
141  if (scheduler != -1) {
142  mThread = new Activity(scheduler, priority, 0.0, this, "Timer");
143  mThread->start();
144  }
145  }
146 
148  {
149  delete mThread;
150  }
151 
152 
153  void Timer::timeout(TimerId timer_id)
154  {
155  // User must implement this method.
156  }
157 
159  {
160  MutexLock locker(mmutex);
161  mtimers.resize(max, TimerInfo() );
162  }
163 
164  bool Timer::startTimer(TimerId timer_id, double period)
165  {
166  if ( timer_id < 0 || timer_id >= int(mtimers.size()) || period < 0.0)
167  {
168  log(Error) << "Invalid timer id or period" << endlog();
169  return false;
170  }
171 
172  Time due_time = rtos_get_time_ns() + Seconds_to_nsecs( period );
173 
174  {
175  MutexLock locker(mmutex);
176  mtimers[timer_id].expires = due_time;
177  mtimers[timer_id].period = Seconds_to_nsecs( period );
178  }
179  mcond.broadcast();
180  return true;
181  }
182 
183  bool Timer::arm(TimerId timer_id, double wait_time)
184  {
185  if ( timer_id < 0 || timer_id >= int(mtimers.size()) || wait_time < 0.0)
186  {
187  log(Error) << "Invalid timer id or wait time" << endlog();
188  return false;
189  }
190 
191  Time now = rtos_get_time_ns();
192  Time due_time = now + Seconds_to_nsecs( wait_time );
193 
194  {
195  MutexLock locker(mmutex);
196  mtimers[timer_id].expires = due_time;
197  mtimers[timer_id].period = 0;
198  }
199  mcond.broadcast();
200  return true;
201  }
202 
203  bool Timer::isArmed(TimerId timer_id) const
204  {
205  MutexLock locker(mmutex);
206  if (timer_id < 0 || timer_id >= int(mtimers.size()) )
207  {
208  log(Error) << "Invalid timer id" << endlog();
209  return false;
210  }
211  return mtimers[timer_id].expires != 0;
212  }
213 
214  double Timer::timeRemaining(TimerId timer_id) const
215  {
216  MutexLock locker(mmutex);
217  if (timer_id < 0 || timer_id >= int(mtimers.size()) )
218  {
219  log(Error) << "Invalid timer id" << endlog();
220  return 0.0;
221  }
222  Time now = rtos_get_time_ns();
223  Time result = mtimers[timer_id].expires - now;
224  // detect corner cases.
225  if ( result < 0 )
226  return 0.0;
227  return nsecs_to_Seconds( result );
228  }
229 
230  bool Timer::killTimer(TimerId timer_id)
231  {
232  MutexLock locker(mmutex);
233  if (timer_id < 0 || timer_id >= int(mtimers.size()) )
234  {
235  log(Error) << "Invalid timer id" << endlog();
236  return false;
237  }
238  mtimers[timer_id].expires = 0;
239  mtimers[timer_id].period = 0;
240  mtimers[timer_id].expired.broadcast();
241  return true;
242  }
243 
244  bool Timer::waitFor(TimerId timer_id)
245  {
246  MutexLock locker(mmutex);
247  if (timer_id < 0 || timer_id >= int(mtimers.size()) )
248  {
249  log(Error) << "Invalid timer id" << endlog();
250  return false;
251  }
252  if (mtimers[timer_id].expires == 0) return false;
253 
254  return mtimers[timer_id].expired.wait(mmutex);
255  }
256 
257  bool Timer::waitForUntil(TimerId timer_id, nsecs abs_time)
258  {
259  MutexLock locker(mmutex);
260  if (timer_id < 0 || timer_id >= int(mtimers.size()) )
261  {
262  log(Error) << "Invalid timer id" << endlog();
263  return false;
264  }
265  if (mtimers[timer_id].expires == 0) return false;
266 
267  return mtimers[timer_id].expired.wait_until(mmutex, abs_time);
268  }
269 }
void finalize()
The method that will be called after the last periodical execution of step() ( or non periodical exec...
Definition: Timer.cpp:55
bool initialize()
The method that will be called before the first periodical execution of step() ( or non periodical ex...
Definition: Timer.cpp:50
TimeService::Seconds timeRemaining(TimerId timer_id) const
Returns the remaining time before this timer elapses.
Definition: Timer.cpp:214
Condition mcond
Definition: Timer.hpp:77
bool startTimer(TimerId timer_id, Seconds period)
Start a periodic timer which starts first over period seconds and then every period seconds...
Definition: Timer.cpp:164
bool breakLoop()
This method is called by the framework to break out of the loop() method.
Definition: Timer.cpp:126
Seconds nsecs_to_Seconds(const nsecs ns)
Definition: Time.hpp:108
NANO_TIME rtos_get_time_ns(void)
Get "system" time in nanoseconds.
Definition: fosi.h:113
bool killTimer(TimerId timer_id)
Disable an armed timer.
Definition: Timer.cpp:230
base::ActivityInterface * mThread
Definition: Timer.hpp:76
int TimerId
A positive numeric ID representing a timer.
Definition: Timer.hpp:74
bool isArmed(TimerId timer_id) const
Check if a given timer id is armed.
Definition: Timer.cpp:203
bool arm(TimerId timer_id, Seconds wait_time)
Arm a timer to fire once over wait_time seconds.
Definition: Timer.cpp:183
TimeService::nsecs Time
Definition: Timer.hpp:79
void step()
The method that will be periodically executed when this class is run in a periodic thread...
Definition: Timer.cpp:57
void setMaxTimers(TimerId max)
Change the maximum number of timers in this object.
Definition: Timer.cpp:158
Timer(TimerId max_timers, int scheduler=-1, int priority=0)
Create a timer object which can hold max_timers timers.
Definition: Timer.cpp:137
TimerIds mtimers
Definition: Timer.hpp:97
An Activity is an object that represents a thread.
Definition: Activity.hpp:63
bool waitForUntil(RTT::os::Timer::TimerId id, nsecs abs_time)
Wait for a timer to expire with timeout.
Definition: Timer.cpp:257
void loop()
The method that will be executed once when this class is run in a non periodic thread.
Definition: Timer.cpp:61
Mutex mmutex
Definition: Timer.hpp:78
nsecs Seconds_to_nsecs(const Seconds s)
Definition: Time.hpp:107
virtual bool start()=0
Start the activity.
bool waitFor(RTT::os::Timer::TimerId id)
Wait for a timer to expire.
Definition: Timer.cpp:244
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:51
long long nsecs
nanoseconds as a signed long long.
Definition: Time.hpp:69
virtual void timeout(TimerId timer_id)
This function is called each time an armed or periodic timer expires.
Definition: Timer.cpp:153
void broadcast()
Wake all threads that are blocking in wait() or wait_until().
Definition: Condition.hpp:113
MutexLock is a scope based Monitor, protecting critical sections with a Mutex object through locking ...
Definition: MutexLock.hpp:51