1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_Mutex_h 8 #define mozilla_Mutex_h 9 10 #include "prlock.h" 11 12 #include "mozilla/BlockingResourceBase.h" 13 #include "mozilla/GuardObjects.h" 14 15 // 16 // Provides: 17 // 18 // - Mutex, a non-recursive mutex 19 // - MutexAutoLock, an RAII class for ensuring that Mutexes are properly 20 // locked and unlocked 21 // - MutexAutoUnlock, complementary sibling to MutexAutoLock 22 // 23 // - OffTheBooksMutex, a non-recursive mutex that doesn't do leak checking 24 // - OffTheBooksMutexAuto{Lock,Unlock} - Like MutexAuto{Lock,Unlock}, but for 25 // an OffTheBooksMutex. 26 // 27 // Using MutexAutoLock/MutexAutoUnlock etc. is MUCH preferred to making bare 28 // calls to Lock and Unlock. 29 // 30 namespace mozilla { 31 32 /** 33 * OffTheBooksMutex is identical to Mutex, except that OffTheBooksMutex doesn't 34 * include leak checking. Sometimes you want to intentionally "leak" a mutex 35 * until shutdown; in these cases, OffTheBooksMutex is for you. 36 */ 37 class OffTheBooksMutex : BlockingResourceBase 38 { 39 public: 40 /** 41 * @param aName A name which can reference this lock 42 * @returns If failure, nullptr 43 * If success, a valid Mutex* which must be destroyed 44 * by Mutex::DestroyMutex() 45 **/ OffTheBooksMutex(const char * aName)46 explicit OffTheBooksMutex(const char* aName) 47 : BlockingResourceBase(aName, eMutex) 48 { 49 mLock = PR_NewLock(); 50 if (!mLock) { 51 NS_RUNTIMEABORT("Can't allocate mozilla::Mutex"); 52 } 53 } 54 ~OffTheBooksMutex()55 ~OffTheBooksMutex() 56 { 57 NS_ASSERTION(mLock, 58 "improperly constructed Lock or double free"); 59 // NSPR does consistency checks for us 60 PR_DestroyLock(mLock); 61 mLock = 0; 62 } 63 64 #ifndef DEBUG 65 /** 66 * Lock 67 * @see prlock.h 68 **/ Lock()69 void Lock() { PR_Lock(mLock); } 70 71 /** 72 * Unlock 73 * @see prlock.h 74 **/ Unlock()75 void Unlock() { PR_Unlock(mLock); } 76 77 /** 78 * AssertCurrentThreadOwns 79 * @see prlock.h 80 **/ AssertCurrentThreadOwns()81 void AssertCurrentThreadOwns() const {} 82 83 /** 84 * AssertNotCurrentThreadOwns 85 * @see prlock.h 86 **/ AssertNotCurrentThreadOwns()87 void AssertNotCurrentThreadOwns() const {} 88 89 #else 90 void Lock(); 91 void Unlock(); 92 AssertCurrentThreadOwns()93 void AssertCurrentThreadOwns() const 94 { 95 PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(mLock); 96 } 97 AssertNotCurrentThreadOwns()98 void AssertNotCurrentThreadOwns() const 99 { 100 // FIXME bug 476536 101 } 102 103 #endif // ifndef DEBUG 104 105 private: 106 OffTheBooksMutex(); 107 OffTheBooksMutex(const OffTheBooksMutex&); 108 OffTheBooksMutex& operator=(const OffTheBooksMutex&); 109 110 PRLock* mLock; 111 112 friend class CondVar; 113 114 // MozPromise needs to access mLock for debugging purpose. 115 template<typename, typename, bool> 116 friend class MozPromise; 117 }; 118 119 /** 120 * Mutex 121 * When possible, use MutexAutoLock/MutexAutoUnlock to lock/unlock this 122 * mutex within a scope, instead of calling Lock/Unlock directly. 123 */ 124 class Mutex : public OffTheBooksMutex 125 { 126 public: Mutex(const char * aName)127 explicit Mutex(const char* aName) 128 : OffTheBooksMutex(aName) 129 { 130 MOZ_COUNT_CTOR(Mutex); 131 } 132 ~Mutex()133 ~Mutex() 134 { 135 MOZ_COUNT_DTOR(Mutex); 136 } 137 138 private: 139 Mutex(); 140 Mutex(const Mutex&); 141 Mutex& operator=(const Mutex&); 142 }; 143 144 /** 145 * MutexAutoLock 146 * Acquires the Mutex when it enters scope, and releases it when it leaves 147 * scope. 148 * 149 * MUCH PREFERRED to bare calls to Mutex.Lock and Unlock. 150 */ 151 template<typename T> 152 class MOZ_RAII BaseAutoLock 153 { 154 public: 155 /** 156 * Constructor 157 * The constructor aquires the given lock. The destructor 158 * releases the lock. 159 * 160 * @param aLock A valid mozilla::Mutex* returned by 161 * mozilla::Mutex::NewMutex. 162 **/ BaseAutoLock(T & aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)163 explicit BaseAutoLock(T& aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM) 164 : mLock(&aLock) 165 { 166 MOZ_GUARD_OBJECT_NOTIFIER_INIT; 167 NS_ASSERTION(mLock, "null mutex"); 168 mLock->Lock(); 169 } 170 ~BaseAutoLock(void)171 ~BaseAutoLock(void) 172 { 173 mLock->Unlock(); 174 } 175 176 private: 177 BaseAutoLock(); 178 BaseAutoLock(BaseAutoLock&); 179 BaseAutoLock& operator=(BaseAutoLock&); 180 static void* operator new(size_t) CPP_THROW_NEW; 181 182 T* mLock; 183 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER 184 }; 185 186 typedef BaseAutoLock<Mutex> MutexAutoLock; 187 typedef BaseAutoLock<OffTheBooksMutex> OffTheBooksMutexAutoLock; 188 189 /** 190 * MutexAutoUnlock 191 * Releases the Mutex when it enters scope, and re-acquires it when it leaves 192 * scope. 193 * 194 * MUCH PREFERRED to bare calls to Mutex.Unlock and Lock. 195 */ 196 template<typename T> 197 class MOZ_RAII BaseAutoUnlock 198 { 199 public: BaseAutoUnlock(T & aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)200 explicit BaseAutoUnlock(T& aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM) 201 : mLock(&aLock) 202 { 203 MOZ_GUARD_OBJECT_NOTIFIER_INIT; 204 NS_ASSERTION(mLock, "null lock"); 205 mLock->Unlock(); 206 } 207 ~BaseAutoUnlock()208 ~BaseAutoUnlock() 209 { 210 mLock->Lock(); 211 } 212 213 private: 214 BaseAutoUnlock(); 215 BaseAutoUnlock(BaseAutoUnlock&); 216 BaseAutoUnlock& operator=(BaseAutoUnlock&); 217 static void* operator new(size_t) CPP_THROW_NEW; 218 219 T* mLock; 220 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER 221 }; 222 223 typedef BaseAutoUnlock<Mutex> MutexAutoUnlock; 224 typedef BaseAutoUnlock<OffTheBooksMutex> OffTheBooksMutexAutoUnlock; 225 226 } // namespace mozilla 227 228 229 #endif // ifndef mozilla_Mutex_h 230