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);  } | 
