00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00038 #include "blocxx/BLOCXX_config.h"
00039 #include "blocxx/TimeoutTimer.hpp"
00040 #include "blocxx/DateTime.hpp"
00041 #include "blocxx/Infinity.hpp"
00042
00043 #include <limits>
00044
00045 namespace BLOCXX_NAMESPACE
00046 {
00047
00048 TimeoutTimer::TimeoutTimer(const Timeout& x)
00049 : m_timeout(x)
00050 , m_start(getCurrentTime())
00051 , m_loopTime(m_start)
00052 {
00053 }
00054
00055 TimeoutTimer::~TimeoutTimer()
00056 {
00057 }
00058
00059 void
00060 TimeoutTimer::start()
00061 {
00062 m_start = m_loopTime = getCurrentTime();
00063 }
00064
00065 void
00066 TimeoutTimer::resetOnLoop()
00067 {
00068 loop();
00069 if (m_timeout.getType() == Timeout::E_RELATIVE_WITH_RESET)
00070 {
00071 m_start = m_loopTime;
00072 }
00073 }
00074
00075 void
00076 TimeoutTimer::loop()
00077 {
00078 m_loopTime = getCurrentTime();
00079 }
00080
00081 namespace
00082 {
00083
00084 template <typename T, typename U>
00085 void safeAssign(T& x, U y)
00086 {
00087 if (y < (std::numeric_limits<T>::min)())
00088 {
00089 x = (std::numeric_limits<T>::min)();
00090 }
00091 else if (y > (std::numeric_limits<T>::max)())
00092 {
00093 x = (std::numeric_limits<T>::max)();
00094 }
00095 else
00096 {
00097 x = static_cast<T>(y + 0.5);
00098 }
00099 }
00100
00101 bool compareInterval(const DateTime& first, const DateTime& timeToTest, double seconds)
00102 {
00103
00104
00105 DateTime diff = timeToTest - first;
00106 double diff1 = diff.get() + diff.getMicrosecond() * 1e-6;
00107 return diff1 >= seconds;
00108 }
00109
00110 }
00111
00112 bool
00113 TimeoutTimer::expired() const
00114 {
00115 if (infinite())
00116 {
00117 return false;
00118 }
00119
00120 switch (m_timeout.getType())
00121 {
00122 case Timeout::E_ABSOLUTE:
00123 return m_loopTime >= m_timeout.getAbsolute();
00124
00125 case Timeout::E_RELATIVE:
00126 case Timeout::E_RELATIVE_WITH_RESET:
00127 return compareInterval(m_start, m_loopTime, m_timeout.getRelative());
00128 }
00129 return false;
00130 }
00131
00132 bool
00133 TimeoutTimer::infinite() const
00134 {
00135 return m_timeout == Timeout::infinite;
00136 }
00137
00138 #ifdef BLOCXX_HAVE_STRUCT_TIMEVAL
00139
00140 ::timeval*
00141 TimeoutTimer::asTimeval(::timeval& tv, double maxSeconds) const
00142 {
00143 if (infinite() && maxSeconds == INFINITY)
00144 {
00145 return 0;
00146 }
00147
00148 asTimeval(tv);
00149
00150
00151 ::timeval temp;
00152 safeAssign(temp.tv_sec, maxSeconds);
00153 double dummy;
00154 safeAssign(temp.tv_usec, modf(maxSeconds, &dummy) * 1e6);
00155 if (infinite() || temp.tv_sec < tv.tv_sec)
00156 {
00157 tv = temp;
00158 }
00159 else if (temp.tv_sec == tv.tv_sec && temp.tv_usec < tv.tv_usec)
00160 {
00161 tv.tv_usec = temp.tv_usec;
00162 }
00163
00164 return &tv;
00165 }
00166
00167
00168 ::timeval*
00169 TimeoutTimer::asTimeval(::timeval& tv) const
00170 {
00171 if (infinite())
00172 {
00173 return 0;
00174 }
00175
00176 if (m_timeout.getType() == Timeout::E_ABSOLUTE)
00177 {
00178
00179 DateTime timeoutTime = m_timeout.getAbsolute();
00180 if (timeoutTime > m_loopTime)
00181 {
00182 DateTime diff = m_timeout.getAbsolute() - m_loopTime;
00183 tv.tv_sec = diff.get();
00184 tv.tv_usec = diff.getMicrosecond();
00185 }
00186 else
00187 {
00188
00189 tv.tv_sec = 0;
00190 tv.tv_usec = 0;
00191 }
00192 }
00193 else
00194 {
00195 double timeTillExpiration = calcSeconds();
00196 safeAssign(tv.tv_sec, timeTillExpiration);
00197 double dummy;
00198 safeAssign(tv.tv_usec, modf(timeTillExpiration, &dummy) * 1e6);
00199 }
00200
00201
00202 return &tv;
00203 }
00204 #endif
00205
00206 Timeout
00207 TimeoutTimer::asTimeout() const
00208 {
00209 return m_timeout;
00210 }
00211
00212 double
00213 TimeoutTimer::calcSeconds() const
00214 {
00215
00216 double seconds;
00217 if (m_timeout.getType() == Timeout::E_ABSOLUTE)
00218 {
00219 DateTime diff = m_timeout.getAbsolute() - m_loopTime;
00220 seconds = static_cast<double>(diff.get()) + (static_cast<double>(diff.getMicrosecond()) / 1e6);
00221 }
00222 else
00223 {
00224
00225 double start = static_cast<double>(m_start.get()) + (static_cast<double>(m_start.getMicrosecond()) / 1e6);
00226 double loop = static_cast<double>(m_loopTime.get()) + (static_cast<double>(m_loopTime.getMicrosecond()) / 1e6);
00227 seconds = start + m_timeout.getRelative() - loop;
00228 }
00229 return seconds;
00230 }
00231
00232 double
00233 TimeoutTimer::calcSeconds(double maxSeconds) const
00234 {
00235 double seconds = calcSeconds();
00236 seconds = seconds > maxSeconds ? maxSeconds : seconds;
00237 return seconds;
00238 }
00239
00240 Timeout
00241 TimeoutTimer::asRelativeTimeout() const
00242 {
00243 return Timeout::relative(calcSeconds());
00244 }
00245
00246 Timeout
00247 TimeoutTimer::asRelativeTimeout(double maxSeconds) const
00248 {
00249 return Timeout::relative(calcSeconds(maxSeconds));
00250 }
00251
00252 Timeout
00253 TimeoutTimer::asAbsoluteTimeout() const
00254 {
00255
00256 if (infinite())
00257 {
00258 return m_timeout;
00259 }
00260 if (m_timeout.getType() == Timeout::E_ABSOLUTE)
00261 {
00262 return m_timeout;
00263 }
00264 else
00265 {
00266 const long MICROSECONDS_PER_SECOND = 1000000;
00267 DateTime endTime(m_start);
00268 time_t secs;
00269 safeAssign(secs, m_start.get() + static_cast<double>(m_timeout.getRelative()));
00270 UInt32 microSecs;
00271 double dummy;
00272 safeAssign(microSecs,
00273 m_start.getMicrosecond() +
00274 modf(m_timeout.getRelative(), &dummy) * MICROSECONDS_PER_SECOND);
00275
00276
00277 secs += microSecs / MICROSECONDS_PER_SECOND;
00278 microSecs = microSecs % MICROSECONDS_PER_SECOND;
00279
00280 return Timeout::absolute(DateTime(secs, microSecs));
00281 }
00282 }
00283
00284 #ifdef BLOCXX_WIN32
00285 DWORD
00286 TimeoutTimer::asDWORDMs() const
00287 {
00288 if (infinite())
00289 {
00290 return INFINITE;
00291 }
00292
00293 DWORD rval;
00294 safeAssign(rval, calcSeconds() * 1000.0);
00295 return rval;
00296 }
00297 #endif
00298
00299 int
00300 TimeoutTimer::asIntMs() const
00301 {
00302 if (infinite())
00303 {
00304 return -1;
00305 }
00306
00307 int rval;
00308 safeAssign(rval, calcSeconds() * 1000.0);
00309 return rval;
00310 }
00311
00312 int
00313 TimeoutTimer::asIntMs(double maxSeconds) const
00314 {
00315 if (infinite() && maxSeconds == INFINITY)
00316 {
00317 return -1;
00318 }
00319
00320 int rval;
00321 safeAssign(rval, calcSeconds(maxSeconds) * 1000.0);
00322 return rval;
00323 }
00324
00325 #ifdef BLOCXX_HAVE_STRUCT_TIMESPEC
00326 ::timespec*
00327 TimeoutTimer::asTimespec(::timespec& ts) const
00328 {
00329 const long NANOSECONDS_PER_MICROSECOND = 1000;
00330 const long NANOSECONDS_PER_MILLISECOND = 1000000;
00331 const long NANOSECONDS_PER_SECOND = 1000000000;
00332
00333 if (m_timeout.getType() == Timeout::E_ABSOLUTE)
00334 {
00335
00336 DateTime timeoutTime = m_timeout.getAbsolute();
00337 if (timeoutTime > m_loopTime)
00338 {
00339 ts.tv_sec = timeoutTime.get();
00340 ts.tv_nsec = timeoutTime.getMicrosecond() * NANOSECONDS_PER_MICROSECOND;
00341 }
00342 else
00343 {
00344
00345 ts.tv_sec = 0;
00346 ts.tv_nsec = 0;
00347 }
00348 }
00349 else
00350 {
00351 safeAssign(ts.tv_sec, m_start.get() + static_cast<double>(m_timeout.getRelative()));
00352 double dummy;
00353 safeAssign(ts.tv_nsec,
00354 static_cast<double>(m_start.getMicrosecond()) * NANOSECONDS_PER_MICROSECOND +
00355 modf(m_timeout.getRelative(), &dummy) * NANOSECONDS_PER_SECOND);
00356
00357
00358 ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
00359 ts.tv_nsec = ts.tv_nsec % NANOSECONDS_PER_SECOND;
00360 }
00361
00362 return &ts;
00363 }
00364 #endif
00365
00366 DateTime
00367 TimeoutTimer::getCurrentTime() const
00368 {
00369 return DateTime::getCurrent();
00370 }
00371
00372 }
00373
00374
00375
00376