Timer.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002   tag: FMTC  Tue Mar 11 21:49:25 CET 2008  Timer.cpp
00003 
00004                         Timer.cpp -  description
00005                            -------------------
00006     begin                : Tue March 11 2008
00007     copyright            : (C) 2008 FMTC
00008     email                : peter.soetens@fmtc.be
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037 
00038 
00039 #include "Timer.hpp"
00040 #include "MutexLock.hpp"
00041 #include "../Activity.hpp"
00042 #include "../Logger.hpp"
00043 #include "../os/fosi.h"
00044 #include <limits>
00045 
00046 namespace RTT {
00047     using namespace base;
00048     using namespace os;
00049 
00050     bool Timer::initialize() {
00051         mdo_quit = false;
00052         // only start if non periodic.
00053         return this->getThread()->getPeriod() == 0;
00054     }
00055     void Timer::finalize() {}
00056 
00057     void Timer::step() {
00058         // no implementation for periodic execution.
00059     }
00060 
00061     void Timer::loop()
00062     {
00063         // This code is executed from mThread's thread
00064         while (!mdo_quit) {
00065             Time wake_up_time;
00066             TimerId next_timer_id = 0;
00067 
00068             // Select next timer.
00069             {// This scope is for MutexLock.
00070                 // find wake_up_time
00071                 // check timers queue.
00072                 MutexLock locker(m);
00073                 // We can't use infinite as the OS may internally use time_spec, which can not
00074                 // represent as much in the future (until 2038) // XXX Year-2038 Bug
00075                 wake_up_time = 1000000000LL * std::numeric_limits<int32_t>::max();
00076                 for (TimerIds::iterator it = mtimers.begin(); it != mtimers.end(); ++it) {
00077                     if ( it->expires != 0 && it->expires < wake_up_time  ) {
00078                         wake_up_time = it->expires;
00079                         next_timer_id = it - mtimers.begin();
00080                     }
00081                 }
00082             }// MutexLock
00083 
00084             // Wait
00085             int ret = 0;
00086             Time now = rtos_get_time_ns();
00087             if ( wake_up_time > now )
00088                 ret = msem.waitUntil( wake_up_time ); // case of no timers or running timers
00089             else
00090                 ret = -1; // case of timer overrun.
00091 
00092             // Timeout handling
00093             if (ret == -1) {
00094                 // a timer expired
00095                 // expires: reset/reprogram the timer that expired:
00096                 {
00097                     MutexLock locker(m);
00098                     // detect corner case for resize:
00099                     if ( next_timer_id < int(mtimers.size()) ) {
00100                         // now clear or reprogram it.
00101                         TimerIds::iterator tim = mtimers.begin() + next_timer_id;
00102                         if ( tim->period ) {
00103                             // periodic timer
00104                             // if late by more than 4 periods, skip late updates
00105                             int maxDelayInPeriods = 4;
00106                             if (now - tim->expires > tim->period*maxDelayInPeriods) {
00107                                 tim->expires += tim->period*((now - tim->expires) / tim->period);
00108                             }
00109                             tim->expires += tim->period;
00110                         } else {
00111                             // aperiodic timer
00112                             tim->expires = 0;
00113                         }
00114                     }
00115                 }
00116 
00117                 // Second: notify waiting threads
00118                 {// This scope is for MutexLock.
00119                     MutexLock locker(m);
00120                     mtimers[next_timer_id].expired.broadcast();
00121                 }// MutexLock
00122 
00123                 // Third: send the timeout signal and allow (within the callback)
00124                 // to reprogram the timer.
00125                 // If we would expires call timeout(), the code above would overwrite
00126                 // user settings.
00127                 timeout( next_timer_id );
00128             }
00129         }
00130     }
00131 
00132     bool Timer::breakLoop()
00133     {
00134         mdo_quit = true;
00135         msem.signal();
00136         // kill all timers to abort all threads blocking in waitFor()
00137         for (TimerId i = 0; i < (int) mtimers.size(); ++i) {
00138             killTimer(i);
00139         }
00140         return true;
00141     }
00142 
00143     Timer::Timer(TimerId max_timers, int scheduler, int priority)
00144         : mThread(0), msem(0), mdo_quit(false)
00145     {
00146         mtimers.resize(max_timers);
00147         if (scheduler != -1) {
00148             mThread = new Activity(scheduler, priority, 0.0, this, "Timer");
00149             mThread->start();
00150         }
00151     }
00152 
00153     Timer::~Timer()
00154     {
00155         delete mThread;
00156     }
00157 
00158 
00159     void Timer::timeout(TimerId timer_id)
00160     {
00161         // User must implement this method.
00162     }
00163 
00164     void Timer::setMaxTimers(TimerId max)
00165     {
00166         MutexLock locker(m);
00167         mtimers.resize(max, TimerInfo() );
00168     }
00169 
00170     bool Timer::startTimer(TimerId timer_id, double period)
00171     {
00172         if ( timer_id < 0 || timer_id >= int(mtimers.size()) || period < 0.0)
00173         {
00174             log(Error) << "Invalid timer id or period" << endlog();
00175             return false;
00176         }
00177 
00178         Time due_time = rtos_get_time_ns() + Seconds_to_nsecs( period );
00179 
00180         {
00181             MutexLock locker(m);
00182             mtimers[timer_id].expires = due_time;
00183             mtimers[timer_id].period = Seconds_to_nsecs( period );
00184         }
00185         msem.signal();
00186         return true;
00187     }
00188 
00189     bool Timer::arm(TimerId timer_id, double wait_time)
00190     {
00191         if ( timer_id < 0 || timer_id >= int(mtimers.size()) || wait_time < 0.0)
00192         {
00193             log(Error) << "Invalid timer id or wait time" << endlog();
00194             return false;
00195         }
00196 
00197         Time now = rtos_get_time_ns();
00198         Time due_time = now + Seconds_to_nsecs( wait_time );
00199 
00200         {
00201             MutexLock locker(m);
00202             mtimers[timer_id].expires  = due_time;
00203             mtimers[timer_id].period = 0;
00204         }
00205         msem.signal();
00206         return true;
00207     }
00208 
00209     bool Timer::isArmed(TimerId timer_id) const
00210     {
00211         MutexLock locker(m);
00212         if (timer_id < 0 || timer_id >= int(mtimers.size()) )
00213         {
00214             log(Error) << "Invalid timer id" << endlog();
00215             return false;
00216         }
00217         return mtimers[timer_id].expires != 0;
00218     }
00219 
00220     double Timer::timeRemaining(TimerId timer_id) const
00221     {
00222         MutexLock locker(m);
00223         if (timer_id < 0 || timer_id >= int(mtimers.size()) )
00224         {
00225             log(Error) << "Invalid timer id" << endlog();
00226             return 0.0;
00227         }
00228         Time now = rtos_get_time_ns();
00229         Time result = mtimers[timer_id].expires - now;
00230         // detect corner cases.
00231         if ( result < 0 )
00232             return 0.0;
00233         return nsecs_to_Seconds( result );
00234     }
00235 
00236     bool Timer::killTimer(TimerId timer_id)
00237     {
00238         MutexLock locker(m);
00239         if (timer_id < 0 || timer_id >= int(mtimers.size()) )
00240         {
00241             log(Error) << "Invalid timer id" << endlog();
00242             return false;
00243         }
00244         mtimers[timer_id].expires = 0;
00245         mtimers[timer_id].period = 0;
00246         mtimers[timer_id].expired.broadcast();
00247         return true;
00248     }
00249 
00250     bool Timer::waitFor(TimerId timer_id)
00251     {
00252         MutexLock locker(m);
00253         if (timer_id < 0 || timer_id >= int(mtimers.size()) )
00254         {
00255             log(Error) << "Invalid timer id" << endlog();
00256             return false;
00257         }
00258         if (mtimers[timer_id].expires == 0) return false;
00259 
00260         return mtimers[timer_id].expired.wait(m);
00261     }
00262 
00263     bool Timer::waitForUntil(TimerId timer_id, nsecs abs_time)
00264     {
00265         MutexLock locker(m);
00266         if (timer_id < 0 || timer_id >= int(mtimers.size()) )
00267         {
00268             log(Error) << "Invalid timer id" << endlog();
00269             return false;
00270         }
00271         if (mtimers[timer_id].expires == 0) return false;
00272 
00273         return mtimers[timer_id].expired.wait_until(m, abs_time);
00274     }
00275 
00276 
00277 
00278 }


rtt
Author(s): RTT Developers
autogenerated on Sat Jun 8 2019 18:46:33