Bug 1755481: correct documentation of `nsIClipboard::getData`. r=mccr8
[gecko.git] / xpcom / threads / RWLock.h
blobad6103480bdd1b77924f0d6df39e7b126391db17
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 // An interface for read-write locks.
9 #ifndef mozilla_RWLock_h
10 #define mozilla_RWLock_h
12 #include "mozilla/Assertions.h"
13 #include "mozilla/Atomics.h"
14 #include "mozilla/BlockingResourceBase.h"
16 #ifndef XP_WIN
17 # include <pthread.h>
18 #endif
20 namespace mozilla {
22 // A RWLock is similar to a Mutex, but whereas a Mutex permits only a single
23 // reader thread or a single writer thread to access a piece of data, a
24 // RWLock distinguishes between readers and writers: you may have multiple
25 // reader threads concurrently accessing a piece of data or a single writer
26 // thread. This difference should guide your usage of RWLock: if you are not
27 // reading the data from multiple threads simultaneously or you are writing
28 // to the data roughly as often as read from it, then Mutex will suit your
29 // purposes just fine.
31 // You should be using the AutoReadLock and AutoWriteLock classes, below,
32 // for RAII read locking and write locking, respectively. If you really must
33 // take a read lock manually, call the ReadLock method; to relinquish that
34 // read lock, call the ReadUnlock method. Similarly, WriteLock and WriteUnlock
35 // perform the same operations, but for write locks.
37 // It is unspecified what happens when a given thread attempts to acquire the
38 // same lock in multiple ways; some underlying implementations of RWLock do
39 // support acquiring a read lock multiple times on a given thread, but you
40 // should not rely on this behavior.
42 // It is unspecified whether RWLock gives priority to waiting readers or
43 // a waiting writer when unlocking.
44 class RWLock : public BlockingResourceBase {
45 public:
46 explicit RWLock(const char* aName);
48 // Windows rwlocks don't need any special handling to be destroyed, but
49 // POSIX ones do.
50 #ifdef XP_WIN
51 ~RWLock() = default;
52 #else
53 ~RWLock();
54 #endif
56 #ifdef DEBUG
57 bool LockedForWritingByCurrentThread();
58 bool TryReadLock();
59 void ReadLock();
60 void ReadUnlock();
61 bool TryWriteLock();
62 void WriteLock();
63 void WriteUnlock();
64 #else
65 bool TryReadLock() { return TryReadLockInternal(); }
66 void ReadLock() { ReadLockInternal(); }
67 void ReadUnlock() { ReadUnlockInternal(); }
68 bool TryWriteLock() { return TryWriteLockInternal(); }
69 void WriteLock() { WriteLockInternal(); }
70 void WriteUnlock() { WriteUnlockInternal(); }
71 #endif
73 private:
74 bool TryReadLockInternal();
75 void ReadLockInternal();
76 void ReadUnlockInternal();
77 bool TryWriteLockInternal();
78 void WriteLockInternal();
79 void WriteUnlockInternal();
81 RWLock() = delete;
82 RWLock(const RWLock&) = delete;
83 RWLock& operator=(const RWLock&) = delete;
85 #ifndef XP_WIN
86 pthread_rwlock_t mRWLock;
87 #else
88 // SRWLock is pointer-sized. We declare it in such a fashion here to
89 // avoid pulling in windows.h wherever this header is used.
90 void* mRWLock;
91 #endif
93 #ifdef DEBUG
94 // We record the owning thread for write locks only.
95 PRThread* mOwningThread;
96 #endif
99 template <typename T>
100 class MOZ_RAII BaseAutoTryReadLock {
101 public:
102 explicit BaseAutoTryReadLock(T& aLock)
103 : mLock(aLock.TryReadLock() ? &aLock : nullptr) {}
105 ~BaseAutoTryReadLock() {
106 if (mLock) {
107 mLock->ReadUnlock();
111 explicit operator bool() const { return mLock; }
113 private:
114 BaseAutoTryReadLock() = delete;
115 BaseAutoTryReadLock(const BaseAutoTryReadLock&) = delete;
116 BaseAutoTryReadLock& operator=(const BaseAutoTryReadLock&) = delete;
118 T* mLock;
121 template <typename T>
122 class MOZ_RAII BaseAutoReadLock {
123 public:
124 explicit BaseAutoReadLock(T& aLock) : mLock(&aLock) {
125 MOZ_ASSERT(mLock, "null lock");
126 mLock->ReadLock();
129 ~BaseAutoReadLock() { mLock->ReadUnlock(); }
131 private:
132 BaseAutoReadLock() = delete;
133 BaseAutoReadLock(const BaseAutoReadLock&) = delete;
134 BaseAutoReadLock& operator=(const BaseAutoReadLock&) = delete;
136 T* mLock;
139 template <typename T>
140 class MOZ_RAII BaseAutoTryWriteLock {
141 public:
142 explicit BaseAutoTryWriteLock(T& aLock)
143 : mLock(aLock.TryWriteLock() ? &aLock : nullptr) {}
145 ~BaseAutoTryWriteLock() {
146 if (mLock) {
147 mLock->WriteUnlock();
151 explicit operator bool() const { return mLock; }
153 private:
154 BaseAutoTryWriteLock() = delete;
155 BaseAutoTryWriteLock(const BaseAutoTryWriteLock&) = delete;
156 BaseAutoTryWriteLock& operator=(const BaseAutoTryWriteLock&) = delete;
158 T* mLock;
161 template <typename T>
162 class MOZ_RAII BaseAutoWriteLock final {
163 public:
164 explicit BaseAutoWriteLock(T& aLock) : mLock(&aLock) {
165 MOZ_ASSERT(mLock, "null lock");
166 mLock->WriteLock();
169 ~BaseAutoWriteLock() { mLock->WriteUnlock(); }
171 private:
172 BaseAutoWriteLock() = delete;
173 BaseAutoWriteLock(const BaseAutoWriteLock&) = delete;
174 BaseAutoWriteLock& operator=(const BaseAutoWriteLock&) = delete;
176 T* mLock;
179 // Read try-lock and unlock a RWLock with RAII semantics. Much preferred to
180 // bare calls to TryReadLock() and ReadUnlock().
181 typedef BaseAutoTryReadLock<RWLock> AutoTryReadLock;
183 // Read lock and unlock a RWLock with RAII semantics. Much preferred to bare
184 // calls to ReadLock() and ReadUnlock().
185 typedef BaseAutoReadLock<RWLock> AutoReadLock;
187 // Write try-lock and unlock a RWLock with RAII semantics. Much preferred to
188 // bare calls to TryWriteLock() and WriteUnlock().
189 typedef BaseAutoTryWriteLock<RWLock> AutoTryWriteLock;
191 // Write lock and unlock a RWLock with RAII semantics. Much preferred to bare
192 // calls to WriteLock() and WriteUnlock().
193 typedef BaseAutoWriteLock<RWLock> AutoWriteLock;
195 // XXX: normally we would define StaticRWLock as
196 // MOZ_ONLY_USED_TO_AVOID_STATIC_CONSTRUCTORS, but the contexts in which it
197 // is used (e.g. member variables in a third-party library) are non-trivial
198 // to modify to properly declare everything at static scope. As those
199 // third-party libraries are the only clients, put it behind the detail
200 // namespace to discourage other (possibly erroneous) uses from popping up.
202 namespace detail {
204 class StaticRWLock {
205 public:
206 // In debug builds, check that mLock is initialized for us as we expect by
207 // the compiler. In non-debug builds, don't declare a constructor so that
208 // the compiler can see that the constructor is trivial.
209 #ifdef DEBUG
210 StaticRWLock() { MOZ_ASSERT(!mLock); }
211 #endif
213 bool TryReadLock() { return Lock()->TryReadLock(); }
214 void ReadLock() { Lock()->ReadLock(); }
215 void ReadUnlock() { Lock()->ReadUnlock(); }
216 bool TryWriteLock() { return Lock()->TryWriteLock(); }
217 void WriteLock() { Lock()->WriteLock(); }
218 void WriteUnlock() { Lock()->WriteUnlock(); }
220 private:
221 RWLock* Lock() {
222 if (mLock) {
223 return mLock;
226 RWLock* lock = new RWLock("StaticRWLock");
227 if (!mLock.compareExchange(nullptr, lock)) {
228 delete lock;
231 return mLock;
234 Atomic<RWLock*> mLock;
236 // Disallow copy constructor, but only in debug mode. We only define
237 // a default constructor in debug mode (see above); if we declared
238 // this constructor always, the compiler wouldn't generate a trivial
239 // default constructor for us in non-debug mode.
240 #ifdef DEBUG
241 StaticRWLock(const StaticRWLock& aOther);
242 #endif
244 // Disallow these operators.
245 StaticRWLock& operator=(StaticRWLock* aRhs);
246 static void* operator new(size_t) noexcept(true);
247 static void operator delete(void*);
250 typedef BaseAutoTryReadLock<StaticRWLock> StaticAutoTryReadLock;
251 typedef BaseAutoReadLock<StaticRWLock> StaticAutoReadLock;
252 typedef BaseAutoTryWriteLock<StaticRWLock> StaticAutoTryWriteLock;
253 typedef BaseAutoWriteLock<StaticRWLock> StaticAutoWriteLock;
255 } // namespace detail
257 } // namespace mozilla
259 #endif // mozilla_RWLock_h