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 
38 #include "blocxx/BLOCXX_config.h"
39 #include "blocxx/TimeoutTimer.hpp"
40 #include "blocxx/DateTime.hpp"
41 #include "blocxx/Infinity.hpp"
42 
43 #include <limits>
44 
45 namespace BLOCXX_NAMESPACE
46 {
47 
49  : m_timeout(x)
50  , m_start(getCurrentTime())
51  , m_loopTime(m_start)
52 {
53 }
54 
56 {
57 }
58 
59 void
61 {
63 }
64 
65 void
67 {
68  loop();
70  {
72  }
73 }
74 
75 void
77 {
79 }
80 
81 namespace
82 {
83 
84 template <typename T, typename U>
85 void 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 
101 bool 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 
112 bool
114 {
115  if (infinite())
116  {
117  return false;
118  }
119 
120  switch (m_timeout.getType())
121  {
122  case Timeout::E_ABSOLUTE:
123  return m_loopTime >= m_timeout.getAbsolute();
124 
125  case Timeout::E_RELATIVE:
127  return compareInterval(m_start, m_loopTime, m_timeout.getRelative());
128  }
129  return false;
130 }
131 
132 bool
134 {
135  return m_timeout == Timeout::infinite;
136 }
137 
138 #ifdef BLOCXX_HAVE_STRUCT_TIMEVAL
139 // return 0 for infinite, otherwise a pointer to tv
140 ::timeval*
141 TimeoutTimer::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*
169 TimeoutTimer::asTimeval(::timeval& tv) const
170 {
171  if (infinite())
172  {
173  return 0;
174  }
175 
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  {
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 
206 Timeout
208 {
209  return m_timeout;
210 }
211 
212 double
214 {
215  // return the number of seconds until the timeout expires.
216  double seconds;
218  {
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 
232 double
233 TimeoutTimer::calcSeconds(double maxSeconds) const
234 {
235  double seconds = calcSeconds();
236  seconds = seconds > maxSeconds ? maxSeconds : seconds;
237  return seconds;
238 }
239 
240 Timeout
242 {
243  return Timeout::relative(calcSeconds());
244 }
245 
246 Timeout
247 TimeoutTimer::asRelativeTimeout(double maxSeconds) const
248 {
249  return Timeout::relative(calcSeconds(maxSeconds));
250 }
251 
252 Timeout
254 {
255  // an infinite timeout cannot be converted to absolute, it stays infinite
256  if (infinite())
257  {
258  return m_timeout;
259  }
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,
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
285 DWORD
286 TimeoutTimer::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 
299 int
301 {
302  if (infinite())
303  {
304  return -1;
305  }
306 
307  int rval;
308  safeAssign(rval, calcSeconds() * 1000.0);
309  return rval;
310 }
311 
312 int
313 TimeoutTimer::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*
327 TimeoutTimer::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 
366 DateTime
368 {
369  return DateTime::getCurrent();
370 }
371 
372 } // end namespace BLOCXX_NAMESPACE
373 
374 
375 
376 
Taken from RFC 1321.
bool infinite() const
Indicates whether the timeout will never expire.
void loop()
Meant to be called by timeout functions which loop, but don&#39;t want to reset the interval.
#define INFINITY
Definition: Infinity.hpp:53
UInt32 getMicrosecond() const
Get the microsecond of the second for this DateTime object.
Definition: DateTime.cpp:1064
static Timeout relative(float seconds)
Definition: Timeout.cpp:58
virtual DateTime getCurrentTime() const
A timeout can be absolute, which means that it will happen at the specified DateTime.
Definition: Timeout.hpp:55
Timeout asAbsoluteTimeout() const
Converts the timer to an absolute timeout.
void start()
Meant to be called by timeout functions which loop.
static Timeout infinite
Definition: Timeout.hpp:62
The DateTime class is an abstraction for date time data.
Definition: DateTime.hpp:80
static DateTime getCurrent()
Gets a DateTime instance set to the current system time.
Definition: DateTime.cpp:1329
DateTime getAbsolute() const
Definition: Timeout.cpp:82
TimeoutTimer(const Timeout &x)
void resetOnLoop()
Meant to be called by timeout functions which loop, and that want to reset the interval.
static Timeout absolute(const DateTime &dt)
Definition: Timeout.cpp:50
float getRelative() const
Definition: Timeout.cpp:88
ETimeoutType getType() const
Definition: Timeout.cpp:76
bool expired() const
Indicates whether the last loop time has exceeded the timeout.