|
1 #ifndef mozilla_StaticMutex_h |
|
2 #define mozilla_StaticMutex_h |
|
3 |
|
4 #include "mozilla/Atomics.h" |
|
5 #include "mozilla/Mutex.h" |
|
6 |
|
7 namespace mozilla { |
|
8 |
|
9 /** |
|
10 * StaticMutex is a Mutex that can (and in fact, must) be used as a |
|
11 * global/static variable. |
|
12 * |
|
13 * The main reason to use StaticMutex as opposed to |
|
14 * StaticAutoPtr<OffTheBooksMutex> is that we instantiate the StaticMutex in a |
|
15 * thread-safe manner the first time it's used. |
|
16 * |
|
17 * The same caveats that apply to StaticAutoPtr apply to StaticMutex. In |
|
18 * particular, do not use StaticMutex as a stack variable or a class instance |
|
19 * variable, because this class relies on the fact that global variablies are |
|
20 * initialized to 0 in order to initialize mMutex. It is only safe to use |
|
21 * StaticMutex as a global or static variable. |
|
22 */ |
|
23 class StaticMutex |
|
24 { |
|
25 public: |
|
26 // In debug builds, check that mMutex is initialized for us as we expect by |
|
27 // the compiler. In non-debug builds, don't declare a constructor so that |
|
28 // the compiler can see that the constructor is trivial. |
|
29 #ifdef DEBUG |
|
30 StaticMutex() |
|
31 { |
|
32 MOZ_ASSERT(!mMutex); |
|
33 } |
|
34 #endif |
|
35 |
|
36 void Lock() |
|
37 { |
|
38 Mutex()->Lock(); |
|
39 } |
|
40 |
|
41 void Unlock() |
|
42 { |
|
43 Mutex()->Unlock(); |
|
44 } |
|
45 |
|
46 void AssertCurrentThreadOwns() |
|
47 { |
|
48 #ifdef DEBUG |
|
49 Mutex()->AssertCurrentThreadOwns(); |
|
50 #endif |
|
51 } |
|
52 |
|
53 private: |
|
54 OffTheBooksMutex* Mutex() |
|
55 { |
|
56 if (mMutex) { |
|
57 return mMutex; |
|
58 } |
|
59 |
|
60 OffTheBooksMutex* mutex = new OffTheBooksMutex("StaticMutex"); |
|
61 if (!mMutex.compareExchange(nullptr, mutex)) { |
|
62 delete mutex; |
|
63 } |
|
64 |
|
65 return mMutex; |
|
66 } |
|
67 |
|
68 Atomic<OffTheBooksMutex*> mMutex; |
|
69 |
|
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 StaticMutex(StaticMutex &other); |
|
77 #endif |
|
78 |
|
79 // Disallow these operators. |
|
80 StaticMutex& operator=(StaticMutex* rhs); |
|
81 static void* operator new(size_t) CPP_THROW_NEW; |
|
82 static void operator delete(void*); |
|
83 }; |
|
84 |
|
85 typedef BaseAutoLock<StaticMutex> StaticMutexAutoLock; |
|
86 typedef BaseAutoUnlock<StaticMutex> StaticMutexAutoUnlock; |
|
87 |
|
88 } // namespace mozilla |
|
89 |
|
90 #endif |