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_ReentrantMonitor_h michael@0: #define mozilla_ReentrantMonitor_h michael@0: michael@0: #include "prmon.h" michael@0: michael@0: #ifdef MOZILLA_INTERNAL_API michael@0: #include "GeckoProfiler.h" michael@0: #endif //MOZILLA_INTERNAL_API michael@0: michael@0: #include "mozilla/BlockingResourceBase.h" michael@0: michael@0: // michael@0: // Provides: michael@0: // michael@0: // - ReentrantMonitor, a Java-like monitor michael@0: // - ReentrantMonitorAutoEnter, an RAII class for ensuring that michael@0: // ReentrantMonitors are properly entered and exited michael@0: // michael@0: // Using ReentrantMonitorAutoEnter is MUCH preferred to making bare calls to michael@0: // ReentrantMonitor.Enter and Exit. michael@0: // michael@0: namespace mozilla { michael@0: michael@0: michael@0: /** michael@0: * ReentrantMonitor michael@0: * Java-like monitor. michael@0: * When possible, use ReentrantMonitorAutoEnter to hold this monitor within a michael@0: * scope, instead of calling Enter/Exit directly. michael@0: **/ michael@0: class NS_COM_GLUE ReentrantMonitor : BlockingResourceBase michael@0: { michael@0: public: michael@0: /** michael@0: * ReentrantMonitor michael@0: * @param aName A name which can reference this monitor michael@0: */ michael@0: ReentrantMonitor(const char* aName) : michael@0: BlockingResourceBase(aName, eReentrantMonitor) michael@0: #ifdef DEBUG michael@0: , mEntryCount(0) michael@0: #endif michael@0: { michael@0: MOZ_COUNT_CTOR(ReentrantMonitor); michael@0: mReentrantMonitor = PR_NewMonitor(); michael@0: if (!mReentrantMonitor) michael@0: NS_RUNTIMEABORT("Can't allocate mozilla::ReentrantMonitor"); michael@0: } michael@0: michael@0: /** michael@0: * ~ReentrantMonitor michael@0: **/ michael@0: ~ReentrantMonitor() michael@0: { michael@0: NS_ASSERTION(mReentrantMonitor, michael@0: "improperly constructed ReentrantMonitor or double free"); michael@0: PR_DestroyMonitor(mReentrantMonitor); michael@0: mReentrantMonitor = 0; michael@0: MOZ_COUNT_DTOR(ReentrantMonitor); michael@0: } michael@0: michael@0: #ifndef DEBUG michael@0: /** michael@0: * Enter michael@0: * @see prmon.h michael@0: **/ michael@0: void Enter() michael@0: { michael@0: PR_EnterMonitor(mReentrantMonitor); michael@0: } michael@0: michael@0: /** michael@0: * Exit michael@0: * @see prmon.h michael@0: **/ michael@0: void Exit() michael@0: { michael@0: PR_ExitMonitor(mReentrantMonitor); michael@0: } michael@0: michael@0: /** michael@0: * Wait michael@0: * @see prmon.h michael@0: **/ michael@0: nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) michael@0: { michael@0: #ifdef MOZILLA_INTERNAL_API michael@0: GeckoProfilerSleepRAII profiler_sleep; michael@0: #endif //MOZILLA_INTERNAL_API michael@0: return PR_Wait(mReentrantMonitor, interval) == PR_SUCCESS ? michael@0: NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: #else // ifndef DEBUG michael@0: void Enter(); michael@0: void Exit(); michael@0: nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT); michael@0: michael@0: #endif // ifndef DEBUG michael@0: michael@0: /** michael@0: * Notify michael@0: * @see prmon.h michael@0: **/ michael@0: nsresult Notify() michael@0: { michael@0: return PR_Notify(mReentrantMonitor) == PR_SUCCESS michael@0: ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: /** michael@0: * NotifyAll michael@0: * @see prmon.h michael@0: **/ michael@0: nsresult NotifyAll() michael@0: { michael@0: return PR_NotifyAll(mReentrantMonitor) == PR_SUCCESS michael@0: ? NS_OK : NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: /** michael@0: * AssertCurrentThreadIn michael@0: * @see prmon.h michael@0: **/ michael@0: void AssertCurrentThreadIn() michael@0: { michael@0: PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mReentrantMonitor); michael@0: } michael@0: michael@0: /** michael@0: * AssertNotCurrentThreadIn michael@0: * @see prmon.h michael@0: **/ michael@0: void AssertNotCurrentThreadIn() michael@0: { michael@0: // FIXME bug 476536 michael@0: } michael@0: michael@0: #else michael@0: void AssertCurrentThreadIn() michael@0: { michael@0: } michael@0: void AssertNotCurrentThreadIn() michael@0: { michael@0: } michael@0: michael@0: #endif // ifdef DEBUG michael@0: michael@0: private: michael@0: ReentrantMonitor(); michael@0: ReentrantMonitor(const ReentrantMonitor&); michael@0: ReentrantMonitor& operator =(const ReentrantMonitor&); michael@0: michael@0: PRMonitor* mReentrantMonitor; michael@0: #ifdef DEBUG michael@0: int32_t mEntryCount; michael@0: #endif michael@0: }; michael@0: michael@0: michael@0: /** michael@0: * ReentrantMonitorAutoEnter michael@0: * Enters the ReentrantMonitor when it enters scope, and exits it when michael@0: * it leaves scope. michael@0: * michael@0: * MUCH PREFERRED to bare calls to ReentrantMonitor.Enter and Exit. michael@0: */ michael@0: class NS_COM_GLUE MOZ_STACK_CLASS ReentrantMonitorAutoEnter 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 aReentrantMonitor A valid mozilla::ReentrantMonitor*. michael@0: **/ michael@0: ReentrantMonitorAutoEnter(mozilla::ReentrantMonitor &aReentrantMonitor) : michael@0: mReentrantMonitor(&aReentrantMonitor) michael@0: { michael@0: NS_ASSERTION(mReentrantMonitor, "null monitor"); michael@0: mReentrantMonitor->Enter(); michael@0: } michael@0: michael@0: ~ReentrantMonitorAutoEnter(void) michael@0: { michael@0: mReentrantMonitor->Exit(); michael@0: } michael@0: michael@0: nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) michael@0: { michael@0: return mReentrantMonitor->Wait(interval); michael@0: } michael@0: michael@0: nsresult Notify() michael@0: { michael@0: return mReentrantMonitor->Notify(); michael@0: } michael@0: michael@0: nsresult NotifyAll() michael@0: { michael@0: return mReentrantMonitor->NotifyAll(); michael@0: } michael@0: michael@0: private: michael@0: ReentrantMonitorAutoEnter(); michael@0: ReentrantMonitorAutoEnter(const ReentrantMonitorAutoEnter&); michael@0: ReentrantMonitorAutoEnter& operator =(const ReentrantMonitorAutoEnter&); michael@0: static void* operator new(size_t) CPP_THROW_NEW; michael@0: static void operator delete(void*); michael@0: michael@0: mozilla::ReentrantMonitor* mReentrantMonitor; michael@0: }; michael@0: michael@0: /** michael@0: * ReentrantMonitorAutoExit michael@0: * Exit the ReentrantMonitor when it enters scope, and enters it when it leaves michael@0: * scope. michael@0: * michael@0: * MUCH PREFERRED to bare calls to ReentrantMonitor.Exit and Enter. michael@0: */ michael@0: class MOZ_STACK_CLASS ReentrantMonitorAutoExit michael@0: { michael@0: public: michael@0: /** michael@0: * Constructor michael@0: * The constructor releases the given lock. The destructor michael@0: * acquires the lock. The lock must be held before constructing michael@0: * this object! michael@0: * michael@0: * @param aReentrantMonitor A valid mozilla::ReentrantMonitor*. It michael@0: * must be already locked. michael@0: **/ michael@0: ReentrantMonitorAutoExit(ReentrantMonitor& aReentrantMonitor) : michael@0: mReentrantMonitor(&aReentrantMonitor) michael@0: { michael@0: NS_ASSERTION(mReentrantMonitor, "null monitor"); michael@0: mReentrantMonitor->AssertCurrentThreadIn(); michael@0: mReentrantMonitor->Exit(); michael@0: } michael@0: michael@0: ~ReentrantMonitorAutoExit(void) michael@0: { michael@0: mReentrantMonitor->Enter(); michael@0: } michael@0: michael@0: private: michael@0: ReentrantMonitorAutoExit(); michael@0: ReentrantMonitorAutoExit(const ReentrantMonitorAutoExit&); michael@0: ReentrantMonitorAutoExit& operator =(const ReentrantMonitorAutoExit&); michael@0: static void* operator new(size_t) CPP_THROW_NEW; michael@0: static void operator delete(void*); michael@0: michael@0: ReentrantMonitor* mReentrantMonitor; michael@0: }; michael@0: michael@0: } // namespace mozilla michael@0: michael@0: michael@0: #endif // ifndef mozilla_ReentrantMonitor_h