Bug 1265824 - Add StaticMonitor r?froydnj draft
authorDoug Thayer <dothayer@mozilla.com>
Fri, 29 Jun 2018 15:27:22 -0700
changeset 816211 cbe7962f7da9138172774b54cddae654f8c1944e
parent 816210 f5cbdceb802df4f80d36d7b0c31f3e2959fa1a18
child 816212 787c3b0b9e52ebc250cfee72e1a29547c0de2731
child 816222 7015cab49b6854c272a283876a40c94c1d7ab916
child 816224 4625baf10bc41a75fad8b4e3eef24142a9fa7064
child 816938 8341bd2efba8e405adfb2d2f35d152b4c4c0a16b
push id115776
push userbmo:dothayer@mozilla.com
push dateTue, 10 Jul 2018 18:33:51 +0000
reviewersfroydnj
bugs1265824
milestone63.0a1
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
@@ -112,16 +112,17 @@ EXPORTS.mozilla += [
     'IntentionalCrash.h',
     'JSObjectHolder.h',
     'Logging.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