as_thread.cpp 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313
  1. /*
  2. AngelCode Scripting Library
  3. Copyright (c) 2003-2012 Andreas Jonsson
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any
  6. damages arising from the use of this software.
  7. Permission is granted to anyone to use this software for any
  8. purpose, including commercial applications, and to alter it and
  9. redistribute it freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you
  11. must not claim that you wrote the original software. If you use
  12. this software in a product, an acknowledgment in the product
  13. documentation would be appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and
  15. must not be misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source
  17. distribution.
  18. The original version of this library can be located at:
  19. http://www.angelcode.com/angelscript/
  20. Andreas Jonsson
  21. [email protected]
  22. */
  23. //
  24. // as_thread.cpp
  25. //
  26. // Functions for multi threading support
  27. //
  28. #include "as_config.h"
  29. #include "as_thread.h"
  30. #include "as_atomic.h"
  31. BEGIN_AS_NAMESPACE
  32. //======================================================================
  33. extern "C"
  34. {
  35. // Global API function
  36. AS_API int asThreadCleanup()
  37. {
  38. return asCThreadManager::CleanupLocalData();
  39. }
  40. }
  41. //=======================================================================
  42. // Singleton
  43. static asCThreadManager *threadManager = 0;
  44. #ifndef AS_NO_THREADS
  45. static DECLARECRITICALSECTION(criticalSection)
  46. #endif
  47. //======================================================================
  48. asCThreadManager::asCThreadManager()
  49. {
  50. // We're already in the critical section when this function is called
  51. #ifdef AS_NO_THREADS
  52. tld = 0;
  53. #endif
  54. refCount = 1;
  55. }
  56. void asCThreadManager::AddRef()
  57. {
  58. // It's necessary to protect this section to
  59. // avoid two threads attempting to create thread
  60. // managers at the same time.
  61. ENTERCRITICALSECTION(criticalSection);
  62. if( threadManager == 0 )
  63. threadManager = asNEW(asCThreadManager);
  64. else
  65. threadManager->refCount++;
  66. LEAVECRITICALSECTION(criticalSection);
  67. }
  68. void asCThreadManager::Release()
  69. {
  70. // It's necessary to protect this section so no
  71. // other thread attempts to call AddRef or Release
  72. // while clean up is in progress.
  73. ENTERCRITICALSECTION(criticalSection);
  74. if( --threadManager->refCount == 0 )
  75. {
  76. // The last engine has been destroyed, so we
  77. // need to delete the thread manager as well
  78. asDELETE(threadManager,asCThreadManager);
  79. threadManager = 0;
  80. }
  81. LEAVECRITICALSECTION(criticalSection);
  82. }
  83. asCThreadManager::~asCThreadManager()
  84. {
  85. #ifndef AS_NO_THREADS
  86. // Delete all thread local datas
  87. asSMapNode<asPWORD,asCThreadLocalData*> *cursor = 0;
  88. if( tldMap.MoveFirst(&cursor) )
  89. {
  90. do
  91. {
  92. if( tldMap.GetValue(cursor) )
  93. {
  94. asDELETE(tldMap.GetValue(cursor),asCThreadLocalData);
  95. }
  96. } while( tldMap.MoveNext(&cursor, cursor) );
  97. }
  98. #else
  99. if( tld )
  100. {
  101. asDELETE(tld,asCThreadLocalData);
  102. }
  103. tld = 0;
  104. #endif
  105. }
  106. int asCThreadManager::CleanupLocalData()
  107. {
  108. #ifndef AS_NO_THREADS
  109. int r = 0;
  110. #if defined AS_POSIX_THREADS
  111. asPWORD id = (asPWORD)pthread_self();
  112. #elif defined AS_WINDOWS_THREADS
  113. asPWORD id = (asPWORD)GetCurrentThreadId();
  114. #endif
  115. ENTERCRITICALSECTION(criticalSection);
  116. if( threadManager == 0 )
  117. {
  118. LEAVECRITICALSECTION(criticalSection);
  119. return 0;
  120. }
  121. asSMapNode<asPWORD,asCThreadLocalData*> *cursor = 0;
  122. if( threadManager->tldMap.MoveTo(&cursor, id) )
  123. {
  124. asCThreadLocalData *tld = threadManager->tldMap.GetValue(cursor);
  125. // Can we really remove it at this time?
  126. if( tld->activeContexts.GetLength() == 0 )
  127. {
  128. asDELETE(tld,asCThreadLocalData);
  129. threadManager->tldMap.Erase(cursor);
  130. r = 0;
  131. }
  132. else
  133. r = asCONTEXT_ACTIVE;
  134. }
  135. LEAVECRITICALSECTION(criticalSection);
  136. return r;
  137. #else
  138. if( threadManager && threadManager->tld )
  139. {
  140. if( threadManager->tld->activeContexts.GetLength() == 0 )
  141. {
  142. asDELETE(threadManager->tld,asCThreadLocalData);
  143. threadManager->tld = 0;
  144. }
  145. else
  146. return asCONTEXT_ACTIVE;
  147. }
  148. return 0;
  149. #endif
  150. }
  151. #ifndef AS_NO_THREADS
  152. asCThreadLocalData *asCThreadManager::GetLocalData(asPWORD threadId)
  153. {
  154. // We're already in the critical section when this function is called
  155. asCThreadLocalData *tld = 0;
  156. asSMapNode<asPWORD,asCThreadLocalData*> *cursor = 0;
  157. if( threadManager->tldMap.MoveTo(&cursor, threadId) )
  158. tld = threadManager->tldMap.GetValue(cursor);
  159. return tld;
  160. }
  161. void asCThreadManager::SetLocalData(asPWORD threadId, asCThreadLocalData *tld)
  162. {
  163. // We're already in the critical section when this function is called
  164. tldMap.Insert(threadId, tld);
  165. }
  166. #endif
  167. asCThreadLocalData *asCThreadManager::GetLocalData()
  168. {
  169. #ifndef AS_NO_THREADS
  170. #if defined AS_POSIX_THREADS
  171. asPWORD id = (asPWORD)pthread_self();
  172. #elif defined AS_WINDOWS_THREADS
  173. asPWORD id = (asPWORD)GetCurrentThreadId();
  174. #endif
  175. ENTERCRITICALSECTION(criticalSection);
  176. asASSERT(threadManager);
  177. if( threadManager == 0 )
  178. {
  179. LEAVECRITICALSECTION(criticalSection);
  180. return 0;
  181. }
  182. asCThreadLocalData *tld = threadManager->GetLocalData(id);
  183. if( tld == 0 )
  184. {
  185. // Create a new tld
  186. tld = asNEW(asCThreadLocalData)();
  187. threadManager->SetLocalData(id, tld);
  188. }
  189. LEAVECRITICALSECTION(criticalSection);
  190. return tld;
  191. #else
  192. if( threadManager == 0 )
  193. return 0;
  194. if( threadManager->tld == 0 )
  195. threadManager->tld = asNEW(asCThreadLocalData)();
  196. return threadManager->tld;
  197. #endif
  198. }
  199. //=========================================================================
  200. asCThreadLocalData::asCThreadLocalData()
  201. {
  202. }
  203. asCThreadLocalData::~asCThreadLocalData()
  204. {
  205. }
  206. //=========================================================================
  207. #ifndef AS_NO_THREADS
  208. asCThreadCriticalSection::asCThreadCriticalSection()
  209. {
  210. #if defined AS_POSIX_THREADS
  211. pthread_mutex_init(&criticalSection, 0);
  212. #elif defined AS_WINDOWS_THREADS
  213. InitializeCriticalSection(&criticalSection);
  214. #endif
  215. }
  216. asCThreadCriticalSection::~asCThreadCriticalSection()
  217. {
  218. #if defined AS_POSIX_THREADS
  219. pthread_mutex_destroy(&criticalSection);
  220. #elif defined AS_WINDOWS_THREADS
  221. DeleteCriticalSection(&criticalSection);
  222. #endif
  223. }
  224. void asCThreadCriticalSection::Enter()
  225. {
  226. #if defined AS_POSIX_THREADS
  227. pthread_mutex_lock(&criticalSection);
  228. #elif defined AS_WINDOWS_THREADS
  229. EnterCriticalSection(&criticalSection);
  230. #endif
  231. }
  232. void asCThreadCriticalSection::Leave()
  233. {
  234. #if defined AS_POSIX_THREADS
  235. pthread_mutex_unlock(&criticalSection);
  236. #elif defined AS_WINDOWS_THREADS
  237. LeaveCriticalSection(&criticalSection);
  238. #endif
  239. }
  240. bool asCThreadCriticalSection::TryEnter()
  241. {
  242. #if defined AS_POSIX_THREADS
  243. return !pthread_mutex_trylock(&criticalSection);
  244. #elif defined AS_WINDOWS_THREADS
  245. return TryEnterCriticalSection(&criticalSection) ? true : false;
  246. #else
  247. return true;
  248. #endif
  249. }
  250. #endif
  251. //========================================================================
  252. END_AS_NAMESPACE