/work/obj-fuzz/dist/include/mozilla/Mutex.h
Line | Count | Source (jump to first uncovered line) |
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 | | explicit OffTheBooksMutex(const char* aName, |
46 | | recordreplay::Behavior aRecorded = recordreplay::Behavior::Preserve) |
47 | | : detail::MutexImpl(aRecorded) |
48 | | , BlockingResourceBase(aName, eMutex) |
49 | | #ifdef DEBUG |
50 | | , mOwningThread(nullptr) |
51 | | #endif |
52 | 748 | { |
53 | 748 | } |
54 | | |
55 | | ~OffTheBooksMutex() |
56 | 6 | { |
57 | | #ifdef DEBUG |
58 | | MOZ_ASSERT(!mOwningThread, "destroying a still-owned lock!"); |
59 | | #endif |
60 | | } |
61 | | |
62 | | #ifndef DEBUG |
63 | | /** |
64 | | * Lock this mutex. |
65 | | **/ |
66 | 4.47M | void Lock() { this->lock(); } |
67 | | |
68 | | /** |
69 | | * Unlock this mutex. |
70 | | **/ |
71 | 4.47M | void Unlock() { this->unlock(); } |
72 | | |
73 | | /** |
74 | | * Assert that the current thread owns this mutex in debug builds. |
75 | | * |
76 | | * Does nothing in non-debug builds. |
77 | | **/ |
78 | 20.1k | void AssertCurrentThreadOwns() const {} |
79 | | |
80 | | /** |
81 | | * Assert that the current thread does not own this mutex. |
82 | | * |
83 | | * Note that this function is not implemented for debug builds *and* |
84 | | * non-debug builds due to difficulties in dealing with memory ordering. |
85 | | * |
86 | | * It is therefore mostly useful as documentation. |
87 | | **/ |
88 | 0 | void AssertNotCurrentThreadOwns() const {} |
89 | | |
90 | | #else |
91 | | void Lock(); |
92 | | void Unlock(); |
93 | | |
94 | | void AssertCurrentThreadOwns() const; |
95 | | |
96 | | void AssertNotCurrentThreadOwns() const |
97 | | { |
98 | | // FIXME bug 476536 |
99 | | } |
100 | | |
101 | | #endif // ifndef DEBUG |
102 | | |
103 | | private: |
104 | | OffTheBooksMutex(); |
105 | | OffTheBooksMutex(const OffTheBooksMutex&); |
106 | | OffTheBooksMutex& operator=(const OffTheBooksMutex&); |
107 | | |
108 | | friend class OffTheBooksCondVar; |
109 | | |
110 | | #ifdef DEBUG |
111 | | PRThread* mOwningThread; |
112 | | #endif |
113 | | }; |
114 | | |
115 | | /** |
116 | | * Mutex |
117 | | * When possible, use MutexAutoLock/MutexAutoUnlock to lock/unlock this |
118 | | * mutex within a scope, instead of calling Lock/Unlock directly. |
119 | | */ |
120 | | class Mutex : public OffTheBooksMutex |
121 | | { |
122 | | public: |
123 | | explicit Mutex(const char* aName, |
124 | | recordreplay::Behavior aRecorded = recordreplay::Behavior::Preserve) |
125 | | : OffTheBooksMutex(aName, aRecorded) |
126 | 717 | { |
127 | 717 | MOZ_COUNT_CTOR(Mutex); |
128 | 717 | } |
129 | | |
130 | | ~Mutex() |
131 | 0 | { |
132 | 0 | MOZ_COUNT_DTOR(Mutex); |
133 | 0 | } |
134 | | |
135 | | private: |
136 | | Mutex(); |
137 | | Mutex(const Mutex&); |
138 | | Mutex& operator=(const Mutex&); |
139 | | }; |
140 | | |
141 | | template<typename T> |
142 | | class MOZ_RAII BaseAutoUnlock; |
143 | | |
144 | | /** |
145 | | * MutexAutoLock |
146 | | * Acquires the Mutex when it enters scope, and releases it when it leaves |
147 | | * scope. |
148 | | * |
149 | | * MUCH PREFERRED to bare calls to Mutex.Lock and Unlock. |
150 | | */ |
151 | | template<typename T> |
152 | | class MOZ_RAII BaseAutoLock |
153 | | { |
154 | | public: |
155 | | /** |
156 | | * Constructor |
157 | | * The constructor aquires the given lock. The destructor |
158 | | * releases the lock. |
159 | | * |
160 | | * @param aLock A valid mozilla::Mutex* returned by |
161 | | * mozilla::Mutex::NewMutex. |
162 | | **/ |
163 | | explicit BaseAutoLock(T aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
164 | | : mLock(aLock) |
165 | 1.95M | { |
166 | 1.95M | MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
167 | 1.95M | mLock.Lock(); |
168 | 1.95M | } mozilla::BaseAutoLock<mozilla::Mutex&>::BaseAutoLock(mozilla::Mutex&) Line | Count | Source | 165 | 29.6k | { | 166 | 29.6k | MOZ_GUARD_OBJECT_NOTIFIER_INIT; | 167 | 29.6k | mLock.Lock(); | 168 | 29.6k | } |
mozilla::BaseAutoLock<mozilla::AnyStaticMutex>::BaseAutoLock(mozilla::AnyStaticMutex) Line | Count | Source | 165 | 1.47k | { | 166 | 1.47k | MOZ_GUARD_OBJECT_NOTIFIER_INIT; | 167 | 1.47k | mLock.Lock(); | 168 | 1.47k | } |
mozilla::BaseAutoLock<mozilla::OffTheBooksMutex&>::BaseAutoLock(mozilla::OffTheBooksMutex&) Line | Count | Source | 165 | 167 | { | 166 | 167 | MOZ_GUARD_OBJECT_NOTIFIER_INIT; | 167 | 167 | mLock.Lock(); | 168 | 167 | } |
mozilla::BaseAutoLock<SafeMutex&>::BaseAutoLock(SafeMutex&) Line | Count | Source | 165 | 1.92M | { | 166 | 1.92M | MOZ_GUARD_OBJECT_NOTIFIER_INIT; | 167 | 1.92M | mLock.Lock(); | 168 | 1.92M | } |
mozilla::BaseAutoLock<PSMutex&>::BaseAutoLock(PSMutex&) Line | Count | Source | 165 | 58 | { | 166 | 58 | MOZ_GUARD_OBJECT_NOTIFIER_INIT; | 167 | 58 | mLock.Lock(); | 168 | 58 | } |
|
169 | | |
170 | | ~BaseAutoLock(void) |
171 | 1.95M | { |
172 | 1.95M | mLock.Unlock(); |
173 | 1.95M | } mozilla::BaseAutoLock<mozilla::Mutex&>::~BaseAutoLock() Line | Count | Source | 171 | 29.6k | { | 172 | 29.6k | mLock.Unlock(); | 173 | 29.6k | } |
mozilla::BaseAutoLock<mozilla::AnyStaticMutex>::~BaseAutoLock() Line | Count | Source | 171 | 1.47k | { | 172 | 1.47k | mLock.Unlock(); | 173 | 1.47k | } |
mozilla::BaseAutoLock<mozilla::OffTheBooksMutex&>::~BaseAutoLock() Line | Count | Source | 171 | 167 | { | 172 | 167 | mLock.Unlock(); | 173 | 167 | } |
mozilla::BaseAutoLock<SafeMutex&>::~BaseAutoLock() Line | Count | Source | 171 | 1.92M | { | 172 | 1.92M | mLock.Unlock(); | 173 | 1.92M | } |
mozilla::BaseAutoLock<PSMutex&>::~BaseAutoLock() Line | Count | Source | 171 | 58 | { | 172 | 58 | mLock.Unlock(); | 173 | 58 | } |
|
174 | | |
175 | | // Assert that aLock is the mutex passed to the constructor and that the |
176 | | // current thread owns the mutex. In coding patterns such as: |
177 | | // |
178 | | // void LockedMethod(const MutexAutoLock& aProofOfLock) |
179 | | // { |
180 | | // aProofOfLock.AssertOwns(mMutex); |
181 | | // ... |
182 | | // } |
183 | | // |
184 | | // Without this assertion, it could be that mMutex is not actually |
185 | | // locked. It's possible to have code like: |
186 | | // |
187 | | // MutexAutoLock lock(someMutex); |
188 | | // ... |
189 | | // MutexAutoUnlock unlock(someMutex); |
190 | | // ... |
191 | | // LockedMethod(lock); |
192 | | // |
193 | | // and in such a case, simply asserting that the mutex pointers match is not |
194 | | // sufficient; mutex ownership must be asserted as well. |
195 | | // |
196 | | // Note that if you are going to use the coding pattern presented above, you |
197 | | // should use this method in preference to using AssertCurrentThreadOwns on |
198 | | // the mutex you expected to be held, since this method provides stronger |
199 | | // guarantees. |
200 | | void AssertOwns(const T& aLock) const |
201 | 0 | { |
202 | 0 | MOZ_ASSERT(&aLock == &mLock); |
203 | 0 | mLock.AssertCurrentThreadOwns(); |
204 | 0 | } |
205 | | |
206 | | private: |
207 | | BaseAutoLock(); |
208 | | BaseAutoLock(BaseAutoLock&); |
209 | | BaseAutoLock& operator=(BaseAutoLock&); |
210 | | static void* operator new(size_t) CPP_THROW_NEW; |
211 | | |
212 | | friend class BaseAutoUnlock<T>; |
213 | | |
214 | | T mLock; |
215 | | MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
216 | | }; |
217 | | |
218 | | typedef BaseAutoLock<Mutex&> MutexAutoLock; |
219 | | typedef BaseAutoLock<OffTheBooksMutex&> OffTheBooksMutexAutoLock; |
220 | | |
221 | | /** |
222 | | * MutexAutoUnlock |
223 | | * Releases the Mutex when it enters scope, and re-acquires it when it leaves |
224 | | * scope. |
225 | | * |
226 | | * MUCH PREFERRED to bare calls to Mutex.Unlock and Lock. |
227 | | */ |
228 | | template<typename T> |
229 | | class MOZ_RAII BaseAutoUnlock |
230 | | { |
231 | | public: |
232 | | explicit BaseAutoUnlock(T aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
233 | | : mLock(aLock) |
234 | 100 | { |
235 | 100 | MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
236 | 100 | mLock.Unlock(); |
237 | 100 | } Unexecuted instantiation: mozilla::BaseAutoUnlock<mozilla::Mutex&>::BaseAutoUnlock(mozilla::Mutex&) mozilla::BaseAutoUnlock<SafeMutex&>::BaseAutoUnlock(SafeMutex&) Line | Count | Source | 234 | 100 | { | 235 | 100 | MOZ_GUARD_OBJECT_NOTIFIER_INIT; | 236 | 100 | mLock.Unlock(); | 237 | 100 | } |
Unexecuted instantiation: mozilla::BaseAutoUnlock<mozilla::AnyStaticMutex>::BaseAutoUnlock(mozilla::AnyStaticMutex) |
238 | | |
239 | | explicit BaseAutoUnlock( |
240 | | BaseAutoLock<T>& aAutoLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM) |
241 | | : mLock(aAutoLock.mLock) |
242 | | { |
243 | | MOZ_GUARD_OBJECT_NOTIFIER_INIT; |
244 | | NS_ASSERTION(mLock, "null lock"); |
245 | | mLock->Unlock(); |
246 | | } |
247 | | |
248 | | ~BaseAutoUnlock() |
249 | 100 | { |
250 | 100 | mLock.Lock(); |
251 | 100 | } Unexecuted instantiation: mozilla::BaseAutoUnlock<mozilla::Mutex&>::~BaseAutoUnlock() mozilla::BaseAutoUnlock<SafeMutex&>::~BaseAutoUnlock() Line | Count | Source | 249 | 100 | { | 250 | 100 | mLock.Lock(); | 251 | 100 | } |
Unexecuted instantiation: mozilla::BaseAutoUnlock<mozilla::AnyStaticMutex>::~BaseAutoUnlock() |
252 | | |
253 | | private: |
254 | | BaseAutoUnlock(); |
255 | | BaseAutoUnlock(BaseAutoUnlock&); |
256 | | BaseAutoUnlock& operator=(BaseAutoUnlock&); |
257 | | static void* operator new(size_t) CPP_THROW_NEW; |
258 | | |
259 | | T mLock; |
260 | | MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER |
261 | | }; |
262 | | |
263 | | typedef BaseAutoUnlock<Mutex&> MutexAutoUnlock; |
264 | | typedef BaseAutoUnlock<OffTheBooksMutex&> OffTheBooksMutexAutoUnlock; |
265 | | |
266 | | } // namespace mozilla |
267 | | |
268 | | |
269 | | #endif // ifndef mozilla_Mutex_h |