michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: sw=4 ts=4 et : michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef mozilla_Mutex_h michael@0: #define mozilla_Mutex_h michael@0: michael@0: #include "prlock.h" michael@0: michael@0: #include "mozilla/BlockingResourceBase.h" michael@0: #include "mozilla/GuardObjects.h" michael@0: michael@0: // michael@0: // Provides: michael@0: // michael@0: // - Mutex, a non-recursive mutex michael@0: // - MutexAutoLock, an RAII class for ensuring that Mutexes are properly michael@0: // locked and unlocked michael@0: // - MutexAutoUnlock, complementary sibling to MutexAutoLock michael@0: // michael@0: // - OffTheBooksMutex, a non-recursive mutex that doesn't do leak checking michael@0: // - OffTheBooksMutexAuto{Lock,Unlock} - Like MutexAuto{Lock,Unlock}, but for michael@0: // an OffTheBooksMutex. michael@0: // michael@0: // Using MutexAutoLock/MutexAutoUnlock etc. is MUCH preferred to making bare michael@0: // calls to Lock and Unlock. michael@0: // michael@0: namespace mozilla { michael@0: michael@0: /** michael@0: * OffTheBooksMutex is identical to Mutex, except that OffTheBooksMutex doesn't michael@0: * include leak checking. Sometimes you want to intentionally "leak" a mutex michael@0: * until shutdown; in these cases, OffTheBooksMutex is for you. michael@0: */ michael@0: class NS_COM_GLUE OffTheBooksMutex : BlockingResourceBase michael@0: { michael@0: public: michael@0: /** michael@0: * @param name A name which can reference this lock michael@0: * @returns If failure, nullptr michael@0: * If success, a valid Mutex* which must be destroyed michael@0: * by Mutex::DestroyMutex() michael@0: **/ michael@0: OffTheBooksMutex(const char* name) : michael@0: BlockingResourceBase(name, eMutex) michael@0: { michael@0: mLock = PR_NewLock(); michael@0: if (!mLock) michael@0: NS_RUNTIMEABORT("Can't allocate mozilla::Mutex"); michael@0: } michael@0: michael@0: ~OffTheBooksMutex() michael@0: { michael@0: NS_ASSERTION(mLock, michael@0: "improperly constructed Lock or double free"); michael@0: // NSPR does consistency checks for us michael@0: PR_DestroyLock(mLock); michael@0: mLock = 0; michael@0: } michael@0: michael@0: #ifndef DEBUG michael@0: /** michael@0: * Lock michael@0: * @see prlock.h michael@0: **/ michael@0: void Lock() michael@0: { michael@0: PR_Lock(mLock); michael@0: } michael@0: michael@0: /** michael@0: * Unlock michael@0: * @see prlock.h michael@0: **/ michael@0: void Unlock() michael@0: { michael@0: PR_Unlock(mLock); michael@0: } michael@0: michael@0: /** michael@0: * AssertCurrentThreadOwns michael@0: * @see prlock.h michael@0: **/ michael@0: void AssertCurrentThreadOwns () const michael@0: { michael@0: } michael@0: michael@0: /** michael@0: * AssertNotCurrentThreadOwns michael@0: * @see prlock.h michael@0: **/ michael@0: void AssertNotCurrentThreadOwns () const michael@0: { michael@0: } michael@0: michael@0: #else michael@0: void Lock(); michael@0: void Unlock(); michael@0: michael@0: void AssertCurrentThreadOwns () const michael@0: { michael@0: PR_ASSERT_CURRENT_THREAD_OWNS_LOCK(mLock); michael@0: } michael@0: michael@0: void AssertNotCurrentThreadOwns () const michael@0: { michael@0: // FIXME bug 476536 michael@0: } michael@0: michael@0: #endif // ifndef DEBUG michael@0: michael@0: private: michael@0: OffTheBooksMutex(); michael@0: OffTheBooksMutex(const OffTheBooksMutex&); michael@0: OffTheBooksMutex& operator=(const OffTheBooksMutex&); michael@0: michael@0: PRLock* mLock; michael@0: michael@0: friend class CondVar; michael@0: }; michael@0: michael@0: /** michael@0: * Mutex michael@0: * When possible, use MutexAutoLock/MutexAutoUnlock to lock/unlock this michael@0: * mutex within a scope, instead of calling Lock/Unlock directly. michael@0: */ michael@0: class NS_COM_GLUE Mutex : public OffTheBooksMutex michael@0: { michael@0: public: michael@0: Mutex(const char* name) michael@0: : OffTheBooksMutex(name) michael@0: { michael@0: MOZ_COUNT_CTOR(Mutex); michael@0: } michael@0: michael@0: ~Mutex() michael@0: { michael@0: MOZ_COUNT_DTOR(Mutex); michael@0: } michael@0: michael@0: private: michael@0: Mutex(); michael@0: Mutex(const Mutex&); michael@0: Mutex& operator=(const Mutex&); michael@0: }; michael@0: michael@0: /** michael@0: * MutexAutoLock michael@0: * Acquires the Mutex when it enters scope, and releases it when it leaves michael@0: * scope. michael@0: * michael@0: * MUCH PREFERRED to bare calls to Mutex.Lock and Unlock. michael@0: */ michael@0: template michael@0: class NS_COM_GLUE MOZ_STACK_CLASS BaseAutoLock michael@0: { michael@0: public: michael@0: /** michael@0: * Constructor michael@0: * The constructor aquires the given lock. The destructor michael@0: * releases the lock. michael@0: * michael@0: * @param aLock A valid mozilla::Mutex* returned by michael@0: * mozilla::Mutex::NewMutex. michael@0: **/ michael@0: BaseAutoLock(T& aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : michael@0: mLock(&aLock) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: NS_ASSERTION(mLock, "null mutex"); michael@0: mLock->Lock(); michael@0: } michael@0: michael@0: ~BaseAutoLock(void) { michael@0: mLock->Unlock(); michael@0: } michael@0: michael@0: private: michael@0: BaseAutoLock(); michael@0: BaseAutoLock(BaseAutoLock&); michael@0: BaseAutoLock& operator=(BaseAutoLock&); michael@0: static void* operator new(size_t) CPP_THROW_NEW; michael@0: static void operator delete(void*); michael@0: michael@0: T* mLock; michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: typedef BaseAutoLock MutexAutoLock; michael@0: typedef BaseAutoLock OffTheBooksMutexAutoLock; michael@0: michael@0: /** michael@0: * MutexAutoUnlock michael@0: * Releases the Mutex when it enters scope, and re-acquires it when it leaves michael@0: * scope. michael@0: * michael@0: * MUCH PREFERRED to bare calls to Mutex.Unlock and Lock. michael@0: */ michael@0: template michael@0: class NS_COM_GLUE MOZ_STACK_CLASS BaseAutoUnlock michael@0: { michael@0: public: michael@0: BaseAutoUnlock(T& aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM) : michael@0: mLock(&aLock) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: NS_ASSERTION(mLock, "null lock"); michael@0: mLock->Unlock(); michael@0: } michael@0: michael@0: ~BaseAutoUnlock() michael@0: { michael@0: mLock->Lock(); michael@0: } michael@0: michael@0: private: michael@0: BaseAutoUnlock(); michael@0: BaseAutoUnlock(BaseAutoUnlock&); michael@0: BaseAutoUnlock& operator =(BaseAutoUnlock&); michael@0: static void* operator new(size_t) CPP_THROW_NEW; michael@0: static void operator delete(void*); michael@0: michael@0: T* mLock; michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: }; michael@0: michael@0: typedef BaseAutoUnlock MutexAutoUnlock; michael@0: typedef BaseAutoUnlock OffTheBooksMutexAutoUnlock; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: michael@0: #endif // ifndef mozilla_Mutex_h