Bug 1667008 [wpt PR 25754] - [css-flex] Change some test expectations for image flex...
[gecko.git] / xpcom / threads / Mutex.h
blob0fa6e1700921f770b595caee4ebd6949a6024ac7
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/. */
7 #ifndef mozilla_Mutex_h
8 #define mozilla_Mutex_h
10 #include "mozilla/BlockingResourceBase.h"
11 #include "mozilla/PlatformMutex.h"
14 // Provides:
16 // - Mutex, a non-recursive mutex
17 // - MutexAutoLock, an RAII class for ensuring that Mutexes are properly
18 // locked and unlocked
19 // - MutexAutoUnlock, complementary sibling to MutexAutoLock
21 // - OffTheBooksMutex, a non-recursive mutex that doesn't do leak checking
22 // - OffTheBooksMutexAuto{Lock,Unlock} - Like MutexAuto{Lock,Unlock}, but for
23 // an OffTheBooksMutex.
25 // Using MutexAutoLock/MutexAutoUnlock etc. is MUCH preferred to making bare
26 // calls to Lock and Unlock.
28 namespace mozilla {
30 /**
31 * OffTheBooksMutex is identical to Mutex, except that OffTheBooksMutex doesn't
32 * include leak checking. Sometimes you want to intentionally "leak" a mutex
33 * until shutdown; in these cases, OffTheBooksMutex is for you.
35 class OffTheBooksMutex : public detail::MutexImpl, BlockingResourceBase {
36 public:
37 /**
38 * @param aName A name which can reference this lock
39 * @returns If failure, nullptr
40 * If success, a valid Mutex* which must be destroyed
41 * by Mutex::DestroyMutex()
42 **/
43 explicit OffTheBooksMutex(const char* aName)
44 : BlockingResourceBase(aName, eMutex)
45 #ifdef DEBUG
47 mOwningThread(nullptr)
48 #endif
52 ~OffTheBooksMutex() {
53 #ifdef DEBUG
54 MOZ_ASSERT(!mOwningThread, "destroying a still-owned lock!");
55 #endif
58 #ifndef DEBUG
59 /**
60 * Lock this mutex.
61 **/
62 void Lock() { this->lock(); }
64 /**
65 * Try to lock this mutex, returning true if we were successful.
66 **/
67 [[nodiscard]] bool TryLock() { return this->tryLock(); }
69 /**
70 * Unlock this mutex.
71 **/
72 void Unlock() { this->unlock(); }
74 /**
75 * Assert that the current thread owns this mutex in debug builds.
77 * Does nothing in non-debug builds.
78 **/
79 void AssertCurrentThreadOwns() const {}
81 /**
82 * Assert that the current thread does not own this mutex.
84 * Note that this function is not implemented for debug builds *and*
85 * non-debug builds due to difficulties in dealing with memory ordering.
87 * It is therefore mostly useful as documentation.
88 **/
89 void AssertNotCurrentThreadOwns() const {}
91 #else
92 void Lock();
93 [[nodiscard]] bool TryLock();
94 void Unlock();
96 void AssertCurrentThreadOwns() const;
98 void AssertNotCurrentThreadOwns() const {
99 // FIXME bug 476536
102 #endif // ifndef DEBUG
104 private:
105 OffTheBooksMutex();
106 OffTheBooksMutex(const OffTheBooksMutex&);
107 OffTheBooksMutex& operator=(const OffTheBooksMutex&);
109 friend class OffTheBooksCondVar;
111 #ifdef DEBUG
112 PRThread* mOwningThread;
113 #endif
117 * Mutex
118 * When possible, use MutexAutoLock/MutexAutoUnlock to lock/unlock this
119 * mutex within a scope, instead of calling Lock/Unlock directly.
121 class Mutex : public OffTheBooksMutex {
122 public:
123 explicit Mutex(const char* aName) : OffTheBooksMutex(aName) {
124 MOZ_COUNT_CTOR(Mutex);
127 MOZ_COUNTED_DTOR(Mutex)
129 private:
130 Mutex();
131 Mutex(const Mutex&);
132 Mutex& operator=(const Mutex&);
135 namespace detail {
136 template <typename T>
137 class MOZ_RAII BaseAutoUnlock;
140 * MutexAutoLock
141 * Acquires the Mutex when it enters scope, and releases it when it leaves
142 * scope.
144 * MUCH PREFERRED to bare calls to Mutex.Lock and Unlock.
146 template <typename T>
147 class MOZ_RAII BaseAutoLock {
148 public:
150 * Constructor
151 * The constructor aquires the given lock. The destructor
152 * releases the lock.
154 * @param aLock A valid mozilla::Mutex* returned by
155 * mozilla::Mutex::NewMutex.
157 explicit BaseAutoLock(T aLock) : mLock(aLock) { mLock.Lock(); }
159 ~BaseAutoLock(void) { mLock.Unlock(); }
161 // Assert that aLock is the mutex passed to the constructor and that the
162 // current thread owns the mutex. In coding patterns such as:
164 // void LockedMethod(const BaseAutoLock<T>& aProofOfLock)
165 // {
166 // aProofOfLock.AssertOwns(mMutex);
167 // ...
168 // }
170 // Without this assertion, it could be that mMutex is not actually
171 // locked. It's possible to have code like:
173 // BaseAutoLock lock(someMutex);
174 // ...
175 // BaseAutoUnlock unlock(someMutex);
176 // ...
177 // LockedMethod(lock);
179 // and in such a case, simply asserting that the mutex pointers match is not
180 // sufficient; mutex ownership must be asserted as well.
182 // Note that if you are going to use the coding pattern presented above, you
183 // should use this method in preference to using AssertCurrentThreadOwns on
184 // the mutex you expected to be held, since this method provides stronger
185 // guarantees.
186 void AssertOwns(const T& aMutex) const {
187 MOZ_ASSERT(&aMutex == &mLock);
188 mLock.AssertCurrentThreadOwns();
191 private:
192 BaseAutoLock();
193 BaseAutoLock(BaseAutoLock&);
194 BaseAutoLock& operator=(BaseAutoLock&);
195 static void* operator new(size_t) noexcept(true);
197 friend class BaseAutoUnlock<T>;
199 T mLock;
202 template <typename MutexType>
203 BaseAutoLock(MutexType&) -> BaseAutoLock<MutexType&>;
204 } // namespace detail
206 typedef detail::BaseAutoLock<Mutex&> MutexAutoLock;
207 typedef detail::BaseAutoLock<OffTheBooksMutex&> OffTheBooksMutexAutoLock;
209 namespace detail {
211 * BaseAutoUnlock
212 * Releases the Mutex when it enters scope, and re-acquires it when it leaves
213 * scope.
215 * MUCH PREFERRED to bare calls to Mutex.Unlock and Lock.
217 template <typename T>
218 class MOZ_RAII BaseAutoUnlock {
219 public:
220 explicit BaseAutoUnlock(T aLock) : mLock(aLock) { mLock.Unlock(); }
222 explicit BaseAutoUnlock(BaseAutoLock<T>& aAutoLock) : mLock(aAutoLock.mLock) {
223 NS_ASSERTION(mLock, "null lock");
224 mLock->Unlock();
227 ~BaseAutoUnlock() { mLock.Lock(); }
229 private:
230 BaseAutoUnlock();
231 BaseAutoUnlock(BaseAutoUnlock&);
232 BaseAutoUnlock& operator=(BaseAutoUnlock&);
233 static void* operator new(size_t) noexcept(true);
235 T mLock;
238 template <typename MutexType>
239 BaseAutoUnlock(MutexType&) -> BaseAutoUnlock<MutexType&>;
240 } // namespace detail
242 typedef detail::BaseAutoUnlock<Mutex&> MutexAutoUnlock;
243 typedef detail::BaseAutoUnlock<OffTheBooksMutex&> OffTheBooksMutexAutoUnlock;
245 } // namespace mozilla
247 #endif // ifndef mozilla_Mutex_h