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

Reply via email to