Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qreadwritelock_p.h
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// Copyright (C) 2016 Olivier Goffart <ogoffart@woboq.com>
3// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4// Qt-Security score:significant reason:default
5
6#ifndef QREADWRITELOCK_P_H
7#define QREADWRITELOCK_P_H
8
9//
10// W A R N I N G
11// -------------
12//
13// This file is not part of the Qt API. It exists for the convenience
14// of the implementation. This header file may change from version to
15// version without notice, or even be removed.
16//
17// We mean it.
18//
19
20#include <QtCore/private/qlocking_p.h>
21#include <QtCore/private/qwaitcondition_p.h>
22#include <QtCore/qreadwritelock.h>
23#include <QtCore/qvarlengtharray.h>
24
26
27QT_BEGIN_NAMESPACE
28
29class QReadWriteLockPrivate
30{
31public:
32 // export the State constants protected in QReadWriteLock
33 static constexpr quintptr StateLockedForRead = QReadWriteLock::StateLockedForRead;
34 static constexpr quintptr StateLockedForWrite = QReadWriteLock::StateLockedForWrite;
35 static constexpr quintptr StateMask = QReadWriteLock::StateMask;
36 static constexpr quintptr MultiplyLocked = QReadWriteLock::Counter;
37 static constexpr quintptr IsRecursiveLock = MultiplyLocked << 1;
38 static constexpr quintptr RecursivelyLockedForWrite =
39 StateLockedForWrite | MultiplyLocked | IsRecursiveLock;
40
41 explicit QReadWriteLockPrivate(bool isRecursive = false)
42 : recursive(isRecursive) {}
43
44 alignas(QtPrivate::IdealMutexAlignment) std::condition_variable writerCond;
45 std::condition_variable readerCond;
46
47 alignas(QtPrivate::IdealMutexAlignment) std::mutex mutex;
48 int readerCount = 0;
49 int writerCount = 0;
50 int waitingReaders = 0;
51 int waitingWriters = 0;
52 const bool recursive;
53
54 //Called with the mutex locked
55 bool lockForWrite(std::unique_lock<std::mutex> &lock, QDeadlineTimer timeout);
56 bool lockForRead(std::unique_lock<std::mutex> &lock, QDeadlineTimer timeout);
57 void unlock();
58
59 //memory management
60 int id = 0;
61 void release();
62 static QReadWriteLockPrivate *allocate();
63
64 // Recursive mutex handling
65 Qt::HANDLE currentWriter = {};
66
67 struct Reader {
68 Qt::HANDLE handle;
69 int recursionLevel;
70 };
71
72 QVarLengthArray<Reader, 16> currentReaders;
73
74 // called with the mutex unlocked
75 bool recursiveLockForWrite(QDeadlineTimer timeout);
76 bool recursiveLockForRead(QDeadlineTimer timeout);
77 void recursiveUnlock();
78
79 /*!
80 * \internal
81 * Describes the state of the QReadWriteLock whose private is \a dd.
82 *
83 * Returns one of:
84 * \list
85 * \li 0 (unlocked)
86 * \li \c IsRecursiveLock (still unlocked)
87 * \li \c StateLockedForRead
88 * \li \c{StateLockedForRead | IsRecursiveLock}
89 * \li \c StateLockedForWrite
90 * \li \c{StateLockedForWrite | IsRecursiveLock}
91 * \li \c{StateLockedForWrite | IsRecursiveLock | MultiplyLocked} = \c RecursivelyLockedForWrite
92 * \endlist
93 */
94 static quintptr describeState(void *dd) noexcept
95 {
96 quintptr u = quintptr(dd);
97 if (u < StateMask) {
98 // non-recursive; unlocked or uncontended
99 return u;
100 }
101
102 auto d = static_cast<QReadWriteLockPrivate *>(dd);
103 const auto lock = qt_scoped_lock(d->mutex);
104 u = 0;
105 if (d->writerCount)
106 u |= StateLockedForWrite;
107 else if (d->readerCount)
108 u |= StateLockedForRead;
109 if (d->recursive) {
110 u |= IsRecursiveLock;
111 if (d->writerCount > 1) {
112 u |= MultiplyLocked;
113 Q_ASSERT(u == RecursivelyLockedForWrite);
114 }
115 } else {
116 // non-recursive, quick check of the state
117 Q_ASSERT(d->writerCount <= 1);
118 }
119 return u;
120 }
121
122 // used by QWaitCondition::wait
123 template <typename Prep, typename DoWait>
124 static bool waitConditionWait(QReadWriteLock *readWriteLock, Prep &&prep, DoWait &&doWait);
125};
126Q_DECLARE_TYPEINFO(QReadWriteLockPrivate::Reader, Q_PRIMITIVE_TYPE);
127
128template <typename Prep, typename DoWait>
129inline bool QReadWriteLockPrivate::waitConditionWait(QReadWriteLock *readWriteLock, Prep &&prep, DoWait &&doWait)
130{
131 if (!readWriteLock)
132 return false;
133 auto previousState = describeState(readWriteLock->d_ptr.loadAcquire());
134 if (previousState == 0) // unlocked
135 return false;
136 if (previousState == RecursivelyLockedForWrite) {
137 qWarning("QWaitCondition: cannot wait on QReadWriteLocks with recursive lockForWrite()");
138 return false;
139 }
140
141 prep();
142 readWriteLock->unlock();
143 bool returnValue = doWait();
144
145 // relock
146 if (previousState & StateLockedForWrite)
147 readWriteLock->lockForWrite();
148 else
149 readWriteLock->lockForRead();
150
151 return returnValue;
152}
153
154QT_END_NAMESPACE
155
156#endif // QREADWRITELOCK_P_H
QT_REQUIRE_CONFIG(liburing)
static Q_ALWAYS_INLINE bool fastTryLock(QAtomicPointer< QReadWriteLockPrivate > &d_ptr, QReadWriteLockPrivate *dummyValue, QReadWriteLockPrivate *&d)
static QT_BEGIN_NAMESPACE auto dummyLockedForRead()
static bool isUncontendedLocked(const QReadWriteLockPrivate *d)
static auto dummyLockedForWrite()
static auto handleEquals(Qt::HANDLE handle)
Q_DECLARE_TYPEINFO(QReadWriteLockPrivate::Reader, Q_PRIMITIVE_TYPE)