summaryrefslogtreecommitdiffstats
path: root/unix/tclUnixTime.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tclUnixTime.c')
-rw-r--r--unix/tclUnixTime.c355
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);
}