eathread_storage.cpp 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <eathread/eathread_storage.h>
  5. #include <eathread/eathread.h>
  6. EA_DISABLE_VC_WARNING(4574)
  7. #include <new>
  8. EA_RESTORE_VC_WARNING()
  9. #if defined(EA_PLATFORM_SONY)
  10. #include <kernel.h>
  11. EA::Thread::ThreadLocalStorage::ThreadLocalStorage()
  12. : mTLSData()
  13. {
  14. // To consider: Support the specification of a destructor instead of just passing NULL.
  15. mTLSData.mResult = scePthreadKeyCreate(&mTLSData.mKey, NULL);
  16. EAT_ASSERT(mTLSData.mResult == 0);
  17. }
  18. EA::Thread::ThreadLocalStorage::~ThreadLocalStorage()
  19. {
  20. if(mTLSData.mResult == 0)
  21. scePthreadKeyDelete(mTLSData.mKey);
  22. }
  23. void* EA::Thread::ThreadLocalStorage::GetValue()
  24. {
  25. return scePthreadGetspecific(mTLSData.mKey);
  26. }
  27. bool EA::Thread::ThreadLocalStorage::SetValue(const void* pData)
  28. {
  29. if(scePthreadSetspecific(mTLSData.mKey, pData) == 0)
  30. return true;
  31. return false;
  32. }
  33. #elif (defined(EA_PLATFORM_UNIX) || EA_POSIX_THREADS_AVAILABLE) && !defined(CS_UNDEFINED_STRING)
  34. #if defined(EA_PLATFORM_UNIX)
  35. #include <unistd.h>
  36. #elif defined(EA_PLATFORM_WINDOWS)
  37. EA_DISABLE_ALL_VC_WARNINGS()
  38. #include <Windows.h>
  39. EA_RESTORE_ALL_VC_WARNINGS()
  40. #endif
  41. EA::Thread::ThreadLocalStorage::ThreadLocalStorage()
  42. : mTLSData()
  43. {
  44. // To consider: Support the specification of a destructor instead of just passing NULL.
  45. mTLSData.mResult = pthread_key_create(&mTLSData.mKey, NULL);
  46. EAT_ASSERT(mTLSData.mResult == 0);
  47. }
  48. EA::Thread::ThreadLocalStorage::~ThreadLocalStorage()
  49. {
  50. if(mTLSData.mResult == 0)
  51. pthread_key_delete(mTLSData.mKey);
  52. }
  53. void* EA::Thread::ThreadLocalStorage::GetValue()
  54. {
  55. return pthread_getspecific(mTLSData.mKey);
  56. }
  57. bool EA::Thread::ThreadLocalStorage::SetValue(const void* pData)
  58. {
  59. if(pthread_setspecific(mTLSData.mKey, pData) == 0)
  60. return true;
  61. return false;
  62. }
  63. #elif defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_WINDOWS_PHONE) && !(defined(EA_PLATFORM_WINDOWS) && !EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP))
  64. EA_DISABLE_ALL_VC_WARNINGS()
  65. #include <Windows.h>
  66. EA_RESTORE_ALL_VC_WARNINGS()
  67. EA::Thread::ThreadLocalStorage::ThreadLocalStorage()
  68. : mTLSData(TlsAlloc())
  69. {
  70. EAT_ASSERT(mTLSData != TLS_OUT_OF_INDEXES);
  71. }
  72. EA::Thread::ThreadLocalStorage::~ThreadLocalStorage()
  73. {
  74. if(mTLSData != TLS_OUT_OF_INDEXES)
  75. TlsFree(mTLSData);
  76. }
  77. void* EA::Thread::ThreadLocalStorage::GetValue()
  78. {
  79. return TlsGetValue(mTLSData);
  80. }
  81. bool EA::Thread::ThreadLocalStorage::SetValue(const void* pData)
  82. {
  83. if(TlsSetValue(mTLSData, (void*)pData))
  84. return true;
  85. return false;
  86. }
  87. #elif (!EA_THREADS_AVAILABLE || defined(EA_PLATFORM_CONSOLE)) && !defined(CS_UNDEFINED_STRING)
  88. #include <string.h>
  89. #if !EA_THREADS_AVAILABLE
  90. #define OSEnableInterrupts()
  91. #define OSDisableInterrupts()
  92. #else
  93. #error Need to define EnableInterrupts/DisableInterrupts for the given platform.
  94. #endif
  95. EAThreadLocalStorageData::ThreadToDataPair* EAThreadLocalStorageData::GetTLSEntry(bool bCreateIfNotFound)
  96. {
  97. const int kArraySize = (sizeof(mDataArray) / sizeof(mDataArray[0]));
  98. ThreadToDataPair* pCurrent, *pEnd;
  99. EA::Thread::ThreadUniqueId nCurrentThreadID;
  100. EAThreadGetUniqueId(nCurrentThreadID);
  101. // The code below is likely to execute very quickly and never transfers
  102. // execution outside the function, so we can very briefly disable interrupts
  103. // for the period needed to do the logic below.
  104. OSDisableInterrupts();
  105. // We make the assumption that there are likely to be less than 10 threads most of
  106. // the time. Thus, instead of maintaining a sorted array and do a binary search
  107. // within that array, we do a linear search. An improvement would be to make the
  108. // array be sorted if it goes above some preset size, such as 20.
  109. for(pCurrent = mDataArray, pEnd = mDataArray + mDataArrayCount; pCurrent < pEnd; ++pCurrent)
  110. {
  111. if(pCurrent->mThreadID == nCurrentThreadID)
  112. {
  113. OSEnableInterrupts();
  114. return pCurrent;
  115. }
  116. }
  117. 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...
  118. {
  119. pCurrent = mDataArray + mDataArrayCount++;
  120. pCurrent->mThreadID = nCurrentThreadID;
  121. }
  122. else
  123. pCurrent = NULL;
  124. OSEnableInterrupts();
  125. return pCurrent;
  126. }
  127. EA::Thread::ThreadLocalStorage::ThreadLocalStorage()
  128. {
  129. memset(mTLSData.mDataArray, 0, sizeof(mTLSData.mDataArray));
  130. mTLSData.mDataArrayCount = 0;
  131. }
  132. EA::Thread::ThreadLocalStorage::~ThreadLocalStorage()
  133. {
  134. // Nothing to do.
  135. }
  136. void* EA::Thread::ThreadLocalStorage::GetValue()
  137. {
  138. EAThreadLocalStorageData::ThreadToDataPair* const pTDP = mTLSData.GetTLSEntry(false);
  139. if(pTDP)
  140. return (void*)pTDP->mpData;
  141. return NULL;
  142. }
  143. bool EA::Thread::ThreadLocalStorage::SetValue(const void* pData)
  144. {
  145. if(pData == NULL)
  146. { // We remove it from the container so that the container can have room for others.
  147. EAThreadLocalStorageData::ThreadToDataPair* pTDP = mTLSData.GetTLSEntry(false);
  148. if(pTDP)
  149. {
  150. OSDisableInterrupts(); // Briefly disable interrupts for the duration of the logic below.
  151. const EAThreadLocalStorageData::ThreadToDataPair* const pTDPEnd = mTLSData.mDataArray + mTLSData.mDataArrayCount;
  152. while(++pTDP <= pTDPEnd) // What we do here is move all the other values downward. This is an O(n) operation,
  153. pTDP[-1] = pTDP[0]; // but the number of unique threads usinug us is likely to be pretty small.
  154. mTLSData.mDataArrayCount = (int)(pTDPEnd - mTLSData.mDataArray - 1);
  155. OSEnableInterrupts();
  156. }
  157. return true;
  158. }
  159. EAThreadLocalStorageData::ThreadToDataPair* const pTDP = mTLSData.GetTLSEntry(true);
  160. if(pTDP)
  161. pTDP->mpData = pData;
  162. return (pTDP != NULL);
  163. }
  164. #else
  165. // Use reference std::map implementation.
  166. EA_DISABLE_VC_WARNING(4574)
  167. #include <map>
  168. EA_RESTORE_VC_WARNING()
  169. #include <eathread/eathread_futex.h>
  170. void** EAThreadLocalStorageData::GetTLSEntry(bool bCreateIfNotFound)
  171. {
  172. EA::Thread::ThreadUniqueId nThreadID;
  173. EAThreadGetUniqueId(nThreadID);
  174. EA::Thread::AutoFutex autoFutex(mFutex);
  175. if(bCreateIfNotFound) // We expect this to be true most of the time.
  176. {
  177. // Create as needed
  178. if (mThreadToDataMap == NULL)
  179. {
  180. mThreadToDataMap = new std::map<EA::Thread::ThreadUniqueId, const void*>;
  181. }
  182. return (void**)(char*)&((*mThreadToDataMap)[nThreadID]); // Dereferencing a std::map value by index inserts the value if it is not present.
  183. }
  184. if (mThreadToDataMap == NULL)
  185. {
  186. return NULL;
  187. }
  188. std::map<EA::Thread::ThreadUniqueId, const void*>::iterator it(mThreadToDataMap->find(nThreadID));
  189. if(it != mThreadToDataMap->end())
  190. {
  191. std::map<EA::Thread::ThreadUniqueId, const void*>::value_type& value = *it;
  192. return (void**)(char*)&value.second;
  193. }
  194. return NULL;
  195. }
  196. EA::Thread::ThreadLocalStorage::ThreadLocalStorage()
  197. {
  198. }
  199. EA::Thread::ThreadLocalStorage::~ThreadLocalStorage()
  200. {
  201. // Nothing to do.
  202. }
  203. void* EA::Thread::ThreadLocalStorage::GetValue()
  204. {
  205. void** const ppData = mTLSData.GetTLSEntry(false);
  206. if(ppData)
  207. return *ppData;
  208. return NULL;
  209. }
  210. bool EA::Thread::ThreadLocalStorage::SetValue(const void* pData)
  211. {
  212. if(pData == NULL)
  213. {
  214. ThreadUniqueId nThreadID;
  215. EAThreadGetUniqueId(nThreadID);
  216. EA::Thread::AutoFutex autoFutex(mTLSData.mFutex);
  217. if (mTLSData.mThreadToDataMap)
  218. {
  219. std::map<EA::Thread::ThreadUniqueId, const void*>::iterator it(mTLSData.mThreadToDataMap->find(nThreadID));
  220. if(it != mTLSData.mThreadToDataMap->end())
  221. mTLSData.mThreadToDataMap->erase(it);
  222. }
  223. return true;
  224. }
  225. void** const ppData = mTLSData.GetTLSEntry(true);
  226. if(ppData)
  227. *ppData = (void*)pData;
  228. return (*ppData != NULL);
  229. }
  230. #endif
  231. namespace EA
  232. {
  233. namespace Thread
  234. {
  235. extern Allocator* gpAllocator;
  236. }
  237. }
  238. EA::Thread::ThreadLocalStorage* EA::Thread::ThreadLocalStorageFactory::CreateThreadLocalStorage()
  239. {
  240. if(gpAllocator)
  241. return new(gpAllocator->Alloc(sizeof(EA::Thread::ThreadLocalStorage))) EA::Thread::ThreadLocalStorage;
  242. else
  243. return new EA::Thread::ThreadLocalStorage;
  244. }
  245. void EA::Thread::ThreadLocalStorageFactory::DestroyThreadLocalStorage(EA::Thread::ThreadLocalStorage* pThreadLocalStorage)
  246. {
  247. if(gpAllocator)
  248. {
  249. pThreadLocalStorage->~ThreadLocalStorage();
  250. gpAllocator->Free(pThreadLocalStorage);
  251. }
  252. else
  253. delete pThreadLocalStorage;
  254. }
  255. size_t EA::Thread::ThreadLocalStorageFactory::GetThreadLocalStorageSize()
  256. {
  257. return sizeof(EA::Thread::ThreadLocalStorage);
  258. }
  259. EA::Thread::ThreadLocalStorage* EA::Thread::ThreadLocalStorageFactory::ConstructThreadLocalStorage(void* pMemory)
  260. {
  261. return new(pMemory) EA::Thread::ThreadLocalStorage;
  262. }
  263. void EA::Thread::ThreadLocalStorageFactory::DestructThreadLocalStorage(EA::Thread::ThreadLocalStorage* pThreadLocalStorage)
  264. {
  265. pThreadLocalStorage->~ThreadLocalStorage();
  266. }
  267. #undef OSEnableInterrupts
  268. #undef OSDisableInterrupts