Mutex.h 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <mutex>
  5. #include <shared_mutex>
  6. #include <thread>
  7. #include <Core/Profiler.h>
  8. #include <Core/NonCopyable.h>
  9. namespace JPH {
  10. #ifdef JPH_PLATFORM_BLUE
  11. // On Platform Blue the mutex class is not very fast so we implement it using the official APIs
  12. class MutexBase : public NonCopyable
  13. {
  14. public:
  15. MutexBase()
  16. {
  17. JPH_PLATFORM_BLUE_MUTEX_INIT(mMutex);
  18. }
  19. ~MutexBase()
  20. {
  21. JPH_PLATFORM_BLUE_MUTEX_DESTROY(mMutex);
  22. }
  23. inline bool try_lock()
  24. {
  25. return JPH_PLATFORM_BLUE_MUTEX_TRYLOCK(mMutex);
  26. }
  27. inline void lock()
  28. {
  29. JPH_PLATFORM_BLUE_MUTEX_LOCK(mMutex);
  30. }
  31. inline void unlock()
  32. {
  33. JPH_PLATFORM_BLUE_MUTEX_UNLOCK(mMutex);
  34. }
  35. private:
  36. JPH_PLATFORM_BLUE_MUTEX mMutex;
  37. };
  38. // On Platform Blue the shared_mutex class is not very fast so we implement it using the official APIs
  39. class SharedMutexBase : public NonCopyable
  40. {
  41. public:
  42. SharedMutexBase()
  43. {
  44. JPH_PLATFORM_BLUE_RWLOCK_INIT(mRWLock);
  45. }
  46. ~SharedMutexBase()
  47. {
  48. JPH_PLATFORM_BLUE_RWLOCK_DESTROY(mRWLock);
  49. }
  50. inline bool try_lock()
  51. {
  52. return JPH_PLATFORM_BLUE_RWLOCK_TRYWLOCK(mRWLock);
  53. }
  54. inline bool try_lock_shared()
  55. {
  56. return JPH_PLATFORM_BLUE_RWLOCK_TRYRLOCK(mRWLock);
  57. }
  58. inline void lock()
  59. {
  60. JPH_PLATFORM_BLUE_RWLOCK_WLOCK(mRWLock);
  61. }
  62. inline void unlock()
  63. {
  64. JPH_PLATFORM_BLUE_RWLOCK_WUNLOCK(mRWLock);
  65. }
  66. inline void lock_shared()
  67. {
  68. JPH_PLATFORM_BLUE_RWLOCK_RLOCK(mRWLock);
  69. }
  70. inline void unlock_shared()
  71. {
  72. JPH_PLATFORM_BLUE_RWLOCK_RUNLOCK(mRWLock);
  73. }
  74. private:
  75. JPH_PLATFORM_BLUE_RWLOCK mRWLock;
  76. };
  77. #else
  78. // On other platforms just use the STL implementation
  79. using MutexBase = mutex;
  80. using SharedMutexBase = shared_mutex;
  81. #endif // JPH_PLATFORM_BLUE
  82. #if defined(JPH_ENABLE_ASSERTS) || defined(JPH_PROFILE_ENABLED) || defined(JPH_EXTERNAL_PROFILE)
  83. /// Very simple wrapper around MutexBase which tracks lock contention in the profiler
  84. /// and asserts that locks/unlocks take place on the same thread
  85. class Mutex : public MutexBase
  86. {
  87. public:
  88. inline bool try_lock()
  89. {
  90. JPH_ASSERT(mLockedThreadID != this_thread::get_id());
  91. if (MutexBase::try_lock())
  92. {
  93. JPH_IF_ENABLE_ASSERTS(mLockedThreadID = this_thread::get_id();)
  94. return true;
  95. }
  96. return false;
  97. }
  98. inline void lock()
  99. {
  100. if (!try_lock())
  101. {
  102. JPH_PROFILE("Lock", 0xff00ffff);
  103. MutexBase::lock();
  104. JPH_IF_ENABLE_ASSERTS(mLockedThreadID = this_thread::get_id();)
  105. }
  106. }
  107. inline void unlock()
  108. {
  109. JPH_ASSERT(mLockedThreadID == this_thread::get_id());
  110. JPH_IF_ENABLE_ASSERTS(mLockedThreadID = thread::id();)
  111. MutexBase::unlock();
  112. }
  113. #ifdef JPH_ENABLE_ASSERTS
  114. inline bool is_locked()
  115. {
  116. return mLockedThreadID != thread::id();
  117. }
  118. #endif // JPH_ENABLE_ASSERTS
  119. private:
  120. JPH_IF_ENABLE_ASSERTS(thread::id mLockedThreadID;)
  121. };
  122. /// Very simple wrapper around SharedMutexBase which tracks lock contention in the profiler
  123. /// and asserts that locks/unlocks take place on the same thread
  124. class SharedMutex : public SharedMutexBase
  125. {
  126. public:
  127. inline bool try_lock()
  128. {
  129. JPH_ASSERT(mLockedThreadID != this_thread::get_id());
  130. if (SharedMutexBase::try_lock())
  131. {
  132. JPH_IF_ENABLE_ASSERTS(mLockedThreadID = this_thread::get_id();)
  133. return true;
  134. }
  135. return false;
  136. }
  137. inline void lock()
  138. {
  139. if (!try_lock())
  140. {
  141. JPH_PROFILE("WLock", 0xff00ffff);
  142. SharedMutexBase::lock();
  143. JPH_IF_ENABLE_ASSERTS(mLockedThreadID = this_thread::get_id();)
  144. }
  145. }
  146. inline void unlock()
  147. {
  148. JPH_ASSERT(mLockedThreadID == this_thread::get_id());
  149. JPH_IF_ENABLE_ASSERTS(mLockedThreadID = thread::id();)
  150. SharedMutexBase::unlock();
  151. }
  152. #ifdef JPH_ENABLE_ASSERTS
  153. inline bool is_locked()
  154. {
  155. return mLockedThreadID != thread::id();
  156. }
  157. #endif // JPH_ENABLE_ASSERTS
  158. inline void lock_shared()
  159. {
  160. if (!try_lock_shared())
  161. {
  162. JPH_PROFILE("RLock", 0xff00ffff);
  163. SharedMutexBase::lock_shared();
  164. }
  165. }
  166. private:
  167. JPH_IF_ENABLE_ASSERTS(thread::id mLockedThreadID;)
  168. };
  169. #else
  170. using Mutex = MutexBase;
  171. using SharedMutex = SharedMutexBase;
  172. #endif
  173. } // JPH