blocxx
TimeoutTimer.cpp
Go to the documentation of this file.
1/*******************************************************************************
2* Copyright (C) 2005, Vintela, Inc. All rights reserved.
3* Copyright (C) 2006, Novell, Inc. All rights reserved.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7*
8* * Redistributions of source code must retain the above copyright notice,
9* this list of conditions and the following disclaimer.
10* * Redistributions in binary form must reproduce the above copyright
11* notice, this list of conditions and the following disclaimer in the
12* documentation and/or other materials provided with the distribution.
13* * Neither the name of
14* Vintela, Inc.,
15* nor Novell, Inc.,
16* nor the names of its contributors or employees may be used to
17* endorse or promote products derived from this software without
18* specific prior written permission.
19*
20* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
24* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30* POSSIBILITY OF SUCH DAMAGE.
31*******************************************************************************/
32
33
37
38#include "blocxx/BLOCXX_config.h"
40#include "blocxx/DateTime.hpp"
41#include "blocxx/Infinity.hpp"
42
43#include <limits>
44
45namespace BLOCXX_NAMESPACE
46{
47
54
58
59void
64
65void
67{
68 loop();
70 {
72 }
73}
74
75void
80
81namespace
82{
83
84template <typename T, typename U>
85void safeAssign(T& x, U y)
86{
87 if (y < (std::numeric_limits<T>::min)())
88 {
89 x = (std::numeric_limits<T>::min)();
90 }
91 else if (y > (std::numeric_limits<T>::max)())
92 {
93 x = (std::numeric_limits<T>::max)();
94 }
95 else
96 {
97 x = static_cast<T>(y + 0.5); // we add 0.5 so the behavior is like rounding, instead of truncation.
98 }
99}
100
101bool compareInterval(const DateTime& first, const DateTime& timeToTest, double seconds)
102{
103 // Return first + seconds < timeToTest <==> timeToTest - first >= seconds.
104 // The latter form avoids overflow problems.
105 DateTime diff = timeToTest - first;
106 double diff1 = diff.get() + diff.getMicrosecond() * 1e-6;
107 return diff1 >= seconds;
108}
109
110} // end unnamed namespace
111
112bool
114{
115 if (infinite())
116 {
117 return false;
118 }
119
120 switch (m_timeout.getType())
121 {
123 return m_loopTime >= m_timeout.getAbsolute();
124
127 return compareInterval(m_start, m_loopTime, m_timeout.getRelative());
128 }
129 return false;
130}
131
132bool
134{
136}
137
138#ifdef BLOCXX_HAVE_STRUCT_TIMEVAL
139// return 0 for infinite, otherwise a pointer to tv
140::timeval*
141TimeoutTimer::asTimeval(::timeval& tv, double maxSeconds) const
142{
143 if (infinite() && maxSeconds == INFINITY)
144 {
145 return 0;
146 }
147
148 asTimeval(tv);
149
150 // check & enforce maxSeconds parameter
151 ::timeval temp;
152 safeAssign(temp.tv_sec, maxSeconds);
153 double dummy;
154 safeAssign(temp.tv_usec, modf(maxSeconds, &dummy) * 1e6);
155 if (infinite() || temp.tv_sec < tv.tv_sec)
156 {
157 tv = temp;
158 }
159 else if (temp.tv_sec == tv.tv_sec && temp.tv_usec < tv.tv_usec)
160 {
161 tv.tv_usec = temp.tv_usec;
162 }
163
164 return &tv;
165}
166
167// return 0 for infinite, otherwise a pointer to tv
168::timeval*
169TimeoutTimer::asTimeval(::timeval& tv) const
170{
171 if (infinite())
172 {
173 return 0;
174 }
175
176 if (m_timeout.getType() == Timeout::E_ABSOLUTE)
177 {
178 // convert the difference between the last loop and the absolute timeout into a timeval
179 DateTime timeoutTime = m_timeout.getAbsolute();
180 if (timeoutTime > m_loopTime)
181 {
182 DateTime diff = m_timeout.getAbsolute() - m_loopTime;
183 tv.tv_sec = diff.get();
184 tv.tv_usec = diff.getMicrosecond();
185 }
186 else
187 {
188 // somehow we got past the timeout, so just return a 0 length timeval.
189 tv.tv_sec = 0;
190 tv.tv_usec = 0;
191 }
192 }
193 else // it's relative
194 {
195 double timeTillExpiration = calcSeconds();
196 safeAssign(tv.tv_sec, timeTillExpiration);
197 double dummy;
198 safeAssign(tv.tv_usec, modf(timeTillExpiration, &dummy) * 1e6);
199 }
200
201
202 return &tv;
203}
204#endif
205
208{
209 return m_timeout;
210}
211
212double
214{
215 // return the number of seconds until the timeout expires.
216 double seconds;
217 if (m_timeout.getType() == Timeout::E_ABSOLUTE)
218 {
219 DateTime diff = m_timeout.getAbsolute() - m_loopTime;
220 seconds = static_cast<double>(diff.get()) + (static_cast<double>(diff.getMicrosecond()) / 1e6);
221 }
222 else
223 {
224 // seconds = (m_start + m_timeout.getRelative()) - m_loopTime
225 double start = static_cast<double>(m_start.get()) + (static_cast<double>(m_start.getMicrosecond()) / 1e6);
226 double loop = static_cast<double>(m_loopTime.get()) + (static_cast<double>(m_loopTime.getMicrosecond()) / 1e6);
227 seconds = start + m_timeout.getRelative() - loop;
228 }
229 return seconds;
230}
231
232double
233TimeoutTimer::calcSeconds(double maxSeconds) const
234{
235 double seconds = calcSeconds();
236 seconds = seconds > maxSeconds ? maxSeconds : seconds;
237 return seconds;
238}
239
240Timeout
245
246Timeout
247TimeoutTimer::asRelativeTimeout(double maxSeconds) const
248{
249 return Timeout::relative(calcSeconds(maxSeconds));
250}
251
252Timeout
254{
255 // an infinite timeout cannot be converted to absolute, it stays infinite
256 if (infinite())
257 {
258 return m_timeout;
259 }
260 if (m_timeout.getType() == Timeout::E_ABSOLUTE)
261 {
262 return m_timeout;
263 }
264 else
265 {
266 const long MICROSECONDS_PER_SECOND = 1000000;
267 DateTime endTime(m_start);
268 time_t secs;
269 safeAssign(secs, m_start.get() + static_cast<double>(m_timeout.getRelative()));
270 UInt32 microSecs;
271 double dummy;
272 safeAssign(microSecs,
273 m_start.getMicrosecond() +
274 modf(m_timeout.getRelative(), &dummy) * MICROSECONDS_PER_SECOND);
275
276 // handle any overflow
277 secs += microSecs / MICROSECONDS_PER_SECOND;
278 microSecs = microSecs % MICROSECONDS_PER_SECOND;
279
280 return Timeout::absolute(DateTime(secs, microSecs));
281 }
282}
283
284#ifdef BLOCXX_WIN32
285DWORD
286TimeoutTimer::asDWORDMs() const
287{
288 if (infinite())
289 {
290 return INFINITE;
291 }
292
293 DWORD rval;
294 safeAssign(rval, calcSeconds() * 1000.0);
295 return rval;
296}
297#endif
298
299int
301{
302 if (infinite())
303 {
304 return -1;
305 }
306
307 int rval;
308 safeAssign(rval, calcSeconds() * 1000.0);
309 return rval;
310}
311
312int
313TimeoutTimer::asIntMs(double maxSeconds) const
314{
315 if (infinite() && maxSeconds == INFINITY)
316 {
317 return -1;
318 }
319
320 int rval;
321 safeAssign(rval, calcSeconds(maxSeconds) * 1000.0);
322 return rval;
323}
324
325#ifdef BLOCXX_HAVE_STRUCT_TIMESPEC
326::timespec*
327TimeoutTimer::asTimespec(::timespec& ts) const
328{
329 const long NANOSECONDS_PER_MICROSECOND = 1000;
330 const long NANOSECONDS_PER_MILLISECOND = 1000000;
331 const long NANOSECONDS_PER_SECOND = 1000000000;
332
334 {
335 // convert the timeout to a timespec
336 DateTime timeoutTime = m_timeout.getAbsolute();
337 if (timeoutTime > m_loopTime)
338 {
339 ts.tv_sec = timeoutTime.get();
340 ts.tv_nsec = timeoutTime.getMicrosecond() * NANOSECONDS_PER_MICROSECOND;
341 }
342 else
343 {
344 // somehow we got past the timeout (a time warp?), so just return a 0 timespec.
345 ts.tv_sec = 0;
346 ts.tv_nsec = 0;
347 }
348 }
349 else // relative
350 {
351 safeAssign(ts.tv_sec, m_start.get() + static_cast<double>(m_timeout.getRelative()));
352 double dummy;
353 safeAssign(ts.tv_nsec,
354 static_cast<double>(m_start.getMicrosecond()) * NANOSECONDS_PER_MICROSECOND +
355 modf(m_timeout.getRelative(), &dummy) * NANOSECONDS_PER_SECOND);
356
357 // handle any overflow because ts.tv_nsec has to be in the correct range.
358 ts.tv_sec += ts.tv_nsec / NANOSECONDS_PER_SECOND;
359 ts.tv_nsec = ts.tv_nsec % NANOSECONDS_PER_SECOND;
360 }
361
362 return &ts;
363}
364#endif
365
371
372} // end namespace BLOCXX_NAMESPACE
373
374
375
376
#define INFINITY
Definition Infinity.hpp:53
The DateTime class is an abstraction for date time data.
Definition DateTime.hpp:81
UInt32 getMicrosecond() const
Get the microsecond of the second for this DateTime object.
static DateTime getCurrent()
Gets a DateTime instance set to the current system time.
A timeout can be absolute, which means that it will happen at the specified DateTime.
Definition Timeout.hpp:56
DateTime getAbsolute() const
Definition Timeout.cpp:82
ETimeoutType getType() const
Definition Timeout.cpp:76
static Timeout relative(float seconds)
Definition Timeout.cpp:58
static Timeout absolute(const DateTime &dt)
Definition Timeout.cpp:50
static Timeout infinite
Definition Timeout.hpp:62
bool expired() const
Indicates whether the last loop time has exceeded the timeout.
void start()
Meant to be called by timeout functions which loop.
void loop()
Meant to be called by timeout functions which loop, but don't want to reset the interval.
Timeout asAbsoluteTimeout() const
Converts the timer to an absolute timeout.
virtual DateTime getCurrentTime() const
void resetOnLoop()
Meant to be called by timeout functions which loop, and that want to reset the interval.
bool infinite() const
Indicates whether the timeout will never expire.
Taken from RFC 1321.