eathread_futex.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. ///////////////////////////////////////////////////////////////////////////////
  2. // Copyright (c) Electronic Arts Inc. All rights reserved.
  3. ///////////////////////////////////////////////////////////////////////////////
  4. #include <eathread/eathread_futex.h>
  5. #include <new>
  6. #if defined(EA_THREAD_NONTHREADED_FUTEX) && EA_THREAD_NONTHREADED_FUTEX
  7. void EA::Thread::Futex::CreateFSemaphore()
  8. {
  9. mSemaphore.mnCount = 0;
  10. }
  11. void EA::Thread::Futex::DestroyFSemaphore()
  12. {
  13. // Do nothing;
  14. }
  15. void EA::Thread::Futex::SignalFSemaphore()
  16. {
  17. mSemaphore.mnCount++;
  18. }
  19. void EA::Thread::Futex::WaitFSemaphore()
  20. {
  21. while(mSemaphore.mnCount <= 0)
  22. EA_THREAD_DO_SPIN();
  23. mSemaphore.mnCount--;
  24. }
  25. bool EA::Thread::Futex::WaitFSemaphore(const ThreadTime&)
  26. {
  27. WaitFSemaphore();
  28. return true;
  29. }
  30. #elif defined(EA_PLATFORM_APPLE) && EATHREAD_MANUAL_FUTEX_ENABLED
  31. #include <semaphore.h>
  32. #include <stdio.h>
  33. #include <errno.h>
  34. #include <string.h>
  35. #include <libkern/OSAtomic.h>
  36. void EA::Thread::Futex::CreateFSemaphore()
  37. {
  38. mSemaphore.Init(0);
  39. }
  40. void EA::Thread::Futex::DestroyFSemaphore()
  41. {
  42. // Do nothing;
  43. }
  44. void EA::Thread::Futex::SignalFSemaphore()
  45. {
  46. mSemaphore.Post();
  47. }
  48. void EA::Thread::Futex::WaitFSemaphore()
  49. {
  50. mSemaphore.Wait();
  51. }
  52. bool EA::Thread::Futex::WaitFSemaphore(const ThreadTime& timeoutAbsolute)
  53. {
  54. return (mSemaphore.Wait(timeoutAbsolute) >= 0);
  55. }
  56. #elif defined(EA_PLATFORM_SONY) && !EATHREAD_MANUAL_FUTEX_ENABLED
  57. #include <kernel.h>
  58. #include <eathread/eathread_atomic.h>
  59. EA::Thread::Futex::Futex()
  60. : mSpinCount(EATHREAD_FUTEX_SPIN_COUNT)
  61. {
  62. }
  63. EA::Thread::Futex::~Futex()
  64. {
  65. }
  66. void EA::Thread::Futex::Lock()
  67. {
  68. Uint spinCount(mSpinCount);
  69. while(--spinCount)
  70. {
  71. if(TryLock())
  72. return;
  73. }
  74. mMutex.Lock();
  75. }
  76. void EA::Thread::Futex::Unlock()
  77. {
  78. mMutex.Unlock();
  79. }
  80. bool EA::Thread::Futex::TryLock()
  81. {
  82. if(mMutex.Lock(EA::Thread::kTimeoutImmediate) > 0) // This calls scePthreadMutexTrylock
  83. return true;
  84. return false;
  85. }
  86. int EA::Thread::Futex::Lock(const ThreadTime& timeoutAbsolute)
  87. {
  88. return mMutex.Lock(timeoutAbsolute);
  89. }
  90. int EA::Thread::Futex::GetLockCount() const
  91. {
  92. return mMutex.GetLockCount();
  93. }
  94. bool EA::Thread::Futex::HasLock() const
  95. {
  96. return mMutex.HasLock();
  97. }
  98. void EA::Thread::Futex::SetSpinCount(Uint spinCount)
  99. {
  100. mSpinCount = spinCount;
  101. }
  102. #elif defined(EA_PLATFORM_SONY) && EATHREAD_MANUAL_FUTEX_ENABLED
  103. #include <kernel/semaphore.h>
  104. #include <sceerror.h>
  105. void EA::Thread::Futex::CreateFSemaphore()
  106. {
  107. // To consider: Copy the Futex name into this semaphore name.
  108. int result = sceKernelCreateSema(&mSemaphore, "Futex", SCE_KERNEL_SEMA_ATTR_TH_FIFO, 0, 100000, NULL);
  109. EA_UNUSED(result);
  110. EAT_ASSERT(result == SCE_OK);
  111. }
  112. void EA::Thread::Futex::DestroyFSemaphore()
  113. {
  114. int result = sceKernelDeleteSema(mSemaphore);
  115. EA_UNUSED(result);
  116. EAT_ASSERT(result == SCE_OK);
  117. }
  118. void EA::Thread::Futex::SignalFSemaphore()
  119. {
  120. int result = sceKernelSignalSema(mSemaphore, 1);
  121. EA_UNUSED(result);
  122. EAT_ASSERT(result == SCE_OK);
  123. }
  124. void EA::Thread::Futex::WaitFSemaphore()
  125. {
  126. int result = sceKernelWaitSema(mSemaphore, 1, NULL);
  127. EA_UNUSED(result);
  128. EAT_ASSERT(result == SCE_OK);
  129. }
  130. bool EA::Thread::Futex::WaitFSemaphore(const ThreadTime& timeoutAbsolute)
  131. {
  132. SceKernelUseconds timeoutRelativeUs = static_cast<SceKernelUseconds>(RelativeTimeoutFromAbsoluteTimeout(timeoutAbsolute));
  133. if(timeoutRelativeUs < 1)
  134. timeoutRelativeUs = 1;
  135. return (sceKernelWaitSema(mSemaphore, 1, &timeoutRelativeUs) == SCE_OK);
  136. }
  137. #elif (defined(EA_PLATFORM_UNIX) || EA_POSIX_THREADS_AVAILABLE) && EATHREAD_MANUAL_FUTEX_ENABLED
  138. #include <semaphore.h>
  139. #include <errno.h>
  140. void EA::Thread::Futex::CreateFSemaphore()
  141. {
  142. const int result = sem_init(&mSemaphore, 0, 0);
  143. (void)result;
  144. EAT_ASSERT(result != -1);
  145. }
  146. void EA::Thread::Futex::DestroyFSemaphore()
  147. {
  148. #if defined (EA_PLATFORM_APPLE)
  149. sem_close(&mSemaphore);
  150. #elif defined(EA_PLATFORM_ANDROID)
  151. sem_destroy(&mSemaphore); // Android's sem_destroy is broken. http://code.google.com/p/android/issues/detail?id=3106
  152. #else
  153. int result = -1;
  154. for(;;)
  155. {
  156. result = sem_destroy(&mSemaphore);
  157. if((result == -1) && (errno == EBUSY)) // If another thread or process is blocked on this semaphore...
  158. ThreadSleep(kTimeoutYield); // Yield. If we don't yield, it's possible we could block other other threads or processes from running, on some systems.
  159. else
  160. break;
  161. }
  162. EAT_ASSERT(result != -1);
  163. #endif
  164. }
  165. void EA::Thread::Futex::SignalFSemaphore()
  166. {
  167. sem_post(&mSemaphore);
  168. }
  169. void EA::Thread::Futex::WaitFSemaphore()
  170. {
  171. // We don't have much choice but to retry interrupted waits,
  172. // as there is no lock failure return value.
  173. while((sem_wait(&mSemaphore) == -1) && (errno == EINTR))
  174. continue;
  175. }
  176. bool EA::Thread::Futex::WaitFSemaphore(const ThreadTime&)
  177. {
  178. WaitFSemaphore();
  179. return true;
  180. }
  181. #elif defined(EA_PLATFORM_MICROSOFT) && !EA_USE_CPP11_CONCURRENCY && !EATHREAD_MANUAL_FUTEX_ENABLED
  182. EA_DISABLE_ALL_VC_WARNINGS()
  183. #include <Windows.h>
  184. EA_RESTORE_ALL_VC_WARNINGS()
  185. // Validate what we assume to be invariants.
  186. EAT_COMPILETIME_ASSERT(sizeof(CRITICAL_SECTION) <= (EA::Thread::FUTEX_PLATFORM_DATA_SIZE / sizeof(uint64_t) * sizeof(uint64_t)));
  187. #if defined(EA_PLATFORM_MICROSOFT) && defined(EA_PROCESSOR_X86_64)
  188. EAT_COMPILETIME_ASSERT(offsetof(CRITICAL_SECTION, RecursionCount) == (3 * sizeof(int)));
  189. EAT_COMPILETIME_ASSERT(offsetof(CRITICAL_SECTION, OwningThread) == (4 * sizeof(int)));
  190. #elif defined(EA_PLATFORM_WIN32)
  191. EAT_COMPILETIME_ASSERT(offsetof(CRITICAL_SECTION, RecursionCount) == (2 * sizeof(int)));
  192. EAT_COMPILETIME_ASSERT(offsetof(CRITICAL_SECTION, OwningThread) == (3 * sizeof(int)));
  193. #else
  194. EAT_FAIL_MSG("Need to verify offsetof.");
  195. #endif
  196. #elif defined(EA_PLATFORM_MICROSOFT) && EATHREAD_MANUAL_FUTEX_ENABLED
  197. #if defined(EA_PLATFORM_WINDOWS)
  198. EA_DISABLE_ALL_VC_WARNINGS()
  199. #include <Windows.h>
  200. EA_RESTORE_ALL_VC_WARNINGS()
  201. #endif
  202. void EA::Thread::Futex::CreateFSemaphore()
  203. {
  204. mSemaphore = CreateSemaphoreA(NULL, 0, INT_MAX / 2, NULL);
  205. EAT_ASSERT(mSemaphore != 0);
  206. }
  207. void EA::Thread::Futex::DestroyFSemaphore()
  208. {
  209. if(mSemaphore)
  210. CloseHandle(mSemaphore);
  211. }
  212. void EA::Thread::Futex::SignalFSemaphore()
  213. {
  214. ReleaseSemaphore(mSemaphore, 1, NULL);
  215. }
  216. void EA::Thread::Futex::WaitFSemaphore()
  217. {
  218. WaitForSingleObject(mSemaphore, INFINITE);
  219. }
  220. bool EA::Thread::Futex::WaitFSemaphore(const ThreadTime& timeoutAbsolute)
  221. {
  222. int64_t timeoutRelativeMS = (int64_t)(timeoutAbsolute - GetThreadTime());
  223. if(timeoutRelativeMS < 1)
  224. timeoutRelativeMS = 1;
  225. return WaitForSingleObject(mSemaphore, (DWORD)timeoutRelativeMS) == WAIT_OBJECT_0;
  226. }
  227. #endif
  228. namespace EA
  229. {
  230. namespace Thread
  231. {
  232. extern Allocator* gpAllocator;
  233. }
  234. }
  235. EA::Thread::Futex* EA::Thread::FutexFactory::CreateFutex()
  236. {
  237. if(gpAllocator)
  238. return new(gpAllocator->Alloc(sizeof(EA::Thread::Futex))) EA::Thread::Futex;
  239. else
  240. return new EA::Thread::Futex;
  241. }
  242. void EA::Thread::FutexFactory::DestroyFutex(EA::Thread::Futex* pFutex)
  243. {
  244. if(gpAllocator)
  245. {
  246. pFutex->~Futex();
  247. gpAllocator->Free(pFutex);
  248. }
  249. else
  250. delete pFutex;
  251. }
  252. size_t EA::Thread::FutexFactory::GetFutexSize()
  253. {
  254. return sizeof(EA::Thread::Futex);
  255. }
  256. EA::Thread::Futex* EA::Thread::FutexFactory::ConstructFutex(void* pMemory)
  257. {
  258. return new(pMemory) EA::Thread::Futex;
  259. }
  260. void EA::Thread::FutexFactory::DestructFutex(EA::Thread::Futex* pFutex)
  261. {
  262. pFutex->~Futex();
  263. }