From 1f09368b39073bc30f3957f2f70911a722f5c781 Mon Sep 17 00:00:00 2001 From: Kevin B Kenny Date: Fri, 14 May 2004 21:41:04 +0000 Subject: 2004-05-14 Kevin B. Kenny * generic/tclInt.decls: Promoted TclpLocaltime and TclpGmtime * generic/tclIntDecls.h: from Unix-specific stubs to the generic * generic/tclIntPlatDecls.h: internal Stubs table. Reran 'genstubs' * generic/tclStubInit.c: * unix/tclUnixPort.h: * generic/tclClock.c: Changed a buggy 'GMT' timezone specification to the correct 'GMT0'. [Bug #922848] * unix/tclUnixThrd.c: Moved TclpGmtime and TclpLocaltime to unix/tclUnixTime.c where they belong. * unix/tclUnixTime.c (TclpGmtime, TclpLocaltime, TclpGetTimeZone, ThreadSafeGMTime [removed], ThreadSafeLocalTime [removed], SetTZIfNecessary, CleanupMemory): Restructured to make sure that the same mutex protects all calls to localtime, gmtime, and tzset. Added a check in front of those calls to make sure that the TZ env var hasn't changed since the last call to tzset, and repeat tzset if necessary. [Bug #942078] Removed a buggy test of the Daylight Saving Time information in 'gettimeofday' in favor of applying 'localtime' to a known value. [Bug #922848] * tests/clock.test (clock-3.14): Added test to make sure that changes to $env(TZ) take effect immediately. * win/tclWinTime.c (TclpLocaltime, TclpGmtime): Added porting layer for 'localtime' and 'gmtime' calls. --- ChangeLog | 33 +++++++ generic/tclClock.c | 4 +- generic/tclInt.decls | 18 +++- generic/tclIntDecls.h | 40 +++++++- generic/tclIntPlatDecls.h | 22 ++--- generic/tclStubInit.c | 16 ++- tests/clock.test | 24 ++++- unix/tclUnixPort.h | 12 ++- unix/tclUnixThrd.c | 47 --------- unix/tclUnixTime.c | 247 ++++++++++++++++++++++++++++++---------------- win/tclWinTime.c | 64 +++++++++++- 11 files changed, 366 insertions(+), 161 deletions(-) diff --git a/ChangeLog b/ChangeLog index d5b7a57..1529f9c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,36 @@ +2004-05-14 Kevin B. Kenny + + * generic/tclInt.decls: Promoted TclpLocaltime and TclpGmtime + * generic/tclIntDecls.h: from Unix-specific stubs to the generic + * generic/tclIntPlatDecls.h: internal Stubs table. Reran 'genstubs' + * generic/tclStubInit.c: + * unix/tclUnixPort.h: + + * generic/tclClock.c: Changed a buggy 'GMT' timezone specification + to the correct 'GMT0'. [Bug #922848] + + * unix/tclUnixThrd.c: Moved TclpGmtime and TclpLocaltime to + unix/tclUnixTime.c where they belong. + + * unix/tclUnixTime.c (TclpGmtime, TclpLocaltime, TclpGetTimeZone, + ThreadSafeGMTime [removed], + ThreadSafeLocalTime [removed], + SetTZIfNecessary, CleanupMemory): + Restructured to make sure that the same mutex protects + all calls to localtime, gmtime, and tzset. Added a check + in front of those calls to make sure that the TZ env var + hasn't changed since the last call to tzset, and repeat + tzset if necessary. [Bug #942078] Removed a buggy test + of the Daylight Saving Time information in 'gettimeofday' + in favor of applying 'localtime' to a known value. + [Bug #922848] + + * tests/clock.test (clock-3.14): Added test to make sure that + changes to $env(TZ) take effect immediately. + + * win/tclWinTime.c (TclpLocaltime, TclpGmtime): + Added porting layer for 'localtime' and 'gmtime' calls. + 2004-05-10 David Gravereaux * win/tclWinPipe.c (BuildCommandLine): Append a space when the diff --git a/generic/tclClock.c b/generic/tclClock.c index 55c3bab..9683abb 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclClock.c,v 1.20 2003/02/01 21:27:55 kennykb Exp $ + * RCS: @(#) $Id: tclClock.c,v 1.20.2.1 2004/05/14 21:41:11 kennykb Exp $ */ #include "tcl.h" @@ -310,7 +310,7 @@ FormatClock(interp, clockVal, useGMT, format) } else { savedTZEnv = NULL; } - Tcl_SetVar2(interp, "env", "TZ", "GMT", TCL_GLOBAL_ONLY); + Tcl_SetVar2(interp, "env", "TZ", "GMT0", TCL_GLOBAL_ONLY); savedTimeZone = timezone; timezone = 0; tzset(); diff --git a/generic/tclInt.decls b/generic/tclInt.decls index 8a68f70..927e65c 100644 --- a/generic/tclInt.decls +++ b/generic/tclInt.decls @@ -12,7 +12,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: tclInt.decls,v 1.59 2003/02/18 02:25:45 hobbs Exp $ +# RCS: @(#) $Id: tclInt.decls,v 1.59.2.1 2004/05/14 21:41:11 kennykb Exp $ library tcl @@ -697,6 +697,15 @@ declare 173 generic { CONST Tcl_UniChar *pattern, int ptnLen, int nocase) } +# TclpGmtime and TclpLocaltime promoted to the generic interface from unix + +declare 182 generic { + struct tm *TclpLocaltime(CONST time_t *clock) +} +declare 183 generic { + struct tm *TclpGmtime(CONST time_t *clock) +} + ############################################################################## # Define the platform specific internal Tcl interface. These functions are @@ -977,12 +986,15 @@ declare 10 unix { Tcl_DirEntry * TclpReaddir(DIR * dir) } +# Slots 11 and 12 are forwarders for functions that were promoted to +# generic Stubs + declare 11 unix { - struct tm * TclpLocaltime(time_t * clock) + struct tm * TclpLocaltime_unix(CONST time_t * clock) } declare 12 unix { - struct tm * TclpGmtime(time_t * clock) + struct tm * TclpGmtime_unix(CONST time_t * clock) } declare 13 unix { diff --git a/generic/tclIntDecls.h b/generic/tclIntDecls.h index e41dca6..d706a37 100644 --- a/generic/tclIntDecls.h +++ b/generic/tclIntDecls.h @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclIntDecls.h,v 1.49 2003/02/18 02:25:45 hobbs Exp $ + * RCS: @(#) $Id: tclIntDecls.h,v 1.49.2.1 2004/05/14 21:41:11 kennykb Exp $ */ #ifndef _TCLINTDECLS @@ -503,6 +503,18 @@ EXTERN int TclUniCharMatch _ANSI_ARGS_(( CONST Tcl_UniChar * string, int strLen, CONST Tcl_UniChar * pattern, int ptnLen, int nocase)); +/* Slot 174 is reserved */ +/* Slot 175 is reserved */ +/* Slot 176 is reserved */ +/* Slot 177 is reserved */ +/* Slot 178 is reserved */ +/* Slot 179 is reserved */ +/* Slot 180 is reserved */ +/* Slot 181 is reserved */ +/* 182 */ +EXTERN struct tm * TclpLocaltime _ANSI_ARGS_((CONST time_t * clock)); +/* 183 */ +EXTERN struct tm * TclpGmtime _ANSI_ARGS_((CONST time_t * clock)); typedef struct TclIntStubs { int magic; @@ -706,6 +718,16 @@ typedef struct TclIntStubs { int (*tclCheckExecutionTraces) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * command, int numChars, Command * cmdPtr, int result, int traceFlags, int objc, Tcl_Obj *CONST objv[])); /* 171 */ int (*tclInThreadExit) _ANSI_ARGS_((void)); /* 172 */ int (*tclUniCharMatch) _ANSI_ARGS_((CONST Tcl_UniChar * string, int strLen, CONST Tcl_UniChar * pattern, int ptnLen, int nocase)); /* 173 */ + void *reserved174; + void *reserved175; + void *reserved176; + void *reserved177; + void *reserved178; + void *reserved179; + void *reserved180; + void *reserved181; + struct tm * (*tclpLocaltime) _ANSI_ARGS_((CONST time_t * clock)); /* 182 */ + struct tm * (*tclpGmtime) _ANSI_ARGS_((CONST time_t * clock)); /* 183 */ } TclIntStubs; #ifdef __cplusplus @@ -1316,6 +1338,22 @@ extern TclIntStubs *tclIntStubsPtr; #define TclUniCharMatch \ (tclIntStubsPtr->tclUniCharMatch) /* 173 */ #endif +/* Slot 174 is reserved */ +/* Slot 175 is reserved */ +/* Slot 176 is reserved */ +/* Slot 177 is reserved */ +/* Slot 178 is reserved */ +/* Slot 179 is reserved */ +/* Slot 180 is reserved */ +/* Slot 181 is reserved */ +#ifndef TclpLocaltime +#define TclpLocaltime \ + (tclIntStubsPtr->tclpLocaltime) /* 182 */ +#endif +#ifndef TclpGmtime +#define TclpGmtime \ + (tclIntStubsPtr->tclpGmtime) /* 183 */ +#endif #endif /* defined(USE_TCL_STUBS) && !defined(USE_TCL_STUB_PROCS) */ diff --git a/generic/tclIntPlatDecls.h b/generic/tclIntPlatDecls.h index 09c1226..c349486 100644 --- a/generic/tclIntPlatDecls.h +++ b/generic/tclIntPlatDecls.h @@ -9,7 +9,7 @@ * Copyright (c) 1998-1999 by Scriptics Corporation. * All rights reserved. * - * RCS: @(#) $Id: tclIntPlatDecls.h,v 1.19 2002/12/06 23:22:59 hobbs Exp $ + * RCS: @(#) $Id: tclIntPlatDecls.h,v 1.19.2.1 2004/05/14 21:41:11 kennykb Exp $ */ #ifndef _TCLINTPLATDECLS @@ -62,9 +62,9 @@ EXTERN TclFile TclpCreateTempFile _ANSI_ARGS_(( /* 10 */ EXTERN Tcl_DirEntry * TclpReaddir _ANSI_ARGS_((DIR * dir)); /* 11 */ -EXTERN struct tm * TclpLocaltime _ANSI_ARGS_((time_t * clock)); +EXTERN struct tm * TclpLocaltime_unix _ANSI_ARGS_((CONST time_t * clock)); /* 12 */ -EXTERN struct tm * TclpGmtime _ANSI_ARGS_((time_t * clock)); +EXTERN struct tm * TclpGmtime_unix _ANSI_ARGS_((CONST time_t * clock)); /* 13 */ EXTERN char * TclpInetNtoa _ANSI_ARGS_((struct in_addr addr)); #endif /* UNIX */ @@ -229,8 +229,8 @@ typedef struct TclIntPlatStubs { int (*tclUnixWaitForFile) _ANSI_ARGS_((int fd, int mask, int timeout)); /* 8 */ TclFile (*tclpCreateTempFile) _ANSI_ARGS_((CONST char * contents)); /* 9 */ Tcl_DirEntry * (*tclpReaddir) _ANSI_ARGS_((DIR * dir)); /* 10 */ - struct tm * (*tclpLocaltime) _ANSI_ARGS_((time_t * clock)); /* 11 */ - struct tm * (*tclpGmtime) _ANSI_ARGS_((time_t * clock)); /* 12 */ + struct tm * (*tclpLocaltime_unix) _ANSI_ARGS_((CONST time_t * clock)); /* 11 */ + struct tm * (*tclpGmtime_unix) _ANSI_ARGS_((CONST time_t * clock)); /* 12 */ char * (*tclpInetNtoa) _ANSI_ARGS_((struct in_addr addr)); /* 13 */ #endif /* UNIX */ #ifdef __WIN32__ @@ -351,13 +351,13 @@ extern TclIntPlatStubs *tclIntPlatStubsPtr; #define TclpReaddir \ (tclIntPlatStubsPtr->tclpReaddir) /* 10 */ #endif -#ifndef TclpLocaltime -#define TclpLocaltime \ - (tclIntPlatStubsPtr->tclpLocaltime) /* 11 */ +#ifndef TclpLocaltime_unix +#define TclpLocaltime_unix \ + (tclIntPlatStubsPtr->tclpLocaltime_unix) /* 11 */ #endif -#ifndef TclpGmtime -#define TclpGmtime \ - (tclIntPlatStubsPtr->tclpGmtime) /* 12 */ +#ifndef TclpGmtime_unix +#define TclpGmtime_unix \ + (tclIntPlatStubsPtr->tclpGmtime_unix) /* 12 */ #endif #ifndef TclpInetNtoa #define TclpInetNtoa \ diff --git a/generic/tclStubInit.c b/generic/tclStubInit.c index c1ed1df..238a559 100644 --- a/generic/tclStubInit.c +++ b/generic/tclStubInit.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclStubInit.c,v 1.79.2.2 2003/05/13 08:41:26 das Exp $ + * RCS: @(#) $Id: tclStubInit.c,v 1.79.2.3 2004/05/14 21:41:11 kennykb Exp $ */ #include "tclInt.h" @@ -268,6 +268,16 @@ TclIntStubs tclIntStubs = { TclCheckExecutionTraces, /* 171 */ TclInThreadExit, /* 172 */ TclUniCharMatch, /* 173 */ + NULL, /* 174 */ + NULL, /* 175 */ + NULL, /* 176 */ + NULL, /* 177 */ + NULL, /* 178 */ + NULL, /* 179 */ + NULL, /* 180 */ + NULL, /* 181 */ + TclpLocaltime, /* 182 */ + TclpGmtime, /* 183 */ }; TclIntPlatStubs tclIntPlatStubs = { @@ -285,8 +295,8 @@ TclIntPlatStubs tclIntPlatStubs = { TclUnixWaitForFile, /* 8 */ TclpCreateTempFile, /* 9 */ TclpReaddir, /* 10 */ - TclpLocaltime, /* 11 */ - TclpGmtime, /* 12 */ + TclpLocaltime_unix, /* 11 */ + TclpGmtime_unix, /* 12 */ TclpInetNtoa, /* 13 */ #endif /* UNIX */ #ifdef __WIN32__ diff --git a/tests/clock.test b/tests/clock.test index 3b2ad27..72c254e 100644 --- a/tests/clock.test +++ b/tests/clock.test @@ -10,7 +10,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: clock.test,v 1.22.2.1 2003/04/12 20:11:34 kennykb Exp $ +# RCS: @(#) $Id: clock.test,v 1.22.2.2 2004/05/14 21:41:11 kennykb Exp $ set env(LC_TIME) POSIX @@ -129,6 +129,28 @@ test clock-3.13 {clock format with non-ASCII character in the format string} { set res } "\u00c4" +# Bug 942078 + +test clock-3.14 {change of time zone} -setup { + catch { unset oldTZ } + if { [info exists env(TZ)] } { + set oldTZ $env(TZ) + } +} -body { + set env(TZ) PST8PDT + set s [clock format 0 -format %H%M] + set env(TZ) GMT0 + append s -[clock format 0 -format %H%M] +} -cleanup { + if { [info exists oldTZ] } { + set env(TZ) $oldTZ + unset oldTZ + } else { + unset env(TZ) + } +} -result {1600-0000} + + # clock scan test clock-4.1 {clock scan tests} { list [catch {clock scan} msg] $msg diff --git a/unix/tclUnixPort.h b/unix/tclUnixPort.h index d694488..c183985 100644 --- a/unix/tclUnixPort.h +++ b/unix/tclUnixPort.h @@ -19,7 +19,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUnixPort.h,v 1.27.2.2 2003/12/09 15:32:21 dkf Exp $ + * RCS: @(#) $Id: tclUnixPort.h,v 1.27.2.3 2004/05/14 21:41:12 kennykb Exp $ */ #ifndef _TCLUNIXPORT @@ -564,12 +564,14 @@ EXTERN void TclpMutexInit _ANSI_ARGS_((TclpMutex *mPtr)); EXTERN void TclpMutexLock _ANSI_ARGS_((TclpMutex *mPtr)); EXTERN void TclpMutexUnlock _ANSI_ARGS_((TclpMutex *mPtr)); EXTERN Tcl_DirEntry * TclpReaddir(DIR *); -EXTERN struct tm * TclpLocaltime(time_t *); -EXTERN struct tm * TclpGmtime(time_t *); +#ifndef TclpLocaltime +EXTERN struct tm * TclpLocaltime(CONST time_t *); +#endif +#ifndef TclpGmtime +EXTERN struct tm * TclpGmtime(CONST time_t *); +#endif EXTERN char * TclpInetNtoa(struct in_addr); #define readdir(x) TclpReaddir(x) -#define localtime(x) TclpLocaltime(x) -#define gmtime(x) TclpGmtime(x) #define inet_ntoa(x) TclpInetNtoa(x) #undef TclOSreaddir #define TclOSreaddir(x) TclpReaddir(x) diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c index aa26c51..04eacf4 100644 --- a/unix/tclUnixThrd.c +++ b/unix/tclUnixThrd.c @@ -21,8 +21,6 @@ typedef struct ThreadSpecificData { char nabuf[16]; - struct tm gtbuf; - struct tm ltbuf; struct { Tcl_DirEntry ent; char name[MAXNAMLEN+1]; @@ -864,51 +862,6 @@ TclpReaddir(DIR * dir) #endif return ent; } - -#if defined(TCL_THREADS) && (!defined(HAVE_GMTIME_R) || !defined(HAVE_LOCALTIME_R)) -TCL_DECLARE_MUTEX( tmMutex ) -#undef localtime -#undef gmtime -#endif - -struct tm * -TclpLocaltime(time_t * clock) -{ -#ifdef TCL_THREADS - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - -#ifdef HAVE_LOCALTIME_R - return localtime_r(clock, &tsdPtr->ltbuf); -#else - Tcl_MutexLock( &tmMutex ); - memcpy( (VOID *) &tsdPtr->ltbuf, (VOID *) localtime( clock ), sizeof (struct tm) ); - Tcl_MutexUnlock( &tmMutex ); - return &tsdPtr->ltbuf; -#endif -#else - return localtime(clock); -#endif -} - -struct tm * -TclpGmtime(time_t * clock) -{ -#ifdef TCL_THREADS - ThreadSpecificData *tsdPtr = TCL_TSD_INIT(&dataKey); - -#ifdef HAVE_GMTIME_R - return gmtime_r(clock, &tsdPtr->gtbuf); -#else - Tcl_MutexLock( &tmMutex ); - memcpy( (VOID *) &tsdPtr->gtbuf, (VOID *) gmtime( clock ), sizeof (struct tm) ); - Tcl_MutexUnlock( &tmMutex ); - return &tsdPtr->gtbuf; -#endif -#else - return gmtime(clock); -#endif -} - char * TclpInetNtoa(struct in_addr addr) { diff --git a/unix/tclUnixTime.c b/unix/tclUnixTime.c index fc72f35..4f99801 100644 --- a/unix/tclUnixTime.c +++ b/unix/tclUnixTime.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclUnixTime.c,v 1.15 2002/07/19 12:31:10 dkf Exp $ + * RCS: @(#) $Id: tclUnixTime.c,v 1.15.2.1 2004/05/14 21:41:12 kennykb Exp $ */ #include "tclInt.h" @@ -25,22 +25,27 @@ */ static Tcl_ThreadDataKey tmKey; +typedef struct ThreadSpecificData { + struct tm gmtime_buf; + struct tm localtime_buf; +} ThreadSpecificData; /* * If we fall back on the thread-unsafe versions of gmtime and localtime, * use this mutex to try to protect them. */ -#if !defined(HAVE_GMTIME_R) || !defined(HAVE_LOCALTIME_R) TCL_DECLARE_MUTEX(tmMutex) -#endif -/* - * Forward declarations for procedures defined later in this file. - */ +static char* lastTZ = NULL; /* Holds the last setting of the + * TZ environment variable, or an + * empty string if the variable was + * not set. */ + +/* Static functions declared in this file */ -static struct tm *ThreadSafeGMTime _ANSI_ARGS_(( CONST time_t* )); -static struct tm *ThreadSafeLocalTime _ANSI_ARGS_(( CONST time_t* )); +static void SetTZIfNecessary _ANSI_ARGS_((void)); +static void CleanupMemory _ANSI_ARGS_((ClientData)); /* *----------------------------------------------------------------------------- @@ -129,18 +134,22 @@ TclpGetTimeZone (currentTime) unsigned long currentTime; { /* - * Determine how a timezone is obtained from "struct tm". If there is no - * time zone in this struct (very lame) then use the timezone variable. - * This is done in a way to make the timezone variable the method of last - * resort, as some systems have it in addition to a field in "struct tm". - * The gettimeofday system call can also be used to determine the time - * zone. + * We prefer first to use the time zone in "struct tm" if the + * structure contains such a member. Following that, we try + * to locate the external 'timezone' variable and use its value. + * If both of those methods fail, we attempt to convert a known + * time to local time and use the difference from UTC as the local + * time zone. In all cases, we need to undo any Daylight Saving Time + * adjustment. */ #if defined(HAVE_TM_TZADJ) # define TCL_GOT_TIMEZONE + + /* Struct tm contains tm_tzadj - that value may be used. */ + time_t curTime = (time_t) currentTime; - struct tm *timeDataPtr = ThreadSafeLocalTime(&curTime); + struct tm *timeDataPtr = TclpLocaltime(&curTime); int timeZone; timeZone = timeDataPtr->tm_tzadj / 60; @@ -149,12 +158,16 @@ TclpGetTimeZone (currentTime) } return timeZone; + #endif #if defined(HAVE_TM_GMTOFF) && !defined (TCL_GOT_TIMEZONE) # define TCL_GOT_TIMEZONE + + /* Struct tm contains tm_gmtoff - that value may be used. */ + time_t curTime = (time_t) currentTime; - struct tm *timeDataPtr = ThreadSafeLocalTime(&curTime); + struct tm *timeDataPtr = TclpLocaltime(&curTime); int timeZone; timeZone = -(timeDataPtr->tm_gmtoff / 60); @@ -163,46 +176,17 @@ TclpGetTimeZone (currentTime) } return timeZone; -#endif -#if defined(USE_DELTA_FOR_TZ) -#define TCL_GOT_TIMEZONE 1 - /* - * This hack replaces using global var timezone or gettimeofday - * in situations where they are buggy such as on AIX when libbsd.a - * is linked in. - */ - - int timeZone; - time_t tt; - struct tm *stm; - tt = 849268800L; /* 1996-11-29 12:00:00 GMT */ - stm = ThreadSafeLocalTime(&tt); /* eg 1996-11-29 6:00:00 CST6CDT */ - /* The calculation below assumes a max of +12 or -12 hours from GMT */ - timeZone = (12 - stm->tm_hour)*60 + (0 - stm->tm_min); - return timeZone; /* eg +360 for CST6CDT */ #endif - /* - * Must prefer timezone variable over gettimeofday, as gettimeofday does - * not return timezone information on many systems that have moved this - * information outside of the kernel. - */ - -#if defined(HAVE_TIMEZONE_VAR) && !defined (TCL_GOT_TIMEZONE) +#if defined(HAVE_TIMEZONE_VAR) && !defined(TCL_GOT_TIMEZONE) && !defined(USE_DELTA_FOR_TZ) # define TCL_GOT_TIMEZONE - static int setTZ = 0; -#ifdef TCL_THREADS - static Tcl_Mutex tzMutex; -#endif + int timeZone; - Tcl_MutexLock(&tzMutex); - if (!setTZ) { - tzset(); - setTZ = 1; - } - Tcl_MutexUnlock(&tzMutex); + /* The 'timezone' external var is present and may be used. */ + + SetTZIfNecessary(); /* * Note: this is not a typo in "timezone" below! See tzset @@ -210,30 +194,36 @@ TclpGetTimeZone (currentTime) */ timeZone = timezone / 60; - return timeZone; + #endif -#if !defined(NO_GETTOD) && !defined (TCL_GOT_TIMEZONE) -# define TCL_GOT_TIMEZONE - struct timeval tv; - struct timezone tz; - int timeZone; +#if !defined(TCL_GOT_TIMEZONE) +#define TCL_GOT_TIMEZONE 1 + /* + * Fallback - determine time zone with a known reference time. + */ - gettimeofday(&tv, &tz); - timeZone = tz.tz_minuteswest; - if (tz.tz_dsttime) { + int timeZone; + time_t tt; + struct tm *stm; + tt = 849268800L; /* 1996-11-29 12:00:00 GMT */ + stm = TclpLocaltime(&tt); /* eg 1996-11-29 6:00:00 CST6CDT */ + /* The calculation below assumes a max of +12 or -12 hours from GMT */ + timeZone = (12 - stm->tm_hour)*60 + (0 - stm->tm_min); + if ( stm -> tm_isdst ) { timeZone += 60; } - - return timeZone; + return timeZone; /* eg +360 for CST6CDT */ #endif #ifndef TCL_GOT_TIMEZONE /* * Cause compile error, we don't know how to get timezone. */ - error: autoconf did not figure out how to determine the timezone. + +#error autoconf did not figure out how to determine the timezone. + #endif } @@ -293,9 +283,9 @@ TclpGetDate(time, useGMT) CONST time_t *tp = (CONST time_t *)time; if (useGMT) { - return ThreadSafeGMTime(tp); + return TclpGmtime(tp); } else { - return ThreadSafeLocalTime(tp); + return TclpLocaltime(tp); } } @@ -340,7 +330,7 @@ TclpStrftime(s, maxsize, format, t, useGMT) /* *---------------------------------------------------------------------- * - * ThreadSafeGMTime -- + * TclpGmtime -- * * Wrapper around the 'gmtime' library function to make it thread * safe. @@ -354,33 +344,42 @@ TclpStrftime(s, maxsize, format, t, useGMT) *---------------------------------------------------------------------- */ -static struct tm * -ThreadSafeGMTime(timePtr) +struct tm * +TclpGmtime( timePtr ) CONST time_t *timePtr; /* Pointer to the number of seconds - * since the local system's epoch - */ + * since the local system's epoch */ { /* * Get a thread-local buffer to hold the returned time. */ - struct tm *tmPtr = (struct tm *) - Tcl_GetThreadData(&tmKey, sizeof(struct tm)); + ThreadSpecificData *tsdPtr = TCL_TSD_INIT( &tmKey ); #ifdef HAVE_GMTIME_R - gmtime_r(timePtr, tmPtr); + gmtime_r(timePtr, &( tsdPtr->gmtime_buf )); #else - Tcl_MutexLock(&tmMutex); - memcpy((VOID *) tmPtr, (VOID *) gmtime(timePtr), sizeof(struct tm)); - Tcl_MutexUnlock(&tmMutex); + Tcl_MutexLock( &tmMutex ); + memcpy( (VOID *) &( tsdPtr->gmtime_buf ), + (VOID *) gmtime( timePtr ), + sizeof( struct tm ) ); + Tcl_MutexUnlock( &tmMutex ); #endif - return tmPtr; + return &( tsdPtr->gmtime_buf ); +} +/* + * Forwarder for obsolete item in Stubs + */ +struct tm* +TclpGmtime_unix( timePtr ) + CONST time_t* timePtr; +{ + return TclpGmtime( timePtr ); } /* *---------------------------------------------------------------------- * - * ThreadSafeLocalTime -- + * TclpLocaltime -- * * Wrapper around the 'localtime' library function to make it thread * safe. @@ -394,25 +393,99 @@ ThreadSafeGMTime(timePtr) *---------------------------------------------------------------------- */ -static struct tm * -ThreadSafeLocalTime(timePtr) +struct tm * +TclpLocaltime(timePtr) CONST time_t *timePtr; /* Pointer to the number of seconds - * since the local system's epoch - */ + * since the local system's epoch */ { /* * Get a thread-local buffer to hold the returned time. */ - struct tm *tmPtr = (struct tm *) - Tcl_GetThreadData(&tmKey, sizeof(struct tm)); + ThreadSpecificData *tsdPtr = TCL_TSD_INIT( &tmKey ); + SetTZIfNecessary(); #ifdef HAVE_LOCALTIME_R - localtime_r(timePtr, tmPtr); + localtime_r( timePtr, &( tsdPtr->localtime_buf ) ); #else + Tcl_MutexLock( &tmMutex ); + memcpy( (VOID *) &( tsdPtr -> localtime_buf ), + (VOID *) localtime( timePtr ), + sizeof( struct tm ) ); + Tcl_MutexUnlock( &tmMutex ); +#endif + return &( tsdPtr->localtime_buf ); +} +/* + * Forwarder for obsolete item in Stubs + */ +struct tm* +TclpLocaltime_unix( timePtr ) + CONST time_t* timePtr; +{ + return TclpLocaltime( timePtr ); +} + +/* + *---------------------------------------------------------------------- + * + * SetTZIfNecessary -- + * + * Determines whether a call to 'tzset' is needed prior to the + * next call to 'localtime' or examination of the 'timezone' variable. + * + * Results: + * None. + * + * Side effects: + * If 'tzset' has never been called in the current process, or if + * the value of the environment variable TZ has changed since the + * last call to 'tzset', then 'tzset' is called again. + * + *---------------------------------------------------------------------- + */ + +static void +SetTZIfNecessary() { + + CONST char* newTZ = getenv( "TZ" ); Tcl_MutexLock(&tmMutex); - memcpy((VOID *) tmPtr, (VOID *) localtime(timePtr), sizeof(struct tm)); + if ( newTZ == NULL ) { + newTZ = ""; + } + if ( lastTZ == NULL || strcmp( lastTZ, newTZ ) ) { + tzset(); + if ( lastTZ == NULL ) { + Tcl_CreateExitHandler( CleanupMemory, (ClientData) NULL ); + } else { + Tcl_Free( lastTZ ); + } + lastTZ = Tcl_Alloc( strlen( newTZ ) + 1 ); + strcpy( lastTZ, newTZ ); + } Tcl_MutexUnlock(&tmMutex); -#endif - return tmPtr; + +} + +/* + *---------------------------------------------------------------------- + * + * CleanupMemory -- + * + * Releases the private copy of the TZ environment variable + * upon exit from Tcl. + * + * Results: + * None. + * + * Side effects: + * Frees allocated memory. + * + *---------------------------------------------------------------------- + */ + +static void +CleanupMemory( ClientData ignored ) +{ + Tcl_Free( lastTZ ); } diff --git a/win/tclWinTime.c b/win/tclWinTime.c index 6bc7b10..539dd6c 100644 --- a/win/tclWinTime.c +++ b/win/tclWinTime.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclWinTime.c,v 1.14.2.2 2003/04/15 21:06:36 kennykb Exp $ + * RCS: @(#) $Id: tclWinTime.c,v 1.14.2.3 2004/05/14 21:41:12 kennykb Exp $ */ #include "tclWinInt.h" @@ -1053,3 +1053,65 @@ AccumulateSample( Tcl_WideInt perfCounter, return estFreq; } } + +/* + *---------------------------------------------------------------------- + * + * TclpGmtime -- + * + * Wrapper around the 'gmtime' library function to make it thread + * safe. + * + * Results: + * Returns a pointer to a 'struct tm' in thread-specific data. + * + * Side effects: + * Invokes gmtime or gmtime_r as appropriate. + * + *---------------------------------------------------------------------- + */ + +struct tm * +TclpGmtime( timePtr ) + CONST time_t *timePtr; /* Pointer to the number of seconds + * since the local system's epoch */ + +{ + /* + * The MS implementation of gmtime is thread safe because + * it returns the time in a block of thread-local storage, + * and Windows does not provide a Posix gmtime_r function. + */ + return gmtime( timePtr ); +} + +/* + *---------------------------------------------------------------------- + * + * TclpLocaltime -- + * + * Wrapper around the 'localtime' library function to make it thread + * safe. + * + * Results: + * Returns a pointer to a 'struct tm' in thread-specific data. + * + * Side effects: + * Invokes localtime or localtime_r as appropriate. + * + *---------------------------------------------------------------------- + */ + +struct tm * +TclpLocaltime( timePtr ) + CONST time_t *timePtr; /* Pointer to the number of seconds + * since the local system's epoch */ + +{ + /* + * The MS implementation of localtime is thread safe because + * it returns the time in a block of thread-local storage, + * and Windows does not provide a Posix localtime_r function. + */ + return localtime( timePtr ); +} -- cgit v0.12