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