OSDN Git Service

Updated to tcl 8.4.1
[pf3gnuchains/pf3gnuchains3x.git] / tcl / unix / tclUnixTime.c
index e1bc438..c978bd7 100644 (file)
 
 #include "tclInt.h"
 #include "tclPort.h"
+#include <locale.h>
 #define TM_YEAR_BASE 1900
 #define IsLeapYear(x)   ((x % 4 == 0) && (x % 100 != 0 || x % 400 == 0))
+
+/*
+ * TclpGetDate is coded to return a pointer to a 'struct tm'.  For
+ * thread safety, this structure must be in thread-specific data.
+ * The 'tmKey' variable is the key to this buffer.
+ */
+
+static Tcl_ThreadDataKey tmKey;
+
+/*
+ * 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 struct tm *ThreadSafeGMTime _ANSI_ARGS_(( CONST time_t* ));
+static struct tm *ThreadSafeLocalTime _ANSI_ARGS_(( CONST time_t* ));
 \f
 /*
  *-----------------------------------------------------------------------------
@@ -115,7 +140,7 @@ TclpGetTimeZone (currentTime)
 #if defined(HAVE_TM_TZADJ)
 #   define TCL_GOT_TIMEZONE
     time_t      curTime = (time_t) currentTime;
-    struct tm  *timeDataPtr = localtime(&curTime);
+    struct tm  *timeDataPtr = ThreadSafeLocalTime(&curTime);
     int         timeZone;
 
     timeZone = timeDataPtr->tm_tzadj  / 60;
@@ -129,7 +154,7 @@ TclpGetTimeZone (currentTime)
 #if defined(HAVE_TM_GMTOFF) && !defined (TCL_GOT_TIMEZONE)
 #   define TCL_GOT_TIMEZONE
     time_t     curTime = (time_t) currentTime;
-    struct tm *timeDataPtr = localtime(&curTime);
+    struct tm *timeDataPtr = ThreadSafeLocalTime(&curTime);
     int        timeZone;
 
     timeZone = -(timeDataPtr->tm_gmtoff / 60);
@@ -152,7 +177,7 @@ TclpGetTimeZone (currentTime)
     time_t tt;
     struct tm *stm;
     tt = 849268800L;      /*    1996-11-29 12:00:00  GMT */
-    stm = localtime(&tt); /* eg 1996-11-29  6:00:00  CST6CDT */
+    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 */
@@ -216,7 +241,7 @@ TclpGetTimeZone (currentTime)
 /*
  *----------------------------------------------------------------------
  *
- * TclpGetTime --
+ * Tcl_GetTime --
  *
  *     Gets the current system time in seconds and microseconds
  *     since the beginning of the epoch: 00:00 UCT, January 1, 1970.
@@ -231,7 +256,7 @@ TclpGetTimeZone (currentTime)
  */
 
 void
-TclpGetTime(timePtr)
+Tcl_GetTime(timePtr)
     Tcl_Time *timePtr;         /* Location to store time information. */
 {
     struct timeval tv;
@@ -268,9 +293,9 @@ TclpGetDate(time, useGMT)
     CONST time_t *tp = (CONST time_t *)time;
 
     if (useGMT) {
-       return gmtime(tp);
+       return ThreadSafeGMTime(tp);
     } else {
-       return localtime(tp);
+       return ThreadSafeLocalTime(tp);
     }
 }
 \f
@@ -279,7 +304,8 @@ TclpGetDate(time, useGMT)
  *
  * TclpStrftime --
  *
- *     On Unix, we can safely call the native strftime implementation.
+ *     On Unix, we can safely call the native strftime implementation,
+ *     and also ignore the useGMT parameter.
  *
  * Results:
  *     The normal strftime result.
@@ -291,11 +317,12 @@ TclpGetDate(time, useGMT)
  */
 
 size_t
-TclpStrftime(s, maxsize, format, 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 */
@@ -306,5 +333,86 @@ TclpStrftime(s, maxsize, format, t)
                (((t->tm_hour * 60) + t->tm_min)/144));
        return(strlen(s));
     }
+    setlocale(LC_TIME, "");
     return strftime(s, maxsize, format, t);
 }
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * ThreadSafeGMTime --
+ *
+ *     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.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static struct tm *
+ThreadSafeGMTime(timePtr)
+    CONST time_t *timePtr;     /* Pointer to the number of seconds
+                                * 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));
+#ifdef HAVE_GMTIME_R
+    gmtime_r(timePtr, tmPtr);
+#else
+    Tcl_MutexLock(&tmMutex);
+    memcpy((VOID *) tmPtr, (VOID *) gmtime(timePtr), sizeof(struct tm));
+    Tcl_MutexUnlock(&tmMutex);
+#endif    
+    return tmPtr;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * ThreadSafeLocalTime --
+ *
+ *     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.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static struct tm *
+ThreadSafeLocalTime(timePtr)
+    CONST time_t *timePtr;     /* Pointer to the number of seconds
+                                * 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));
+#ifdef HAVE_LOCALTIME_R
+    localtime_r(timePtr, tmPtr);
+#else
+    Tcl_MutexLock(&tmMutex);
+    memcpy((VOID *) tmPtr, (VOID *) localtime(timePtr), sizeof(struct tm));
+    Tcl_MutexUnlock(&tmMutex);
+#endif    
+    return tmPtr;
+}