diff -r 000000000000 -r 6474c204b198 xpcom/glue/ReentrantMonitor.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/xpcom/glue/ReentrantMonitor.h Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,267 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- + * vim: sw=4 ts=4 et : + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ReentrantMonitor_h +#define mozilla_ReentrantMonitor_h + +#include "prmon.h" + +#ifdef MOZILLA_INTERNAL_API +#include "GeckoProfiler.h" +#endif //MOZILLA_INTERNAL_API + +#include "mozilla/BlockingResourceBase.h" + +// +// Provides: +// +// - ReentrantMonitor, a Java-like monitor +// - ReentrantMonitorAutoEnter, an RAII class for ensuring that +// ReentrantMonitors are properly entered and exited +// +// Using ReentrantMonitorAutoEnter is MUCH preferred to making bare calls to +// ReentrantMonitor.Enter and Exit. +// +namespace mozilla { + + +/** + * ReentrantMonitor + * Java-like monitor. + * When possible, use ReentrantMonitorAutoEnter to hold this monitor within a + * scope, instead of calling Enter/Exit directly. + **/ +class NS_COM_GLUE ReentrantMonitor : BlockingResourceBase +{ +public: + /** + * ReentrantMonitor + * @param aName A name which can reference this monitor + */ + ReentrantMonitor(const char* aName) : + BlockingResourceBase(aName, eReentrantMonitor) +#ifdef DEBUG + , mEntryCount(0) +#endif + { + MOZ_COUNT_CTOR(ReentrantMonitor); + mReentrantMonitor = PR_NewMonitor(); + if (!mReentrantMonitor) + NS_RUNTIMEABORT("Can't allocate mozilla::ReentrantMonitor"); + } + + /** + * ~ReentrantMonitor + **/ + ~ReentrantMonitor() + { + NS_ASSERTION(mReentrantMonitor, + "improperly constructed ReentrantMonitor or double free"); + PR_DestroyMonitor(mReentrantMonitor); + mReentrantMonitor = 0; + MOZ_COUNT_DTOR(ReentrantMonitor); + } + +#ifndef DEBUG + /** + * Enter + * @see prmon.h + **/ + void Enter() + { + PR_EnterMonitor(mReentrantMonitor); + } + + /** + * Exit + * @see prmon.h + **/ + void Exit() + { + PR_ExitMonitor(mReentrantMonitor); + } + + /** + * Wait + * @see prmon.h + **/ + nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) + { +#ifdef MOZILLA_INTERNAL_API + GeckoProfilerSleepRAII profiler_sleep; +#endif //MOZILLA_INTERNAL_API + return PR_Wait(mReentrantMonitor, interval) == PR_SUCCESS ? + NS_OK : NS_ERROR_FAILURE; + } + +#else // ifndef DEBUG + void Enter(); + void Exit(); + nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT); + +#endif // ifndef DEBUG + + /** + * Notify + * @see prmon.h + **/ + nsresult Notify() + { + return PR_Notify(mReentrantMonitor) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + + /** + * NotifyAll + * @see prmon.h + **/ + nsresult NotifyAll() + { + return PR_NotifyAll(mReentrantMonitor) == PR_SUCCESS + ? NS_OK : NS_ERROR_FAILURE; + } + +#ifdef DEBUG + /** + * AssertCurrentThreadIn + * @see prmon.h + **/ + void AssertCurrentThreadIn() + { + PR_ASSERT_CURRENT_THREAD_IN_MONITOR(mReentrantMonitor); + } + + /** + * AssertNotCurrentThreadIn + * @see prmon.h + **/ + void AssertNotCurrentThreadIn() + { + // FIXME bug 476536 + } + +#else + void AssertCurrentThreadIn() + { + } + void AssertNotCurrentThreadIn() + { + } + +#endif // ifdef DEBUG + +private: + ReentrantMonitor(); + ReentrantMonitor(const ReentrantMonitor&); + ReentrantMonitor& operator =(const ReentrantMonitor&); + + PRMonitor* mReentrantMonitor; +#ifdef DEBUG + int32_t mEntryCount; +#endif +}; + + +/** + * ReentrantMonitorAutoEnter + * Enters the ReentrantMonitor when it enters scope, and exits it when + * it leaves scope. + * + * MUCH PREFERRED to bare calls to ReentrantMonitor.Enter and Exit. + */ +class NS_COM_GLUE MOZ_STACK_CLASS ReentrantMonitorAutoEnter +{ +public: + /** + * Constructor + * The constructor aquires the given lock. The destructor + * releases the lock. + * + * @param aReentrantMonitor A valid mozilla::ReentrantMonitor*. + **/ + ReentrantMonitorAutoEnter(mozilla::ReentrantMonitor &aReentrantMonitor) : + mReentrantMonitor(&aReentrantMonitor) + { + NS_ASSERTION(mReentrantMonitor, "null monitor"); + mReentrantMonitor->Enter(); + } + + ~ReentrantMonitorAutoEnter(void) + { + mReentrantMonitor->Exit(); + } + + nsresult Wait(PRIntervalTime interval = PR_INTERVAL_NO_TIMEOUT) + { + return mReentrantMonitor->Wait(interval); + } + + nsresult Notify() + { + return mReentrantMonitor->Notify(); + } + + nsresult NotifyAll() + { + return mReentrantMonitor->NotifyAll(); + } + +private: + ReentrantMonitorAutoEnter(); + ReentrantMonitorAutoEnter(const ReentrantMonitorAutoEnter&); + ReentrantMonitorAutoEnter& operator =(const ReentrantMonitorAutoEnter&); + static void* operator new(size_t) CPP_THROW_NEW; + static void operator delete(void*); + + mozilla::ReentrantMonitor* mReentrantMonitor; +}; + +/** + * ReentrantMonitorAutoExit + * Exit the ReentrantMonitor when it enters scope, and enters it when it leaves + * scope. + * + * MUCH PREFERRED to bare calls to ReentrantMonitor.Exit and Enter. + */ +class MOZ_STACK_CLASS ReentrantMonitorAutoExit +{ +public: + /** + * Constructor + * The constructor releases the given lock. The destructor + * acquires the lock. The lock must be held before constructing + * this object! + * + * @param aReentrantMonitor A valid mozilla::ReentrantMonitor*. It + * must be already locked. + **/ + ReentrantMonitorAutoExit(ReentrantMonitor& aReentrantMonitor) : + mReentrantMonitor(&aReentrantMonitor) + { + NS_ASSERTION(mReentrantMonitor, "null monitor"); + mReentrantMonitor->AssertCurrentThreadIn(); + mReentrantMonitor->Exit(); + } + + ~ReentrantMonitorAutoExit(void) + { + mReentrantMonitor->Enter(); + } + +private: + ReentrantMonitorAutoExit(); + ReentrantMonitorAutoExit(const ReentrantMonitorAutoExit&); + ReentrantMonitorAutoExit& operator =(const ReentrantMonitorAutoExit&); + static void* operator new(size_t) CPP_THROW_NEW; + static void operator delete(void*); + + ReentrantMonitor* mReentrantMonitor; +}; + +} // namespace mozilla + + +#endif // ifndef mozilla_ReentrantMonitor_h