Bug 1700051: part 49) Add some documentation to `Selection::GetRangesForInterval...
[gecko.git] / xpcom / threads / Mutex.h
blobe6d58806c9cab109e07e1bec70d50a1781b42fed
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"
12 #include "nsISupports.h"
15 // Provides:
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
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.
26 // Using MutexAutoLock/MutexAutoUnlock etc. is MUCH preferred to making bare
27 // calls to Lock and Unlock.
29 namespace mozilla {
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.
36 class OffTheBooksMutex : public detail::MutexImpl, BlockingResourceBase {
37 public:
38 /**
39 * @param aName A name which can reference this lock
40 * @returns If failure, nullptr
41 * If success, a valid Mutex* which must be destroyed
42 * by Mutex::DestroyMutex()
43 **/
44 explicit OffTheBooksMutex(const char* aName)
45 : BlockingResourceBase(aName, eMutex)
46 #ifdef DEBUG
48 mOwningThread(nullptr)
49 #endif
53 ~OffTheBooksMutex() {
54 #ifdef DEBUG
55 MOZ_ASSERT(!mOwningThread, "destroying a still-owned lock!");
56 #endif
59 #ifndef DEBUG
60 /**
61 * Lock this mutex.
62 **/
63 void Lock() { this->lock(); }
65 /**
66 * Try to lock this mutex, returning true if we were successful.
67 **/
68 [[nodiscard]] bool TryLock() { return this->tryLock(); }
70 /**
71 * Unlock this mutex.
72 **/
73 void Unlock() { this->unlock(); }
75 /**
76 * Assert that the current thread owns this mutex in debug builds.
78 * Does nothing in non-debug builds.
79 **/
80 void AssertCurrentThreadOwns() const {}
82 /**
83 * Assert that the current thread does not own this mutex.
85 * Note that this function is not implemented for debug builds *and*
86 * non-debug builds due to difficulties in dealing with memory ordering.
88 * It is therefore mostly useful as documentation.
89 **/
90 void AssertNotCurrentThreadOwns() const {}
92 #else
93 void Lock();
94 [[nodiscard]] bool TryLock();
95 void Unlock();
97 void AssertCurrentThreadOwns() const;
99 void AssertNotCurrentThreadOwns() const {
100 // FIXME bug 476536
103 #endif // ifndef DEBUG
105 private:
106 OffTheBooksMutex();
107 OffTheBooksMutex(const OffTheBooksMutex&);
108 OffTheBooksMutex& operator=(const OffTheBooksMutex&);
110 friend class OffTheBooksCondVar;
112 #ifdef DEBUG
113 PRThread* mOwningThread;
114 #endif
118 * Mutex
119 * When possible, use MutexAutoLock/MutexAutoUnlock to lock/unlock this
120 * mutex within a scope, instead of calling Lock/Unlock directly.
122 class Mutex : public OffTheBooksMutex {
123 public:
124 explicit Mutex(const char* aName) : OffTheBooksMutex(aName) {
125 MOZ_COUNT_CTOR(Mutex);
128 MOZ_COUNTED_DTOR(Mutex)
130 private:
131 Mutex();
132 Mutex(const Mutex&);
133 Mutex& operator=(const Mutex&);
136 namespace detail {
137 template <typename T>
138 class MOZ_RAII BaseAutoUnlock;
141 * MutexAutoLock
142 * Acquires the Mutex when it enters scope, and releases it when it leaves
143 * scope.
145 * MUCH PREFERRED to bare calls to Mutex.Lock and Unlock.
147 template <typename T>
148 class MOZ_RAII BaseAutoLock {
149 public:
151 * Constructor
152 * The constructor aquires the given lock. The destructor
153 * releases the lock.
155 * @param aLock A valid mozilla::Mutex* returned by
156 * mozilla::Mutex::NewMutex.
158 explicit BaseAutoLock(T aLock) : mLock(aLock) { mLock.Lock(); }
160 ~BaseAutoLock(void) { mLock.Unlock(); }
162 // Assert that aLock is the mutex passed to the constructor and that the
163 // current thread owns the mutex. In coding patterns such as:
165 // void LockedMethod(const BaseAutoLock<T>& aProofOfLock)
166 // {
167 // aProofOfLock.AssertOwns(mMutex);
168 // ...
169 // }
171 // Without this assertion, it could be that mMutex is not actually
172 // locked. It's possible to have code like:
174 // BaseAutoLock lock(someMutex);
175 // ...
176 // BaseAutoUnlock unlock(someMutex);
177 // ...
178 // LockedMethod(lock);
180 // and in such a case, simply asserting that the mutex pointers match is not
181 // sufficient; mutex ownership must be asserted as well.
183 // Note that if you are going to use the coding pattern presented above, you
184 // should use this method in preference to using AssertCurrentThreadOwns on
185 // the mutex you expected to be held, since this method provides stronger
186 // guarantees.
187 void AssertOwns(const T& aMutex) const {
188 MOZ_ASSERT(&aMutex == &mLock);
189 mLock.AssertCurrentThreadOwns();
192 private:
193 BaseAutoLock();
194 BaseAutoLock(BaseAutoLock&);
195 BaseAutoLock& operator=(BaseAutoLock&);
196 static void* operator new(size_t) noexcept(true);
198 friend class BaseAutoUnlock<T>;
200 T mLock;
203 template <typename MutexType>
204 BaseAutoLock(MutexType&) -> BaseAutoLock<MutexType&>;
205 } // namespace detail
207 typedef detail::BaseAutoLock<Mutex&> MutexAutoLock;
208 typedef detail::BaseAutoLock<OffTheBooksMutex&> OffTheBooksMutexAutoLock;
210 namespace detail {
212 * BaseAutoUnlock
213 * Releases the Mutex when it enters scope, and re-acquires it when it leaves
214 * scope.
216 * MUCH PREFERRED to bare calls to Mutex.Unlock and Lock.
218 template <typename T>
219 class MOZ_RAII BaseAutoUnlock {
220 public:
221 explicit BaseAutoUnlock(T aLock) : mLock(aLock) { mLock.Unlock(); }
223 explicit BaseAutoUnlock(BaseAutoLock<T>& aAutoLock) : mLock(aAutoLock.mLock) {
224 NS_ASSERTION(mLock, "null lock");
225 mLock->Unlock();
228 ~BaseAutoUnlock() { mLock.Lock(); }
230 private:
231 BaseAutoUnlock();
232 BaseAutoUnlock(BaseAutoUnlock&);
233 BaseAutoUnlock& operator=(BaseAutoUnlock&);
234 static void* operator new(size_t) noexcept(true);
236 T mLock;
239 template <typename MutexType>
240 BaseAutoUnlock(MutexType&) -> BaseAutoUnlock<MutexType&>;
241 } // namespace detail
243 typedef detail::BaseAutoUnlock<Mutex&> MutexAutoUnlock;
244 typedef detail::BaseAutoUnlock<OffTheBooksMutex&> OffTheBooksMutexAutoUnlock;
246 } // namespace mozilla
248 #endif // ifndef mozilla_Mutex_h