Mutex.h 4.1 KB

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