[fdo-commits] r724 - branches/3.2.x/Fdo/Unmanaged/Src/Common

svn_fdo at osgeo.org svn_fdo at osgeo.org
Wed Feb 7 02:20:44 EST 2007


Author: gavincramer
Date: 2007-02-07 02:20:44 -0500 (Wed, 07 Feb 2007)
New Revision: 724

Modified:
   branches/3.2.x/Fdo/Unmanaged/Src/Common/ArrayHelper.cpp
Log:
Fix Geometry pool sharing objects between threads

Modified: branches/3.2.x/Fdo/Unmanaged/Src/Common/ArrayHelper.cpp
===================================================================
--- branches/3.2.x/Fdo/Unmanaged/Src/Common/ArrayHelper.cpp	2007-02-07 07:16:59 UTC (rev 723)
+++ branches/3.2.x/Fdo/Unmanaged/Src/Common/ArrayHelper.cpp	2007-02-07 07:20:44 UTC (rev 724)
@@ -21,6 +21,7 @@
 
 #define MIN_ALLOC 1
 #define GROWTH_FACTOR 1     /* Proportion of array size to grow when needed. */
+#define POOL_ENTRY_BYTESIZE_LIMIT   (8*1024)    // 8KB limit on pooled FdoByteArray values, to suppress retention of large values in memory.
 
 FdoArrayHelper::GenericArray* FdoArrayHelper::Append(GenericArray* array, FdoInt32 numElements, FdoByte* elements, FdoInt32 elementSize)
 {
@@ -92,6 +93,69 @@
 	return array;
 }
 
+
+////////////////////////////////////////////////////////////////////////////
+// Implement thread-local storage for pooled FdoByteArray instances.
+////////////////////////////////////////////////////////////////////////////
+
+#ifdef _WIN32
+#include <windows.h>
+typedef int FdoCommonThreadDataKey;
+#else
+#include <pthread.h>
+typedef pthread_key_t FdoCommonThreadDataKey;
+#endif
+#include "../Geometry/Fgf/Pool.h"
+
+FDOPOOL_DEFINE(FdoPoolFgfByteArray, FdoByteArray)
+
+static FdoCommonThreadDataKey threadDataKey_S = 0;
+
+struct FdoCommonThreadData
+{
+    FdoPtr<FdoPoolFgfByteArray>         byteArrayPool;
+
+    static FdoCommonThreadData *        GetValue();
+    static void                         ReleaseValue();
+    static FdoCommonThreadDataKey       GetKey()                           { return threadDataKey_S; }
+    static void                         SetKey(FdoCommonThreadDataKey key) { threadDataKey_S = key; }
+};
+
+
+#ifdef _WIN32
+#define GET_VALUE(key)          ((FdoCommonThreadData *) TlsGetValue(key))
+#define SET_VALUE(key, value)   (TlsSetValue((key), (value)))
+#else
+#define GET_VALUE(key)          ((FdoCommonThreadData *) pthread_getspecific(key))
+#define SET_VALUE(key, value)   (pthread_setspecific((key), (value)))
+#endif
+
+FdoCommonThreadData *
+FdoCommonThreadData::GetValue()
+{
+    FdoCommonThreadData *data = GET_VALUE(threadDataKey_S);
+
+	if (NULL == data)
+	{
+        data = new FdoCommonThreadData;
+        if (NULL == data)
+            throw FdoException::Create(FdoException::NLSGetMessage(FDO_NLSID(FDO_1_BADALLOC)));
+        SET_VALUE(threadDataKey_S, data);
+	}
+	return data;
+}
+
+void FdoCommonThreadData::ReleaseValue()
+{
+    FdoCommonThreadData *data = GET_VALUE(threadDataKey_S);
+
+    if (NULL != data)
+    {
+        SET_VALUE(threadDataKey_S, NULL);
+        delete data;
+    }
+}
+
 /*
  * Allocate some more memory for the array.
  * If the given array is NULL, a new array of zero size 
@@ -117,7 +181,7 @@
 			newAlloc *= 1 + GROWTH_FACTOR;
 	}
 
-    FdoInt32 newAllocBytes = (newAlloc*elementSize) + sizeof(Metadata);
+    FdoInt32 newAllocBytes = (newAlloc*elementSize) + sizeof(GenericArray);
 
 	/*
 	 * The main trick: GenericArray's only real "member" data is the metadata.
@@ -128,18 +192,57 @@
      * array content is also composed of struct or class types.
 	 */
 
-	GenericArray* newArray = (GenericArray*) new FdoByte[newAllocBytes];
+    GenericArray* newArray = NULL;
+
+    if (sizeof(FdoByte) == elementSize)
+    {
+        // Try to acquire an FdoByteArray from the pool that is in thread-local storage.
+        // This is faster than going to the heap with the "new" operator.
+        FdoCommonThreadData * threadData = FdoCommonThreadData::GetValue();
+        FdoPoolFgfByteArray * pool = threadData->byteArrayPool;
+        if (NULL == pool)
+        {
+            threadData->byteArrayPool = FdoPoolFgfByteArray::Create(10);
+        }
+        else
+        {
+            GenericArray * pooledArray = (GenericArray*)pool->FindReusableItem();
+            if (NULL != pooledArray)
+            {
+                // The pooling template only knows that the entry is available.  It
+                // doesn't know other attributes, such as adequate size.  We'll test
+                // it here.  If it is not beg enough, we'll delete it and fall through
+                // to a new allocation.
+                if (pooledArray->m_metadata.alloc >= newAlloc)
+                {
+                    newArray = (GenericArray*) pooledArray;
+                }
+                else
+                {
+		            (void) memset(pooledArray, 0xfa, sizeof(GenericArray) + (pooledArray->m_metadata.alloc*elementSize));
+		            delete [] ((FdoByte*) pooledArray);
+		            pooledArray = 0;
+                }
+            }
+        }
+    }
+
+    if (NULL == newArray)
+	    newArray = (GenericArray*) new FdoByte[newAllocBytes];
 	if (0==newArray)
 		throw FdoException::Create(FdoException::NLSGetMessage(FDO_NLSID(FDO_1_BADALLOC)));
 
 	// Copy data from old array.
 	if (0!=array)
 	{
-		newArray->m_metadata = array->m_metadata;
-		if (oldSize > 0)
+        // Copy all metadata.
+        *newArray = *array;
+        // Copy elements.
+        if (oldSize > 0)
 			(void) memcpy( newArray->GetData(), array->GetData(), oldSize*elementSize );
     	// Make sure that stale pointers cannot do much.
-		(void) memset(array, 0xfd, sizeof(Metadata) + (array->m_metadata.alloc*elementSize));
+		(void) memset(array, 0xfd, sizeof(GenericArray) + (array->m_metadata.alloc*elementSize));
+        // Delete old storage.
 		delete [] ((FdoByte*) array);
 		array = 0;
 	}
@@ -155,8 +258,134 @@
 
 void FdoArrayHelper::DisposeOfArray(GenericArray* array, FdoInt32 elementSize)
 {
-	// Make sure that stale pointers cannot do much.
-    (void) memset(array, 0xff, sizeof(Metadata)+ (array->m_metadata.alloc*elementSize));
-	delete [] ((FdoByte*)array);
+    bool isPooled = false;
+
+    if (sizeof(FdoByte) == elementSize && array->m_metadata.alloc <= POOL_ENTRY_BYTESIZE_LIMIT)
+    {
+        // This is an FdoByteArray (or something with the same element size, 
+        // which is all that matters).  See if we can send it into the object pool,
+        // rather that actually freeing it.
+        FdoCommonThreadData * threadData = FdoCommonThreadData::GetValue();
+        if (threadData->byteArrayPool != NULL)
+            isPooled = threadData->byteArrayPool->AddItem((FdoByteArray *)array);
+    }
+    if (!isPooled)
+    {
+	    // Make sure that stale pointers cannot do much.
+        void * destination = array;
+        size_t size = sizeof(GenericArray) + (array->m_metadata.alloc*elementSize);
+        (void) memset(destination, 0xfc, size);
+
+        // Free the memory.
+	    delete [] ((FdoByte*)array);
+    }
 }
 
+
+#ifdef _WIN32
+
+#include <windows.h>
+
+static wchar_t module[MAX_PATH];
+static wchar_t home_dir[MAX_PATH];
+
+/// <summary>
+/// Main entry point for the dll.
+/// </summary>
+/// <param name="hModule">Handle to the DLL module.</param> 
+/// <param name="ul_reason_for_call">Reason for calling function.</param> 
+/// <param name="lpReserved">Reserved.</param> 
+/// <returns>TRUE if it succeeds or FALSE if initialization fails.</returns> 
+BOOL APIENTRY DllMain( HANDLE hModule,
+                       DWORD  ul_reason_for_call,
+                       LPVOID lpReserved
+					 )
+{
+    DWORD nchars;
+    wchar_t* last;
+    BOOL ret;
+
+    ret = TRUE;
+    switch (ul_reason_for_call)
+    {
+
+        case DLL_PROCESS_ATTACH:
+        {
+            // hModule - The value is the base address of the DLL.
+            // The HINSTANCE of a DLL is the same as the HMODULE of the DLL,
+            // so hinstDLL can be used in calls to functions that require a module handle.
+            nchars = GetModuleFileNameW ((HINSTANCE)hModule, module, MAX_PATH);
+            if (0 == nchars)
+                ret = FALSE;
+            else
+            {   
+                // scan the string for the last occurrence of a slash
+                wcscpy (home_dir, module);
+                last = wcsrchr (home_dir, L'\\');
+                if (NULL == last)
+                    ret = FALSE;
+                else
+                {
+                    last++; // move past the slash
+                    *last = L'\0'; // null terminate it there
+                }
+            }
+            FdoCommonThreadDataKey tlsIndex = TlsAlloc();
+            FdoCommonThreadData::SetKey(tlsIndex);
+            break;
+        }
+
+
+        case DLL_THREAD_ATTACH: 
+ 
+            // Nothing essential here.  We to defer any pre-allocation
+            // until someone calls FdoCommonThreadData::GetValue().
+ 
+            break; 
+ 
+        case DLL_THREAD_DETACH: 
+
+            FdoCommonThreadData::ReleaseValue();
+            break; 
+ 
+        case DLL_PROCESS_DETACH: 
+ 
+            FdoCommonThreadData::ReleaseValue();
+            TlsFree(FdoCommonThreadData::GetKey());
+            break; 
+
+    }
+
+    return (ret);
+}
+
+#else   // no _WIN32
+
+// This destructor function is called automatically when the
+// threading library destroys a thread key.
+void _FdoCommonThreadDataDestructor(void * voidData)
+{
+    FdoCommonThreadData *data = (FdoCommonThreadData *) voidData;
+                                                                                                           
+    if (NULL != data)
+    {
+        delete data;
+    }
+}
+
+void _loadFdoCommon()
+{
+    FdoCommonThreadDataKey key=0;
+    pthread_key_create(&key, _FdoCommonThreadDataDestructor);
+    FdoCommonThreadData::SetKey(key);
+}
+
+
+void _unloadFdoCommon()
+{
+    FdoCommonThreadDataKey key = FdoCommonThreadData::GetKey();
+    pthread_key_delete(key);
+}
+
+#endif
+



More information about the fdo-commits mailing list