| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350 |
- ///////////////////////////////////////////////////////////////////////////////
- // Copyright (c) Electronic Arts Inc. All rights reserved.
- ///////////////////////////////////////////////////////////////////////////////
- #include <eathread/eathread_storage.h>
- #include <eathread/eathread.h>
- EA_DISABLE_VC_WARNING(4574)
- #include <new>
- EA_RESTORE_VC_WARNING()
- #if defined(EA_PLATFORM_SONY)
- #include <kernel.h>
- EA::Thread::ThreadLocalStorage::ThreadLocalStorage()
- : mTLSData()
- {
- // To consider: Support the specification of a destructor instead of just passing NULL.
- mTLSData.mResult = scePthreadKeyCreate(&mTLSData.mKey, NULL);
- EAT_ASSERT(mTLSData.mResult == 0);
- }
- EA::Thread::ThreadLocalStorage::~ThreadLocalStorage()
- {
- if(mTLSData.mResult == 0)
- scePthreadKeyDelete(mTLSData.mKey);
- }
- void* EA::Thread::ThreadLocalStorage::GetValue()
- {
- return scePthreadGetspecific(mTLSData.mKey);
- }
- bool EA::Thread::ThreadLocalStorage::SetValue(const void* pData)
- {
- if(scePthreadSetspecific(mTLSData.mKey, pData) == 0)
- return true;
- return false;
- }
- #elif (defined(EA_PLATFORM_UNIX) || EA_POSIX_THREADS_AVAILABLE) && !defined(CS_UNDEFINED_STRING)
- #if defined(EA_PLATFORM_UNIX)
- #include <unistd.h>
- #elif defined(EA_PLATFORM_WINDOWS)
- EA_DISABLE_ALL_VC_WARNINGS()
- #include <Windows.h>
- EA_RESTORE_ALL_VC_WARNINGS()
- #endif
- EA::Thread::ThreadLocalStorage::ThreadLocalStorage()
- : mTLSData()
- {
- // To consider: Support the specification of a destructor instead of just passing NULL.
- mTLSData.mResult = pthread_key_create(&mTLSData.mKey, NULL);
- EAT_ASSERT(mTLSData.mResult == 0);
- }
- EA::Thread::ThreadLocalStorage::~ThreadLocalStorage()
- {
- if(mTLSData.mResult == 0)
- pthread_key_delete(mTLSData.mKey);
- }
- void* EA::Thread::ThreadLocalStorage::GetValue()
- {
- return pthread_getspecific(mTLSData.mKey);
- }
- bool EA::Thread::ThreadLocalStorage::SetValue(const void* pData)
- {
- if(pthread_setspecific(mTLSData.mKey, pData) == 0)
- return true;
- return false;
- }
- #elif defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_WINDOWS_PHONE) && !(defined(EA_PLATFORM_WINDOWS) && !EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP))
- EA_DISABLE_ALL_VC_WARNINGS()
- #include <Windows.h>
- EA_RESTORE_ALL_VC_WARNINGS()
- EA::Thread::ThreadLocalStorage::ThreadLocalStorage()
- : mTLSData(TlsAlloc())
- {
- EAT_ASSERT(mTLSData != TLS_OUT_OF_INDEXES);
- }
- EA::Thread::ThreadLocalStorage::~ThreadLocalStorage()
- {
- if(mTLSData != TLS_OUT_OF_INDEXES)
- TlsFree(mTLSData);
- }
- void* EA::Thread::ThreadLocalStorage::GetValue()
- {
- return TlsGetValue(mTLSData);
- }
- bool EA::Thread::ThreadLocalStorage::SetValue(const void* pData)
- {
- if(TlsSetValue(mTLSData, (void*)pData))
- return true;
- return false;
- }
- #elif (!EA_THREADS_AVAILABLE || defined(EA_PLATFORM_CONSOLE)) && !defined(CS_UNDEFINED_STRING)
- #include <string.h>
- #if !EA_THREADS_AVAILABLE
- #define OSEnableInterrupts()
- #define OSDisableInterrupts()
- #else
- #error Need to define EnableInterrupts/DisableInterrupts for the given platform.
- #endif
- EAThreadLocalStorageData::ThreadToDataPair* EAThreadLocalStorageData::GetTLSEntry(bool bCreateIfNotFound)
- {
- const int kArraySize = (sizeof(mDataArray) / sizeof(mDataArray[0]));
- ThreadToDataPair* pCurrent, *pEnd;
- EA::Thread::ThreadUniqueId nCurrentThreadID;
- EAThreadGetUniqueId(nCurrentThreadID);
- // The code below is likely to execute very quickly and never transfers
- // execution outside the function, so we can very briefly disable interrupts
- // for the period needed to do the logic below.
- OSDisableInterrupts();
- // We make the assumption that there are likely to be less than 10 threads most of
- // the time. Thus, instead of maintaining a sorted array and do a binary search
- // within that array, we do a linear search. An improvement would be to make the
- // array be sorted if it goes above some preset size, such as 20.
- for(pCurrent = mDataArray, pEnd = mDataArray + mDataArrayCount; pCurrent < pEnd; ++pCurrent)
- {
- if(pCurrent->mThreadID == nCurrentThreadID)
- {
- OSEnableInterrupts();
- return pCurrent;
- }
- }
- if((pCurrent >= pEnd) && ((mDataArrayCount + 1) < kArraySize) && bCreateIfNotFound) // If we didn't find it above and there is more room and we should create if not found...
- {
- pCurrent = mDataArray + mDataArrayCount++;
- pCurrent->mThreadID = nCurrentThreadID;
- }
- else
- pCurrent = NULL;
- OSEnableInterrupts();
- return pCurrent;
- }
- EA::Thread::ThreadLocalStorage::ThreadLocalStorage()
- {
- memset(mTLSData.mDataArray, 0, sizeof(mTLSData.mDataArray));
- mTLSData.mDataArrayCount = 0;
- }
- EA::Thread::ThreadLocalStorage::~ThreadLocalStorage()
- {
- // Nothing to do.
- }
- void* EA::Thread::ThreadLocalStorage::GetValue()
- {
- EAThreadLocalStorageData::ThreadToDataPair* const pTDP = mTLSData.GetTLSEntry(false);
- if(pTDP)
- return (void*)pTDP->mpData;
- return NULL;
- }
- bool EA::Thread::ThreadLocalStorage::SetValue(const void* pData)
- {
- if(pData == NULL)
- { // We remove it from the container so that the container can have room for others.
- EAThreadLocalStorageData::ThreadToDataPair* pTDP = mTLSData.GetTLSEntry(false);
- if(pTDP)
- {
- OSDisableInterrupts(); // Briefly disable interrupts for the duration of the logic below.
- const EAThreadLocalStorageData::ThreadToDataPair* const pTDPEnd = mTLSData.mDataArray + mTLSData.mDataArrayCount;
- while(++pTDP <= pTDPEnd) // What we do here is move all the other values downward. This is an O(n) operation,
- pTDP[-1] = pTDP[0]; // but the number of unique threads usinug us is likely to be pretty small.
- mTLSData.mDataArrayCount = (int)(pTDPEnd - mTLSData.mDataArray - 1);
- OSEnableInterrupts();
- }
- return true;
- }
- EAThreadLocalStorageData::ThreadToDataPair* const pTDP = mTLSData.GetTLSEntry(true);
- if(pTDP)
- pTDP->mpData = pData;
- return (pTDP != NULL);
- }
- #else
- // Use reference std::map implementation.
- EA_DISABLE_VC_WARNING(4574)
- #include <map>
- EA_RESTORE_VC_WARNING()
- #include <eathread/eathread_futex.h>
- void** EAThreadLocalStorageData::GetTLSEntry(bool bCreateIfNotFound)
- {
- EA::Thread::ThreadUniqueId nThreadID;
- EAThreadGetUniqueId(nThreadID);
- EA::Thread::AutoFutex autoFutex(mFutex);
- if(bCreateIfNotFound) // We expect this to be true most of the time.
- {
- // Create as needed
- if (mThreadToDataMap == NULL)
- {
- mThreadToDataMap = new std::map<EA::Thread::ThreadUniqueId, const void*>;
- }
- return (void**)(char*)&((*mThreadToDataMap)[nThreadID]); // Dereferencing a std::map value by index inserts the value if it is not present.
- }
- if (mThreadToDataMap == NULL)
- {
- return NULL;
- }
-
- std::map<EA::Thread::ThreadUniqueId, const void*>::iterator it(mThreadToDataMap->find(nThreadID));
- if(it != mThreadToDataMap->end())
- {
- std::map<EA::Thread::ThreadUniqueId, const void*>::value_type& value = *it;
- return (void**)(char*)&value.second;
- }
- return NULL;
- }
- EA::Thread::ThreadLocalStorage::ThreadLocalStorage()
- {
- }
- EA::Thread::ThreadLocalStorage::~ThreadLocalStorage()
- {
- // Nothing to do.
- }
- void* EA::Thread::ThreadLocalStorage::GetValue()
- {
- void** const ppData = mTLSData.GetTLSEntry(false);
- if(ppData)
- return *ppData;
- return NULL;
- }
- bool EA::Thread::ThreadLocalStorage::SetValue(const void* pData)
- {
- if(pData == NULL)
- {
- ThreadUniqueId nThreadID;
- EAThreadGetUniqueId(nThreadID);
- EA::Thread::AutoFutex autoFutex(mTLSData.mFutex);
-
- if (mTLSData.mThreadToDataMap)
- {
- std::map<EA::Thread::ThreadUniqueId, const void*>::iterator it(mTLSData.mThreadToDataMap->find(nThreadID));
- if(it != mTLSData.mThreadToDataMap->end())
- mTLSData.mThreadToDataMap->erase(it);
- }
- return true;
- }
- void** const ppData = mTLSData.GetTLSEntry(true);
- if(ppData)
- *ppData = (void*)pData;
- return (*ppData != NULL);
- }
- #endif
- namespace EA
- {
- namespace Thread
- {
- extern Allocator* gpAllocator;
- }
- }
- EA::Thread::ThreadLocalStorage* EA::Thread::ThreadLocalStorageFactory::CreateThreadLocalStorage()
- {
- if(gpAllocator)
- return new(gpAllocator->Alloc(sizeof(EA::Thread::ThreadLocalStorage))) EA::Thread::ThreadLocalStorage;
- else
- return new EA::Thread::ThreadLocalStorage;
- }
- void EA::Thread::ThreadLocalStorageFactory::DestroyThreadLocalStorage(EA::Thread::ThreadLocalStorage* pThreadLocalStorage)
- {
- if(gpAllocator)
- {
- pThreadLocalStorage->~ThreadLocalStorage();
- gpAllocator->Free(pThreadLocalStorage);
- }
- else
- delete pThreadLocalStorage;
- }
- size_t EA::Thread::ThreadLocalStorageFactory::GetThreadLocalStorageSize()
- {
- return sizeof(EA::Thread::ThreadLocalStorage);
- }
- EA::Thread::ThreadLocalStorage* EA::Thread::ThreadLocalStorageFactory::ConstructThreadLocalStorage(void* pMemory)
- {
- return new(pMemory) EA::Thread::ThreadLocalStorage;
- }
- void EA::Thread::ThreadLocalStorageFactory::DestructThreadLocalStorage(EA::Thread::ThreadLocalStorage* pThreadLocalStorage)
- {
- pThreadLocalStorage->~ThreadLocalStorage();
- }
- #undef OSEnableInterrupts
- #undef OSDisableInterrupts
|