reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
Time.cxx
Go to the documentation of this file.
1#include "Time.hxx"
2#if defined(WIN32)
3#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
4#include <windows.h>
5#include <mmsystem.h>
6#if (_MSC_VER >= 1400) //no atomic intrinsics on Visual Studio 2003 and below
7#include <intrin.h>
8#pragma intrinsic(_InterlockedCompareExchange64)
9#endif
10#endif
11#include "rutil/Random.hxx"
12#include "rutil/Logger.hxx"
13#include "rutil/Lock.hxx"
14
15#define RESIPROCATE_SUBSYSTEM Subsystem::SIP
16
17using namespace resip;
18
19void resip::sleepMs(unsigned int ms)
20{
21#ifdef WIN32
22 Sleep(ms);
23#else
24 usleep(ms*1000);
25#endif
26}
27
28void resip::sleepSeconds(unsigned int seconds)
29{
30#ifdef WIN32
31 Sleep(seconds*1000);
32#else
33 sleep(seconds);
34#endif
35}
36
40
44
45#if defined(WIN32) && defined(_RESIP_MONOTONIC_CLOCK)
46unsigned ResipClock::mMaxSystemTimeWaitMs = 60000; //set low initially, may get adjusted by actual timer chosen
47#else
48unsigned ResipClock::mMaxSystemTimeWaitMs = UINT_MAX;
49#endif
50
51#ifdef WIN32
52ResipClock::WinMonoClock::PGTC64 ResipClock::WinMonoClock::mGTC64 = &ResipClock::WinMonoClock::GTCLockDuringRange::GTC64;
53
54ResipClock::WinMonoClock::WinMonoClock()
55{
56 Initialize();
57}
58
59void
60ResipClock::WinMonoClock::Initialize(void)
61{
62 static Mutex mtxStart;
63 static volatile bool isInitialized=false;
64
65 Lock lock(mtxStart);
66
67 if (isInitialized)
68 {
69 return;
70 }
71
72#if defined(_MSC_VER) && (_MSC_VER >= 1400)
73 ResipClock::mMaxSystemTimeWaitMs = GTCInterlocked::GetMaxWaitMs();
74 mGTC64 = (PGTC64)&GTCInterlocked::GTC64;
75 DebugLog(<< "Using GTCInterlocked::GTC64 as the monotonic clock for time functions.");
76#else
77 ResipClock::mMaxSystemTimeWaitMs = GTCLockDuringRange::GetMaxWaitMs();
78 mGTC64 = (PGTC64)&GTCLockDuringRange::GTC64;
79 DebugLog(<< "Using GTCLockDuringRange::GTC64 as the monotonic clock for time functions.");
80#endif
81
82 unsigned min=0,max=0,actual=0;
83 bool isMono = false;
84
85 ResipClock::queryTimerInfo(min,max,actual,isMono);
86
87 InfoLog(<< "Timer resolution: (min/max/actual/isMonotonic) = " << min << '/' << max << '/' << actual <<
88 '/' << ((isMono)?("true"):("false")));
89
90 isInitialized = true;
91}
92
93#define IS_ALIGNED(_pointer, _alignment) ((((ULONG_PTR) (_pointer)) & ((_alignment) - 1)) == 0)
94
95uint64_t ResipClock::WinMonoClock::GTCInterlocked::GTC64(void)
96{
97#if defined(_MSC_VER) && (_MSC_VER >= 1400) //no atomic intrinsics on Visual Studio 2003 and below
98 ULARGE_INTEGER timeVal;
99
100 resip_assert(IS_ALIGNED(&mBaseTime,8)); //if the implementation ever changes to use 64-bit atomic read/write then 64-bit alignment will be required.
101
102 //InterlockedCompareExchange64 will issue a LOCK CMPXCHG8B to ensure atomic access to mBaseTime
103 //Not the most efficient wat to do a 64-bit atomic read (see fild instruction), but no intrinsic for 64-bit atomic read.
104 timeVal.QuadPart = _InterlockedCompareExchange64((LONGLONG volatile *)&mBaseTime,0,0);
105
106 DWORD tickNow = ::timeGetTime();
107
108 if (tickNow != timeVal.LowPart)
109 {
110 //the difference in the low 32-bits and the current 32-bit timeGetTime will be the time difference from
111 //the base time till now. Integer arithmentic will correctly handle cases where tickNow < timeVal.LowPart (rollover).
112 //This diff cannot be greater than 0xFFFFFFFF, so this function must be called more frequently than once
113 //every 49.7 days.
114
115 DWORD diff = tickNow - timeVal.LowPart;
116
117 //periodically update the basetime, only really necessary at least once every 49.7 days.
118 if (diff > mBaseTimeUpdateInterval)
119 {
120 ULARGE_INTEGER newVal;
121
122 newVal.QuadPart = timeVal.QuadPart + diff; //any 32-bit rollover is now part of the high 32-bits.
123
124 //don't care if this CAS64 actually writes mBaseTime, as long as at least 1 thread updates mBaseTime.
125 _InterlockedCompareExchange64((LONGLONG volatile *)&mBaseTime,(LONGLONG)newVal.QuadPart,(LONGLONG)timeVal.QuadPart);
126 }
127
128 timeVal.QuadPart += diff; //any 32-bit rollover is now part of the high 32-bits.
129 }
130
131 return timeVal.QuadPart;
132#else
133 resip_assert(0); //this counter only compiles on Visual Studio 2005 +
134 return GTCLock::GTC64();
135#endif //#if (_MSC_VER >= 1400) //no atomic intrinsics on Visual Studio 2003 and below
136}
137
138volatile uint64_t ResipClock::WinMonoClock::GTCInterlocked::mBaseTime = 0;
139
141ResipClock::WinMonoClock::GTCLock::GTC64(void)
142{
143 Lock lock(mMutex);
144
145 DWORD tickNow = ::timeGetTime();
146
147 if (tickNow != mBaseTime.LowPart)
148 {
149 mBaseTime.QuadPart += (tickNow - mBaseTime.LowPart);
150 }
151
152 return mBaseTime.QuadPart;
153}
154
155ULARGE_INTEGER ResipClock::WinMonoClock::GTCLock::mBaseTime = {0,0};
156Mutex ResipClock::WinMonoClock::GTCLock::mMutex;
157
158uint64_t ResipClock::WinMonoClock::GTCLockDuringRange::GTC64(void)
159{
160 // we assume that this function is called reasonable often
161 // monitor wrap around only in dangerous time range:
162 // empiric constants
163 const DWORD TIMER_BEGIN_SAFE_RANGE = 0xffff; // about one minute after
164 const DWORD TIMER_END_SAFE_RANGE = 0xffff0000; // and before wrap around
165
166 DWORD tick = ::timeGetTime();
167
168 if ( ( tick > TIMER_BEGIN_SAFE_RANGE ) && ( tick < TIMER_END_SAFE_RANGE ) )
169 {
170 LARGE_INTEGER ret;
171 ret.HighPart = mWrapCounter;
172 ret.LowPart = tick;
173 return (uint64_t)ret.QuadPart;
174 }
175 // most application will never be here - only long running servers
176 Lock lock(mWrapCounterMutex);
177 if (mPrevTick > tick)
178 {
179 mWrapCounter++;
180 }
181 mPrevTick = tick;
182 LARGE_INTEGER ret;
183 ret.HighPart = mWrapCounter;
184 ret.LowPart = tick;
185 return (uint64_t)ret.QuadPart;
186}
187
188uint32_t ResipClock::WinMonoClock::GTCLockDuringRange::mWrapCounter = 0;
189DWORD ResipClock::WinMonoClock::GTCLockDuringRange::mPrevTick = 0;
190Mutex ResipClock::WinMonoClock::GTCLockDuringRange::mWrapCounterMutex;
191#endif
192
194ResipClock::getSystemTime()
195{
196 resip_assert(sizeof(uint64_t) == 64/8);
197
198#if defined(WIN32) || defined(UNDER_CE)
199#ifdef _RESIP_MONOTONIC_CLOCK
200 static ResipClock::WinMonoClock clockInit;
201 return WinMonoClock::GetClock64() * 1000;
202#else
203 FILETIME ft;
204
205#ifdef UNDER_CE
206 SYSTEMTIME st;
207 ::GetSystemTime(&st);
208 ::SystemTimeToFileTime(&st,&ft);
209#else
210 ::GetSystemTimeAsFileTime(&ft);
211#endif
212
213 ULARGE_INTEGER li;
214 li.LowPart = ft.dwLowDateTime;
215 li.HighPart = ft.dwHighDateTime;
216 return li.QuadPart/10;
217
218#endif //_RESIP_MONOTONIC_CLOCK
219
220#else //#if defined(WIN32) || defined(UNDER_CE)
221
222 uint64_t time=0;
223#ifdef _RESIP_MONOTONIC_CLOCK
224 struct timespec now_monotonic;
225 if (clock_gettime( CLOCK_MONOTONIC, &now_monotonic ) == 0)
226// if ( syscall( __NR_clock_gettime, CLOCK_MONOTONIC, &now_monotonic ) == 0 )
227 {
228 time = now_monotonic.tv_sec;
229 time = time*1000000;
230 time += now_monotonic.tv_nsec/1000;
231 return time;
232 }
233#endif
234 struct timeval now;
235 gettimeofday( &now , NULL );
236 //assert( now );
237 time = now.tv_sec;
238 time = time*1000000;
239 time += now.tv_usec;
240 return time;
241#endif
242}
243
246{
247 resip_assert( sizeof(uint64_t) == 8 );
248#if defined(WIN32) && !defined(__GNUC__)
249 return 18446744073709551615ui64;
250#else
251 return 18446744073709551615ULL;
252#endif
253}
254
257{
258 uint64_t now = getTimeMs();
259
260 // make r a random number between 5000 and 9000
261 int r = Random::getRandom()%4000;
262 r += 5000;
263
264 uint64_t ret = now;
265 ret += (futureMs*r)/10000;
266
267 resip_assert( ret >= now );
268 resip_assert( ret >= now+(futureMs/2) );
269 resip_assert( ret <= now+futureMs );
270
271 return ret;
272}
273
274void
275ResipClock::queryTimerInfo(unsigned &min, unsigned &max, unsigned &actual, bool &isMonotonic)
276{
277 min = max = actual = 0;
278 isMonotonic = false;
279
280#if defined(WIN32)
281#if defined(_RESIP_MONOTONIC_CLOCK)
282#if !defined(NTSTATUS)
283#define NTSTATUS DWORD
284#endif
285 typedef NTSTATUS (WINAPI*PNTQTR)(PULONG,PULONG,PULONG);
286
287 HMODULE hm = ::LoadLibrary("ntdll");
288
289 if (hm != NULL)
290 {
291 PNTQTR ntqtr = (PNTQTR)::GetProcAddress(hm,"NtQueryTimerResolution");
292
293 if (ntqtr)
294 {
295 ntqtr((PULONG)&min,(PULONG)&max,(PULONG)&actual);
296 min /= 10;
297 max /= 10;
298 actual /= 10;
299 }
300
301 ::FreeLibrary(hm);
302 hm = NULL;
303 }
304 isMonotonic = true;
305#else
306 DWORD timeAdjustment=0;
307 BOOL timeAdjustmentDisabled=0;
308 //on Vista it looks like GetSystemTime has 1ms resolution, but GetSystemTimeAdjustment still returns 15ms
309 //so just set the min resolution to whatever is reported, no actual resolution can be consistently found.
310 ::GetSystemTimeAdjustment(&timeAdjustment,(PDWORD)&min,&timeAdjustmentDisabled);
311 min /= 10;
312 isMonotonic = false;
313#endif
314#else //WIN32
315#ifdef __APPLE__
316 //@TODO
317#else
318 clockid_t clock = CLOCK_REALTIME; //need to test/verify CLOCK_REALTIME returns the gettimeofday resolution.
319#if defined(_RESIP_MONOTONIC_CLOCK)
320 clock = CLOCK_MONOTONIC;
321 isMonotonic = true;
322#endif
323 struct timespec res;
324 if (clock_getres(clock,&res) == 0)
325 {
326 actual = (res.tv_sec * 1000000) + (res.tv_nsec / 1000);
327 }
328#endif
329#endif
330}
331
332/* ====================================================================
333 * The Vovida Software License, Version 1.0
334 *
335 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
336 *
337 * Redistribution and use in source and binary forms, with or without
338 * modification, are permitted provided that the following conditions
339 * are met:
340 *
341 * 1. Redistributions of source code must retain the above copyright
342 * notice, this list of conditions and the following disclaimer.
343 *
344 * 2. Redistributions in binary form must reproduce the above copyright
345 * notice, this list of conditions and the following disclaimer in
346 * the documentation and/or other materials provided with the
347 * distribution.
348 *
349 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
350 * and "Vovida Open Communication Application Library (VOCAL)" must
351 * not be used to endorse or promote products derived from this
352 * software without prior written permission. For written
353 * permission, please contact vocal@vovida.org.
354 *
355 * 4. Products derived from this software may not be called "VOCAL", nor
356 * may "VOCAL" appear in their name, without prior written
357 * permission of Vovida Networks, Inc.
358 *
359 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
360 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
361 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
362 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
363 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
364 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
365 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
366 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
367 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
368 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
369 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
370 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
371 * DAMAGE.
372 *
373 * ====================================================================
374 *
375 * This software consists of voluntary contributions made by Vovida
376 * Networks, Inc. and many individuals on behalf of Vovida Networks,
377 * Inc. For more information on Vovida Networks, Inc., please see
378 * <http://www.vovida.org/>.
379 *
380 * vi: set shiftwidth=3 expandtab:
381 */
382
#define max(x, y)
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define resip_assert(x)
This file needs to work for both C and C++ code.
static int getRandom()
Returns a postive integer (31 bits) of randomness.
Definition Random.cxx:261
ResipClock(void)
Definition Time.cxx:37
static uint64_t getTimeMs()
Returns the current clock time in milliseconds.
Definition Time.hxx:69
static uint64_t getForever()
Infinit time in future.
Definition Time.cxx:245
static uint64_t getRandomFutureTimeMs(uint64_t futureMs)
Returns an absolute time in ms that is between 50% and 90% of passed in ms from now.
Definition Time.cxx:256
~ResipClock(void)
Definition Time.cxx:41
static void queryTimerInfo(unsigned &minRes, unsigned &maxRes, unsigned &actualRes, bool &isMonotonic)
Gets the current clock's minimum, maximum and current/actual timer resolution and returns if the cloc...
Definition Time.cxx:275
dcm! – add UnusedChecking(_enum) below;
std::mutex Mutex
A semaphore that can be locked by only one thread at a time.
Definition Mutex.hxx:37
void sleepSeconds(unsigned int seconds)
Definition Time.cxx:28
std::unique_lock< Mutex > Lock
A convenience class to lock a Lockable (such as a Mutex) on object creation, and unlock on destructio...
Definition Lock.hxx:28
unsigned long long uint64_t
Definition Stun.hxx:39
void sleepMs(unsigned int ms)
Definition Time.cxx:19
unsigned int uint32_t
Definition stdint.h:85
unsigned __int64 uint64_t
Definition stdint.h:95