@@ -71,13 +71,17 @@ void static inline DeleteLock(void* cs) {}
7171#define AssertLockNotHeld (cs ) AssertLockNotHeldInternal(#cs, __FILE__, __LINE__, &cs)
7272
7373/* *
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.
7676 */
7777template <typename PARENT>
7878class LOCKABLE AnnotatedMixin : public PARENT
7979{
8080public:
81+ ~AnnotatedMixin () {
82+ DeleteLock ((void *)this );
83+ }
84+
8185 void lock () EXCLUSIVE_LOCK_FUNCTION()
8286 {
8387 PARENT::lock ();
@@ -92,19 +96,15 @@ class LOCKABLE AnnotatedMixin : public PARENT
9296 {
9397 return PARENT::try_lock ();
9498 }
99+
100+ using UniqueLock = std::unique_lock<PARENT>;
95101};
96102
97103/* *
98104 * Wrapped mutex: supports recursive locking, but no waiting
99105 * TODO: We should move away from using the recursive lock by default.
100106 */
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;
108108
109109/* * Wrapped mutex: supports waiting but not recursive locking */
110110typedef AnnotatedMixin<std::mutex> CWaitableCriticalSection;
@@ -119,48 +119,47 @@ typedef std::unique_lock<std::mutex> WaitableLock;
119119void PrintLockContention (const char * pszName, const char * pszFile, int nLine);
120120#endif
121121
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
124125{
125126private:
126- std::unique_lock<CCriticalSection> lock;
127-
128127 void Enter (const char * pszName, const char * pszFile, int nLine)
129128 {
130- EnterCritical (pszName, pszFile, nLine, (void *)(lock. mutex ()));
129+ EnterCritical (pszName, pszFile, nLine, (void *)(Base:: mutex ()));
131130#ifdef DEBUG_LOCKCONTENTION
132- if (!lock. try_lock ()) {
131+ if (!Base:: try_lock ()) {
133132 PrintLockContention (pszName, pszFile, nLine);
134133#endif
135- lock. lock ();
134+ Base:: lock ();
136135#ifdef DEBUG_LOCKCONTENTION
137136 }
138137#endif
139138 }
140139
141140 bool TryEnter (const char * pszName, const char * pszFile, int nLine)
142141 {
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 ())
146145 LeaveCritical ();
147- return lock. owns_lock ();
146+ return Base:: owns_lock ();
148147 }
149148
150149public:
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)
152151 {
153152 if (fTry )
154153 TryEnter (pszName, pszFile, nLine);
155154 else
156155 Enter (pszName, pszFile, nLine);
157156 }
158157
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)
160159 {
161160 if (!pmutexIn) return ;
162161
163- lock = std::unique_lock<CCriticalSection> (*pmutexIn, std::defer_lock);
162+ * static_cast <Base*>( this ) = Base (*pmutexIn, std::defer_lock);
164163 if (fTry )
165164 TryEnter (pszName, pszFile, nLine);
166165 else
@@ -169,22 +168,28 @@ class SCOPED_LOCKABLE CCriticalBlock
169168
170169 ~CCriticalBlock () UNLOCK_FUNCTION ()
171170 {
172- if (lock. owns_lock ())
171+ if (Base:: owns_lock ())
173172 LeaveCritical ();
174173 }
175174
176175 operator bool ()
177176 {
178- return lock. owns_lock ();
177+ return Base:: owns_lock ();
179178 }
180179};
181180
181+ template <typename MutexArg>
182+ using DebugLock = CCriticalBlock<typename std::remove_reference<typename std::remove_pointer<MutexArg>::type>::type>;
183+
182184#define PASTE (x, y ) x ## y
183185#define PASTE2 (x, y ) PASTE(x, y)
184186
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__)
188193
189194#define ENTER_CRITICAL_SECTION (cs ) \
190195 { \
0 commit comments