1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_StaticMonitor_h 8 #define mozilla_StaticMonitor_h 9 10 #include "mozilla/Atomics.h" 11 #include "mozilla/CondVar.h" 12 13 namespace mozilla { 14 15 class MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS StaticMonitor { 16 public: 17 // In debug builds, check that mMutex is initialized for us as we expect by 18 // the compiler. In non-debug builds, don't declare a constructor so that 19 // the compiler can see that the constructor is trivial. 20 #ifdef DEBUG StaticMonitor()21 StaticMonitor() { MOZ_ASSERT(!mMutex); } 22 #endif 23 Lock()24 void Lock() { Mutex()->Lock(); } 25 Unlock()26 void Unlock() { Mutex()->Unlock(); } 27 Wait()28 void Wait() { CondVar()->Wait(); } Wait(TimeDuration aDuration)29 CVStatus Wait(TimeDuration aDuration) { return CondVar()->Wait(aDuration); } 30 Notify()31 void Notify() { CondVar()->Notify(); } NotifyAll()32 void NotifyAll() { CondVar()->NotifyAll(); } 33 AssertCurrentThreadOwns()34 void AssertCurrentThreadOwns() { 35 #ifdef DEBUG 36 Mutex()->AssertCurrentThreadOwns(); 37 #endif 38 } 39 40 private: Mutex()41 OffTheBooksMutex* Mutex() { 42 if (mMutex) { 43 return mMutex; 44 } 45 46 OffTheBooksMutex* mutex = new OffTheBooksMutex("StaticMutex"); 47 if (!mMutex.compareExchange(nullptr, mutex)) { 48 delete mutex; 49 } 50 51 return mMutex; 52 } 53 CondVar()54 OffTheBooksCondVar* CondVar() { 55 if (mCondVar) { 56 return mCondVar; 57 } 58 59 OffTheBooksCondVar* condvar = 60 new OffTheBooksCondVar(*Mutex(), "StaticCondVar"); 61 if (!mCondVar.compareExchange(nullptr, condvar)) { 62 delete condvar; 63 } 64 65 return mCondVar; 66 } 67 68 Atomic<OffTheBooksMutex*> mMutex; 69 Atomic<OffTheBooksCondVar*> mCondVar; 70 71 // Disallow copy constructor, but only in debug mode. We only define 72 // a default constructor in debug mode (see above); if we declared 73 // this constructor always, the compiler wouldn't generate a trivial 74 // default constructor for us in non-debug mode. 75 #ifdef DEBUG 76 StaticMonitor(const StaticMonitor& aOther); 77 #endif 78 79 // Disallow these operators. 80 StaticMonitor& operator=(const StaticMonitor& aRhs); 81 static void* operator new(size_t) noexcept(true); 82 static void operator delete(void*); 83 }; 84 85 class MOZ_STACK_CLASS StaticMonitorAutoLock { 86 public: StaticMonitorAutoLock(StaticMonitor & aMonitor)87 explicit StaticMonitorAutoLock(StaticMonitor& aMonitor) 88 : mMonitor(&aMonitor) { 89 mMonitor->Lock(); 90 } 91 ~StaticMonitorAutoLock()92 ~StaticMonitorAutoLock() { mMonitor->Unlock(); } 93 Wait()94 void Wait() { mMonitor->Wait(); } Wait(TimeDuration aDuration)95 CVStatus Wait(TimeDuration aDuration) { return mMonitor->Wait(aDuration); } 96 Notify()97 void Notify() { mMonitor->Notify(); } NotifyAll()98 void NotifyAll() { mMonitor->NotifyAll(); } 99 100 private: 101 StaticMonitorAutoLock(); 102 StaticMonitorAutoLock(const StaticMonitorAutoLock&); 103 StaticMonitorAutoLock& operator=(const StaticMonitorAutoLock&); 104 static void* operator new(size_t) noexcept(true); 105 106 StaticMonitor* mMonitor; 107 }; 108 109 } // namespace mozilla 110 111 #endif 112