Bug 1265824 - Add StaticMonitor r=froydnj
authorDoug Thayer <dothayer@mozilla.com>
Fri, 29 Jun 2018 15:27:22 -0700
changeset 427961 ce33d2c68119f450cd888e8dca12d9a23361e5dd
parent 427960 ee6b49ee41c92b42bc9808bf1465829b5fa18b09
child 427962 c7ea73331fc83097578c144a9fe5566eecf56088
push id34322
push userrgurzau@mozilla.com
push dateTue, 24 Jul 2018 15:47:07 +0000
treeherdermozilla-central@db9d47b49936 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersfroydnj
bugs1265824
milestone63.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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
xpcom/base/StaticMonitor.h
xpcom/base/moz.build
xpcom/threads/BlockingResourceBase.cpp
xpcom/threads/CondVar.h
xpcom/threads/Mutex.h
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
@@ -100,17 +100,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