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
25QT_REQUIRE_CONFIG(thread);
26
27QT_BEGIN_NAMESPACE
28
29namespace QReadWriteLockStates {
30enum {
31 StateMask = 0x3,
32 StateLockedForRead = 0x1,
33 StateLockedForWrite = 0x2,
34};
35enum StateForWaitCondition {
36 LockedForRead,
37 LockedForWrite,
38 Unlocked,
39 RecursivelyLocked
40};
41}
42
43class QReadWriteLockPrivate
44{
45public:
46 explicit QReadWriteLockPrivate(bool isRecursive = false)
47 : recursive(isRecursive) {}
48
49 alignas(QtPrivate::IdealMutexAlignment) std::condition_variable writerCond;
50 std::condition_variable readerCond;
51
52 alignas(QtPrivate::IdealMutexAlignment) std::mutex mutex;
53 int readerCount = 0;
54 int writerCount = 0;
55 int waitingReaders = 0;
56 int waitingWriters = 0;
57 const bool recursive;
58
59 //Called with the mutex locked
60 bool lockForWrite(std::unique_lock<std::mutex> &lock, QDeadlineTimer timeout);
61 bool lockForRead(std::unique_lock<std::mutex> &lock, QDeadlineTimer timeout);
62 void unlock();
63
64 //memory management
65 int id = 0;
66 void release();
67 static QReadWriteLockPrivate *allocate();
68
69 // Recursive mutex handling
70 Qt::HANDLE currentWriter = {};
71
72 struct Reader {
73 Qt::HANDLE handle;
74 int recursionLevel;
75 };
76
77 QVarLengthArray<Reader, 16> currentReaders;
78
79 // called with the mutex unlocked
80 bool recursiveLockForWrite(QDeadlineTimer timeout);
81 bool recursiveLockForRead(QDeadlineTimer timeout);
82 void recursiveUnlock();
83
84 static QReadWriteLockStates::StateForWaitCondition
85 stateForWaitCondition(const QReadWriteLock *lock);
86};
87Q_DECLARE_TYPEINFO(QReadWriteLockPrivate::Reader, Q_PRIMITIVE_TYPE);\
88
89/*! \internal Helper for QWaitCondition::wait */
90inline QReadWriteLockStates::StateForWaitCondition
91QReadWriteLockPrivate::stateForWaitCondition(const QReadWriteLock *q)
92{
93 using namespace QReadWriteLockStates;
94 QReadWriteLockPrivate *d = q->d_ptr.loadAcquire();
95 switch (quintptr(d) & StateMask) {
96 case StateLockedForRead: return LockedForRead;
97 case StateLockedForWrite: return LockedForWrite;
98 }
99
100 if (!d)
101 return Unlocked;
102 const auto lock = qt_scoped_lock(mutex&: d->mutex);
103 if (d->writerCount > 1)
104 return RecursivelyLocked;
105 else if (d->writerCount == 1)
106 return LockedForWrite;
107 return LockedForRead;
108
109}
110
111QT_END_NAMESPACE
112
113#endif // QREADWRITELOCK_P_H
114

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