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 : // An interface for read-write locks.
8 :
9 : #ifndef mozilla_RWLock_h
10 : #define mozilla_RWLock_h
11 :
12 : #include "mozilla/Assertions.h"
13 : #include "mozilla/BlockingResourceBase.h"
14 : #include "mozilla/GuardObjects.h"
15 :
16 : #ifndef XP_WIN
17 : #include <pthread.h>
18 : #endif
19 :
20 : namespace mozilla {
21 :
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.
30 : //
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.
36 : //
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.
41 : //
42 : // It is unspecified whether RWLock gives priority to waiting readers or
43 : // a waiting writer when unlocking.
44 : class RWLock : public BlockingResourceBase
45 : {
46 : public:
47 : explicit RWLock(const char* aName);
48 :
49 : // Windows rwlocks don't need any special handling to be destroyed, but
50 : // POSIX ones do.
51 : #ifdef XP_WIN
52 : ~RWLock() = default;
53 : #else
54 : ~RWLock();
55 : #endif
56 :
57 : #ifdef DEBUG
58 : bool LockedForWritingByCurrentThread();
59 : void ReadLock();
60 : void ReadUnlock();
61 : void WriteLock();
62 : void WriteUnlock();
63 : #else
64 : void ReadLock() { ReadLockInternal(); }
65 : void ReadUnlock() { ReadUnlockInternal(); }
66 : void WriteLock() { WriteLockInternal(); }
67 : void WriteUnlock() { WriteUnlockInternal(); }
68 : #endif
69 :
70 : private:
71 : void ReadLockInternal();
72 : void ReadUnlockInternal();
73 : void WriteLockInternal();
74 : void WriteUnlockInternal();
75 :
76 : RWLock() = delete;
77 : RWLock(const RWLock&) = delete;
78 : RWLock& operator=(const RWLock&) = delete;
79 :
80 : #ifndef XP_WIN
81 : pthread_rwlock_t mRWLock;
82 : #else
83 : // SRWLock is pointer-sized. We declare it in such a fashion here to
84 : // avoid pulling in windows.h wherever this header is used.
85 : void* mRWLock;
86 : #endif
87 :
88 : #ifdef DEBUG
89 : // We record the owning thread for write locks only.
90 : PRThread* mOwningThread;
91 : #endif
92 : };
93 :
94 : // Read lock and unlock a RWLock with RAII semantics. Much preferred to bare
95 : // calls to ReadLock() and ReadUnlock().
96 : class MOZ_RAII AutoReadLock final
97 : {
98 : public:
99 0 : explicit AutoReadLock(RWLock& aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
100 0 : : mLock(&aLock)
101 : {
102 0 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
103 0 : MOZ_ASSERT(mLock, "null lock");
104 0 : mLock->ReadLock();
105 0 : }
106 :
107 0 : ~AutoReadLock()
108 0 : {
109 0 : mLock->ReadUnlock();
110 0 : }
111 :
112 : private:
113 : AutoReadLock() = delete;
114 : AutoReadLock(const AutoReadLock&) = delete;
115 : AutoReadLock& operator=(const AutoReadLock&) = delete;
116 :
117 : RWLock* mLock;
118 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
119 : };
120 :
121 : // Write lock and unlock a RWLock with RAII semantics. Much preferred to bare
122 : // calls to WriteLock() and WriteUnlock().
123 : class MOZ_RAII AutoWriteLock final
124 : {
125 : public:
126 0 : explicit AutoWriteLock(RWLock& aLock MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
127 0 : : mLock(&aLock)
128 : {
129 0 : MOZ_GUARD_OBJECT_NOTIFIER_INIT;
130 0 : MOZ_ASSERT(mLock, "null lock");
131 0 : mLock->WriteLock();
132 0 : }
133 :
134 0 : ~AutoWriteLock()
135 0 : {
136 0 : mLock->WriteUnlock();
137 0 : }
138 :
139 : private:
140 : AutoWriteLock() = delete;
141 : AutoWriteLock(const AutoWriteLock&) = delete;
142 : AutoWriteLock& operator=(const AutoWriteLock&) = delete;
143 :
144 : RWLock* mLock;
145 : MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
146 : };
147 :
148 : } // namespace mozilla
149 :
150 : #endif // mozilla_RWLock_h
|