michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- michael@0: * vim: sw=2 ts=2 et lcs=trail\:.,tab\:>~ : 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_storage_SQLiteMutex_h_ michael@0: #define mozilla_storage_SQLiteMutex_h_ michael@0: michael@0: #include "mozilla/BlockingResourceBase.h" michael@0: #include "sqlite3.h" michael@0: michael@0: namespace mozilla { michael@0: namespace storage { michael@0: michael@0: /** michael@0: * Wrapper class for sqlite3_mutexes. To be used whenever we want to use a michael@0: * sqlite3_mutex. michael@0: * michael@0: * @warning Never EVER wrap the same sqlite3_mutex with a different SQLiteMutex. michael@0: * If you do this, you void the deadlock detector's warranty! michael@0: */ michael@0: class SQLiteMutex : private BlockingResourceBase michael@0: { michael@0: public: michael@0: /** michael@0: * Constructs a wrapper for a sqlite3_mutex that has deadlock detecting. michael@0: * michael@0: * @param aName michael@0: * A name which can be used to reference this mutex. michael@0: */ michael@0: SQLiteMutex(const char *aName) michael@0: : BlockingResourceBase(aName, eMutex) michael@0: , mMutex(nullptr) michael@0: { michael@0: } michael@0: michael@0: /** michael@0: * Sets the mutex that we are wrapping. We generally do not have access to michael@0: * our mutex at class construction, so we have to set it once we get access to michael@0: * it. michael@0: * michael@0: * @param aMutex michael@0: * The sqlite3_mutex that we are going to wrap. michael@0: */ michael@0: void initWithMutex(sqlite3_mutex *aMutex) michael@0: { michael@0: NS_ASSERTION(aMutex, "You must pass in a valid mutex!"); michael@0: NS_ASSERTION(!mMutex, "A mutex has already been set for this!"); michael@0: mMutex = aMutex; michael@0: } michael@0: michael@0: #if !defined(DEBUG) || defined(MOZ_NATIVE_SQLITE) michael@0: /** michael@0: * Acquires the mutex. michael@0: */ michael@0: void lock() michael@0: { michael@0: sqlite3_mutex_enter(mMutex); michael@0: } michael@0: michael@0: /** michael@0: * Releases the mutex. michael@0: */ michael@0: void unlock() michael@0: { michael@0: sqlite3_mutex_leave(mMutex); michael@0: } michael@0: michael@0: /** michael@0: * Asserts that the current thread owns the mutex. michael@0: */ michael@0: void assertCurrentThreadOwns() michael@0: { michael@0: } michael@0: michael@0: /** michael@0: * Asserts that the current thread does not own the mutex. michael@0: */ michael@0: void assertNotCurrentThreadOwns() michael@0: { michael@0: } michael@0: michael@0: #else michael@0: void lock() michael@0: { michael@0: NS_ASSERTION(mMutex, "No mutex associated with this wrapper!"); michael@0: michael@0: // While SQLite Mutexes may be recursive, in our own code we do not want to michael@0: // treat them as such. michael@0: CallStack callContext = CallStack(); michael@0: michael@0: CheckAcquire(callContext); michael@0: sqlite3_mutex_enter(mMutex); michael@0: Acquire(callContext); // Call is protected by us holding the mutex. michael@0: } michael@0: michael@0: void unlock() michael@0: { michael@0: NS_ASSERTION(mMutex, "No mutex associated with this wrapper!"); michael@0: michael@0: // While SQLite Mutexes may be recursive, in our own code we do not want to michael@0: // treat them as such. michael@0: Release(); // Call is protected by us holding the mutex. michael@0: sqlite3_mutex_leave(mMutex); michael@0: } michael@0: michael@0: void assertCurrentThreadOwns() michael@0: { michael@0: NS_ASSERTION(mMutex, "No mutex associated with this wrapper!"); michael@0: NS_ASSERTION(sqlite3_mutex_held(mMutex), michael@0: "Mutex is not held, but we expect it to be!"); michael@0: } michael@0: michael@0: void assertNotCurrentThreadOwns() michael@0: { michael@0: NS_ASSERTION(mMutex, "No mutex associated with this wrapper!"); michael@0: NS_ASSERTION(sqlite3_mutex_notheld(mMutex), michael@0: "Mutex is held, but we expect it to not be!"); michael@0: } michael@0: #endif // ifndef DEBUG michael@0: michael@0: private: michael@0: sqlite3_mutex *mMutex; michael@0: }; michael@0: michael@0: /** michael@0: * Automatically acquires the mutex when it enters scope, and releases it when michael@0: * it leaves scope. michael@0: */ michael@0: class MOZ_STACK_CLASS SQLiteMutexAutoLock michael@0: { michael@0: public: michael@0: SQLiteMutexAutoLock(SQLiteMutex &aMutex) michael@0: : mMutex(aMutex) michael@0: { michael@0: mMutex.lock(); michael@0: } michael@0: michael@0: ~SQLiteMutexAutoLock() michael@0: { michael@0: mMutex.unlock(); michael@0: } michael@0: michael@0: private: michael@0: SQLiteMutex &mMutex; michael@0: }; michael@0: michael@0: /** michael@0: * Automatically releases the mutex when it enters scope, and acquires it when michael@0: * it leaves scope. michael@0: */ michael@0: class MOZ_STACK_CLASS SQLiteMutexAutoUnlock michael@0: { michael@0: public: michael@0: SQLiteMutexAutoUnlock(SQLiteMutex &aMutex) michael@0: : mMutex(aMutex) michael@0: { michael@0: mMutex.unlock(); michael@0: } michael@0: michael@0: ~SQLiteMutexAutoUnlock() michael@0: { michael@0: mMutex.lock(); michael@0: } michael@0: michael@0: private: michael@0: SQLiteMutex &mMutex; michael@0: }; michael@0: michael@0: } // namespace storage michael@0: } // namespace mozilla michael@0: michael@0: #endif // mozilla_storage_SQLiteMutex_h_