Orocos Real-Time Toolkit
2.5.0
|
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 00044 namespace RTT { 00045 using namespace base; 00046 using namespace os; 00047 00048 bool Timer::initialize() { 00049 // only start if non periodic. 00050 return this->getThread()->getPeriod() == 0; 00051 } 00052 void Timer::finalize() {} 00053 00054 void Timer::step() { 00055 // no implementation for periodic execution. 00056 } 00057 00058 void Timer::loop() 00059 { 00060 // This code is executed from mThread's thread 00061 while (!mdo_quit) { 00062 Time wake_up_time; 00063 TimerId next_timer_id = 0; 00064 00065 // Select next timer. 00066 {// This scope is for MutexLock. 00067 // find wake_up_time 00068 // check timers queue. 00069 MutexLock locker(m); 00070 // We can't use infinite as the OS may internally use time_spec, which can not 00071 // represent as much in the future (until 2038) // XXX Year-2038 Bug 00072 wake_up_time = (TimeService::InfiniteNSecs/4)-1; 00073 for (TimerIds::iterator it = mtimers.begin(); it != mtimers.end(); ++it) { 00074 if ( it->first != 0 && it->first < wake_up_time ) { 00075 wake_up_time = it->first; 00076 next_timer_id = it - mtimers.begin(); 00077 } 00078 } 00079 }// MutexLock 00080 00081 // Wait 00082 int ret = 0; 00083 if ( wake_up_time > mTimeserv->getNSecs() ) 00084 ret = msem.waitUntil( wake_up_time ); // case of no timers or running timers 00085 else 00086 ret = -1; // case of timer overrun. 00087 00088 // Timeout handling 00089 if (ret == -1) { 00090 // a timer expired 00091 // First: reset/reprogram the timer that expired: 00092 { 00093 MutexLock locker(m); 00094 // detect corner case for resize: 00095 if ( next_timer_id < int(mtimers.size()) ) { 00096 // now clear or reprogram it. 00097 TimerIds::iterator tim = mtimers.begin() + next_timer_id; 00098 if ( tim->second ) { 00099 // periodic timer 00100 tim->first += tim->second; 00101 } else { 00102 // aperiodic timer 00103 tim->first = 0; 00104 } 00105 } 00106 } 00107 // Second: send the timeout signal and allow (within the callback) 00108 // to reprogram the timer. 00109 // If we would first call timeout(), the code above would overwrite 00110 // user settings. 00111 timeout( next_timer_id ); 00112 } 00113 } 00114 } 00115 00116 bool Timer::breakLoop() 00117 { 00118 mdo_quit = true; 00119 msem.signal(); 00120 return true; 00121 } 00122 00123 Timer::Timer(TimerId max_timers, int scheduler, int priority) 00124 : mThread(0), msem(0), mdo_quit(false) 00125 { 00126 mTimeserv = TimeService::Instance(); 00127 mtimers.resize(max_timers); 00128 if (scheduler != -1) { 00129 mThread = new Activity(scheduler, priority, 0.0, this, "Timer"); 00130 mThread->start(); 00131 } 00132 } 00133 00134 Timer::~Timer() 00135 { 00136 delete mThread; 00137 } 00138 00139 00140 void Timer::timeout(TimerId timer_id) 00141 { 00142 // User must implement this method. 00143 } 00144 00145 void Timer::setMaxTimers(TimerId max) 00146 { 00147 MutexLock locker(m); 00148 mtimers.resize(max, std::make_pair(Time(0), Time(0)) ); 00149 } 00150 00151 bool Timer::startTimer(TimerId timer_id, double period) 00152 { 00153 if ( timer_id < 0 || timer_id > int(mtimers.size()) || period < 0.0) 00154 { 00155 log(Error) << "Invalid timer id or period" << endlog(); 00156 return false; 00157 } 00158 00159 Time due_time = mTimeserv->getNSecs() + Seconds_to_nsecs( period ); 00160 00161 { 00162 MutexLock locker(m); 00163 mtimers[timer_id].first = due_time; 00164 mtimers[timer_id].second = Seconds_to_nsecs( period ); 00165 } 00166 msem.signal(); 00167 return true; 00168 } 00169 00170 bool Timer::arm(TimerId timer_id, double wait_time) 00171 { 00172 if ( timer_id < 0 || timer_id > int(mtimers.size()) || wait_time < 0.0) 00173 { 00174 log(Error) << "Invalid timer id or wait time" << endlog(); 00175 return false; 00176 } 00177 00178 Time now = mTimeserv->getNSecs(); 00179 Time due_time = now + Seconds_to_nsecs( wait_time ); 00180 00181 { 00182 MutexLock locker(m); 00183 mtimers[timer_id].first = due_time; 00184 mtimers[timer_id].second = 0; 00185 } 00186 msem.signal(); 00187 return true; 00188 } 00189 00190 bool Timer::isArmed(TimerId timer_id) const 00191 { 00192 MutexLock locker(m); 00193 if (timer_id < 0 || timer_id > int(mtimers.size()) ) 00194 { 00195 log(Error) << "Invalid timer id" << endlog(); 00196 return false; 00197 } 00198 return mtimers[timer_id].first != 0; 00199 } 00200 00201 double Timer::timeRemaining(TimerId timer_id) const 00202 { 00203 MutexLock locker(m); 00204 if (timer_id < 0 || timer_id > int(mtimers.size()) ) 00205 { 00206 log(Error) << "Invalid timer id" << endlog(); 00207 return 0.0; 00208 } 00209 Time now = mTimeserv->getNSecs(); 00210 Time result = mtimers[timer_id].first - now; 00211 // detect corner cases. 00212 if ( result < 0 ) 00213 return 0.0; 00214 return nsecs_to_Seconds( result ); 00215 } 00216 00217 bool Timer::killTimer(TimerId timer_id) 00218 { 00219 MutexLock locker(m); 00220 if (timer_id < 0 || timer_id > int(mtimers.size()) ) 00221 { 00222 log(Error) << "Invalid timer id" << endlog(); 00223 return false; 00224 } 00225 mtimers[timer_id].first = 0; 00226 mtimers[timer_id].second = 0; 00227 return true; 00228 } 00229 00230 00231 00232 }