Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/jolt_physics/Jolt/Physics/PhysicsLock.h
9912 views
1
// Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
2
// SPDX-FileCopyrightText: 2021 Jorrit Rouwe
3
// SPDX-License-Identifier: MIT
4
5
#pragma once
6
7
#include <Jolt/Core/Mutex.h>
8
9
JPH_NAMESPACE_BEGIN
10
11
#ifdef JPH_ENABLE_ASSERTS
12
13
/// 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
14
enum class EPhysicsLockTypes
15
{
16
BroadPhaseQuery = 1 << 0,
17
PerBody = 1 << 1,
18
BodiesList = 1 << 2,
19
BroadPhaseUpdate = 1 << 3,
20
ConstraintsList = 1 << 4,
21
ActiveBodiesList = 1 << 5,
22
};
23
24
/// A token that indicates the context of a lock (we use 1 per physics system and we use the body manager pointer because it's convenient)
25
class BodyManager;
26
using PhysicsLockContext = const BodyManager *;
27
28
#endif // !JPH_ENABLE_ASSERTS
29
30
/// Helpers to safely lock the different mutexes that are part of the physics system while preventing deadlock
31
/// Class that keeps track per thread which lock are taken and if the order of locking is correct
32
class JPH_EXPORT PhysicsLock
33
{
34
public:
35
#ifdef JPH_ENABLE_ASSERTS
36
/// Call before taking the lock
37
static inline void sCheckLock(PhysicsLockContext inContext, EPhysicsLockTypes inType)
38
{
39
uint32 &mutexes = sGetLockedMutexes(inContext);
40
JPH_ASSERT(uint32(inType) > mutexes, "A lock of same or higher priority was already taken, this can create a deadlock!");
41
mutexes = mutexes | uint32(inType);
42
}
43
44
/// Call after releasing the lock
45
static inline void sCheckUnlock(PhysicsLockContext inContext, EPhysicsLockTypes inType)
46
{
47
uint32 &mutexes = sGetLockedMutexes(inContext);
48
JPH_ASSERT((mutexes & uint32(inType)) != 0, "Mutex was not locked!");
49
mutexes = mutexes & ~uint32(inType);
50
}
51
#endif // !JPH_ENABLE_ASSERTS
52
53
template <class LockType>
54
static inline void sLock(LockType &inMutex JPH_IF_ENABLE_ASSERTS(, PhysicsLockContext inContext, EPhysicsLockTypes inType))
55
{
56
JPH_IF_ENABLE_ASSERTS(sCheckLock(inContext, inType);)
57
inMutex.lock();
58
}
59
60
template <class LockType>
61
static inline void sUnlock(LockType &inMutex JPH_IF_ENABLE_ASSERTS(, PhysicsLockContext inContext, EPhysicsLockTypes inType))
62
{
63
JPH_IF_ENABLE_ASSERTS(sCheckUnlock(inContext, inType);)
64
inMutex.unlock();
65
}
66
67
template <class LockType>
68
static inline void sLockShared(LockType &inMutex JPH_IF_ENABLE_ASSERTS(, PhysicsLockContext inContext, EPhysicsLockTypes inType))
69
{
70
JPH_IF_ENABLE_ASSERTS(sCheckLock(inContext, inType);)
71
inMutex.lock_shared();
72
}
73
74
template <class LockType>
75
static inline void sUnlockShared(LockType &inMutex JPH_IF_ENABLE_ASSERTS(, PhysicsLockContext inContext, EPhysicsLockTypes inType))
76
{
77
JPH_IF_ENABLE_ASSERTS(sCheckUnlock(inContext, inType);)
78
inMutex.unlock_shared();
79
}
80
81
#ifdef JPH_ENABLE_ASSERTS
82
private:
83
struct LockData
84
{
85
uint32 mLockedMutexes = 0;
86
PhysicsLockContext mContext = nullptr;
87
};
88
89
// Helper function to find the locked mutexes for a particular context
90
static uint32 & sGetLockedMutexes(PhysicsLockContext inContext)
91
{
92
static thread_local LockData sLocks[4];
93
94
// If we find a matching context we can use it
95
for (LockData &l : sLocks)
96
if (l.mContext == inContext)
97
return l.mLockedMutexes;
98
99
// Otherwise we look for an entry that is not in use
100
for (LockData &l : sLocks)
101
if (l.mLockedMutexes == 0)
102
{
103
l.mContext = inContext;
104
return l.mLockedMutexes;
105
}
106
107
JPH_ASSERT(false, "Too many physics systems locked at the same time!");
108
return sLocks[0].mLockedMutexes;
109
}
110
#endif // !JPH_ENABLE_ASSERTS
111
};
112
113
/// Helper class that is similar to std::unique_lock
114
template <class LockType>
115
class UniqueLock : public NonCopyable
116
{
117
public:
118
explicit UniqueLock(LockType &inLock JPH_IF_ENABLE_ASSERTS(, PhysicsLockContext inContext, EPhysicsLockTypes inType)) :
119
mLock(inLock)
120
#ifdef JPH_ENABLE_ASSERTS
121
, mContext(inContext),
122
mType(inType)
123
#endif // JPH_ENABLE_ASSERTS
124
{
125
PhysicsLock::sLock(mLock JPH_IF_ENABLE_ASSERTS(, mContext, mType));
126
}
127
128
~UniqueLock()
129
{
130
PhysicsLock::sUnlock(mLock JPH_IF_ENABLE_ASSERTS(, mContext, mType));
131
}
132
133
private:
134
LockType & mLock;
135
#ifdef JPH_ENABLE_ASSERTS
136
PhysicsLockContext mContext;
137
EPhysicsLockTypes mType;
138
#endif // JPH_ENABLE_ASSERTS
139
};
140
141
/// Helper class that is similar to std::shared_lock
142
template <class LockType>
143
class SharedLock : public NonCopyable
144
{
145
public:
146
explicit SharedLock(LockType &inLock JPH_IF_ENABLE_ASSERTS(, PhysicsLockContext inContext, EPhysicsLockTypes inType)) :
147
mLock(inLock)
148
#ifdef JPH_ENABLE_ASSERTS
149
, mContext(inContext)
150
, mType(inType)
151
#endif // JPH_ENABLE_ASSERTS
152
{
153
PhysicsLock::sLockShared(mLock JPH_IF_ENABLE_ASSERTS(, mContext, mType));
154
}
155
156
~SharedLock()
157
{
158
PhysicsLock::sUnlockShared(mLock JPH_IF_ENABLE_ASSERTS(, mContext, mType));
159
}
160
161
private:
162
LockType & mLock;
163
#ifdef JPH_ENABLE_ASSERTS
164
PhysicsLockContext mContext;
165
EPhysicsLockTypes mType;
166
#endif // JPH_ENABLE_ASSERTS
167
};
168
169
JPH_NAMESPACE_END
170
171