[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