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
5#ifndef QREADWRITELOCK_P_H
6#define QREADWRITELOCK_P_H
7
8//
9// W A R N I N G
10// -------------
11//
12// This file is not part of the Qt API. It exists for the convenience
13// of the implementation. This header file may change from version to
14// version without notice, or even be removed.
15//
16// We mean it.
17//
18
19#include <QtCore/private/qlocking_p.h>
20#include <QtCore/private/qwaitcondition_p.h>
21#include <QtCore/qreadwritelock.h>
22#include <QtCore/qvarlengtharray.h>
23
24QT_REQUIRE_CONFIG(thread);
25
26QT_BEGIN_NAMESPACE
27
28namespace QReadWriteLockStates {
29enum {
30 StateMask = 0x3,
31 StateLockedForRead = 0x1,
32 StateLockedForWrite = 0x2,
33};
34enum StateForWaitCondition {
35 LockedForRead,
36 LockedForWrite,
37 Unlocked,
38 RecursivelyLocked
39};
40}
41
42class QReadWriteLockPrivate
43{
44public:
45 explicit QReadWriteLockPrivate(bool isRecursive = false)
46 : recursive(isRecursive) {}
47
48 QtPrivate::mutex mutex;
49 QtPrivate::condition_variable writerCond;
50 QtPrivate::condition_variable readerCond;
51 int readerCount = 0;
52 int writerCount = 0;
53 int waitingReaders = 0;
54 int waitingWriters = 0;
55 const bool recursive;
56
57 //Called with the mutex locked
58 bool lockForWrite(std::unique_lock<QtPrivate::mutex> &lock, QDeadlineTimer timeout);
59 bool lockForRead(std::unique_lock<QtPrivate::mutex> &lock, QDeadlineTimer timeout);
60 void unlock();
61
62 //memory management
63 int id = 0;
64 void release();
65 static QReadWriteLockPrivate *allocate();
66
67 // Recursive mutex handling
68 Qt::HANDLE currentWriter = {};
69
70 struct Reader {
71 Qt::HANDLE handle;
72 int recursionLevel;
73 };
74
75 QVarLengthArray<Reader, 16> currentReaders;
76
77 // called with the mutex unlocked
78 bool recursiveLockForWrite(QDeadlineTimer timeout);
79 bool recursiveLockForRead(QDeadlineTimer timeout);
80 void recursiveUnlock();
81
82 static QReadWriteLockStates::StateForWaitCondition
83 stateForWaitCondition(const QReadWriteLock *lock);
84};
85Q_DECLARE_TYPEINFO(QReadWriteLockPrivate::Reader, Q_PRIMITIVE_TYPE);\
86
87/*! \internal Helper for QWaitCondition::wait */
88inline QReadWriteLockStates::StateForWaitCondition
89QReadWriteLockPrivate::stateForWaitCondition(const QReadWriteLock *q)
90{
91 using namespace QReadWriteLockStates;
92 QReadWriteLockPrivate *d = q->d_ptr.loadAcquire();
93 switch (quintptr(d) & StateMask) {
94 case StateLockedForRead: return LockedForRead;
95 case StateLockedForWrite: return LockedForWrite;
96 }
97
98 if (!d)
99 return Unlocked;
100 const auto lock = qt_scoped_lock(mutex&: d->mutex);
101 if (d->writerCount > 1)
102 return RecursivelyLocked;
103 else if (d->writerCount == 1)
104 return LockedForWrite;
105 return LockedForRead;
106
107}
108
109QT_END_NAMESPACE
110
111#endif // QREADWRITELOCK_P_H
112

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