michael@0: #ifndef mozilla_StaticMutex_h michael@0: #define mozilla_StaticMutex_h michael@0: michael@0: #include "mozilla/Atomics.h" michael@0: #include "mozilla/Mutex.h" michael@0: michael@0: namespace mozilla { michael@0: michael@0: /** michael@0: * StaticMutex is a Mutex that can (and in fact, must) be used as a michael@0: * global/static variable. michael@0: * michael@0: * The main reason to use StaticMutex as opposed to michael@0: * StaticAutoPtr is that we instantiate the StaticMutex in a michael@0: * thread-safe manner the first time it's used. michael@0: * michael@0: * The same caveats that apply to StaticAutoPtr apply to StaticMutex. In michael@0: * particular, do not use StaticMutex as a stack variable or a class instance michael@0: * variable, because this class relies on the fact that global variablies are michael@0: * initialized to 0 in order to initialize mMutex. It is only safe to use michael@0: * StaticMutex as a global or static variable. michael@0: */ michael@0: class StaticMutex michael@0: { michael@0: public: michael@0: // In debug builds, check that mMutex is initialized for us as we expect by michael@0: // the compiler. In non-debug builds, don't declare a constructor so that michael@0: // the compiler can see that the constructor is trivial. michael@0: #ifdef DEBUG michael@0: StaticMutex() michael@0: { michael@0: MOZ_ASSERT(!mMutex); michael@0: } michael@0: #endif michael@0: michael@0: void Lock() michael@0: { michael@0: Mutex()->Lock(); michael@0: } michael@0: michael@0: void Unlock() michael@0: { michael@0: Mutex()->Unlock(); michael@0: } michael@0: michael@0: void AssertCurrentThreadOwns() michael@0: { michael@0: #ifdef DEBUG michael@0: Mutex()->AssertCurrentThreadOwns(); michael@0: #endif michael@0: } michael@0: michael@0: private: michael@0: OffTheBooksMutex* Mutex() michael@0: { michael@0: if (mMutex) { michael@0: return mMutex; michael@0: } michael@0: michael@0: OffTheBooksMutex* mutex = new OffTheBooksMutex("StaticMutex"); michael@0: if (!mMutex.compareExchange(nullptr, mutex)) { michael@0: delete mutex; michael@0: } michael@0: michael@0: return mMutex; michael@0: } michael@0: michael@0: Atomic mMutex; michael@0: michael@0: michael@0: // Disallow copy constructor, but only in debug mode. We only define michael@0: // a default constructor in debug mode (see above); if we declared michael@0: // this constructor always, the compiler wouldn't generate a trivial michael@0: // default constructor for us in non-debug mode. michael@0: #ifdef DEBUG michael@0: StaticMutex(StaticMutex &other); michael@0: #endif michael@0: michael@0: // Disallow these operators. michael@0: StaticMutex& operator=(StaticMutex* rhs); michael@0: static void* operator new(size_t) CPP_THROW_NEW; michael@0: static void operator delete(void*); michael@0: }; michael@0: michael@0: typedef BaseAutoLock StaticMutexAutoLock; michael@0: typedef BaseAutoUnlock StaticMutexAutoUnlock; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: #endif