eathread_storage.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. /////////////////////////////////////////////////////////////////////////////
  5. // Defines thread-local storage and related concepts in a platform-independent
  6. // and thread-safe manner.
  7. //
  8. // As of this writing (10/2003), documentation concerning thread-local
  9. // storage implementations under GCC, pthreads, and MSVC/Windows can be found at:
  10. // http://gcc.gnu.org/onlinedocs/gcc-3.3.2/gcc/Thread-Local.html#Thread-Local
  11. // http://java.icmc.sc.usp.br/library/books/ibm_pthreads/users-33.htm#324811
  12. // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vccore/html/_core_Thread_Local_Storage_.28.TLS.29.asp
  13. /////////////////////////////////////////////////////////////////////////////
  14. #ifndef EATHREAD_EATHREAD_STORAGE_H
  15. #define EATHREAD_EATHREAD_STORAGE_H
  16. #include <eathread/internal/config.h>
  17. EA_DISABLE_VC_WARNING(4574)
  18. #include <stddef.h>
  19. EA_RESTORE_VC_WARNING()
  20. #if defined(EA_PRAGMA_ONCE_SUPPORTED)
  21. #pragma once // Some compilers (e.g. VC++) benefit significantly from using this. We've measured 3-4% build speed improvements in apps as a result.
  22. #endif
  23. namespace EA
  24. {
  25. namespace Thread
  26. {
  27. /////////////////////////////////////////////////////////////////////////
  28. /// EA_THREAD_LOCAL
  29. ///
  30. /// Documentation (partially culled from online information):
  31. /// Thread Local Storage (a.k.a. TLS and Thread Specific Storage) is a
  32. /// mechanism by which each thread in a multithreaded process allocates
  33. /// storage for thread-specific data. In standard multithreaded programs,
  34. /// data is shared among all threads of a given process, whereas thread
  35. /// local storage is the mechanism for allocating per-thread data.
  36. ///
  37. /// The EA_THREAD_LOCAL specifier may be used alone, with the extern or
  38. /// static specifiers, but with no other storage class specifier.
  39. /// When used with extern or static, EA_THREAD_LOCAL must appear
  40. /// immediately after the other storage class specifier.
  41. ///
  42. /// The EA_THREAD_LOCAL specifier may be applied to any global, file-scoped
  43. /// static, function-scoped static, or static data member of a class.
  44. /// It may not be applied to block-scoped automatic or non-static data member.
  45. ///
  46. /// When the address-of operator is applied to a thread-local variable,
  47. /// it is evaluated at run-time and returns the address of the current
  48. /// thread's instance of that variable. An address so obtained may be used
  49. /// by any thread. When a thread terminates, any pointers to thread-local
  50. /// variables in that thread become invalid.
  51. ///
  52. /// No static initialization may refer to the address of a thread-local variable.
  53. /// In C++, if an initializer is present for a thread-local variable,
  54. /// it must be a constant-expression, as defined in 5.19.2 of the ANSI/ISO C++ standard.
  55. ///
  56. /// Windows has special considerations for using thread local storage in a DLL.
  57. ///
  58. /// Example usage:
  59. /// #if defined(EA_THREAD_LOCAL)
  60. /// EA_THREAD_LOCAL int n = 0; // OK
  61. /// extern EA_THREAD_LOCAL struct Data s; // OK
  62. /// static EA_THREAD_LOCAL char* p; // OK
  63. /// EA_THREAD_LOCAL int i = sizeof(i); // OK.
  64. /// EA_THREAD_LOCAL std::string s("hello"); // Bad -- Can't be used for initialized objects.
  65. /// EA_THREAD_LOCAL int Function(); // Bad -- Can't be used as return value.
  66. /// void Function(){ EA_THREAD_LOCAL int i = 0; } // Bad -- Can't be used in function.
  67. /// void Function(EA_THREAD_LOCAL int i){ } // Bad -- can't be used as argument.
  68. /// extern int i; EA_THREAD_LOCAL int i; // Bad -- Declarations differ.
  69. /// int EA_THREAD_LOCAL i; // Bad -- Can't be used as a type modifier.
  70. /// EA_THREAD_LOCAL int i = i; // Bad -- Can't reference self before initialization.
  71. /// #else
  72. /// Need to use EA::Thread::ThreadLocalStorage.
  73. /// #endif
  74. #if !EA_THREADS_AVAILABLE
  75. #define EA_THREAD_LOCAL
  76. // Disabled until we have at least one C++11 compiler that supports this which can be tested.
  77. //#elif (EABASE_VERSION_N >= 20040) && !defined(EA_COMPILER_NO_THREAD_LOCAL)
  78. // #define EA_THREAD_LOCAL thread_local
  79. #elif EA_USE_CPP11_CONCURRENCY
  80. #if defined(EA_COMPILER_MSVC11_0) // VC11 doesn't support C++11 thread_local storage class yet
  81. #define EA_THREAD_LOCAL __declspec(thread)
  82. #else
  83. #define EA_THREAD_LOCAL thread_local
  84. #endif
  85. #elif defined(__APPLE__)
  86. // http://clang.llvm.org/docs/LanguageExtensions.html
  87. #if __has_feature(cxx_thread_local)
  88. #define EA_THREAD_LOCAL thread_local
  89. #else
  90. #define EA_THREAD_LOCAL
  91. #endif
  92. #elif (defined(__GNUC__) && ((__GNUC__ >= 4) || ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)))) && (defined(EA_PLATFORM_WINDOWS) || defined(EA_PLATFORM_UNIX)) // Any of the Unix variants, including Mac OSX.
  93. // While GNUC v3.3 is the first version that supports thread local storage
  94. // declarators, not all versions of GNUC for all platforms support it,
  95. // as it requires support from other tools and libraries beyond the compiler.
  96. #if defined(__CYGWIN__) // Cygwin's branch of the GCC toolchain does not currently support TLS.
  97. // Not supported.
  98. #else
  99. #define EA_THREAD_LOCAL __thread
  100. #endif
  101. #elif defined(EA_COMPILER_MSVC) || defined(EA_COMPILER_BORLAND) || (defined(EA_PLATFORM_WINDOWS) && defined(EA_COMPILER_INTEL))
  102. // This appears to be supported by VC++, Borland C++.
  103. // And it is supported by all compilers for the Windows platform.
  104. #define EA_THREAD_LOCAL __declspec(thread)
  105. #elif defined(EA_PLATFORM_SONY) || defined(CS_UNDEFINED_STRING)
  106. #define EA_THREAD_LOCAL __thread
  107. #else
  108. // Else don't define it as anything. This will result in a compilation
  109. // error reporting the problem. We cannot simply #define away the
  110. // EA_THEAD_LOCAL term, as doing so would defeat the purpose of the
  111. // specifier. Dynamic thread local storage is a more flexible and
  112. // portable solution to the problem.
  113. // #define EA_THREAD_LOCAL
  114. #endif
  115. /////////////////////////////////////////////////////////////////////////
  116. } // namespace Thread
  117. } // namespace EA
  118. /////////////////////////////////////////////////////////////////////////
  119. /// EAThreadLocalStorageData
  120. ///
  121. /// This is used internally by class ThreadLocalStorage.
  122. /// Todo: Consider moving this declaration into a platform-specific
  123. /// header file.
  124. ///
  125. #if defined(EA_PLATFORM_SONY)
  126. #include <kernel.h>
  127. struct EAThreadLocalStorageData{
  128. ScePthreadKey mKey; // This is usually a pointer.
  129. int mResult; // Result of call to scePthreadKeyCreate, so we can know if mKey is valid.
  130. };
  131. #elif (defined(EA_PLATFORM_UNIX) || EA_POSIX_THREADS_AVAILABLE) && !defined(CS_UNDEFINED_STRING)
  132. // In this case we will be using pthread_key_create, pthread_key_delete, pthread_getspecific, pthread_setspecific.
  133. #include <pthread.h>
  134. struct EAThreadLocalStorageData{
  135. pthread_key_t mKey; // This is usually a pointer.
  136. int mResult; // Result of call to pthread_key_create, so we can know if mKey is valid.
  137. };
  138. #elif defined(EA_PLATFORM_MICROSOFT) && !defined(EA_PLATFORM_WINDOWS_PHONE) && !(defined(EA_PLATFORM_WINDOWS) && !EA_WINAPI_FAMILY_PARTITION(EA_WINAPI_PARTITION_DESKTOP))
  139. // In this case we will be using TlsAlloc, TlsFree, TlsGetValue, TlsSetValue.
  140. typedef uint32_t EAThreadLocalStorageData;
  141. #elif (!EA_THREADS_AVAILABLE || defined(EA_PLATFORM_CONSOLE)) && !defined(CS_UNDEFINED_STRING)
  142. #include <eathread/eathread.h>
  143. struct EAThreadLocalStorageData
  144. {
  145. struct ThreadToDataPair
  146. {
  147. EA::Thread::ThreadUniqueId mThreadID;
  148. const void* mpData;
  149. };
  150. #ifndef EA_TLS_MAX_COUNT
  151. #define EA_TLS_MAX_COUNT 16 // This is the max number of threads that might want to use the given thread-local-storage item.
  152. #endif
  153. ThreadToDataPair* GetTLSEntry(bool bCreateIfNotFound);
  154. ThreadToDataPair mDataArray[EA_TLS_MAX_COUNT];
  155. int mDataArrayCount;
  156. };
  157. #else // STL version which uses less memory but uses heap memory.
  158. // If you use this version, then you want to make sure your STL is using new/delete
  159. // by default and then make sure you are globally mapping new/delete to your
  160. // custom allocation system. STLPort, for example, tends to want to use its
  161. // own internal allocator which is non-optimal for serious uses.
  162. EA_DISABLE_VC_WARNING(4574 4350)
  163. #include <map> // Note that this dependency on STL map is only present if you use this pathway, which is disabled by default.
  164. EA_RESTORE_VC_WARNING()
  165. #include <eathread/eathread.h>
  166. #include <eathread/eathread_futex.h>
  167. struct EAThreadLocalStorageData
  168. {
  169. EAThreadLocalStorageData() : mThreadToDataMap(NULL) {}
  170. ~EAThreadLocalStorageData() { delete mThreadToDataMap; mThreadToDataMap = NULL; }
  171. void** GetTLSEntry(bool bCreateIfNotFound);
  172. // We allocate this map only when needed
  173. // This prevents too early allocations before our allocator initialization
  174. std::map<EA::Thread::ThreadUniqueId, const void*> *mThreadToDataMap;
  175. EA::Thread::Futex mFutex;
  176. private:
  177. // Disable copy and assignment
  178. EAThreadLocalStorageData(const EAThreadLocalStorageData&);
  179. EAThreadLocalStorageData operator=(const EAThreadLocalStorageData&);
  180. };
  181. #endif
  182. /////////////////////////////////////////////////////////////////////////
  183. namespace EA
  184. {
  185. namespace Thread
  186. {
  187. /////////////////////////////////////////////////////////////////////////
  188. /// class ThreadLocalStorage
  189. ///
  190. /// This is a class that lets you store a pointer to data uniquely for
  191. /// each thread. It thus allows access to a pointer as if it were local
  192. /// but each thread gets its own copy.
  193. ///
  194. /// The implementation behind this class maps to the PThreads API under
  195. /// Unix-like systems, maps to the Windows TLS SPI under Windows, and
  196. /// maps to a custom implementation otherwise. The PThreads API has a
  197. /// mechanism whereby you can set a callback to execute when a thread
  198. /// exits; the callback will call the callback once for each pointer
  199. /// that was stored in all thread local storage objects. Due to the
  200. /// general weaknesses of the PThread mechanism and due to our interest
  201. /// in being as lean as possible, we don't support automatic callbacks
  202. /// such as with PThreads. The same effect can be achieved manually
  203. /// when needed.
  204. ///
  205. /// Example usage:
  206. /// ThreadLocalStorage tls;
  207. /// void* pValue;
  208. /// bool bResult;
  209. ///
  210. /// pValue = tls.GetValue(); // Return value will be NULL.
  211. /// bResult = tls.SetValue(NULL); // This is fine and bResult should be true.
  212. /// pValue = tls.GetValue(); // Return value will be NULL.
  213. /// bResult = tls.SetValue(pSomeObject); // Set thread-specific value to pSomeObject.
  214. /// bResult = tls.SetValue(pOtherObject); // Set thread-specific value to pOtherObject.
  215. /// pValue = tls.GetValue(); // Return value will be pOtherObject.
  216. /// bResult = tls.SetValue(NULL); // This is fine and bResult should be true.
  217. ///
  218. class EATHREADLIB_API ThreadLocalStorage
  219. {
  220. public:
  221. ThreadLocalStorage();
  222. ~ThreadLocalStorage();
  223. /// GetValue
  224. /// Returns the pointer previous stored via GetValue or returns NULL if there
  225. /// is not stored value or if the user stored NULL.
  226. void* GetValue();
  227. /// SetValue
  228. /// Stores a pointer, returns true if the storage was possible. In general,
  229. /// the only reason that false would ever be returned is if there wasn't
  230. /// sufficient memory remaining for the operation. When a thread exits,
  231. /// it should call SetValue(NULL), as there is currently no mechanism to
  232. /// automatically detect thread exits on some platforms and thus there is
  233. /// no way to automatically clear these values.
  234. bool SetValue(const void* pData);
  235. /// GetPlatformData
  236. /// Returns the platform-specific thread local storage handle for debugging
  237. /// uses or other cases whereby special (and non-portable) uses are required.
  238. void* GetPlatformData()
  239. { return &mTLSData; }
  240. protected:
  241. EAThreadLocalStorageData mTLSData;
  242. private:
  243. // Disable copy and assignment
  244. ThreadLocalStorage(const ThreadLocalStorage&);
  245. ThreadLocalStorage operator=(const ThreadLocalStorage&);
  246. };
  247. /////////////////////////////////////////////////////////////////////////
  248. /// ThreadLocalStorageFactory
  249. ///
  250. /// Implements a factory-based creation and destruction mechanism for class ThreadLocalStorage.
  251. /// A primary use of this would be to allow the ThreadLocalStorage implementation to reside in
  252. /// a private library while users of the class interact only with the interface
  253. /// header and the factory. The factory provides conventional create/destroy
  254. /// semantics which use global operator new, but also provides manual construction/
  255. /// destruction semantics so that the user can provide for memory allocation
  256. /// and deallocation.
  257. class EATHREADLIB_API ThreadLocalStorageFactory
  258. {
  259. public:
  260. static ThreadLocalStorage* CreateThreadLocalStorage(); // Internally implemented as: return new ThreadLocalStorage;
  261. static void DestroyThreadLocalStorage(ThreadLocalStorage* pTLS); // Internally implemented as: delete pTLS;
  262. static size_t GetThreadLocalStorageSize(); // Internally implemented as: return sizeof(ThreadLocalStorage);
  263. static ThreadLocalStorage* ConstructThreadLocalStorage(void* pMemory); // Internally implemented as: return new(pMemory) ThreadLocalStorage;
  264. static void DestructThreadLocalStorage(ThreadLocalStorage* pTLS); // Internally implemented as: pTLS->~ThreadLocalStorage();
  265. };
  266. // ThreadLocalPointer
  267. // This is a class that adds pointer type awareness to ThreadLocalStorage.
  268. // The interface is designed to look like the standard auto_ptr class.
  269. //
  270. // The following is disabled until we provide a way to enumerate and delete
  271. // the pointers when the object goes out of scope or delete the thread-specific
  272. // pointer when the thread ends. Both are require before this class fully acts
  273. // as one would expect.
  274. //
  275. //template <typename T>
  276. //class ThreadLocalPointer
  277. //{
  278. //public:
  279. // T* get() const { return static_cast<T*>(mTLS.GetValue()); }
  280. // T* operator->() const { return static_cast<T*>(mTLS.GetValue()); }
  281. // T& operator*() const { return *static_cast<T*>(mTLS.GetValue()); }
  282. // void reset(T* pNew = 0){
  283. // T* const pTemp = get();
  284. // if(pNew != pTemp){
  285. // delete pTemp;
  286. // mTLS.SetValue(pTemp);
  287. // }
  288. // }
  289. //
  290. //protected:
  291. // ThreadLocalStorage mTLS;
  292. //
  293. //private:
  294. // ThreadLocalPointer(const ThreadLocalPointer&);
  295. // const ThreadLocalPointer& operator=(const ThreadLocalPointer&);
  296. //};
  297. /////////////////////////////////////////////////////////////////////////
  298. } // namespace Thread
  299. } // namespace EA
  300. #endif // #ifdef EATHREAD_EATHREAD_STORAGE_H