33 #define EPICS_EXPOSE_LIBCOM_MONOTONIC_PRIVATE 42 # define debugPrintf(argsInParen) ::printf argsInParen 44 # define debugPrintf(argsInParen) 47 extern "C" void setThreadName ( DWORD dwThreadID, LPCSTR szThreadName );
53 #if !defined ( MAXLONGLONG ) 54 # define MAXLONGLONG 0x7fffffffffffffffLL 56 #if !defined ( MINLONGLONG ) 57 # define MINLONGLONG ~0x7fffffffffffffffLL 59 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION 60 # define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000 63 static const LONGLONG epicsEpochInFileTime = 0x01b41e2a18d64000LL;
65 static unsigned __stdcall _pllThreadEntry (
void * pCurrentTimeIn );
74 CRITICAL_SECTION mutex;
75 LONGLONG lastPerfCounter;
76 LONGLONG perfCounterFreq;
77 LONGLONG epicsTimeLast;
78 LONGLONG perfCounterFreqPLL;
79 LONGLONG lastPerfCounterPLL;
80 LONGLONG lastFileTimePLL;
84 bool threadShutdownCmd;
87 static const int pllDelay;
92 const int currentTime :: pllDelay = 5;
95 static const LONGLONG FILE_TIME_TICKS_PER_SEC = 10000000;
96 static const LONGLONG EPICS_TIME_TICKS_PER_SEC = 1000000000;
97 static const LONGLONG ET_TICKS_PER_FT_TICK =
98 EPICS_TIME_TICKS_PER_SEC / FILE_TIME_TICKS_PER_SEC;
103 static int timeRegister(
void)
114 static int done = timeRegister();
130 struct tm * pRet = gmtime ( pAnsiTime );
142 const time_t * pAnsiTime,
struct tm * pTM )
144 struct tm * pRet = localtime ( pAnsiTime );
155 lastPerfCounter ( 0 ),
156 perfCounterFreq ( 0 ),
158 perfCounterFreqPLL ( 0 ),
159 lastPerfCounterPLL ( 0 ),
160 lastFileTimePLL ( 0 ),
163 perfCtrPresent (
false ),
164 threadShutdownCmd (
false ),
165 threadHasExited (
false )
167 InitializeCriticalSection ( & this->mutex );
170 int originalPriority = GetThreadPriority ( GetCurrentThread () );
171 SetThreadPriority ( GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL );
174 GetSystemTimeAsFileTime ( & ft );
176 QueryPerformanceCounter ( & tmp );
177 this->lastPerfCounter = tmp.QuadPart;
179 if ( QueryPerformanceFrequency ( & tmp ) ) {
180 this->perfCounterFreq = tmp.QuadPart;
181 this->perfCtrPresent =
true;
183 SetThreadPriority ( GetCurrentThread (), originalPriority );
185 LARGE_INTEGER liFileTime;
186 liFileTime.LowPart = ft.dwLowDateTime;
187 liFileTime.HighPart = ft.dwHighDateTime;
189 if ( liFileTime.QuadPart >= epicsEpochInFileTime ) {
192 this->epicsTimeLast =
193 ( liFileTime.QuadPart - epicsEpochInFileTime ) *
194 ET_TICKS_PER_FT_TICK;
198 "win32 osdTime.cpp init detected questionable " 199 "system date prior to EPICS epoch, epics time will not advance\n" );
200 this->epicsTimeLast = 0;
203 this->perfCounterFreqPLL = this->perfCounterFreq;
204 this->lastPerfCounterPLL = this->lastPerfCounter;
205 this->lastFileTimePLL = liFileTime.QuadPart;
211 if ( this->perfCtrPresent && ! this->threadHandle ) {
212 this->threadHandle = (HANDLE)
216 assert ( this->threadHandle );
217 BOOL bstat = SetThreadPriority (
218 this->threadHandle, THREAD_PRIORITY_HIGHEST );
220 DWORD wstat = ResumeThread ( this->threadHandle );
221 assert ( wstat != 0xFFFFFFFF );
227 EnterCriticalSection ( & this->mutex );
228 this->threadShutdownCmd =
true;
229 while ( ! this->threadHasExited ) {
230 LeaveCriticalSection ( & this->mutex );
232 EnterCriticalSection ( & this->mutex );
234 LeaveCriticalSection ( & this->mutex );
235 DeleteCriticalSection ( & this->mutex );
240 if ( this->perfCtrPresent ) {
241 EnterCriticalSection ( & this->mutex );
243 LARGE_INTEGER curPerfCounter;
244 QueryPerformanceCounter ( & curPerfCounter );
247 if ( curPerfCounter.QuadPart >= this->lastPerfCounter ) {
248 offset = curPerfCounter.QuadPart - this->lastPerfCounter;
263 if ( offset <
MAXLONGLONG / EPICS_TIME_TICKS_PER_SEC ) {
264 offset *= EPICS_TIME_TICKS_PER_SEC;
265 offset /= this->perfCounterFreq;
268 double fpOffset = static_cast <
double > ( offset );
269 fpOffset *= EPICS_TIME_TICKS_PER_SEC;
270 fpOffset /= static_cast <
double > ( this->perfCounterFreq );
271 offset = static_cast < LONGLONG > ( fpOffset );
273 LONGLONG epicsTimeCurrent = this->epicsTimeLast + offset;
274 if ( this->epicsTimeLast > epicsTimeCurrent ) {
275 double diff = static_cast <
double >
276 ( this->epicsTimeLast - epicsTimeCurrent ) / EPICS_TIME_TICKS_PER_SEC;
278 "currentTime::getCurrentTime(): %f sec " 279 "time discontinuity detected\n",
282 this->epicsTimeLast = epicsTimeCurrent;
283 this->lastPerfCounter = curPerfCounter.QuadPart;
285 LeaveCriticalSection ( & this->mutex );
288 ( epicsTimeCurrent / EPICS_TIME_TICKS_PER_SEC );
290 ( epicsTimeCurrent % EPICS_TIME_TICKS_PER_SEC );
296 GetSystemTimeAsFileTime ( & ft );
297 dest = epicsTime ( ft );
305 void currentTime :: updatePLL ()
307 EnterCriticalSection ( & this->mutex );
310 LARGE_INTEGER curFileTime;
311 LARGE_INTEGER curPerfCounter;
313 int originalPriority = GetThreadPriority ( GetCurrentThread () );
314 SetThreadPriority ( GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL );
316 GetSystemTimeAsFileTime ( & ft );
317 QueryPerformanceCounter ( & curPerfCounter );
318 SetThreadPriority ( GetCurrentThread (), originalPriority );
320 curFileTime.LowPart = ft.dwLowDateTime;
321 curFileTime.HighPart = ft.dwHighDateTime;
324 LONGLONG perfCounterDiff;
325 if ( curPerfCounter.QuadPart >= this->lastPerfCounterPLL ) {
326 perfCounterDiff = curPerfCounter.QuadPart - this->lastPerfCounterPLL;
338 perfCounterDiff = (
MAXLONGLONG - this->lastPerfCounterPLL )
341 this->lastPerfCounterPLL = curPerfCounter.QuadPart;
343 LONGLONG fileTimeDiff = curFileTime.QuadPart - this->lastFileTimePLL;
344 this->lastFileTimePLL = curFileTime.QuadPart;
347 if ( fileTimeDiff <= 0 ) {
348 LeaveCriticalSection( & this->mutex );
349 debugPrintf ( (
"currentTime: file time difference in PLL was less than zero\n" ) );
353 LONGLONG freq = ( FILE_TIME_TICKS_PER_SEC * perfCounterDiff ) / fileTimeDiff;
354 LONGLONG delta = freq - this->perfCounterFreqPLL;
357 LONGLONG bound = this->perfCounterFreqPLL >> 10;
358 if ( delta < -bound || delta > bound ) {
359 LeaveCriticalSection( & this->mutex );
360 debugPrintf ( (
"freq est out of bounds l=%d e=%d h=%d\n",
361 static_cast < int > ( -bound ),
362 static_cast < int > ( delta ),
363 static_cast < int > ( bound ) ) );
368 LONGLONG feedback = delta >> 8;
369 this->perfCounterFreqPLL += feedback;
371 LONGLONG perfCounterDiffSinceLastFetch;
372 if ( curPerfCounter.QuadPart >= this->lastPerfCounter ) {
373 perfCounterDiffSinceLastFetch =
374 curPerfCounter.QuadPart - this->lastPerfCounter;
386 perfCounterDiffSinceLastFetch =
393 const LONGLONG expectedDly = this->perfCounterFreq * pllDelay;
394 const LONGLONG bnd = expectedDly / 4;
395 if ( perfCounterDiffSinceLastFetch <= 0 ||
396 perfCounterDiffSinceLastFetch >= expectedDly + bnd ) {
397 LeaveCriticalSection( & this->mutex );
398 debugPrintf ( (
"perf ctr measured delay out of bounds m=%d max=%d\n",
399 static_cast < int > ( perfCounterDiffSinceLastFetch ),
400 static_cast < int > ( expectedDly + bnd ) ) );
406 this->epicsTimeLast +=
407 ( perfCounterDiffSinceLastFetch * EPICS_TIME_TICKS_PER_SEC )
408 / this->perfCounterFreq;
409 this->lastPerfCounter = curPerfCounter.QuadPart;
411 LONGLONG epicsTimeFromCurrentFileTime;
414 static bool firstMessageWasSent =
false;
415 if ( curFileTime.QuadPart >= epicsEpochInFileTime ) {
416 epicsTimeFromCurrentFileTime =
417 ( curFileTime.QuadPart - epicsEpochInFileTime ) *
418 ET_TICKS_PER_FT_TICK;
419 firstMessageWasSent =
false;
428 if ( ! firstMessageWasSent ) {
430 "win32 osdTime.cpp time PLL update detected questionable " 431 "system date prior to EPICS epoch, epics time will not advance\n" );
432 firstMessageWasSent =
true;
434 epicsTimeFromCurrentFileTime = 0;
438 delta = epicsTimeFromCurrentFileTime - this->epicsTimeLast;
439 if ( delta > EPICS_TIME_TICKS_PER_SEC || delta < -EPICS_TIME_TICKS_PER_SEC ) {
444 this->epicsTimeLast = epicsTimeFromCurrentFileTime;
445 this->perfCounterFreq = this->perfCounterFreqPLL;
446 debugPrintf ( (
"currentTime: did someone adjust the date?\n" ) );
451 this->perfCounterFreq =
452 ( EPICS_TIME_TICKS_PER_SEC * this->perfCounterFreqPLL )
453 / ( delta + EPICS_TIME_TICKS_PER_SEC );
456 LONGLONG lowLimit = this->perfCounterFreqPLL - bound;
457 if ( this->perfCounterFreq < lowLimit ) {
458 debugPrintf ( (
"currentTime: out of bounds low freq excursion %d\n",
459 static_cast <int> ( lowLimit - this->perfCounterFreq ) ) );
460 this->perfCounterFreq = lowLimit;
463 LONGLONG highLimit = this->perfCounterFreqPLL + bound;
464 if ( this->perfCounterFreq > highLimit ) {
465 debugPrintf ( (
"currentTime: out of bounds high freq excursion %d\n",
466 static_cast <int> ( this->perfCounterFreq - highLimit ) ) );
467 this->perfCounterFreq = highLimit;
471 # if defined ( DEBUG ) 472 LARGE_INTEGER sysFreq;
473 QueryPerformanceFrequency ( & sysFreq );
474 double freqDiff = static_cast <
int>
475 ( this->perfCounterFreq - sysFreq.QuadPart );
476 freqDiff /= sysFreq.QuadPart;
478 double freqEstDiff = static_cast <
int>
479 ( this->perfCounterFreqPLL - sysFreq.QuadPart );
480 freqEstDiff /= sysFreq.QuadPart;
481 freqEstDiff *= 100.0;
482 debugPrintf ( (
"currentTime: freq delta %f %% freq est " 483 "delta %f %% time delta %f sec\n",
486 static_cast < double > ( delta ) /
487 EPICS_TIME_TICKS_PER_SEC ) );
491 LeaveCriticalSection ( & this->mutex );
497 reinterpret_cast <
currentTime * > ( pCurrentTimeIn );
499 while ( ! pCT->threadShutdownCmd ) {
500 Sleep ( currentTime :: pllDelay * 1000 );
503 EnterCriticalSection ( & pCT->mutex );
504 pCT->threadHasExited =
true;
505 LeaveCriticalSection ( & pCT->mutex );
509 epicsTime::operator FILETIME ()
const 511 LARGE_INTEGER ftTicks;
512 ftTicks.QuadPart = ( this->secPastEpoch * FILE_TIME_TICKS_PER_SEC ) +
513 ( this->nSec / ET_TICKS_PER_FT_TICK );
514 ftTicks.QuadPart += epicsEpochInFileTime;
516 ts.dwLowDateTime = ftTicks.LowPart;
517 ts.dwHighDateTime = ftTicks.HighPart;
521 epicsTime::epicsTime (
const FILETIME & ts )
524 lift.LowPart = ts.dwLowDateTime;
525 lift.HighPart = ts.dwHighDateTime;
526 if ( lift.QuadPart > epicsEpochInFileTime ) {
527 LONGLONG fileTimeTicksSinceEpochEPICS =
528 lift.QuadPart - epicsEpochInFileTime;
530 ( fileTimeTicksSinceEpochEPICS / FILE_TIME_TICKS_PER_SEC );
532 ( ( fileTimeTicksSinceEpochEPICS % FILE_TIME_TICKS_PER_SEC ) *
533 ET_TICKS_PER_FT_TICK );
536 this->secPastEpoch = 0;
541 epicsTime & epicsTime::operator = (
const FILETIME & rhs )
543 *
this = epicsTime ( rhs );
#define assert(exp)
Declare that a condition should be true.
An EPICS-specific replacement for ANSI C's assert.
#define generalTimeCurrentTpRegister
void getCurrentTime(epicsTimeStamp &dest)
#define debugPrintf(argsInParen)
void osdMonotonicInit(void)
#define epicsTimeOK
Success.
#define STACK_SIZE_PARAM_IS_A_RESERVATION
epicsUInt32 secPastEpoch
seconds since 0000 Jan 1, 1990
friend unsigned __stdcall _pllThreadEntry(void *pCurrentTimeIn)
int errlogPrintf(const char *pFormat,...)
EPICS time stamp, for use from C code.
int osdTimeGetCurrent(epicsTimeStamp *pDest)
EPICS time-stamps (epicsTimeStamp), epicsTime C++ class and C functions for handling wall-clock times...
C++ and C descriptions for a thread.
int epicsTime_gmtime(const time_t *pAnsiTime, struct tm *pTM)
Break down a time_t into a struct tm in the UTC timezone.
int epicsTime_localtime(const time_t *clock, struct tm *result)
Break down a time_t into a struct tm in the local timezone.
epicsUInt32 nsec
nanoseconds within second
void setThreadName(DWORD dwThreadID, LPCSTR szThreadName)