Mutex.h 4.3 KB

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