On Monday 28 October 2002 17:03, you wrote:
>
> Zoran, can you post the changes to the list, please, if they're not too
> large?
>
Here it is. This function is at the end of tcl8.3.X/generic/tclClock.c file.
Just replace the one you find there with the copy below and recompile.
This fixes the "clock scan ... -gmt 1" subtle MT-bug on *Solaris* builds.
Linux is afaik not affected. For other platforms: no idea.
When two or more threads try to do the above command, the process env
gets corrupted.
Zoran
<<<<<<< cut here
/*
*-----------------------------------------------------------------------------
*
* FormatClock --
*
* Formats a time value based on seconds into a human readable
* string.
*
* Results:
* Standard Tcl result.
*
* Side effects:
* None.
*
*-----------------------------------------------------------------------------
*/
static int
FormatClock(interp, clockVal, useGMT, format)
Tcl_Interp *interp; /* Current interpreter. */
unsigned long clockVal; /* Time in seconds. */
int useGMT; /* Boolean */
char *format; /* Format string */
{
struct tm *timeDataPtr;
Tcl_DString buffer, uniBuffer;
int bufSize;
char *p;
int result;
time_t tclockVal;
#ifndef HAVE_TM_ZONE
int savedTimeZone = 0; /* lint. */
char *savedTZEnv = NULL; /* lint. */
#endif
#ifdef HAVE_TZSET
/*
* Some systems forgot to call tzset in localtime, make sure its done.
*/
static int calledTzset = 0;
Tcl_MutexLock(&clockMutex);
if (!calledTzset) {
tzset();
calledTzset = 1;
}
Tcl_MutexUnlock(&clockMutex);
#endif
/*
* If the user gave us -format "", just return now
*/
if (*format == '\0') {
return TCL_OK;
}
#ifndef HAVE_TM_ZONE
Tcl_MutexLock(&clockMutex);
/*
* This is a kludge for systems not having the timezone string in
* struct tm. No matter what was specified, they use the local
* timezone string.
*/
if (useGMT) {
char *varValue;
varValue = Tcl_GetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY);
if (varValue != NULL) {
savedTZEnv = strcpy(ckalloc(strlen(varValue) + 1), varValue);
} else {
savedTZEnv = NULL;
}
Tcl_SetVar2(interp, "env", "TZ", "GMT", TCL_GLOBAL_ONLY);
savedTimeZone = timezone;
timezone = 0;
tzset();
}
#endif
tclockVal = clockVal;
timeDataPtr = TclpGetDate((TclpTime_t) &tclockVal, useGMT);
/*
* Make a guess at the upper limit on the substituted string size
* based on the number of percents in the string.
*/
for (bufSize = 1, p = format; *p != '\0'; p++) {
if (*p == '%') {
bufSize += 40;
} else {
bufSize++;
}
}
Tcl_DStringInit(&buffer);
Tcl_DStringSetLength(&buffer, bufSize);
#ifndef HAVE_TM_ZONE
result = TclpStrftime(buffer.string, (unsigned int) bufSize, format,
timeDataPtr);
if (useGMT) {
if (savedTZEnv != NULL) {
Tcl_SetVar2(interp, "env", "TZ", savedTZEnv, TCL_GLOBAL_ONLY);
ckfree(savedTZEnv);
} else {
Tcl_UnsetVar2(interp, "env", "TZ", TCL_GLOBAL_ONLY);
}
timezone = savedTimeZone;
tzset();
}
Tcl_MutexUnlock(&clockMutex);
#else
Tcl_MutexLock(&clockMutex);
result = TclpStrftime(buffer.string, (unsigned int) bufSize, format,
timeDataPtr);
Tcl_MutexUnlock(&clockMutex);
#endif /* not defined HAVE_TM_ZONE */
if (result == 0) {
/*
* A zero return is the error case (can also mean the strftime
* didn't get enough space to write into). We know it doesn't
* mean that we wrote zero chars because the check for an empty
* format string is above.
*/
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
"bad format string \"", format, "\"", (char *) NULL);
return TCL_ERROR;
}
/*
* Convert the time to external encoding, in case we asked for
* a localized return value. [Bug: 3345]
*/
Tcl_DStringInit(&uniBuffer);
Tcl_ExternalToUtfDString(NULL, buffer.string, -1, &uniBuffer);
Tcl_SetStringObj(Tcl_GetObjResult(interp), uniBuffer.string, -1);
Tcl_DStringFree(&uniBuffer);
Tcl_DStringFree(&buffer);
return TCL_OK;
}