Subject: Micro-optimization: remove double checked lock from TclGetAllocCache in favour of initialization in TclInitSubsystems

From: Kevin B Kenny <[email-masked]>
Date: Wed, 21 Oct 2015 23:30:41 +0000

---
 generic/tclEvent.c |  3 +++
 generic/tclInt.h   |  3 +++
 unix/tclUnixThrd.c | 27 ++++++++++-----------------
 win/tclWinThrd.c   | 33 +++++++++++++++------------------
 4 files changed, 31 insertions(+), 35 deletions(-)

diff --git a/generic/tclEvent.c b/generic/tclEvent.c
index 8305410..d62850b 100644
--- a/generic/tclEvent.c
+++ b/generic/tclEvent.c
@@ -1043,6 +1043,9 @@ TclInitSubsystems(void)
 #if USE_TCLALLOC
 	    TclInitAlloc();		/* Process wide mutex init */
 #endif
+#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
+	    TclpInitThreadAlloc();
+#endif
 #ifdef TCL_MEM_DEBUG
 	    TclInitDbCkalloc();		/* Process wide mutex init */
 #endif
diff --git a/generic/tclInt.h b/generic/tclInt.h
index 356d250..d4baed4 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -3146,6 +3146,9 @@ MODULE_SCOPE int	TclpLoadMemory(Tcl_Interp *interp, void *buffer,
 			    Tcl_FSUnloadFileProc **unloadProcPtr, int flags);
 #endif
 MODULE_SCOPE void	TclInitThreadStorage(void);
+#if defined(TCL_THREADS) && defined(USE_THREAD_ALLOC)
+MODULE_SCOPE void	TclpInitThreadAlloc(void);
+#endif
 MODULE_SCOPE void	TclFinalizeThreadDataThread(void);
 MODULE_SCOPE void	TclFinalizeThreadStorage(void);
 #ifdef TCL_WIDE_CLICKS
diff --git a/unix/tclUnixThrd.c b/unix/tclUnixThrd.c
index ea03332..0f4a8a3 100644
--- a/unix/tclUnixThrd.c
+++ b/unix/tclUnixThrd.c
@@ -680,7 +680,6 @@ TclpInetNtoa(
  */
 
 #ifdef USE_THREAD_ALLOC
-static volatile int initialized = 0;
 static pthread_key_t key;
 
 typedef struct allocMutex {
@@ -727,29 +726,23 @@ TclpFreeAllocCache(
 
 	TclFreeAllocCache(ptr);
 	pthread_setspecific(key, NULL);
-
-    } else if (initialized) {
-	/*
-	 * Called by us in TclFinalizeThreadAlloc() during the library
-	 * finalization initiated from Tcl_Finalize()
-	 */
-
+	
+    } else {
 	pthread_key_delete(key);
-	initialized = 0;
     }
 }
 
+void
+TclpInitThreadAlloc(void)
+{
+    pthread_mutex_lock(allocLockPtr);
+    pthread_key_create(&key, TclpFreeAllocCache);
+    pthread_mutex_unlock(allocLockPtr);   
+}
+
 void *
 TclpGetAllocCache(void)
 {
-    if (!initialized) {
-	pthread_mutex_lock(allocLockPtr);
-	if (!initialized) {
-	    pthread_key_create(&key, TclpFreeAllocCache);
-	    initialized = 1;
-	}
-	pthread_mutex_unlock(allocLockPtr);
-    }
     return pthread_getspecific(key);
 }
 
diff --git a/win/tclWinThrd.c b/win/tclWinThrd.c
index 1c9d483..fac8ab3 100644
--- a/win/tclWinThrd.c
+++ b/win/tclWinThrd.c
@@ -122,7 +122,6 @@ typedef struct WinCondition {
  */
 
 #ifdef USE_THREAD_ALLOC
-static int once;
 static DWORD tlsKey;
 
 typedef struct allocMutex {
@@ -971,24 +970,24 @@ TclpFreeAllocMutex(
     free(lockPtr);
 }
 
+void
+TclInitThreadAlloc(void)
+{
+    /*
+     * We need to make sure that TclpFreeAllocCache is called on each
+     * thread that calls this, but only on threads that call this.
+     */
+    
+    tlsKey = TlsAlloc();
+    if (tlsKey == TLS_OUT_OF_INDEXES) {
+	Tcl_Panic("could not allocate thread local storage");
+    }    
+}
+
 void *
 TclpGetAllocCache(void)
 {
     void *result;
-
-    if (!once) {
-	/*
-	 * We need to make sure that TclpFreeAllocCache is called on each
-	 * thread that calls this, but only on threads that call this.
-	 */
-
-	tlsKey = TlsAlloc();
-	once = 1;
-	if (tlsKey == TLS_OUT_OF_INDEXES) {
-	    Tcl_Panic("could not allocate thread local storage");
-	}
-    }
-
     result = TlsGetValue(tlsKey);
     if ((result == NULL) && (GetLastError() != NO_ERROR)) {
 	Tcl_Panic("TlsGetValue failed from TclpGetAllocCache");
@@ -1024,7 +1023,7 @@ TclpFreeAllocCache(
 	if (!success) {
 	    Tcl_Panic("TlsSetValue failed from TclpFreeAllocCache");
 	}
-    } else if (once) {
+    } else {
 	/*
 	 * Called by us in TclFinalizeThreadAlloc() during the library
 	 * finalization initiated from Tcl_Finalize()
@@ -1034,9 +1033,7 @@ TclpFreeAllocCache(
 	if (!success) {
 	    Tcl_Panic("TlsFree failed from TclpFreeAllocCache");
 	}
-	once = 0; /* reset for next time. */
     }
-
 }
 #endif /* USE_THREAD_ALLOC */
 
-- 
cgit v0.12