1 | // Copyright (C) 2016 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only |
3 | |
4 | #ifndef QREADWRITELOCK_H |
5 | #define QREADWRITELOCK_H |
6 | |
7 | #include <QtCore/qglobal.h> |
8 | #include <QtCore/qdeadlinetimer.h> |
9 | |
10 | QT_BEGIN_NAMESPACE |
11 | |
12 | #if QT_CONFIG(thread) |
13 | |
14 | class QReadWriteLockPrivate; |
15 | |
16 | class Q_CORE_EXPORT QReadWriteLock |
17 | { |
18 | public: |
19 | enum RecursionMode { NonRecursive, Recursive }; |
20 | |
21 | QT_CORE_INLINE_SINCE(6, 6) |
22 | explicit QReadWriteLock(RecursionMode recursionMode = NonRecursive); |
23 | QT_CORE_INLINE_SINCE(6, 6) |
24 | ~QReadWriteLock(); |
25 | |
26 | QT_CORE_INLINE_SINCE(6, 6) |
27 | void lockForRead(); |
28 | #if QT_CORE_REMOVED_SINCE(6, 6) |
29 | bool tryLockForRead(); |
30 | #endif |
31 | QT_CORE_INLINE_SINCE(6, 6) |
32 | bool tryLockForRead(int timeout); |
33 | bool tryLockForRead(QDeadlineTimer timeout = {}); |
34 | |
35 | QT_CORE_INLINE_SINCE(6, 6) |
36 | void lockForWrite(); |
37 | #if QT_CORE_REMOVED_SINCE(6, 6) |
38 | bool tryLockForWrite(); |
39 | #endif |
40 | QT_CORE_INLINE_SINCE(6, 6) |
41 | bool tryLockForWrite(int timeout); |
42 | bool tryLockForWrite(QDeadlineTimer timeout = {}); |
43 | |
44 | void unlock(); |
45 | |
46 | private: |
47 | Q_DISABLE_COPY(QReadWriteLock) |
48 | QAtomicPointer<QReadWriteLockPrivate> d_ptr; |
49 | friend class QReadWriteLockPrivate; |
50 | static QReadWriteLockPrivate *initRecursive(); |
51 | static void destroyRecursive(QReadWriteLockPrivate *); |
52 | }; |
53 | |
54 | #if QT_CORE_INLINE_IMPL_SINCE(6, 6) |
55 | QReadWriteLock::QReadWriteLock(RecursionMode recursionMode) |
56 | : d_ptr(recursionMode == Recursive ? initRecursive() : nullptr) |
57 | { |
58 | } |
59 | |
60 | QReadWriteLock::~QReadWriteLock() |
61 | { |
62 | if (auto d = d_ptr.loadAcquire()) |
63 | destroyRecursive(d); |
64 | } |
65 | |
66 | void QReadWriteLock::lockForRead() |
67 | { |
68 | tryLockForRead(timeout: QDeadlineTimer(QDeadlineTimer::Forever)); |
69 | } |
70 | |
71 | bool QReadWriteLock::tryLockForRead(int timeout) |
72 | { |
73 | return tryLockForRead(timeout: QDeadlineTimer(timeout)); |
74 | } |
75 | |
76 | void QReadWriteLock::lockForWrite() |
77 | { |
78 | tryLockForWrite(timeout: QDeadlineTimer(QDeadlineTimer::Forever)); |
79 | } |
80 | |
81 | bool QReadWriteLock::tryLockForWrite(int timeout) |
82 | { |
83 | return tryLockForWrite(timeout: QDeadlineTimer(timeout)); |
84 | } |
85 | #endif // inline since 6.6 |
86 | |
87 | #if defined(Q_CC_MSVC) |
88 | #pragma warning( push ) |
89 | #pragma warning( disable : 4312 ) // ignoring the warning from /Wp64 |
90 | #endif |
91 | |
92 | class QT6_ONLY(Q_CORE_EXPORT) QReadLocker |
93 | { |
94 | public: |
95 | Q_NODISCARD_CTOR |
96 | inline QReadLocker(QReadWriteLock *readWriteLock); |
97 | |
98 | inline ~QReadLocker() |
99 | { unlock(); } |
100 | |
101 | inline void unlock() |
102 | { |
103 | if (q_val) { |
104 | if ((q_val & quintptr(1u)) == quintptr(1u)) { |
105 | q_val &= ~quintptr(1u); |
106 | readWriteLock()->unlock(); |
107 | } |
108 | } |
109 | } |
110 | |
111 | inline void relock() |
112 | { |
113 | if (q_val) { |
114 | if ((q_val & quintptr(1u)) == quintptr(0u)) { |
115 | readWriteLock()->lockForRead(); |
116 | q_val |= quintptr(1u); |
117 | } |
118 | } |
119 | } |
120 | |
121 | inline QReadWriteLock *readWriteLock() const |
122 | { return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); } |
123 | |
124 | private: |
125 | Q_DISABLE_COPY(QReadLocker) |
126 | quintptr q_val; |
127 | }; |
128 | |
129 | inline QReadLocker::QReadLocker(QReadWriteLock *areadWriteLock) |
130 | : q_val(reinterpret_cast<quintptr>(areadWriteLock)) |
131 | { |
132 | Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0), |
133 | "QReadLocker" , "QReadWriteLock pointer is misaligned" ); |
134 | relock(); |
135 | } |
136 | |
137 | class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker |
138 | { |
139 | public: |
140 | Q_NODISCARD_CTOR |
141 | inline QWriteLocker(QReadWriteLock *readWriteLock); |
142 | |
143 | inline ~QWriteLocker() |
144 | { unlock(); } |
145 | |
146 | inline void unlock() |
147 | { |
148 | if (q_val) { |
149 | if ((q_val & quintptr(1u)) == quintptr(1u)) { |
150 | q_val &= ~quintptr(1u); |
151 | readWriteLock()->unlock(); |
152 | } |
153 | } |
154 | } |
155 | |
156 | inline void relock() |
157 | { |
158 | if (q_val) { |
159 | if ((q_val & quintptr(1u)) == quintptr(0u)) { |
160 | readWriteLock()->lockForWrite(); |
161 | q_val |= quintptr(1u); |
162 | } |
163 | } |
164 | } |
165 | |
166 | inline QReadWriteLock *readWriteLock() const |
167 | { return reinterpret_cast<QReadWriteLock *>(q_val & ~quintptr(1u)); } |
168 | |
169 | |
170 | private: |
171 | Q_DISABLE_COPY(QWriteLocker) |
172 | quintptr q_val; |
173 | }; |
174 | |
175 | inline QWriteLocker::QWriteLocker(QReadWriteLock *areadWriteLock) |
176 | : q_val(reinterpret_cast<quintptr>(areadWriteLock)) |
177 | { |
178 | Q_ASSERT_X((q_val & quintptr(1u)) == quintptr(0), |
179 | "QWriteLocker" , "QReadWriteLock pointer is misaligned" ); |
180 | relock(); |
181 | } |
182 | |
183 | #if defined(Q_CC_MSVC) |
184 | #pragma warning( pop ) |
185 | #endif |
186 | |
187 | #else // QT_CONFIG(thread) |
188 | |
189 | class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock |
190 | { |
191 | public: |
192 | enum RecursionMode { NonRecursive, Recursive }; |
193 | inline explicit QReadWriteLock(RecursionMode = NonRecursive) noexcept { } |
194 | inline ~QReadWriteLock() { } |
195 | |
196 | void lockForRead() noexcept { } |
197 | bool tryLockForRead() noexcept { return true; } |
198 | bool tryLockForRead(QDeadlineTimer) noexcept { return true; } |
199 | bool tryLockForRead(int timeout) noexcept { Q_UNUSED(timeout); return true; } |
200 | |
201 | void lockForWrite() noexcept { } |
202 | bool tryLockForWrite() noexcept { return true; } |
203 | bool tryLockForWrite(QDeadlineTimer) noexcept { return true; } |
204 | bool tryLockForWrite(int timeout) noexcept { Q_UNUSED(timeout); return true; } |
205 | |
206 | void unlock() noexcept { } |
207 | |
208 | private: |
209 | Q_DISABLE_COPY(QReadWriteLock) |
210 | }; |
211 | |
212 | class QT6_ONLY(Q_CORE_EXPORT) QReadLocker |
213 | { |
214 | public: |
215 | Q_NODISCARD_CTOR |
216 | inline explicit QReadLocker(QReadWriteLock *) noexcept { } |
217 | inline ~QReadLocker() noexcept { } |
218 | |
219 | void unlock() noexcept { } |
220 | void relock() noexcept { } |
221 | QReadWriteLock *readWriteLock() noexcept { return nullptr; } |
222 | |
223 | private: |
224 | Q_DISABLE_COPY(QReadLocker) |
225 | }; |
226 | |
227 | class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker |
228 | { |
229 | public: |
230 | Q_NODISCARD_CTOR |
231 | inline explicit QWriteLocker(QReadWriteLock *) noexcept { } |
232 | inline ~QWriteLocker() noexcept { } |
233 | |
234 | void unlock() noexcept { } |
235 | void relock() noexcept { } |
236 | QReadWriteLock *readWriteLock() noexcept { return nullptr; } |
237 | |
238 | private: |
239 | Q_DISABLE_COPY(QWriteLocker) |
240 | }; |
241 | |
242 | #endif // QT_CONFIG(thread) |
243 | |
244 | QT_END_NAMESPACE |
245 | |
246 | #endif // QREADWRITELOCK_H |
247 | |