diff options
Diffstat (limited to 'unix/tclUnixTime.c')
-rw-r--r-- | unix/tclUnixTime.c | 355 |
1 files changed, 268 insertions, 87 deletions
diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c index 707dfbc..b98f2e1 100644 --- a/unix/tclUnixTime.c +++ b/unix/tclUnixTime.c @@ -11,8 +11,11 @@ */ #include "tclInt.h" -#include "tclPort.h" #include <locale.h> +#if defined(TCL_WIDE_CLICKS) && defined(MAC_OSX_TCL) +#include <mach/mach_time.h> +#endif + #define TM_YEAR_BASE 1900 #define IsLeapYear(x) (((x)%4 == 0) && ((x)%100 != 0 || (x)%400 == 0)) @@ -43,8 +46,20 @@ static char *lastTZ = NULL; /* Holds the last setting of the TZ * Static functions declared in this file. */ -static void SetTZIfNecessary _ANSI_ARGS_((void)); -static void CleanupMemory _ANSI_ARGS_((ClientData)); +static void SetTZIfNecessary(void); +static void CleanupMemory(ClientData clientData); +static void NativeScaleTime(Tcl_Time *timebuf, + ClientData clientData); +static void NativeGetTime(Tcl_Time *timebuf, + ClientData clientData); + +/* + * TIP #233 (Virtualized Time): Data for the time hooks, if any. + */ + +Tcl_GetTimeProc *tclGetTimeProcPtr = NativeGetTime; +Tcl_ScaleTimeProc *tclScaleTimeProcPtr = NativeScaleTime; +ClientData tclTimeClientData = NULL; /* *---------------------------------------------------------------------- @@ -64,9 +79,9 @@ static void CleanupMemory _ANSI_ARGS_((ClientData)); */ unsigned long -TclpGetSeconds() +TclpGetSeconds(void) { - return time((time_t *) NULL); + return time(NULL); } /* @@ -89,27 +104,124 @@ TclpGetSeconds() */ unsigned long -TclpGetClicks() +TclpGetClicks(void) { unsigned long now; #ifdef NO_GETTOD - struct tms dummy; + if (tclGetTimeProcPtr != NativeGetTime) { + Tcl_Time time; + + (*tclGetTimeProcPtr) (&time, tclTimeClientData); + now = time.sec*1000000 + time.usec; + } else { + /* + * A semi-NativeGetTime, specialized to clicks. + */ + struct tms dummy; + + now = (unsigned long) times(&dummy); + } #else - struct timeval date; + Tcl_Time time; + + (*tclGetTimeProcPtr) (&time, tclTimeClientData); + now = time.sec*1000000 + time.usec; #endif -#ifdef NO_GETTOD - now = (unsigned long) times(&dummy); + return now; +} +#ifdef TCL_WIDE_CLICKS + +/* + *----------------------------------------------------------------------------- + * + * TclpGetWideClicks -- + * + * This procedure returns a WideInt value that represents the highest + * resolution clock available on the system. There are no garantees on + * what the resolution will be. In Tcl we will call this value a "click". + * The start time is also system dependant. + * + * Results: + * Number of WideInt clicks from some start time. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +Tcl_WideInt +TclpGetWideClicks(void) +{ + Tcl_WideInt now; + + if (tclGetTimeProcPtr != NativeGetTime) { + Tcl_Time time; + + (*tclGetTimeProcPtr) (&time, tclTimeClientData); + now = (Tcl_WideInt) (time.sec*1000000 + time.usec); + } else { +#ifdef MAC_OSX_TCL + now = (Tcl_WideInt) (mach_absolute_time() & INT64_MAX); #else - gettimeofday(&date, NULL); - now = date.tv_sec*1000000 + date.tv_usec; +#error Wide high-resolution clicks not implemented on this platform #endif + } return now; } /* + *----------------------------------------------------------------------------- + * + * TclpWideClicksToNanoseconds -- + * + * This procedure converts click values from the TclpGetWideClicks native + * resolution to nanosecond resolution. + * + * Results: + * Number of nanoseconds from some start time. + * + * Side effects: + * None. + * + *----------------------------------------------------------------------------- + */ + +double +TclpWideClicksToNanoseconds( + Tcl_WideInt clicks) +{ + double nsec; + + if (tclGetTimeProcPtr != NativeGetTime) { + nsec = clicks * 1000; + } else { +#ifdef MAC_OSX_TCL + static mach_timebase_info_data_t tb; + static uint64_t maxClicksForUInt64; + + if (!tb.denom) { + mach_timebase_info(&tb); + maxClicksForUInt64 = UINT64_MAX / tb.numer; + } + if ((uint64_t) clicks < maxClicksForUInt64) { + nsec = ((uint64_t) clicks) * tb.numer / tb.denom; + } else { + nsec = ((long double) (uint64_t) clicks) * tb.numer / tb.denom; + } +#else +#error Wide high-resolution clicks not implemented on this platform +#endif + } + + return nsec; +} +#endif /* TCL_WIDE_CLICKS */ + +/* *---------------------------------------------------------------------- * * TclpGetTimeZone -- @@ -128,8 +240,8 @@ TclpGetClicks() */ int -TclpGetTimeZone(currentTime) - Tcl_WideInt currentTime; +TclpGetTimeZone( + unsigned long currentTime) { int timeZone; @@ -149,7 +261,7 @@ TclpGetTimeZone(currentTime) */ time_t curTime = (time_t) currentTime; - struct tm *timeDataPtr = TclpLocaltime((TclpTime_t) &curTime); + struct tm *timeDataPtr = TclpLocaltime(&curTime); timeZone = timeDataPtr->tm_tzadj / 60; if (timeDataPtr->tm_isdst) { @@ -164,7 +276,7 @@ TclpGetTimeZone(currentTime) */ time_t curTime = (time_t) currentTime; - struct tm *timeDataPtr = TclpLocaltime((TclpTime_t) &curTime); + struct tm *timeDataPtr = TclpLocaltime(&curTime); timeZone = -(timeDataPtr->tm_gmtoff / 60); if (timeDataPtr->tm_isdst) { @@ -198,7 +310,7 @@ TclpGetTimeZone(currentTime) struct tm *stm; tt = 849268800L; /* 1996-11-29 12:00:00 GMT */ - stm = TclpLocaltime((TclpTime_t) &tt); /* eg 1996-11-29 6:00:00 CST6CDT */ + stm = TclpLocaltime(&tt); /* eg 1996-11-29 6:00:00 CST6CDT */ /* * The calculation below assumes a max of +12 or -12 hours from GMT. @@ -233,6 +345,9 @@ TclpGetTimeZone(currentTime) * Gets the current system time in seconds and microseconds since the * beginning of the epoch: 00:00 UCT, January 1, 1970. * + * This function is hooked, allowing users to specify their own virtual + * system time. + * * Results: * Returns the current time in timePtr. * @@ -243,14 +358,10 @@ TclpGetTimeZone(currentTime) */ void -Tcl_GetTime(timePtr) - Tcl_Time *timePtr; /* Location to store time information. */ +Tcl_GetTime( + Tcl_Time *timePtr) /* Location to store time information. */ { - struct timeval tv; - - (void) gettimeofday(&tv, NULL); - timePtr->sec = tv.tv_sec; - timePtr->usec = tv.tv_usec; + (*tclGetTimeProcPtr) (timePtr, tclTimeClientData); } /* @@ -272,9 +383,9 @@ Tcl_GetTime(timePtr) */ struct tm * -TclpGetDate(time, useGMT) - TclpTime_t time; - int useGMT; +TclpGetDate( + CONST time_t *time, + int useGMT) { if (useGMT) { return TclpGmtime(time); @@ -286,48 +397,9 @@ TclpGetDate(time, useGMT) /* *---------------------------------------------------------------------- * - * TclpStrftime -- - * - * On Unix, we can safely call the native strftime implementation, - * and also ignore the useGMT parameter. - * - * Results: - * The normal strftime result. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -size_t -TclpStrftime(s, maxsize, format, t, useGMT) - char *s; - size_t maxsize; - CONST char *format; - CONST struct tm *t; - int useGMT; -{ - if (format[0] == '%' && format[1] == 'Q') { - /* Format as a stardate */ - sprintf(s, "Stardate %2d%03d.%01d", - (((t->tm_year + TM_YEAR_BASE) + 377) - 2323), - (((t->tm_yday + 1) * 1000) / - (365 + IsLeapYear((t->tm_year + TM_YEAR_BASE)))), - (((t->tm_hour * 60) + t->tm_min)/144)); - return(strlen(s)); - } - setlocale(LC_TIME, ""); - return strftime(s, maxsize, format, t); -} - -/* - *---------------------------------------------------------------------- - * * TclpGmtime -- * - * Wrapper around the 'gmtime' library function to make it thread - * safe. + * Wrapper around the 'gmtime' library function to make it thread safe. * * Results: * Returns a pointer to a 'struct tm' in thread-specific data. @@ -339,27 +411,24 @@ TclpStrftime(s, maxsize, format, t, useGMT) */ struct tm * -TclpGmtime(tt) - TclpTime_t_CONST tt; +TclpGmtime( + CONST time_t *timePtr) /* Pointer to the number of seconds since the + * local system's epoch */ { - CONST time_t *timePtr = (CONST time_t *) tt; - /* Pointer to the number of seconds - * since the local system's epoch */ - /* * Get a thread-local buffer to hold the returned time. */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tmKey); + #ifdef HAVE_GMTIME_R gmtime_r(timePtr, &(tsdPtr->gmtime_buf)); #else Tcl_MutexLock(&tmMutex); - memcpy((VOID *) &(tsdPtr->gmtime_buf), - (VOID *) gmtime(timePtr), - sizeof(struct tm)); + memcpy(&(tsdPtr->gmtime_buf), gmtime(timePtr), sizeof(struct tm)); Tcl_MutexUnlock(&tmMutex); #endif + return &(tsdPtr->gmtime_buf); } @@ -381,33 +450,145 @@ TclpGmtime(tt) */ struct tm * -TclpLocaltime(tt) - TclpTime_t_CONST tt; +TclpLocaltime( + CONST time_t *timePtr) /* Pointer to the number of seconds since the + * local system's epoch */ { - CONST time_t *timePtr = (CONST time_t *) tt; - /* Pointer to the number of seconds - * since the local system's epoch */ /* * Get a thread-local buffer to hold the returned time. */ ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&tmKey); + SetTZIfNecessary(); #ifdef HAVE_LOCALTIME_R localtime_r(timePtr, &(tsdPtr->localtime_buf)); #else Tcl_MutexLock(&tmMutex); - memcpy((VOID *) &(tsdPtr -> localtime_buf), - (VOID *) localtime(timePtr), - sizeof(struct tm)); + memcpy(&(tsdPtr->localtime_buf), localtime(timePtr), sizeof(struct tm)); Tcl_MutexUnlock(&tmMutex); #endif + return &(tsdPtr->localtime_buf); } /* *---------------------------------------------------------------------- * + * Tcl_SetTimeProc -- + * + * TIP #233 (Virtualized Time): Registers two handlers for the + * virtualization of Tcl's access to time information. + * + * Results: + * None. + * + * Side effects: + * Remembers the handlers, alters core behaviour. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_SetTimeProc( + Tcl_GetTimeProc *getProc, + Tcl_ScaleTimeProc *scaleProc, + ClientData clientData) +{ + tclGetTimeProcPtr = getProc; + tclScaleTimeProcPtr = scaleProc; + tclTimeClientData = clientData; +} + +/* + *---------------------------------------------------------------------- + * + * Tcl_QueryTimeProc -- + * + * TIP #233 (Virtualized Time): Query which time handlers are registered. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +Tcl_QueryTimeProc( + Tcl_GetTimeProc **getProc, + Tcl_ScaleTimeProc **scaleProc, + ClientData *clientData) +{ + if (getProc) { + *getProc = tclGetTimeProcPtr; + } + if (scaleProc) { + *scaleProc = tclScaleTimeProcPtr; + } + if (clientData) { + *clientData = tclTimeClientData; + } +} + +/* + *---------------------------------------------------------------------- + * + * NativeScaleTime -- + * + * TIP #233: Scale from virtual time to the real-time. For native scaling + * the relationship is 1:1 and nothing has to be done. + * + * Results: + * Scales the time in timePtr. + * + * Side effects: + * See above. + * + *---------------------------------------------------------------------- + */ + +static void +NativeScaleTime( + Tcl_Time *timePtr, + ClientData clientData) +{ + /* Native scale is 1:1. Nothing is done */ +} + +/* + *---------------------------------------------------------------------- + * + * NativeGetTime -- + * + * TIP #233: Gets the current system time in seconds and microseconds + * since the beginning of the epoch: 00:00 UCT, January 1, 1970. + * + * Results: + * Returns the current time in timePtr. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static void +NativeGetTime( + Tcl_Time *timePtr, + ClientData clientData) +{ + struct timeval tv; + + (void) gettimeofday(&tv, NULL); + timePtr->sec = tv.tv_sec; + timePtr->usec = tv.tv_usec; +} +/* + *---------------------------------------------------------------------- + * * SetTZIfNecessary -- * * Determines whether a call to 'tzset' is needed prior to the next call @@ -425,7 +606,7 @@ TclpLocaltime(tt) */ static void -SetTZIfNecessary() +SetTZIfNecessary(void) { CONST char *newTZ = getenv("TZ"); @@ -464,8 +645,8 @@ SetTZIfNecessary() */ static void -CleanupMemory(ignored) - ClientData ignored; +CleanupMemory( + ClientData ignored) { ckfree(lastTZ); } |