/************************************************************************/ /* SISCO SOFTWARE MODULE HEADER *****************************************/ /************************************************************************/ /* (c) Copyright Systems Integration Specialists Company, Inc., */ /* 1993 - 2007, All Rights Reserved */ /* */ /* MODULE NAME : stime.c */ /* PRODUCT(S) : */ /* */ /* MODULE DESCRIPTION : */ /* This module implements functions that can be used in */ /* differencial timimg. */ /* */ /* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ /* */ /* MODIFICATION LOG : */ /* Date Who Rev Comments */ /* -------- --- ------ ------------------------------------------- */ /* 01/15/07 EJV 30 Chg S_LOCK_RESOURCES to S_LOCK_UTIL_RESOURCES*/ /* 10/26/06 EJV 29 HP-UX: changed from gettimeofday() to times()*/ /* 07/13/06 EJV 28 Sun: changed from gettimeofday() to times(). */ /* 06/20/06 RKR 27 removed a piece of code from _sGetSysMsTime */ /* 05/31/06 GLB 26 Integrated porting changes for VMS */ /* 03/23/06 EJV 25 Corrected VMS chg to _sGetSysMsTime. */ /* Rearranged includes, del windows.h. */ /* 01/30/06 GLB 24 Integrated porting changes for VMS */ /* 01/30/06 EJV 23 _WIN32 _sGetSysMsTime: added (ST_INT64) cast */ /* before (ST_DOUBLE) to eliminate VS6 compiler*/ /* error after changing ST_UINT64 define to */ /* unsigned __int64. */ /* 06/10/05 EJV 22 Revised the repeating code. */ /* Linux, QNX: rpl gettimeofday() with times(). */ /* Del MSDOS and __OS2__ code. */ /* Del sGetMsStartTime, sSetMsStartTime */ /* Renamed lastTime to initTime. */ /* 03/11/04 GLB 21 Remove "thisFileName" */ /* 12/09/03 JRB 20 Add LYNX support. */ /* 11/04/03 JRB 19 Add sMsSleep (replaces gs_sleep). */ /* 10/13/03 EJV 18 Chg defined(vms) to defined(__VMS) */ /* 04/08/03 EJV 17 Use S_LOCK_RESOURCES (better for non-MT apps)*/ /* 03/21/03 EJV 16 _WIN32: sGetMsTime, sGetSysMsTime must be */ /* protected by mutex,prevent incorect wrapCount*/ /* 03/18/03 EJV 15 Corrected __QNX4__ to __QNX__ (per JRB). */ /* 03/18/03 EJV 14 sGetMsTime: fixed lastTime casting problem */ /* (made lastTime ST_UINT on _WIN32). */ /* 02/17/03 CRM 13 Added "defined(linux)" code. */ /* 02/17/03 JRB 12 Add "sysincs.h" & del other includes. */ /* Del obsolete _WINDOWS, MSOS2 code. */ /* 02/17/03 EJV 11 sGetMsTime, sGetSysMsTime: fixed wrap counter*/ /* Auto-initialize funs with call to stimeInit()*/ /* Chg S_LOCK_RESOURCES to gs_get_sem,avoid loop*/ /* 06/05/02 MDE,EJV 10 sGetMsTime: workaround some math problem */ /* 11/29/01 EJV 09 Del code for old LATT, XENIX, ultrix, RMX86. */ /* 06/19/01 JRB 08 Chg S_LOCK_COMMON.. to S_LOCK_RESOURCES so */ /* glbsem doesn't log (caused infinite loop). */ /* 04/19/00 JRB 07 Lint cleanup. */ /* 11/18/99 EJV 06 Added code to capture wrapping of ms counter */ /* for _WIN32 and PHARLAP_ETS. */ /* 09/13/99 MDE 05 Added SD_CONST modifiers */ /* 11/05/97 DSF 04 Added sGetSysMsTime () */ /* 09/22/97 JRB 03 Fixed some #if's. */ /* 09/09/97 JRB 02 Use GetTickCount for PHARLAP_ETS. */ /* 09/08/97 EJV 01 Added code for QNX. */ /* 04/02/97 DTL 7.00 MMSEASE 7.0 release. See MODL70.DOC for */ /* history. */ /************************************************************************/ #include "glbtypes.h" #include "sysincs.h" #include "glbsem.h" #if defined (_WIN32) #include #if defined (PHARLAP_ETS) #define timeGetTime GetTickCount /* timeGetTime not supported */ #endif /* PHARLAP_ETS */ #endif #if defined(__VMS) #include #endif #if defined(linux) || defined(sun) || defined(__hpux) || \ defined(__QNX__) || defined(__LYNX) #include /* for struct tms */ #endif /************************************************************************/ /* NOTE: Users porting this code to new platform should not use the */ /* gettimeofday() or similar functions. When the system time */ /* is changed, for example during clock synchronization, the */ /* gettimeofday() would also reflect this change. */ /* Application should use times() function if available. */ /* */ /* DEBUG: On UNIX systems we should implement the sTime functions */ /* the same way as on LINUX. */ /************************************************************************/ /*------------------------------------------------------*/ /* stime module variables */ /*------------------------------------------------------*/ #if defined(linux) || defined(sun) || defined(__hpux) static ST_UINT64 wrapCount; /* ms, cumulative wrapped time ticks elapsed since program start*/ #elif (defined (__QNX__) || defined(__LYNX)) static ST_DOUBLE wrapCount; /* ms, cumulative wrapped time ticks elapsed since program start*/ #elif defined (_WIN32) static ST_UINT64 wrapCount; /* wrap count (see timeGetTime or GetTickTime) */ #endif #if defined (__ECOS) #define ST_UINT64 unsigned long long static unsigned long long wrapCount; #endif static ST_ULONG ticksPerSec; /* system dependent value, returned by sysconf(_SC_CLK_TCK) */ static ST_ULONG lastCheckTime; /* last time checked, used to detect clock_t overflow */ static ST_DOUBLE initMsTime; /* in ms, store initialization time */ static ST_INT initialized; /* SD_TRUE if stimeInit func successful */ /************************************************************************/ /* _sGetSysMsTime */ /*----------------------------------------------------------------------*/ /* Combined code from sGetMsTime and sGetSysMsTime, now also called by */ /* stimeInit. */ /* */ /* NOTE: this new implementation on LINUX uses the times() function */ /* to obtain the "number of clock ticks that have elapsed since */ /* an arbitrary point in the past. For Linux this point is the */ /* moment the system was booted. The return from times() may */ /* overflow the possible range of clock_t." */ /* The revision of the IEEE Std 1003.1, 2004 allows the that */ /* reference point can be the start-up time of the process */ /* rather than system start-up time. */ /* IMPORTANT: */ /* This implementation is assuming that POSIX compliant clock_t */ /* type is defined as long (4 bytes integer). If this is not the */ /* case then the code needs to be revised! */ /* */ /* DEBUG: In the future LINUX implementation should be used for all */ /* UNIX systems. */ /************************************************************************/ static ST_DOUBLE _sGetSysMsTime (ST_VOID) { ST_DOUBLE sysMsTime = (ST_DOUBLE) 0.0; /* system time to be returned */ #if defined(linux) || defined(sun) || defined(__hpux) { struct tms tmsTime; /* must be passed to times() but we do not use it */ ST_ULONG sysTime; sysTime = (ST_ULONG) times (&tmsTime); if (sysTime != (ST_ULONG) -1) { /* NOTE: The value returned from the times() function (number of ticks */ /* from some fixed point in time) will wrap. */ /* Wrapping depends on the frequency (ticksPerSec) and can be as */ /* often as every 39 minutes. This function needs to be called */ /* frequently enough to detect when the value wraps. */ #if 0 /* DEBUG: code to test wrapping, */ /* trigger the wrapping every 60 seconds if this funct is called */ if ( (sysTime > ticksPerSec) && /* don't wrap before 1-st second elapses*/ ((sysTime / ticksPerSec) % 60 == 0) ) lastCheckTime=sysTime+1; /* tweek the lastCheckTime */ #endif if (sysTime < lastCheckTime) /* the ticks counter wrapped to 0 */ wrapCount += ((ST_UINT64) 1 << 32); /* increment the high part of ST_UINT64 */ /* convert the sys time to ms accounting for possible wrap */ /* (switch math operations order / with * for better precission, avoid floating point math) */ sysMsTime = (ST_DOUBLE)((wrapCount + (ST_UINT64) sysTime) * 1000 / (ST_UINT64) ticksPerSec); lastCheckTime = sysTime; /* save for next check */ } else { ST_INT err; err = errno; /* can't log this error but we could see it in debugger */ } } #elif defined(__ECOS) { struct timeval tp; struct timezone tzp; gettimeofday (&tp, &tzp); /* avoid floating math */ sysMsTime = (ST_DOUBLE) ( (ST_UINT64) ((ST_ULONG) tp.tv_sec) * (ST_UINT64) 1000 + (ST_UINT64) ((ST_ULONG) tp.tv_usec) / (ST_UINT64) 1000 ); #if 0 cyg_tick_count_t sysTime; /* in ecos, cyg_tick_count_t is defined by cyg_uint64 */ sysTime = cyg_current_time(); sysMsTime = (ST_DOUBLE)((wrapCount + (ST_UINT64) sysTime) * 1000 / (ST_UINT64) ticksPerSec); #endif } #elif defined(_AIX) || (defined(__alpha) && !defined(__VMS)) /* Tru64 alpha */ { struct timeval tp; struct timezone tzp; gettimeofday (&tp, &tzp); /* avoid floating math */ sysMsTime = (ST_DOUBLE) ( (ST_UINT64) ((ST_ULONG) tp.tv_sec) * (ST_UINT64) 1000 + (ST_UINT64) ((ST_ULONG) tp.tv_usec) / (ST_UINT64) 1000 ); } #elif defined(__VMS) /* OpenVMS non-specific */ { struct timeval tp; ST_LONG tzp; gettimeofday (&tp, &tzp); /* avoid floating math */ sysMsTime = (ST_DOUBLE) ( /*(ST_UINT64)*/ ((ST_ULONG) tp.tv_sec) * /*(ST_UINT64)*/ 1000 + /*(ST_UINT64)*/ ((ST_ULONG) tp.tv_usec) / /*(ST_UINT64)*/ 1000 ); } #elif defined (VXWORKS) { /*renxiaobao add*/ struct timeval tp; vx_gettimeofday (&tp,0); sysMsTime = ((ST_DOUBLE)tp.tv_sec)*1000 + ((ST_DOUBLE)tp.tv_usec)/1000; /*sysMsTime = (ST_DOUBLE) time (NULL) * 1000;*/ } #elif (defined (__QNX__) || defined(__LYNX)) { struct tms tmsTime; /* must be passed to times() but we do not use it */ ST_ULONG sysTime; sysTime = (ST_ULONG) times (&tmsTime); if (sysTime != (ST_ULONG) -1) { /* NOTE: The value returned from the times() function (number of ticks */ /* from some fixed point in time) will wrap. */ /* Wrapping depends on the frequency (ticksPerSec) and can be as */ /* often as every 39 minutes. This function needs to be called */ /* frequently enough to detect when the value wraps. */ if (sysTime < lastCheckTime) /* the ticks counter wrapped to 0 */ wrapCount += (ST_DOUBLE) (ULONG_MAX); /* convert the sys time to ms accounting for possible wrap, */ /* note that we do not have ST_INT64 support on QNX or LYNX systems */ sysMsTime = (ST_DOUBLE)((wrapCount + (ST_DOUBLE) sysTime) * 1000.0 / (ST_DOUBLE) ticksPerSec); lastCheckTime = sysTime; /* save for next check */ } } #elif defined (_WIN32) { ST_ULONG msTime; /* the timeGetTime function retrieves the system time, in milliseconds.*/ /* The system time is the time elapsed since Windows was started. */ /* NOTE: The timeGetTime and GetTickCount (used for PHARLAP_ETS) */ /* return DWORD value that wraps to 0 every 49 days. */ /* We need to detect the wrap up moment and save it. */ msTime = (ST_ULONG) timeGetTime (); if ( msTime < lastCheckTime ) /* the ms counter wrapped to 0 */ wrapCount += ( (ST_UINT64) 1 << 32 ); /* increment the high part of ST_UINT64 */ sysMsTime = (ST_DOUBLE) (ST_INT64) (wrapCount + (ST_UINT64) msTime); /* NOTE VC V6.0 compiler: the compiler generates error for the */ /* conversion of unsigned __int64 to double. We will cast to */ /* ST_INT64 before the ST_DOUBLE cast. This should work */ /* because the sum of both numbers will 'never' be negative. */ lastCheckTime = msTime; /* save for next check */ } #else #error Missing stime module implementation for this platform #endif return (sysMsTime); } /************************************************************************/ /* _stimeReset */ /*----------------------------------------------------------------------*/ /* Resets stime module variables. */ /************************************************************************/ static ST_RET _stimeReset (ST_VOID) { ST_RET rtn = SD_SUCCESS; #if (defined(linux) || defined(sun) || defined(__hpux) || defined(_WIN32)) wrapCount = 0; lastCheckTime = 0; #elif (defined(__QNX__) || defined(__LYNX)) wrapCount = 0.0; lastCheckTime = 0; #endif initMsTime = _sGetSysMsTime (); return (rtn); } /************************************************************************/ /* stimeInit */ /*----------------------------------------------------------------------*/ /* Initialize stime module variables. */ /************************************************************************/ ST_RET stimeInit (ST_VOID) { ST_RET rtn = SD_SUCCESS; /* Allow multiple calls */ if (initialized) return (rtn); S_LOCK_UTIL_RESOURCES (); /* NOTE: this macro is now using non-logging gs_get_sem() */ #if defined(linux) || defined(sun) || defined(__hpux) || defined(__QNX__) || defined(__LYNX) { ticksPerSec = 0; ticksPerSec = (ST_ULONG) sysconf(_SC_CLK_TCK); if (ticksPerSec == (ST_ULONG) -1L || ticksPerSec == 0) rtn = SD_FAILURE; /* some error getting the number of clock ticks per second */ } #endif if (rtn == SD_SUCCESS) { rtn = _stimeReset (); if (rtn == SD_SUCCESS) initialized = SD_TRUE; } S_UNLOCK_UTIL_RESOURCES (); return (rtn); } /************************************************************************/ /* sGetMsTime */ /*----------------------------------------------------------------------*/ /* Returns time in milliseconds form the start of the program. */ /************************************************************************/ ST_DOUBLE sGetMsTime (ST_VOID) { ST_DOUBLE sysMsTime, retMsTime; if (!initialized) if (stimeInit () != SD_SUCCESS) return ((ST_DOUBLE)0.0); S_LOCK_UTIL_RESOURCES (); sysMsTime = _sGetSysMsTime(); retMsTime = sysMsTime - initMsTime; S_UNLOCK_UTIL_RESOURCES (); return (retMsTime); } /************************************************************************/ /* sGetSysMsTime */ /*----------------------------------------------------------------------*/ /* Returns system time in milliseconds (time from an arbitrary point */ /* like system start or program start). */ /************************************************************************/ ST_DOUBLE sGetSysMsTime (ST_VOID) { ST_DOUBLE sysMsTime; if (!initialized) if (stimeInit () != SD_SUCCESS) return ((ST_DOUBLE)0.0); S_LOCK_UTIL_RESOURCES (); sysMsTime = _sGetSysMsTime(); S_UNLOCK_UTIL_RESOURCES (); return (sysMsTime); } /************************************************************************/ /* sResetMsTime */ /*----------------------------------------------------------------------*/ /* Reset stime module variables. */ /************************************************************************/ ST_VOID sResetMsTime (ST_VOID) { if (!initialized) { stimeInit (); /* calls the _stimeReset() */ return; } S_LOCK_UTIL_RESOURCES (); _stimeReset (); S_UNLOCK_UTIL_RESOURCES (); } /************************************************************************/ /* stimeExit */ /*----------------------------------------------------------------------*/ /* Terminate timer use. */ /************************************************************************/ ST_VOID stimeExit (ST_VOID) { if (!initialized) return; S_LOCK_UTIL_RESOURCES (); initialized = SD_FALSE; S_UNLOCK_UTIL_RESOURCES (); } /************************************************************************/ /* sMsSleep */ /*----------------------------------------------------------------------*/ /* Calls system function to suspend current task or thread for */ /* specified amount of time. */ /* Parameters: */ /* ST_LONG ms Number of milliseconds to sleep */ /* Return values: */ /* none */ /************************************************************************/ #if defined(_WIN32) ST_VOID sMsSleep (ST_LONG ms) { Sleep (ms); } #elif defined(__VMS) ST_VOID sMsSleep (ST_LONG ms) { ST_ULONG msec = (ST_ULONG) ms; unsigned int us; while (msec > 0) { if (msec >= 1000) { us = 999999; /* microseconds, it must be less than 1000000 for usleep */ msec -= 1000; } else { us = msec * 1000; msec = 0; } usleep (us); /* unistd.h */ } } #else /* all other systems */ /* This version of the function uses the POSIX nanosleep function. */ ST_VOID sMsSleep (ST_LONG ms) { struct timespec rqtp; rqtp.tv_sec = ms / 1000; rqtp.tv_nsec = (ms % 1000) * 1000000; /* 1000 ms/us, 1000 us/ns ... */ nanosleep (&rqtp, NULL); /* should be available on AIX v5.x */ } #endif /* all other systems */