diff --git a/src/libCom/os/WIN32/dllmain.cc b/src/libCom/os/WIN32/dllmain.cc index 510fe22cb..ba1aced91 100644 --- a/src/libCom/os/WIN32/dllmain.cc +++ b/src/libCom/os/WIN32/dllmain.cc @@ -46,9 +46,6 @@ #error This source is specific to WIN32 #endif -extern int init_osi_time (); -extern int exit_osi_time (); - #if !defined(EPICS_DLL_NO) BOOL WINAPI DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { @@ -57,8 +54,6 @@ BOOL WINAPI DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) case DLL_PROCESS_ATTACH: if (!bsdSockAttach()) return FALSE; - if (init_osi_time ()) - return FALSE; # ifdef _DEBUG fprintf(stderr, "Process attached to Com.dll version %s\n", EPICS_VERSION_STRING); # endif @@ -66,7 +61,6 @@ BOOL WINAPI DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) case DLL_PROCESS_DETACH: bsdSockRelease(); - exit_osi_time (); # ifdef _DEBUG fprintf(stderr, "Process detached from Com.dll version %s\n", EPICS_VERSION_STRING); # endif diff --git a/src/libCom/os/WIN32/osdTime.cc b/src/libCom/os/WIN32/osdTime.cc index dd2586c61..d52580a50 100644 --- a/src/libCom/os/WIN32/osdTime.cc +++ b/src/libCom/os/WIN32/osdTime.cc @@ -1,62 +1,199 @@ +// +// osiTime.cc +// +// Author: Jeff Hill +// +// #include #include + #include +/* + * for _ftime() + */ +#include +#include + #define epicsExportSharedSymbols #include -static long offset_time_s = 0; /* time diff (sec) from 1990 when EPICS started */ -static LARGE_INTEGER time_prev, time_freq; +// +// performance counter last value, ticks per sec, +// and its offset from the EPICS epoch. +// +static LONGLONG perf_last, perf_freq, perf_offset; + +// +// divide the offset into seconds and +// fractions of a second so that overflow is less +// likely (we dont know the magnitude of perf_freq +// until run time) +// +static LONGLONG perf_sec_offset=-1, perf_frac_offset; + +static const SYSTEMTIME epicsEpochST = { + 1990, // year + 1, // month + 1, // day of the week (Monday) + 1, // day of the month + 0, // hour + 0, // min + 0, // sec + 0 // milli sec +}; + +static LONGLONG epicsEpoch; + +#define FILE_TIME_TICKS_PER_SEC 10000000L /* - * init_osi_time has to be called before using the timer, - * exit_osi_time has to be called in balance. + * synchronize() */ -int init_osi_time () +void osiTime::synchronize() { - if (offset_time_s == 0) { - /* - * initialize elapsed time counters - * - * All CPUs running win32 currently have HR - * counters (Intel and Mips processors do) - */ - if (QueryPerformanceCounter (&time_prev)==0) { - return 1; - } - if (QueryPerformanceFrequency (&time_freq)==0) { - return 1; - } - offset_time_s = (long)time(NULL) - - (long)(time_prev.QuadPart/time_freq.QuadPart); + static int init = 0; + LONGLONG new_sec_offset, new_frac_offset; + LARGE_INTEGER parm; + LONGLONG secondsSinceBoot; + FILETIME currentTimeFT; + LONGLONG currentTime; + BOOL win32Stat; + + // + // one time initialization of constants + // + if (!init) { + FILETIME epicsEpochFT; + + // + // initialize elapsed time counters + // + // All CPUs running win32 currently have HR + // counters (Intel and Mips processors do) + // + assert (QueryPerformanceFrequency (&parm)!=0); + perf_freq = parm.QuadPart; + + // + // convert the EPICS epoch to file time + // + win32Stat = SystemTimeToFileTime (&epicsEpochST, &epicsEpochFT); + assert (win32Stat!=0); + parm.LowPart = epicsEpochFT.dwLowDateTime; + parm.HighPart = epicsEpochFT.dwHighDateTime; + epicsEpoch = parm.QuadPart; + + init = 1; } - return 0; + // + // its important that the following two time queries + // are close together (immediately adjacent to each + // other) in the code + // + GetSystemTimeAsFileTime (¤tTimeFT); + // this one is second because QueryPerformanceFrequency() + // has forced its code to load + assert (QueryPerformanceCounter (&parm)!=0); + + perf_last = parm.QuadPart; + parm.LowPart = currentTimeFT.dwLowDateTime; + parm.HighPart = currentTimeFT.dwHighDateTime; + currentTime = parm.QuadPart; + + // + // check for strange date, and clamp to the + // epics epoch if so + // + if (currentTime>epicsEpoch) { + // + // compute the offset from the EPICS epoch + // + LONGLONG diff = currentTime - epicsEpoch; + + // + // compute the seconds offset and the + // fractional offset part in the FILETIME timebase + // + new_sec_offset = diff / FILE_TIME_TICKS_PER_SEC; + new_frac_offset = diff % FILE_TIME_TICKS_PER_SEC; + + // + // compute the fractional second offset in the performance + // counter time base + // + new_frac_offset = (new_frac_offset*perf_freq) / FILE_TIME_TICKS_PER_SEC; + } + else { + new_sec_offset = 0; + new_frac_offset = 0; + } + + // + // subtract out the perormance counter ticks since the + // begining of windows + // + secondsSinceBoot = perf_last / perf_freq; + if (new_sec_offset>=secondsSinceBoot) { + new_sec_offset -= secondsSinceBoot; + + LONGLONG fracSinceBoot = perf_last % perf_freq; + if (new_frac_offset>=fracSinceBoot) { + new_frac_offset -= fracSinceBoot; + } + else if (new_sec_offset>0) { + // + // borrow + // + new_sec_offset--; + new_frac_offset += perf_freq - fracSinceBoot; + } + else { + new_frac_offset = 0; + } + } + else { + new_sec_offset = 0; + new_frac_offset = 0; + } + + +#if 0 + // + // calculate the change + // + { + double change; + change = (double) (perf_sec_offset-new_sec_offset)*perf_freq + + (perf_frac_offset-new_frac_offset); + change /= perf_freq; + printf ("The performance counter drifted by %f sec\n", change); + } +#endif + + // + // update the current value + // + perf_sec_offset = new_sec_offset; + perf_frac_offset = new_frac_offset; } -int exit_osi_time () -{ - offset_time_s = 0; - - return 0; -} - - // -// osiTime::getCurrent () +// osiTime::osdGetCurrent () // -osiTime osiTime::getCurrent () +osiTime osiTime::osdGetCurrent () { - LARGE_INTEGER time_cur, time_sec, time_remainder; + LONGLONG time_cur, time_sec, time_remainder; + LARGE_INTEGER parm; unsigned long sec, nsec; /* - * this allows the code to work when it is in an object - * library (in addition to inside a dll) + * lazy init */ - if (offset_time_s==0) { - init_osi_time(); + if (perf_sec_offset<0) { + osiTime::synchronize(); } /* @@ -64,45 +201,42 @@ osiTime osiTime::getCurrent () * during initialization to see if the CPU has HR * counters (Intel and Mips processors do) */ - QueryPerformanceCounter (&time_cur); - if (time_prev.QuadPart > time_cur.QuadPart) { /* must have been a timer roll-over */ - double offset; + QueryPerformanceCounter (&parm); + time_cur = parm.QuadPart; + if (perf_last > time_cur) { /* must have been a timer roll-over */ + /* * must have been a timer roll-over - * It takes 9.223372036855e+18/time_freq sec - * to roll over this counter (time_freq is 1193182 + * It takes 9.223372036855e+18/perf_freq sec + * to roll over this counter (perf_freq is 1193182 * sec on my system). This is currently about 245118 years. * * attempt to add number of seconds in a 64 bit integer * in case the timer resolution improves */ - offset = pow(2.0, 63.0)-1.0/time_freq.QuadPart; - if (offset<=LONG_MAX-offset_time_s) { - offset_time_s += (long) offset; - } - else { - /* - * this problem cant be fixed, but hopefully will never occurr - */ - fprintf (stderr, "%s.%d Timer overflowed\n", __FILE__, __LINE__); - return osiTime (0, 0); + perf_sec_offset += MAXLONGLONG / perf_freq; + perf_frac_offset += MAXLONGLONG % perf_freq; + if (perf_frac_offset>=perf_freq) { + perf_sec_offset++; + perf_frac_offset -= perf_freq; } } - time_sec.QuadPart = time_cur.QuadPart / time_freq.QuadPart; - time_remainder.QuadPart = time_cur.QuadPart % time_freq.QuadPart; - if (time_sec.QuadPart > LONG_MAX-offset_time_s) { - /* - * this problem cant be fixed, but hopefully will never occurr - */ - fprintf (stderr, "%s.%d Timer value larger than storage\n", __FILE__, __LINE__); - return osiTime (0, 0); + time_sec = time_cur / perf_freq; + time_remainder = time_cur % perf_freq; + + /* + * add time (sec) since the EPICS epoch + */ + time_sec += perf_sec_offset; + time_remainder += perf_frac_offset; + if (time_remainder>=perf_freq) { + time_sec += 1; + time_remainder -= perf_freq; } - /* add time (sec) since 1970 */ - sec = offset_time_s + (long)time_sec.QuadPart; - nsec = (long)((time_remainder.QuadPart*1000000000)/time_freq.QuadPart); - - time_prev = time_cur; + perf_last = time_cur; + sec = (unsigned long) (time_sec%ULONG_MAX); + nsec = (unsigned long) ((time_remainder*nSecPerSec)/perf_freq); return osiTime (sec, nsec); } diff --git a/src/libCom/os/generic/osdTime.cc b/src/libCom/os/generic/osdTime.cc index f4d0a57d3..7b0a404cc 100644 --- a/src/libCom/os/generic/osdTime.cc +++ b/src/libCom/os/generic/osdTime.cc @@ -7,6 +7,12 @@ #define epicsExportSharedSymbols #include "osiTime.h" +// +// osiTime::synchronize() +// +void osiTime::synchronize() +{ +} // // osiTime::getCurrent () @@ -19,6 +25,9 @@ osiTime osiTime::getCurrent () status = gettimeofday (&tv, NULL); assert (status==0); - return osiTime(tv.tv_sec, tv.tv_usec * nSecPerUSec); + if (tv.tv_sec #include +// +// osiTime::synchronize() +// +void osiTime::synchronize() +{ +} + // // osiTime::getCurrent () // @@ -17,6 +24,10 @@ osiTime osiTime::getCurrent () ULONG nsec; ULONG rate = sysClkRateGet(); + // + // currently assuming that this has been already adjusted + // for the EPICS epoch + // ticks = tickGet(); sec = ticks/rate; nsec = (ticks%rate)*(nSecPerSec/rate); diff --git a/src/libCom/osi/os/WIN32/dllmain.cpp b/src/libCom/osi/os/WIN32/dllmain.cpp index 510fe22cb..ba1aced91 100644 --- a/src/libCom/osi/os/WIN32/dllmain.cpp +++ b/src/libCom/osi/os/WIN32/dllmain.cpp @@ -46,9 +46,6 @@ #error This source is specific to WIN32 #endif -extern int init_osi_time (); -extern int exit_osi_time (); - #if !defined(EPICS_DLL_NO) BOOL WINAPI DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) { @@ -57,8 +54,6 @@ BOOL WINAPI DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) case DLL_PROCESS_ATTACH: if (!bsdSockAttach()) return FALSE; - if (init_osi_time ()) - return FALSE; # ifdef _DEBUG fprintf(stderr, "Process attached to Com.dll version %s\n", EPICS_VERSION_STRING); # endif @@ -66,7 +61,6 @@ BOOL WINAPI DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved) case DLL_PROCESS_DETACH: bsdSockRelease(); - exit_osi_time (); # ifdef _DEBUG fprintf(stderr, "Process detached from Com.dll version %s\n", EPICS_VERSION_STRING); # endif diff --git a/src/libCom/osi/os/WIN32/osdTime.cpp b/src/libCom/osi/os/WIN32/osdTime.cpp index dd2586c61..d52580a50 100644 --- a/src/libCom/osi/os/WIN32/osdTime.cpp +++ b/src/libCom/osi/os/WIN32/osdTime.cpp @@ -1,62 +1,199 @@ +// +// osiTime.cc +// +// Author: Jeff Hill +// +// #include #include + #include +/* + * for _ftime() + */ +#include +#include + #define epicsExportSharedSymbols #include -static long offset_time_s = 0; /* time diff (sec) from 1990 when EPICS started */ -static LARGE_INTEGER time_prev, time_freq; +// +// performance counter last value, ticks per sec, +// and its offset from the EPICS epoch. +// +static LONGLONG perf_last, perf_freq, perf_offset; + +// +// divide the offset into seconds and +// fractions of a second so that overflow is less +// likely (we dont know the magnitude of perf_freq +// until run time) +// +static LONGLONG perf_sec_offset=-1, perf_frac_offset; + +static const SYSTEMTIME epicsEpochST = { + 1990, // year + 1, // month + 1, // day of the week (Monday) + 1, // day of the month + 0, // hour + 0, // min + 0, // sec + 0 // milli sec +}; + +static LONGLONG epicsEpoch; + +#define FILE_TIME_TICKS_PER_SEC 10000000L /* - * init_osi_time has to be called before using the timer, - * exit_osi_time has to be called in balance. + * synchronize() */ -int init_osi_time () +void osiTime::synchronize() { - if (offset_time_s == 0) { - /* - * initialize elapsed time counters - * - * All CPUs running win32 currently have HR - * counters (Intel and Mips processors do) - */ - if (QueryPerformanceCounter (&time_prev)==0) { - return 1; - } - if (QueryPerformanceFrequency (&time_freq)==0) { - return 1; - } - offset_time_s = (long)time(NULL) - - (long)(time_prev.QuadPart/time_freq.QuadPart); + static int init = 0; + LONGLONG new_sec_offset, new_frac_offset; + LARGE_INTEGER parm; + LONGLONG secondsSinceBoot; + FILETIME currentTimeFT; + LONGLONG currentTime; + BOOL win32Stat; + + // + // one time initialization of constants + // + if (!init) { + FILETIME epicsEpochFT; + + // + // initialize elapsed time counters + // + // All CPUs running win32 currently have HR + // counters (Intel and Mips processors do) + // + assert (QueryPerformanceFrequency (&parm)!=0); + perf_freq = parm.QuadPart; + + // + // convert the EPICS epoch to file time + // + win32Stat = SystemTimeToFileTime (&epicsEpochST, &epicsEpochFT); + assert (win32Stat!=0); + parm.LowPart = epicsEpochFT.dwLowDateTime; + parm.HighPart = epicsEpochFT.dwHighDateTime; + epicsEpoch = parm.QuadPart; + + init = 1; } - return 0; + // + // its important that the following two time queries + // are close together (immediately adjacent to each + // other) in the code + // + GetSystemTimeAsFileTime (¤tTimeFT); + // this one is second because QueryPerformanceFrequency() + // has forced its code to load + assert (QueryPerformanceCounter (&parm)!=0); + + perf_last = parm.QuadPart; + parm.LowPart = currentTimeFT.dwLowDateTime; + parm.HighPart = currentTimeFT.dwHighDateTime; + currentTime = parm.QuadPart; + + // + // check for strange date, and clamp to the + // epics epoch if so + // + if (currentTime>epicsEpoch) { + // + // compute the offset from the EPICS epoch + // + LONGLONG diff = currentTime - epicsEpoch; + + // + // compute the seconds offset and the + // fractional offset part in the FILETIME timebase + // + new_sec_offset = diff / FILE_TIME_TICKS_PER_SEC; + new_frac_offset = diff % FILE_TIME_TICKS_PER_SEC; + + // + // compute the fractional second offset in the performance + // counter time base + // + new_frac_offset = (new_frac_offset*perf_freq) / FILE_TIME_TICKS_PER_SEC; + } + else { + new_sec_offset = 0; + new_frac_offset = 0; + } + + // + // subtract out the perormance counter ticks since the + // begining of windows + // + secondsSinceBoot = perf_last / perf_freq; + if (new_sec_offset>=secondsSinceBoot) { + new_sec_offset -= secondsSinceBoot; + + LONGLONG fracSinceBoot = perf_last % perf_freq; + if (new_frac_offset>=fracSinceBoot) { + new_frac_offset -= fracSinceBoot; + } + else if (new_sec_offset>0) { + // + // borrow + // + new_sec_offset--; + new_frac_offset += perf_freq - fracSinceBoot; + } + else { + new_frac_offset = 0; + } + } + else { + new_sec_offset = 0; + new_frac_offset = 0; + } + + +#if 0 + // + // calculate the change + // + { + double change; + change = (double) (perf_sec_offset-new_sec_offset)*perf_freq + + (perf_frac_offset-new_frac_offset); + change /= perf_freq; + printf ("The performance counter drifted by %f sec\n", change); + } +#endif + + // + // update the current value + // + perf_sec_offset = new_sec_offset; + perf_frac_offset = new_frac_offset; } -int exit_osi_time () -{ - offset_time_s = 0; - - return 0; -} - - // -// osiTime::getCurrent () +// osiTime::osdGetCurrent () // -osiTime osiTime::getCurrent () +osiTime osiTime::osdGetCurrent () { - LARGE_INTEGER time_cur, time_sec, time_remainder; + LONGLONG time_cur, time_sec, time_remainder; + LARGE_INTEGER parm; unsigned long sec, nsec; /* - * this allows the code to work when it is in an object - * library (in addition to inside a dll) + * lazy init */ - if (offset_time_s==0) { - init_osi_time(); + if (perf_sec_offset<0) { + osiTime::synchronize(); } /* @@ -64,45 +201,42 @@ osiTime osiTime::getCurrent () * during initialization to see if the CPU has HR * counters (Intel and Mips processors do) */ - QueryPerformanceCounter (&time_cur); - if (time_prev.QuadPart > time_cur.QuadPart) { /* must have been a timer roll-over */ - double offset; + QueryPerformanceCounter (&parm); + time_cur = parm.QuadPart; + if (perf_last > time_cur) { /* must have been a timer roll-over */ + /* * must have been a timer roll-over - * It takes 9.223372036855e+18/time_freq sec - * to roll over this counter (time_freq is 1193182 + * It takes 9.223372036855e+18/perf_freq sec + * to roll over this counter (perf_freq is 1193182 * sec on my system). This is currently about 245118 years. * * attempt to add number of seconds in a 64 bit integer * in case the timer resolution improves */ - offset = pow(2.0, 63.0)-1.0/time_freq.QuadPart; - if (offset<=LONG_MAX-offset_time_s) { - offset_time_s += (long) offset; - } - else { - /* - * this problem cant be fixed, but hopefully will never occurr - */ - fprintf (stderr, "%s.%d Timer overflowed\n", __FILE__, __LINE__); - return osiTime (0, 0); + perf_sec_offset += MAXLONGLONG / perf_freq; + perf_frac_offset += MAXLONGLONG % perf_freq; + if (perf_frac_offset>=perf_freq) { + perf_sec_offset++; + perf_frac_offset -= perf_freq; } } - time_sec.QuadPart = time_cur.QuadPart / time_freq.QuadPart; - time_remainder.QuadPart = time_cur.QuadPart % time_freq.QuadPart; - if (time_sec.QuadPart > LONG_MAX-offset_time_s) { - /* - * this problem cant be fixed, but hopefully will never occurr - */ - fprintf (stderr, "%s.%d Timer value larger than storage\n", __FILE__, __LINE__); - return osiTime (0, 0); + time_sec = time_cur / perf_freq; + time_remainder = time_cur % perf_freq; + + /* + * add time (sec) since the EPICS epoch + */ + time_sec += perf_sec_offset; + time_remainder += perf_frac_offset; + if (time_remainder>=perf_freq) { + time_sec += 1; + time_remainder -= perf_freq; } - /* add time (sec) since 1970 */ - sec = offset_time_s + (long)time_sec.QuadPart; - nsec = (long)((time_remainder.QuadPart*1000000000)/time_freq.QuadPart); - - time_prev = time_cur; + perf_last = time_cur; + sec = (unsigned long) (time_sec%ULONG_MAX); + nsec = (unsigned long) ((time_remainder*nSecPerSec)/perf_freq); return osiTime (sec, nsec); } diff --git a/src/libCom/osiTime.cc b/src/libCom/osiTime.cc index 7873061ce..bde0c7176 100644 --- a/src/libCom/osiTime.cc +++ b/src/libCom/osiTime.cc @@ -4,34 +4,12 @@ // Author: Jeff Hill // +#include +#include +#include #define epicsExportSharedSymbols -// -// force this module to include code to convert to TS_STAMP -// #include - -// -// force this module to include code that can convert -// to GDD's aitTimeStamp, but dont force it -// to link with gdd -// -#define aitHelpersInclude -class aitTimeStamp { -public: - aitTimeStamp (const unsigned long tv_secIn, const unsigned long tv_nsecIn) : - tv_sec(tv_secIn), tv_nsec(tv_nsecIn) {} - - void get(unsigned long &tv_secOut, unsigned long &tv_nsecOut) const - { - tv_secOut = this->tv_sec; - tv_nsecOut = this->tv_nsec; - } -private: - unsigned long tv_sec; - unsigned long tv_nsec; -}; - #include // @@ -39,3 +17,360 @@ private: // const unsigned osiTime::epicsEpochSecPast1970 = 7305 * 86400; +const unsigned osiTime::mSecPerSec = 1000u; +const unsigned osiTime::nSecPerSec = 1000000000u; +const unsigned osiTime::nSecPerUSec = 1000u; +const unsigned osiTime::secPerMin = 60u; + +// +// osiTime (const unsigned long secIn, const unsigned long nSecIn) +// +osiTime::osiTime (const unsigned long secIn, const unsigned long nSecIn) +{ + if (nSecInsec = secIn; + this->nSec = nSecIn; + } + else if (nSecIn<(nSecPerSec*2)){ + this->sec = secIn + 1u; + this->nSec = nSecIn-nSecPerSec; + } + else { + this->sec = nSecIn/nSecPerSec + secIn; + this->nSec = nSecIn%nSecPerSec; + } +} + +// +// getCurrent () +// +// force a logical progression of time +// +// (this does not appear to add any significant +// overhead when the code is optimized) +// +osiTime osiTime::getCurrent () +{ + static osiTime last; + osiTime ts = osiTime::osdGetCurrent(); + + if (lastsec<=LONG_MAX-osiTime::epicsEpochSecPast1970); + ts.tv_sec = this->sec + osiTime::epicsEpochSecPast1970; + ts.tv_nsec = this->nSec; + return ts; +} + +// +// osiTime (const struct timespec &ts) +// +osiTime::osiTime (const struct timespec &ts) +{ + assert (ts.tv_sec >= osiTime::epicsEpochSecPast1970); + this->sec = ((unsigned long)ts.tv_sec) - osiTime::epicsEpochSecPast1970; + assert (ts.tv_nsec>=0 && ts.tv_nsecnSec = (unsigned long) ts.tv_nsec; +} + +// +// operator = (const struct timespec &rhs) +// +osiTime::operator = (const struct timespec &rhs) +{ + assert (rhs.tv_sec >= osiTime::epicsEpochSecPast1970); + this->sec = ((unsigned long)rhs.tv_sec) - osiTime::epicsEpochSecPast1970; + assert (rhs.tv_nsec>=0 && rhs.tv_nsecnSec = (unsigned long) rhs.tv_nsec; +} + +// +// force this module to include code that can convert +// to GDD's aitTimeStamp, but dont require that it must +// link with gdd. Therefore, gdd.h is not included here. +// +class aitTimeStamp { +public: + unsigned long tv_sec; + unsigned long tv_nsec; +}; + +// +// operator aitTimeStamp () +// +osiTime::operator aitTimeStamp () const +{ + aitTimeStamp ts; + assert (this->sec<=ULONG_MAX-osiTime::epicsEpochSecPast1970); + ts.tv_sec = this->sec + osiTime::epicsEpochSecPast1970; + ts.tv_nsec = this->nSec; + return ts; +} + +// +// osiTime (const aitTimeStamp &ts) +// +osiTime::osiTime (const aitTimeStamp &ts) +{ + assert (ts.tv_sec >= osiTime::epicsEpochSecPast1970); + this->sec = ts.tv_sec - osiTime::epicsEpochSecPast1970; + assert (ts.tv_nsecnSec = ts.tv_nsec; +} + +// +// operator = (const aitTimeStamp &rhs) +// +osiTime::operator = (const aitTimeStamp &rhs) +{ + assert (rhs.tv_sec >= osiTime::epicsEpochSecPast1970); + this->sec = rhs.tv_sec - osiTime::epicsEpochSecPast1970; + assert (rhs.tv_nsecnSec = rhs.tv_nsec; +} + +// +// operator TS_STAMP () +// +osiTime::operator struct TS_STAMP () const +{ + struct TS_STAMP ts; + ts.secPastEpoch = this->sec; + ts.nsec = this->nSec; + return ts; +} + +// +// osiTime (const TS_STAMP &ts) +// +osiTime::osiTime (const struct TS_STAMP &ts) +{ + this->sec = ts.secPastEpoch; + this->nSec = ts.nsec; +} + +// +// operator = (const TS_STAMP &rhs) +// +osiTime::operator = (const struct TS_STAMP &rhs) +{ + this->sec = rhs.secPastEpoch; + this->nSec = rhs.nsec; +} + +// +// osiTime::show (unsigned) +// +void osiTime::show (unsigned) const +{ + // + // lame way to print the time ... + // + printf ("osiTime: sec=%lu nSec=%lu\n", + this->sec, this->nSec); +} + +// +// operator - +// +// Since negative discontinuities in time are of particular +// concern, the "A-B" operator has special code executed +// as follows: +// +// when B is greater than A: +// B-A > one half full scale => assume time stamp wrap around +// B-A <= one half full scale => return a difference of zero +// +// when A is greater than or equal to B +// A-B > one half full scale => return a difference of zero +// A-B <= one half full scale => return A-B +// +osiTime osiTime::operator - (const osiTime &rhs) const +{ + unsigned long nSec, sec; + + if (this->secsec < ULONG_MAX/2) { + // + // In this situation where the difference is less than + // 69 years assume that someone adjusted the time + // backwards slightly. This would happen if a high + // resolution counter drift was realigned to some master + // time source + // + return osiTime (); + } + else { + // + // In this situation where the difference is more than + // 69 years assume that the seconds counter has rolled + // over and compute the "wrap around" difference + // + sec = 1 + this->sec + (ULONG_MAX - rhs.sec); + } + } + else { + sec = this->sec - rhs.sec; + if (sec > ULONG_MAX/2) { + // + // assume that someone adjusted the time + // backwards slightly. This would happen if a high + // resolution counter drift was realigned to some master + // time source + // + return osiTime (); + } + } + + if (this->nSec>=rhs.nSec) { + nSec = this->nSec - rhs.nSec; + } + else { + + if (sec>0) { + // + // Borrow + // + nSec = this->nSec + (osiTime::nSecPerSec - rhs.nSec); + sec--; + } + else { + // + // In this situation where the difference is less than + // 69 years assume that someone adjusted the time + // backwards slightly. This would happen if the high + // resolution counter drift was realigned to some master + // time source + // + return osiTime (); + } + } + return osiTime (sec, nSec); +} + +// +// operator <= +// +int osiTime::operator <= (const osiTime &rhs) const +{ + int rc; + + if (this->secsec < ULONG_MAX/2) { + // + // In this situation where the difference is less than + // 69 years compute the expected result + // + rc = 1; + } + else { + // + // In this situation where the difference is more than + // 69 years assume that the seconds counter has rolled + // over and compute the "wrap around" result + // + rc = 0; + } + } + else if (this->sec>rhs.sec) { + if (this->sec-rhs.sec < ULONG_MAX/2) { + // + // In this situation where the difference is less than + // 69 years compute the expected result + // + rc = 0; + } + else { + // + // In this situation where the difference is more than + // 69 years assume that the seconds counter has rolled + // over and compute the "wrap around" result + // + rc = 1; + } + } + else { + if (this->nSec<=rhs.nSec) { + rc = 1; + } + else { + rc = 0; + } + } + return rc; +} + +// +// operator < +// +int osiTime::operator < (const osiTime &rhs) const +{ + int rc; + + if (this->secsec < ULONG_MAX/2) { + // + // In this situation where the difference is less than + // 69 years compute the expected result + // + rc = 1; + } + else { + // + // In this situation where the difference is more than + // 69 years assume that the seconds counter has rolled + // over and compute the "wrap around" result + // + rc = 0; + } + } + else if (this->sec>rhs.sec) { + if (this->sec-rhs.sec < ULONG_MAX/2) { + // + // In this situation where the difference is less than + // 69 years compute the expected result + // + rc = 0; + } + else { + // + // In this situation where the difference is more than + // 69 years assume that the seconds counter has rolled + // over and compute the "wrap around" result + // + rc = 1; + } + } + else { + if (this->nSec #endif -#define nSecPerSec 1000000000u -#define nSecPerUSec 1000u -#define secPerMin 60u - #include "shareLib.h" +struct timespec; +struct TS_STAMP; +class aitTimeStamp; + +// +// class osiTime +// +// NOTE: this is an unsigned data type. It is not possible +// to store a negative time value using this class. +// class epicsShareClass osiTime { - friend osiTime operator+ - (const osiTime &lhs, const osiTime &rhs); - friend osiTime operator- - (const osiTime &lhs, const osiTime &rhs); - friend int operator>= - (const osiTime &lhs, const osiTime &rhs); - friend int operator> - (const osiTime &lhs, const osiTime &rhs); - friend int operator<= - (const osiTime &lhs, const osiTime &rhs); - friend int operator< - (const osiTime &lhs, const osiTime &rhs); - friend int operator== - (const osiTime &lhs, const osiTime &rhs); public: - osiTime () : sec(0u), nSec(0u) {} - osiTime (const osiTime &t) : sec(t.sec), nSec(t.nSec) {} - osiTime (const unsigned long secIn, const unsigned long nSecIn) - { - if (nSecInsec = secIn; - this->nSec = nSecIn; - } - else if (nSecIn<(nSecPerSec<<1u)){ - this->sec = secIn + 1u; - this->nSec = nSecIn-nSecPerSec; - } - else { - this->sec = nSecIn/nSecPerSec + secIn; - this->nSec = nSecIn%nSecPerSec; - } - } - - osiTime (double t) - { - double intPart; - if (t<0.0l) { - t = 0.0l; - } - this->sec = (unsigned long) t; - intPart = (double) this->sec; - this->nSec = (unsigned long) ((t-intPart)*nSecPerSec); - } - // - // fetch value as an integer + // fetch the current time // - unsigned long getSec() const - { - return this->sec; - } - unsigned long getUSec() const - { - return (this->nSec/nSecPerUSec); - } - unsigned long getNSec() const - { - return this->nSec; - } - + // (always returns a time value that is greater than or equal + // to all previous time values returned) // - // non standard calls for the many strange - // time formats that still exist - // - long getSecTruncToLong() const - { - assert (this->sec<=LONG_MAX); - return (long) this->sec; - } - long getUSecTruncToLong() const - { - return (long) (this->nSec/nSecPerUSec); - } - long getNSecTruncToLong() const - { - assert (this->nSec<=LONG_MAX); - return (long) this->nSec; - } - - - operator double() const - { - return ((double)this->nSec)/nSecPerSec+this->sec; - } - - operator float() const - { - return ((float)this->nSec)/nSecPerSec+this->sec; - } - static osiTime getCurrent(); + // + // some systems have a high resolution time source which + // gradually drifts away from the master time base. Calling + // this routine will cause osiTime to realign the high + // resolution result from getCurrent() with some master + // time base. + // + // if this routine has not been called at least once so far + // by the current process then it is called the first time + // that getCurrent() is called + // + static void synchronize(); + + // + // create an osiTime for the EPICS epoch + // + osiTime () : sec(0u), nSec(0u) {} + + // + // create an osiTime from another osiTime + // + osiTime (const osiTime &t) : sec(t.sec), nSec(t.nSec) {} + + // + // create an osiTime from sec and fractional nano-seconds + // + osiTime (const unsigned long secIn, const unsigned long nSecIn); + + // + // convert to and from floating point + // + osiTime (double t); + operator double() const; + operator float() const; + // // convert to and from EPICS TS_STAMP format // - // include tsDefs.h prior to including osiTime.h - // if you need these capabilities - // -#ifdef INC_tsDefs_h - operator TS_STAMP () const - { - TS_STAMP ts; - assert (this->sec>=osiTime::epicsEpochSecPast1970); - ts.secPastEpoch = this->sec - osiTime::epicsEpochSecPast1970; - ts.nsec = this->nSec; - return ts; - } - - osiTime (const TS_STAMP &ts) - { - this->sec = ts.secPastEpoch + osiTime::epicsEpochSecPast1970; - this->nSec = ts.nsec; - } - - operator = (const TS_STAMP &rhs) - { - this->sec = rhs.secPastEpoch + osiTime::epicsEpochSecPast1970; - this->nSec = rhs.nsec; - } -#endif + operator struct TS_STAMP () const; + osiTime (const struct TS_STAMP &ts); + operator = (const struct TS_STAMP &rhs); // // convert to and from GDD's aitTimeStamp format // - // include aitHelpers.h prior to including osiTime.h - // if you need these capabilities + operator aitTimeStamp () const; + osiTime (const aitTimeStamp &ts); + operator = (const aitTimeStamp &rhs); + // -#ifdef aitHelpersInclude - operator aitTimeStamp () const - { - return aitTimeStamp (this->sec, this->nSec); - } + // convert to and from POSIX RT's "struct timespec" + // + operator struct timespec () const; + osiTime (const struct timespec &ts); + operator = (const struct timespec &rhs); - osiTime (const aitTimeStamp &ts) - { - ts.get (this->sec, this->nSec); - } + // + // arithmetic operators + // + osiTime operator- (const osiTime &rhs) const; + osiTime operator+ (const osiTime &rhs) const; + osiTime operator+= (const osiTime &rhs); + osiTime operator-= (const osiTime &rhs); - operator = (const aitTimeStamp &rhs) - { - rhs.get (this->sec, this->nSec); - } -#endif + // + // comparison operators + // + int operator == (const osiTime &rhs) const; + int operator != (const osiTime &rhs) const; + int operator <= (const osiTime &rhs) const; + int operator < (const osiTime &rhs) const; + int operator >= (const osiTime &rhs) const; + int operator > (const osiTime &rhs) const; - osiTime operator+= (const osiTime &rhs) - { - *this = *this + rhs; - return *this; - } + // + // dump current state to standard out + // + void show (unsigned interestLevel) const; - osiTime operator-= (const osiTime &rhs) - { - *this = *this - rhs; - return *this; - } + // + // useful public constants + // + static const unsigned nSecPerSec; + static const unsigned mSecPerSec; + static const unsigned nSecPerUSec; + static const unsigned secPerMin; + + // + // fetch value as an unsigned integer + // + unsigned long getSec() const; + unsigned long getUSec() const; + unsigned long getNSec() const; + + // + // non standard calls for the many different + // time formats that exist + // + long getSecTruncToLong() const; + long getUSecTruncToLong() const; + long getNSecTruncToLong() const; - void show(unsigned) - { - printf("osiTime: sec=%lu nSec=%lu\n", - this->sec, this->nSec); - } private: unsigned long sec; unsigned long nSec; - static const unsigned epicsEpochSecPast1970; + static const unsigned epicsEpochSecPast1970; + static osiTime osdGetCurrent(); }; -inline osiTime operator+ (const osiTime &lhs, const osiTime &rhs) +inline unsigned long osiTime::getSec() const { - return osiTime(lhs.sec + rhs.sec, lhs.nSec + rhs.nSec); + return this->sec; } -// -// like data type unsigned this assumes that the lhs > rhs -// (otherwise we assume sec wrap around) -// -inline osiTime operator- (const osiTime &lhs, const osiTime &rhs) -{ - unsigned long nSec, sec; - - if (lhs.secnSec/nSecPerUSec); } - -inline int operator <= (const osiTime &lhs, const osiTime &rhs) -{ - int rc; -// -// Sun's CC -O generates bad code when this was rearranged -// - if (lhs.secrhs.sec) { - rc = 0; - } - else { - if (lhs.nSec<=rhs.nSec) { - rc = 1; - } - else { - rc = 0; - } - } - return rc; +inline unsigned long osiTime::getNSec() const +{ + return this->nSec; } -inline int operator < (const osiTime &lhs, const osiTime &rhs) +inline osiTime::osiTime (double t) { - int rc; -// -// Sun's CC -O generates bad code when this was rearranged -// - if (lhs.secrhs.sec) { - rc = 0; - } - else { - if (lhs.nSec0.0); + this->sec = (unsigned long) t; + this->nSec = (unsigned long) ((t-this->sec)*nSecPerSec); } -inline int operator >= (const osiTime &lhs, const osiTime &rhs) +inline osiTime::operator double() const { - int rc; -// -// Sun's CC -O generates bad code here -// -// -// -#if 0 - if (lhs.sec>rhs.sec) { - return 1; - } - else if (lhs.sec==rhs.sec) { - if (lhs.nSec>=rhs.nSec) { - return 1; - } - } - assert(lhs.sec<=rhs.sec); - return 0; -#endif - if (lhs.sec>rhs.sec) { - rc = 1; - } - else if (lhs.sec=rhs.nSec) { - rc = 1; - } - else { - rc = 0; - } - } - return rc; + return ((double)this->nSec)/nSecPerSec+this->sec; } -inline int operator > (const osiTime &lhs, const osiTime &rhs) +inline osiTime::operator float() const { - int rc; -// -// Sun's CC -O generates bad code when this was rearranged -// - if (lhs.sec>rhs.sec) { - rc = 1; - } - else if (lhs.secrhs.nSec) { - rc = 1; - } - else { - rc = 0; - } - } - return rc; + return ((float)this->nSec)/nSecPerSec+this->sec; } -inline int operator== - (const osiTime &lhs, const osiTime &rhs) +inline osiTime osiTime::operator + (const osiTime &rhs) const { - if (lhs.sec == rhs.sec && lhs.nSec == rhs.nSec) { + return osiTime(this->sec + rhs.sec, this->nSec + rhs.nSec); +} + +inline osiTime osiTime::operator += (const osiTime &rhs) +{ + *this = *this + rhs; + return *this; +} + +inline osiTime osiTime::operator -= (const osiTime &rhs) +{ + *this = *this - rhs; + return *this; +} + +inline int osiTime::operator == (const osiTime &rhs) const +{ + if (this->sec == rhs.sec && this->nSec == rhs.nSec) { return 1; } else { @@ -399,5 +264,47 @@ inline int operator== } } +inline int osiTime::operator != (const osiTime &rhs) const +{ + if (this->sec != rhs.sec || this->nSec != rhs.nSec) { + return 1; + } + else { + return 0; + } +} + +// +// operator >= (const osiTime &lhs, const osiTime &rhs) +// +inline int osiTime::operator >= (const osiTime &rhs) const +{ + return !(*this < rhs); +} + +// +// operator > (const osiTime &lhs, const osiTime &rhs) +// +inline int osiTime::operator > (const osiTime &rhs) const +{ + return !(*this <= rhs); +} + +inline long osiTime::getSecTruncToLong() const +{ + assert (this->sec<=LONG_MAX); + return (long) this->sec; +} + +inline long osiTime::getUSecTruncToLong() const +{ + return (long) (this->nSec/nSecPerUSec); +} + +inline long osiTime::getNSecTruncToLong() const +{ + return (long) this->nSec; +} + #endif // osiTimehInclude diff --git a/src/libCom/osiTimer.cc b/src/libCom/osiTimer.cc index 35e4b173e..8643c4f52 100644 --- a/src/libCom/osiTimer.cc +++ b/src/libCom/osiTimer.cc @@ -29,6 +29,9 @@ * * History * $Log$ + * Revision 1.9 1997/08/05 00:37:06 jhill + * removed warnings + * * Revision 1.8 1997/06/25 05:45:54 jhill * cleaned up pc port * @@ -247,7 +250,7 @@ osiTime osiTimerQueue::delayToFirstExpire() const // // no timer in the queue - return a long delay - 30 min // - delay = osiTime(30u * secPerMin, 0u); + delay = osiTime (30u * osiTime::secPerMin, 0u); } #ifdef DEBUG printf("delay to first item on the queue %f\n", (double) delay); diff --git a/src/libCom/timer/osiTimer.cpp b/src/libCom/timer/osiTimer.cpp index 35e4b173e..8643c4f52 100644 --- a/src/libCom/timer/osiTimer.cpp +++ b/src/libCom/timer/osiTimer.cpp @@ -29,6 +29,9 @@ * * History * $Log$ + * Revision 1.9 1997/08/05 00:37:06 jhill + * removed warnings + * * Revision 1.8 1997/06/25 05:45:54 jhill * cleaned up pc port * @@ -247,7 +250,7 @@ osiTime osiTimerQueue::delayToFirstExpire() const // // no timer in the queue - return a long delay - 30 min // - delay = osiTime(30u * secPerMin, 0u); + delay = osiTime (30u * osiTime::secPerMin, 0u); } #ifdef DEBUG printf("delay to first item on the queue %f\n", (double) delay);