PhysicsLock.h 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
  2. // SPDX-License-Identifier: MIT
  3. #pragma once
  4. #include <Jolt/Core/Mutex.h>
  5. JPH_NAMESPACE_BEGIN
  6. /// This is the list of locks used by the physics engine, they need to be locked in a particular order (from top of the list to bottom of the list) in order to prevent deadlocks
  7. enum class EPhysicsLockTypes
  8. {
  9. BroadPhaseQuery = 1 << 0,
  10. PerBody = 1 << 1,
  11. BodiesList = 1 << 2,
  12. BroadPhaseUpdate = 1 << 3,
  13. ConstraintsList = 1 << 4,
  14. ActiveBodiesList = 1 << 5,
  15. };
  16. /// Helpers to safely lock the different mutexes that are part of the physics system while preventing deadlock
  17. /// Class that keeps track per thread which lock are taken and if the order of locking is correct
  18. class PhysicsLock
  19. {
  20. public:
  21. #ifdef JPH_ENABLE_ASSERTS
  22. /// Call before taking the lock
  23. static inline void sCheckLock(EPhysicsLockTypes inType)
  24. {
  25. JPH_ASSERT((uint32)inType > sLockedMutexes, "A lock of same or higher priority was already taken, this can create a deadlock!");
  26. sLockedMutexes = sLockedMutexes | (uint32)inType;
  27. }
  28. /// Call after releasing the lock
  29. static inline void sCheckUnlock(EPhysicsLockTypes inType)
  30. {
  31. JPH_ASSERT((sLockedMutexes & (uint32)inType) != 0, "Mutex was not locked!");
  32. sLockedMutexes = sLockedMutexes & ~(uint32)inType;
  33. }
  34. #endif // !JPH_ENABLE_ASSERTS
  35. template <class LockType>
  36. static inline void sLock(LockType &inMutex, [[maybe_unused]] EPhysicsLockTypes inType)
  37. {
  38. JPH_IF_ENABLE_ASSERTS(sCheckLock(inType);)
  39. inMutex.lock();
  40. }
  41. template <class LockType>
  42. static inline void sUnlock(LockType &inMutex, [[maybe_unused]] EPhysicsLockTypes inType)
  43. {
  44. JPH_IF_ENABLE_ASSERTS(sCheckUnlock(inType);)
  45. inMutex.unlock();
  46. }
  47. template <class LockType>
  48. static inline void sLockShared(LockType &inMutex, [[maybe_unused]] EPhysicsLockTypes inType)
  49. {
  50. JPH_IF_ENABLE_ASSERTS(sCheckLock(inType);)
  51. inMutex.lock_shared();
  52. }
  53. template <class LockType>
  54. static inline void sUnlockShared(LockType &inMutex, [[maybe_unused]] EPhysicsLockTypes inType)
  55. {
  56. JPH_IF_ENABLE_ASSERTS(sCheckUnlock(inType);)
  57. inMutex.unlock_shared();
  58. }
  59. #ifdef JPH_ENABLE_ASSERTS
  60. private:
  61. static thread_local uint32 sLockedMutexes;
  62. #endif // !JPH_ENABLE_ASSERTS
  63. };
  64. /// Helper class that is similar to std::unique_lock
  65. template <class LockType>
  66. class UniqueLock : public NonCopyable
  67. {
  68. public:
  69. UniqueLock(LockType &inLock, EPhysicsLockTypes inType) : mLock(inLock), mType(inType) { PhysicsLock::sLock(mLock, mType); }
  70. ~UniqueLock() { PhysicsLock::sUnlock(mLock, mType); }
  71. private:
  72. LockType & mLock;
  73. EPhysicsLockTypes mType;
  74. };
  75. /// Helper class that is similar to std::shared_lock
  76. template <class LockType>
  77. class SharedLock : public NonCopyable
  78. {
  79. public:
  80. SharedLock(LockType &inLock, EPhysicsLockTypes inType) : mLock(inLock), mType(inType) { PhysicsLock::sLockShared(mLock, mType); }
  81. ~SharedLock() { PhysicsLock::sUnlockShared(mLock, mType); }
  82. private:
  83. LockType & mLock;
  84. EPhysicsLockTypes mType;
  85. };
  86. JPH_NAMESPACE_END