? pkgs
? compat/zlib
? generic/hobbs
? library/config.tcl
? tools/teabuild.tcl
? unix/Makefile.in.pkgs
? unix/autom4te.cache
? win/autom4te.cache
Index: ChangeLog
===================================================================
RCS file: /cvsroot/tcl/tcl/ChangeLog,v
retrieving revision 1.2164
diff -u -u -r1.2164 ChangeLog
--- ChangeLog	21 Jul 2004 00:42:37 -0000	1.2164
+++ ChangeLog	21 Jul 2004 01:45:02 -0000
@@ -1,3 +1,11 @@
+2004-07-20  Jeff Hobbs  <jeffh@ActiveState.com>
+
+	* generic/tclEvent.c:       Correct threaded obj allocator to
+	* generic/tclInt.h:         fully cleanup on exit and allow for
+	* generic/tclThreadAlloc.c: reinitialization. [Bug #736426]
+	* unix/tclUnixThrd.c:       (mistachkin, kenny)
+	* win/tclWinThrd.c:
+
 2004-07-21  Kevin Kenny  <kennykb@acm.org>
 
 	* generic/tclBasic.c (DeleteInterpProc):
Index: generic/tclEvent.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclEvent.c,v
retrieving revision 1.43
diff -u -u -r1.43 tclEvent.c
--- generic/tclEvent.c	15 Jul 2004 20:04:38 -0000	1.43
+++ generic/tclEvent.c	21 Jul 2004 01:45:02 -0000
@@ -973,7 +973,9 @@
 	/*
 	 * There shouldn't be any malloc'ed memory after this.
 	 */
-
+#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
+  TclFinalizeThreadAlloc();
+#endif
 	TclFinalizeMemorySubsystem();
 	inFinalize = 0;
     }
Index: generic/tclInt.h
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclInt.h,v
retrieving revision 1.169
diff -u -u -r1.169 tclInt.h
--- generic/tclInt.h	21 Jul 2004 00:42:38 -0000	1.169
+++ generic/tclInt.h	21 Jul 2004 01:45:02 -0000
@@ -2363,6 +2363,8 @@
 EXTERN Tcl_Mutex *TclpNewAllocMutex _ANSI_ARGS_((void));
 EXTERN void *TclpGetAllocCache _ANSI_ARGS_((void));
 EXTERN void TclpSetAllocCache _ANSI_ARGS_((void *));
+EXTERN void TclFinalizeThreadAlloc _ANSI_ARGS_((void));
+EXTERN void TclpFreeAllocMutex _ANSI_ARGS_((Tcl_Mutex* mutex));
 
 #  define TclAllocObjStorage(objPtr) \
        (objPtr) = TclThreadAllocObj()
Index: generic/tclThreadAlloc.c
===================================================================
RCS file: /cvsroot/tcl/tcl/generic/tclThreadAlloc.c,v
retrieving revision 1.13
diff -u -u -r1.13 tclThreadAlloc.c
--- generic/tclThreadAlloc.c	21 Jun 2004 08:54:34 -0000	1.13
+++ generic/tclThreadAlloc.c	21 Jul 2004 01:45:02 -0000
@@ -631,7 +631,7 @@
 	if (cachePtr == sharedPtr) {
 	    Tcl_DStringAppendElement(dsPtr, "shared");
 	} else {
-	    sprintf(buf, "thread%d", (int) cachePtr->owner);
+	    sprintf(buf, "thread%p", cachePtr->owner);
 	    Tcl_DStringAppendElement(dsPtr, buf);
 	}
 	for (n = 0; n < NBUCKETS; ++n) {
@@ -957,4 +957,62 @@
     return 1;
 }
 
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclFinalizeThreadAlloc --
+ *
+ *	This procedure is used to destroy all private resources used in
+ *	this file.
+ *
+ * Results:
+ *	None.
+ *
+ * Side effects:
+ *	None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclFinalizeThreadAlloc()
+{
+    int i;
+    for (i = 0; i < NBUCKETS; ++i) {
+        TclpFreeAllocMutex(bucketInfo[i].lockPtr); 
+        bucketInfo[i].lockPtr = NULL;
+    }
+
+    TclpFreeAllocMutex(objLockPtr);
+    objLockPtr = NULL;
+
+    TclpFreeAllocMutex(listLockPtr);
+    listLockPtr = NULL;
+}
+
+#else
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TclFinalizeThreadAlloc --
+ *
+ *	This procedure is used to destroy all private resources used in
+ *	this file.
+ *
+ * Results:
+ *	None.
+ *
+ * Side effects:
+ *	None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TclFinalizeThreadAlloc()
+{
+    Tcl_Panic("TclFinalizeThreadAlloc called when threaded memory allocator not in use.");
+}
+
 #endif /* TCL_THREADS */
Index: unix/tclUnixThrd.c
===================================================================
RCS file: /cvsroot/tcl/tcl/unix/tclUnixThrd.c,v
retrieving revision 1.33
diff -u -u -r1.33 tclUnixThrd.c
--- unix/tclUnixThrd.c	15 Jul 2004 22:04:43 -0000	1.33
+++ unix/tclUnixThrd.c	21 Jul 2004 01:45:02 -0000
@@ -934,19 +934,20 @@
  * Additions by AOL for specialized thread memory allocator.
  */
 #ifdef USE_THREAD_ALLOC
-static int initialized = 0;
+static volatile int initialized = 0;
 static pthread_key_t	key;
-static pthread_once_t	once = PTHREAD_ONCE_INIT;
+
+typedef struct allocMutex {
+    Tcl_Mutex       tlock;
+    pthread_mutex_t plock;
+} allocMutex;
 
 Tcl_Mutex *
 TclpNewAllocMutex(void)
 {
-    struct lock {
-        Tcl_Mutex       tlock;
-        pthread_mutex_t plock;
-    } *lockPtr;
+    struct allocMutex *lockPtr;
 
-    lockPtr = malloc(sizeof(struct lock));
+    lockPtr = malloc(sizeof(struct allocMutex));
     if (lockPtr == NULL) {
 	Tcl_Panic("could not allocate lock");
     }
@@ -955,20 +956,41 @@
     return &lockPtr->tlock;
 }
 
-static void
-InitKey(void)
+void
+TclpFreeAllocMutex(mutex)
+    Tcl_Mutex *mutex; /* The alloc mutex to free. */
+{
+    allocMutex* lockPtr = (allocMutex*) mutex;
+    if (!lockPtr) return;
+    pthread_mutex_destroy(&lockPtr->plock);
+    free(lockPtr);
+}
+
+void TclpFreeAllocCache(ptr)
+    void *ptr;
 {
     extern void TclFreeAllocCache(void *);
 
-    pthread_key_create(&key, TclFreeAllocCache);
-    initialized = 1;
+    TclFreeAllocCache(ptr);
+    /*
+     * Perform proper cleanup of things done in TclpGetAllocCache.
+     */
+    if (initialized) {
+        pthread_key_delete(key);
+        initialized = 0;
+    }
 }
 
 void *
 TclpGetAllocCache(void)
 {
     if (!initialized) {
-	pthread_once(&once, InitKey);
+	pthread_mutex_lock(allocLockPtr);
+	if (!initialized) {
+	    pthread_key_create(&key, TclpFreeAllocCache);
+	    initialized = 1;
+	}
+	pthread_mutex_unlock(allocLockPtr);
     }
     return pthread_getspecific(key);
 }
Index: win/tclWinThrd.c
===================================================================
RCS file: /cvsroot/tcl/tcl/win/tclWinThrd.c,v
retrieving revision 1.32
diff -u -u -r1.32 tclWinThrd.c
--- win/tclWinThrd.c	19 Jul 2004 19:19:07 -0000	1.32
+++ win/tclWinThrd.c	21 Jul 2004 01:45:02 -0000
@@ -1040,17 +1040,20 @@
  * Additions by AOL for specialized thread memory allocator.
  */
 #ifdef USE_THREAD_ALLOC
+static int once;
 static DWORD key;
 
+typedef struct allocMutex {
+    Tcl_Mutex        tlock;
+    CRITICAL_SECTION wlock;
+} allocMutex;
+
 Tcl_Mutex *
 TclpNewAllocMutex(void)
 {
-    struct lock {
-        Tcl_Mutex        tlock;
-        CRITICAL_SECTION wlock;
-    } *lockPtr;
+    struct allocMutex *lockPtr;
 
-    lockPtr = malloc(sizeof(struct lock));
+    lockPtr = malloc(sizeof(struct allocMutex));
     if (lockPtr == NULL) {
 	Tcl_Panic("could not allocate lock");
     }
@@ -1059,10 +1062,19 @@
     return &lockPtr->tlock;
 }
 
+void
+TclpFreeAllocMutex(mutex)
+    Tcl_Mutex *mutex; /* The alloc mutex to free. */
+{
+    allocMutex* lockPtr = (allocMutex*) mutex;
+    if (!lockPtr) return;
+    DeleteCriticalSection(&lockPtr->wlock);
+    free(lockPtr);
+}
+
 void *
 TclpGetAllocCache(void)
 {
-    static int once = 0;
     VOID *result;
 
     if (!once) {
@@ -1113,6 +1125,15 @@
           Tcl_Panic("TlsGetValue failed from TclWinFreeAllocCache!");
       }
     }
+
+    if (once) {    
+        success = TlsFree(key);
+        if (!success) {
+            Tcl_Panic("TlsFree failed from TclWinFreeAllocCache!");
+        }
+
+        once = 0; /* reset for next time. */
+    }
 }
 
 #endif /* USE_THREAD_ALLOC */
