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
10QT_BEGIN_NAMESPACE
11
12#if QT_CONFIG(thread)
13
14class QReadWriteLockPrivate;
15
16class Q_CORE_EXPORT QReadWriteLock
17{
18public:
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
46private:
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)
55QReadWriteLock::QReadWriteLock(RecursionMode recursionMode)
56 : d_ptr(recursionMode == Recursive ? initRecursive() : nullptr)
57{
58}
59
60QReadWriteLock::~QReadWriteLock()
61{
62 if (auto d = d_ptr.loadAcquire())
63 destroyRecursive(d);
64}
65
66void QReadWriteLock::lockForRead()
67{
68 tryLockForRead(timeout: QDeadlineTimer(QDeadlineTimer::Forever));
69}
70
71bool QReadWriteLock::tryLockForRead(int timeout)
72{
73 return tryLockForRead(timeout: QDeadlineTimer(timeout));
74}
75
76void QReadWriteLock::lockForWrite()
77{
78 tryLockForWrite(timeout: QDeadlineTimer(QDeadlineTimer::Forever));
79}
80
81bool 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
92class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
93{
94public:
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
124private:
125 Q_DISABLE_COPY(QReadLocker)
126 quintptr q_val;
127};
128
129inline 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
137class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
138{
139public:
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
170private:
171 Q_DISABLE_COPY(QWriteLocker)
172 quintptr q_val;
173};
174
175inline 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
189class QT6_ONLY(Q_CORE_EXPORT) QReadWriteLock
190{
191public:
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
208private:
209 Q_DISABLE_COPY(QReadWriteLock)
210};
211
212class QT6_ONLY(Q_CORE_EXPORT) QReadLocker
213{
214public:
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
223private:
224 Q_DISABLE_COPY(QReadLocker)
225};
226
227class QT6_ONLY(Q_CORE_EXPORT) QWriteLocker
228{
229public:
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
238private:
239 Q_DISABLE_COPY(QWriteLocker)
240};
241
242#endif // QT_CONFIG(thread)
243
244QT_END_NAMESPACE
245
246#endif // QREADWRITELOCK_H
247

source code of qtbase/src/corelib/thread/qreadwritelock.h