Bug 1265824 - Add StaticMonitor r?froydnj
For the IPC work monitoring when textures become unlocked, we
need a Monitor equivalent of StaticMutex - this implements that.
MozReview-Commit-ID: IceQNeqVQ8f
new file mode 100644
--- /dev/null
+++ b/xpcom/base/StaticMonitor.h
@@ -0,0 +1,129 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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_StaticMonitor_h
+#define mozilla_StaticMonitor_h
+
+#include "mozilla/Atomics.h"
+#include "mozilla/CondVar.h"
+
+namespace mozilla {
+
+class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS StaticMonitor
+{
+public:
+ // In debug builds, check that mMutex is initialized for us as we expect by
+ // the compiler. In non-debug builds, don't declare a constructor so that
+ // the compiler can see that the constructor is trivial.
+#ifdef DEBUG
+ StaticMonitor()
+ {
+ MOZ_ASSERT(!mMutex);
+ }
+#endif
+
+ void Lock()
+ {
+ Mutex()->Lock();
+ }
+
+ void Unlock()
+ {
+ Mutex()->Unlock();
+ }
+
+ void Wait() { CondVar()->Wait(); }
+ CVStatus Wait(TimeDuration aDuration) { return CondVar()->Wait(aDuration); }
+
+ nsresult Notify() { return CondVar()->Notify(); }
+ nsresult NotifyAll() { return CondVar()->NotifyAll(); }
+
+ void AssertCurrentThreadOwns()
+ {
+#ifdef DEBUG
+ Mutex()->AssertCurrentThreadOwns();
+#endif
+ }
+
+private:
+ OffTheBooksMutex* Mutex()
+ {
+ if (mMutex) {
+ return mMutex;
+ }
+
+ OffTheBooksMutex* mutex = new OffTheBooksMutex("StaticMutex");
+ if (!mMutex.compareExchange(nullptr, mutex)) {
+ delete mutex;
+ }
+
+ return mMutex;
+ }
+
+ OffTheBooksCondVar* CondVar()
+ {
+ if (mCondVar) {
+ return mCondVar;
+ }
+
+ OffTheBooksCondVar* condvar = new OffTheBooksCondVar(*Mutex(), "StaticCondVar");
+ if (!mCondVar.compareExchange(nullptr, condvar)) {
+ delete condvar;
+ }
+
+ return mCondVar;
+ }
+
+ Atomic<OffTheBooksMutex*> mMutex;
+ Atomic<OffTheBooksCondVar*> mCondVar;
+
+
+ // Disallow copy constructor, but only in debug mode. We only define
+ // a default constructor in debug mode (see above); if we declared
+ // this constructor always, the compiler wouldn't generate a trivial
+ // default constructor for us in non-debug mode.
+#ifdef DEBUG
+ StaticMonitor(const StaticMonitor& aOther);
+#endif
+
+ // Disallow these operators.
+ StaticMonitor& operator=(const StaticMonitor& aRhs);
+ static void* operator new(size_t) CPP_THROW_NEW;
+ static void operator delete(void*);
+};
+
+class MOZ_STACK_CLASS StaticMonitorAutoLock
+{
+public:
+ explicit StaticMonitorAutoLock(StaticMonitor& aMonitor)
+ : mMonitor(&aMonitor)
+ {
+ mMonitor->Lock();
+ }
+
+ ~StaticMonitorAutoLock()
+ {
+ mMonitor->Unlock();
+ }
+
+ void Wait() { mMonitor->Wait(); }
+ CVStatus Wait(TimeDuration aDuration) { return mMonitor->Wait(aDuration); }
+
+ nsresult Notify() { return mMonitor->Notify(); }
+ nsresult NotifyAll() { return mMonitor->NotifyAll(); }
+
+private:
+ StaticMonitorAutoLock();
+ StaticMonitorAutoLock(const StaticMonitorAutoLock&);
+ StaticMonitorAutoLock& operator=(const StaticMonitorAutoLock&);
+ static void* operator new(size_t) CPP_THROW_NEW;
+
+ StaticMonitor* mMonitor;
+};
+
+} // namespace mozilla
+
+#endif
--- a/xpcom/base/moz.build
+++ b/xpcom/base/moz.build
@@ -114,16 +114,17 @@ EXPORTS.mozilla += [
'Logging.h',
'MemoryInfo.h',
'MemoryMapping.h',
'MemoryReportingProcess.h',
'nsMemoryInfoDumper.h',
'NSPRLogModulesParser.h',
'OwningNonNull.h',
'SizeOfState.h',
+ 'StaticMonitor.h',
'StaticMutex.h',
'StaticPtr.h',
]
# nsDebugImpl isn't unified because we disable PGO so that NS_ABORT_OOM isn't
# optimized away oddly.
SOURCES += [
'nsDebugImpl.cpp',
--- a/xpcom/threads/BlockingResourceBase.cpp
+++ b/xpcom/threads/BlockingResourceBase.cpp
@@ -582,25 +582,25 @@ void
RecursiveMutex::AssertCurrentThreadIn()
{
MOZ_ASSERT(IsAcquired() && mOwningThread == PR_GetCurrentThread());
}
//
// Debug implementation of CondVar
void
-CondVar::Wait()
+OffTheBooksCondVar::Wait()
{
- // Forward to the timed version of CondVar::Wait to avoid code duplication.
+ // Forward to the timed version of OffTheBooksCondVar::Wait to avoid code duplication.
CVStatus status = Wait(TimeDuration::Forever());
MOZ_ASSERT(status == CVStatus::NoTimeout);
}
CVStatus
-CondVar::Wait(TimeDuration aDuration)
+OffTheBooksCondVar::Wait(TimeDuration aDuration)
{
AssertCurrentThreadOwnsMutex();
// save mutex state and reset to empty
AcquisitionState savedAcquisitionState = mLock->GetAcquisitionState();
BlockingResourceBase* savedChainPrev = mLock->mChainPrev;
PRThread* savedOwningThread = mLock->mOwningThread;
mLock->ClearAcquisitionState();
--- a/xpcom/threads/CondVar.h
+++ b/xpcom/threads/CondVar.h
@@ -12,50 +12,48 @@
#include "mozilla/Mutex.h"
#ifdef MOZILLA_INTERNAL_API
#include "GeckoProfiler.h"
#endif //MOZILLA_INTERNAL_API
namespace mozilla {
-
/**
- * CondVar
- * Vanilla condition variable. Please don't use this unless you have a
- * compelling reason --- Monitor provides a simpler API.
+ * Similarly to OffTheBooksMutex, OffTheBooksCondvar is identical to CondVar,
+ * except that OffTheBooksCondVar doesn't include leak checking. Sometimes
+ * you want to intentionally "leak" a CondVar until shutdown; in these cases,
+ * OffTheBooksCondVar is for you.
*/
-class CondVar : BlockingResourceBase
+class OffTheBooksCondVar : BlockingResourceBase
{
public:
/**
- * CondVar
+ * OffTheBooksCondVar
*
* The CALLER owns |aLock|.
*
* @param aLock A Mutex to associate with this condition variable.
* @param aName A name which can reference this monitor
* @returns If failure, nullptr.
* If success, a valid Monitor* which must be destroyed
* by Monitor::DestroyMonitor()
**/
- CondVar(Mutex& aLock, const char* aName)
+ OffTheBooksCondVar(OffTheBooksMutex& aLock, const char* aName)
: BlockingResourceBase(aName, eCondVar)
, mLock(&aLock)
{
- MOZ_COUNT_CTOR(CondVar);
}
/**
- * ~CondVar
- * Clean up after this CondVar, but NOT its associated Mutex.
+ * ~OffTheBooksCondVar
+ * Clean up after this OffTheBooksCondVar, but NOT its associated Mutex.
**/
- ~CondVar()
+ ~OffTheBooksCondVar()
{
- MOZ_COUNT_DTOR(CondVar);
}
/**
* Wait
* @see prcvar.h
**/
#ifndef DEBUG
void Wait()
@@ -120,20 +118,45 @@ public:
#else
void AssertCurrentThreadOwnsMutex() {}
void AssertNotCurrentThreadOwnsMutex() {}
#endif // ifdef DEBUG
private:
+ OffTheBooksCondVar();
+ OffTheBooksCondVar(const OffTheBooksCondVar&) = delete;
+ OffTheBooksCondVar& operator=(const OffTheBooksCondVar&) = delete;
+
+ OffTheBooksMutex* mLock;
+ detail::ConditionVariableImpl mImpl;
+};
+
+/**
+ * CondVar
+ * Vanilla condition variable. Please don't use this unless you have a
+ * compelling reason --- Monitor provides a simpler API.
+ */
+class CondVar : public OffTheBooksCondVar
+{
+public:
+ CondVar(OffTheBooksMutex& aLock, const char* aName)
+ : OffTheBooksCondVar(aLock, aName)
+ {
+ MOZ_COUNT_CTOR(CondVar);
+ }
+
+ ~CondVar()
+ {
+ MOZ_COUNT_DTOR(CondVar);
+ }
+
+private:
CondVar();
- CondVar(const CondVar&) = delete;
- CondVar& operator=(const CondVar&) = delete;
-
- Mutex* mLock;
- detail::ConditionVariableImpl mImpl;
+ CondVar(const CondVar&);
+ CondVar& operator=(const CondVar&);
};
} // namespace mozilla
#endif // ifndef mozilla_CondVar_h
--- a/xpcom/threads/Mutex.h
+++ b/xpcom/threads/Mutex.h
@@ -99,17 +99,17 @@ public:
#endif // ifndef DEBUG
private:
OffTheBooksMutex();
OffTheBooksMutex(const OffTheBooksMutex&);
OffTheBooksMutex& operator=(const OffTheBooksMutex&);
- friend class CondVar;
+ friend class OffTheBooksCondVar;
#ifdef DEBUG
PRThread* mOwningThread;
#endif
};
/**
* Mutex