@@ -71,13 +71,17 @@ void static inline DeleteLock(void* cs) {}
71
71
#define AssertLockNotHeld (cs ) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
72
72
73
73
/* *
74
- * Template mixin that adds -Wthread-safety locking
75
- * annotations to a subset of the mutex API.
74
+ * Template mixin that adds -Wthread-safety locking annotations and lock order
75
+ * checking to a subset of the mutex API.
76
76
*/
77
77
template <typename PARENT>
78
78
class LOCKABLE AnnotatedMixin : public PARENT
79
79
{
80
80
public:
81
+ ~AnnotatedMixin () {
82
+ DeleteLock ((void *)this );
83
+ }
84
+
81
85
void lock () EXCLUSIVE_LOCK_FUNCTION()
82
86
{
83
87
PARENT::lock ();
@@ -92,19 +96,15 @@ class LOCKABLE AnnotatedMixin : public PARENT
92
96
{
93
97
return PARENT::try_lock ();
94
98
}
99
+
100
+ using UniqueLock = std::unique_lock<PARENT>;
95
101
};
96
102
97
103
/* *
98
104
* Wrapped mutex: supports recursive locking, but no waiting
99
105
* TODO: We should move away from using the recursive lock by default.
100
106
*/
101
- class CCriticalSection : public AnnotatedMixin <std::recursive_mutex>
102
- {
103
- public:
104
- ~CCriticalSection () {
105
- DeleteLock ((void *)this );
106
- }
107
- };
107
+ typedef AnnotatedMixin<std::recursive_mutex> CCriticalSection;
108
108
109
109
/* * Wrapped mutex: supports waiting but not recursive locking */
110
110
typedef AnnotatedMixin<std::mutex> CWaitableCriticalSection;
@@ -119,48 +119,47 @@ typedef std::unique_lock<std::mutex> WaitableLock;
119
119
void PrintLockContention (const char * pszName, const char * pszFile, int nLine);
120
120
#endif
121
121
122
- /* * Wrapper around std::unique_lock<CCriticalSection> */
123
- class SCOPED_LOCKABLE CCriticalBlock
122
+ /* * Wrapper around std::unique_lock style lock for Mutex. */
123
+ template <typename Mutex, typename Base = typename Mutex::UniqueLock>
124
+ class SCOPED_LOCKABLE CCriticalBlock : public Base
124
125
{
125
126
private:
126
- std::unique_lock<CCriticalSection> lock;
127
-
128
127
void Enter (const char * pszName, const char * pszFile, int nLine)
129
128
{
130
- EnterCritical (pszName, pszFile, nLine, (void *)(lock. mutex ()));
129
+ EnterCritical (pszName, pszFile, nLine, (void *)(Base:: mutex ()));
131
130
#ifdef DEBUG_LOCKCONTENTION
132
- if (!lock. try_lock ()) {
131
+ if (!Base:: try_lock ()) {
133
132
PrintLockContention (pszName, pszFile, nLine);
134
133
#endif
135
- lock. lock ();
134
+ Base:: lock ();
136
135
#ifdef DEBUG_LOCKCONTENTION
137
136
}
138
137
#endif
139
138
}
140
139
141
140
bool TryEnter (const char * pszName, const char * pszFile, int nLine)
142
141
{
143
- EnterCritical (pszName, pszFile, nLine, (void *)(lock. mutex ()), true );
144
- lock. try_lock ();
145
- if (!lock. owns_lock ())
142
+ EnterCritical (pszName, pszFile, nLine, (void *)(Base:: mutex ()), true );
143
+ Base:: try_lock ();
144
+ if (!Base:: owns_lock ())
146
145
LeaveCritical ();
147
- return lock. owns_lock ();
146
+ return Base:: owns_lock ();
148
147
}
149
148
150
149
public:
151
- CCriticalBlock (CCriticalSection & mutexIn, const char * pszName, const char * pszFile, int nLine, bool fTry = false ) EXCLUSIVE_LOCK_FUNCTION (mutexIn) : lock (mutexIn, std::defer_lock)
150
+ CCriticalBlock (Mutex & mutexIn, const char * pszName, const char * pszFile, int nLine, bool fTry = false ) EXCLUSIVE_LOCK_FUNCTION (mutexIn) : Base (mutexIn, std::defer_lock)
152
151
{
153
152
if (fTry )
154
153
TryEnter (pszName, pszFile, nLine);
155
154
else
156
155
Enter (pszName, pszFile, nLine);
157
156
}
158
157
159
- CCriticalBlock (CCriticalSection * pmutexIn, const char * pszName, const char * pszFile, int nLine, bool fTry = false ) EXCLUSIVE_LOCK_FUNCTION (pmutexIn)
158
+ CCriticalBlock (Mutex * pmutexIn, const char * pszName, const char * pszFile, int nLine, bool fTry = false ) EXCLUSIVE_LOCK_FUNCTION (pmutexIn)
160
159
{
161
160
if (!pmutexIn) return ;
162
161
163
- lock = std::unique_lock<CCriticalSection> (*pmutexIn, std::defer_lock);
162
+ * static_cast <Base*>( this ) = Base (*pmutexIn, std::defer_lock);
164
163
if (fTry )
165
164
TryEnter (pszName, pszFile, nLine);
166
165
else
@@ -169,22 +168,28 @@ class SCOPED_LOCKABLE CCriticalBlock
169
168
170
169
~CCriticalBlock () UNLOCK_FUNCTION ()
171
170
{
172
- if (lock. owns_lock ())
171
+ if (Base:: owns_lock ())
173
172
LeaveCritical ();
174
173
}
175
174
176
175
operator bool ()
177
176
{
178
- return lock. owns_lock ();
177
+ return Base:: owns_lock ();
179
178
}
180
179
};
181
180
181
+ template <typename MutexArg>
182
+ using DebugLock = CCriticalBlock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;
183
+
182
184
#define PASTE (x, y ) x ## y
183
185
#define PASTE2 (x, y ) PASTE(x, y)
184
186
185
- #define LOCK (cs ) CCriticalBlock PASTE2 (criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
186
- #define LOCK2 (cs1, cs2 ) CCriticalBlock criticalblock1 (cs1, #cs1, __FILE__, __LINE__), criticalblock2(cs2, #cs2, __FILE__, __LINE__)
187
- #define TRY_LOCK (cs, name ) CCriticalBlock name (cs, #cs, __FILE__, __LINE__, true )
187
+ #define LOCK (cs ) DebugLock<decltype (cs)> PASTE2 (criticalblock, __COUNTER__)(cs, #cs, __FILE__, __LINE__)
188
+ #define LOCK2 (cs1, cs2 ) \
189
+ DebugLock<decltype (cs1)> criticalblock1 (cs1, #cs1, __FILE__, __LINE__); \
190
+ DebugLock<decltype (cs2)> criticalblock2 (cs2, #cs2, __FILE__, __LINE__);
191
+ #define TRY_LOCK (cs, name ) DebugLock<decltype (cs)> name (cs, #cs, __FILE__, __LINE__, true )
192
+ #define WAIT_LOCK (cs, name ) DebugLock<decltype (cs)> name (cs, #cs, __FILE__, __LINE__)
188
193
189
194
#define ENTER_CRITICAL_SECTION (cs ) \
190
195
{ \
0 commit comments