Line data Source code
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_Mutex_h
8 : #define mozilla_Mutex_h
9 :
10 : #include "mozilla/BlockingResourceBase.h"
11 : #include "mozilla/GuardObjects.h"
12 : #include "mozilla/PlatformMutex.h"
13 :
14 : //
15 : // Provides:
16 : //
17 : // - Mutex, a non-recursive mutex
18 : // - MutexAutoLock, an RAII class for ensuring that Mutexes are properly
19 : // locked and unlocked
20 : // - MutexAutoUnlock, complementary sibling to MutexAutoLock
21 : //
22 : // - OffTheBooksMutex, a non-recursive mutex that doesn't do leak checking
23 : // - OffTheBooksMutexAuto{Lock,Unlock} - Like MutexAuto{Lock,Unlock}, but for
24 : // an OffTheBooksMutex.
25 : //
26 : // Using MutexAutoLock/MutexAutoUnlock etc. is MUCH preferred to making bare
27 : // calls to Lock and Unlock.
28 : //
29 : namespace mozilla {
30 :
31 : /**
32 : * OffTheBooksMutex is identical to Mutex, except that OffTheBooksMutex doesn't
33 : * include leak checking. Sometimes you want to intentionally "leak" a mutex
34 : * until shutdown; in these cases, OffTheBooksMutex is for you.
35 : */
36 : class OffTheBooksMutex : public detail::MutexImpl, BlockingResourceBase
37 : {
38 : public:
39 : /**
40 : * @param aName A name which can reference this lock
41 : * @returns If failure, nullptr
42 : * If success, a valid Mutex* which must be destroyed
43 : * by Mutex::DestroyMutex()
44 : **/
45 1316 : explicit OffTheBooksMutex(const char* aName)
46 1316 : : detail::MutexImpl()
47 : , BlockingResourceBase(aName, eMutex)
48 : #ifdef DEBUG
49 1316 : , mOwningThread(nullptr)
50 : #endif
51 : {
52 1317 : }
53 :
54 249 : ~OffTheBooksMutex()
55 249 : {
56 : #ifdef DEBUG
57 249 : MOZ_ASSERT(!mOwningThread, "destroying a still-owned lock!");
58 : #endif
59 249 : }
60 :
61 : #ifndef DEBUG
62 : /**
63 : * Lock this mutex.
64 : **/
65 : void Lock() { this->lock(); }
66 :
67 : /**
68 : * Unlock this mutex.
69 : **/
70 : void Unlock() { this->unlock(); }
71 :
72 : /**
73 : * Assert that the current thread owns this mutex in debug builds.
74 : *
75 : * Does nothing in non-debug builds.
76 : **/
77 : void AssertCurrentThreadOwns() const {}
78 :
79 : /**
80 : * Assert that the current thread does not own this mutex.
81 : *
82 : * Note that this function is not implemented for debug builds *and*
83 : * non-debug builds due to difficulties in dealing with memory ordering.
84 : *
85 : * It is therefore mostly useful as documentation.
86 : **/
87 : void AssertNotCurrentThreadOwns() const {}
88 :
89 : #else
90 : void Lock();
91 : void Unlock();
92 :
93 : void AssertCurrentThreadOwns() const;
94 :
95 1066 : void AssertNotCurrentThreadOwns() const
96 : {
97 : // FIXME bug 476536
98 1066 : }
99 :
100 : #endif // ifndef DEBUG
101 :
102 : private:
103 : OffTheBooksMutex();
104 : OffTheBooksMutex(const OffTheBooksMutex&);
105 : OffTheBooksMutex& operator=(const OffTheBooksMutex&);
106 :
107 : friend class CondVar;
108 :
109 : #ifdef DEBUG
110 : PRThread* mOwningThread;
111 : #endif
112 : };
113 :
114 : /**
115 : * Mutex
116 : * When possible, use MutexAutoLock/MutexAutoUnlock to lock/unlock this
117 : * mutex within a scope, instead of calling Lock/Unlock directly.
118 : */
119 : class Mutex : public OffTheBooksMutex
120 : {
121 : public:
122 1269 : explicit Mutex(const char* aName)
123 1269 : : OffTheBooksMutex(aName)
124 : {
125 1270 : MOZ_COUNT_CTOR(Mutex);
126 1270 : }
127 :
128 249 : ~Mutex()
129 249 : {
130 249 : MOZ_COUNT_DTOR(Mutex);
131 249 : }
132 :
133 : private:
134 : Mutex();
135 : Mutex(const Mutex&);
136 : Mutex& operator=(const Mutex&);
137 : };
138 :
139 : template<typename T>
140 : class MOZ_RAII BaseAutoUnlock;
141 :
142 : /**
143 : * MutexAutoLock
144 : * Acquires the Mutex when it enters scope, and releases it when it leaves
145 : * scope.
146 : *
147 : * MUCH PREFERRED to bare calls to Mutex.Lock and Unlock.
148 : */
149 : template<typename T>
150 : class MOZ_RAII BaseAutoLock
151 : {
152 : public:
153 : /**
154 : * Constructor
155 : * The constructor aquires the given lock. The destructor
156 : * releases the lock.
157 : *
158 : * @param aLock A valid mozilla::Mutex* returned by
159 : * mozilla::Mutex::NewMutex.
160 : **/
161 64963 : explicit BaseAutoLock(T& aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
162 64963 : : mLock(&aLock)
163 : {
164 64964 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
165 64965 : NS_ASSERTION(mLock, "null mutex");
166 64965 : mLock->Lock();
167 64958 : }
168 :
169 64932 : ~BaseAutoLock(void)
170 : {
171 64932 : mLock->Unlock();
172 64935 : }
173 :
174 : private:
175 : BaseAutoLock();
176 : BaseAutoLock(BaseAutoLock&);
177 : BaseAutoLock& operator=(BaseAutoLock&);
178 : static void* operator new(size_t) CPP_THROW_NEW;
179 :
180 : friend class BaseAutoUnlock<T>;
181 :
182 : T* mLock;
183 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
184 : };
185 :
186 : typedef BaseAutoLock<Mutex> MutexAutoLock;
187 : typedef BaseAutoLock<OffTheBooksMutex> OffTheBooksMutexAutoLock;
188 :
189 : /**
190 : * MutexAutoUnlock
191 : * Releases the Mutex when it enters scope, and re-acquires it when it leaves
192 : * scope.
193 : *
194 : * MUCH PREFERRED to bare calls to Mutex.Unlock and Lock.
195 : */
196 : template<typename T>
197 : class MOZ_RAII BaseAutoUnlock
198 : {
199 : public:
200 727 : explicit BaseAutoUnlock(T& aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
201 727 : : mLock(&aLock)
202 : {
203 727 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
204 727 : NS_ASSERTION(mLock, "null lock");
205 727 : mLock->Unlock();
206 727 : }
207 :
208 : explicit BaseAutoUnlock(
209 : BaseAutoLock<T>& aAutoLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
210 : : mLock(aAutoLock.mLock)
211 : {
212 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
213 : NS_ASSERTION(mLock, "null lock");
214 : mLock->Unlock();
215 : }
216 :
217 727 : ~BaseAutoUnlock()
218 : {
219 727 : mLock->Lock();
220 727 : }
221 :
222 : private:
223 : BaseAutoUnlock();
224 : BaseAutoUnlock(BaseAutoUnlock&);
225 : BaseAutoUnlock& operator=(BaseAutoUnlock&);
226 : static void* operator new(size_t) CPP_THROW_NEW;
227 :
228 : T* mLock;
229 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
230 : };
231 :
232 : typedef BaseAutoUnlock<Mutex> MutexAutoUnlock;
233 : typedef BaseAutoUnlock<OffTheBooksMutex> OffTheBooksMutexAutoUnlock;
234 :
235 : } // namespace mozilla
236 :
237 :
238 : #endif // ifndef mozilla_Mutex_h
|