1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the test suite of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include <QtTest/QtTest>
30
31#include <QCoreApplication>
32#include <QReadLocker>
33#include <QSemaphore>
34#include <QThread>
35
36class tst_QReadLockerThread : public QThread
37{
38public:
39 QReadWriteLock lock;
40 QSemaphore semaphore, testSemaphore;
41
42 void waitForTest()
43 {
44 semaphore.release();
45 testSemaphore.acquire();
46 }
47};
48
49class tst_QReadLocker : public QObject
50{
51 Q_OBJECT
52
53public:
54 tst_QReadLockerThread *thread;
55
56 void waitForThread()
57 {
58 thread->semaphore.acquire();
59 }
60 void releaseThread()
61 {
62 thread->testSemaphore.release();
63 }
64
65private slots:
66 void scopeTest();
67 void unlockAndRelockTest();
68 void lockerStateTest();
69};
70
71void tst_QReadLocker::scopeTest()
72{
73 class ScopeTestThread : public tst_QReadLockerThread
74 {
75 public:
76 void run()
77 {
78 waitForTest();
79
80 {
81 QReadLocker locker(&lock);
82 waitForTest();
83 }
84
85 waitForTest();
86 }
87 };
88
89 thread = new ScopeTestThread;
90 thread->start();
91
92 waitForThread();
93 // lock should be unlocked before entering the scope that creates the QReadLocker
94 QVERIFY(thread->lock.tryLockForWrite());
95 thread->lock.unlock();
96 releaseThread();
97
98 waitForThread();
99 // lock should be locked by the QReadLocker
100 QVERIFY(!thread->lock.tryLockForWrite());
101 releaseThread();
102
103 waitForThread();
104 // lock should be unlocked when the QReadLocker goes out of scope
105 QVERIFY(thread->lock.tryLockForWrite());
106 thread->lock.unlock();
107 releaseThread();
108
109 QVERIFY(thread->wait());
110
111 delete thread;
112 thread = 0;
113}
114
115
116void tst_QReadLocker::unlockAndRelockTest()
117{
118 class UnlockAndRelockThread : public tst_QReadLockerThread
119 {
120 public:
121 void run()
122 {
123 QReadLocker locker(&lock);
124
125 waitForTest();
126
127 locker.unlock();
128
129 waitForTest();
130
131 locker.relock();
132
133 waitForTest();
134 }
135 };
136
137 thread = new UnlockAndRelockThread;
138 thread->start();
139
140 waitForThread();
141 // lock should be locked by the QReadLocker
142 QVERIFY(!thread->lock.tryLockForWrite());
143 releaseThread();
144
145 waitForThread();
146 // lock has been explicitly unlocked via QReadLocker
147 QVERIFY(thread->lock.tryLockForWrite());
148 thread->lock.unlock();
149 releaseThread();
150
151 waitForThread();
152 // lock has been explicitly relocked via QReadLocker
153 QVERIFY(!thread->lock.tryLockForWrite());
154 releaseThread();
155
156 QVERIFY(thread->wait());
157
158 delete thread;
159 thread = 0;
160}
161
162void tst_QReadLocker::lockerStateTest()
163{
164 class LockerStateThread : public tst_QReadLockerThread
165 {
166 public:
167 void run()
168 {
169 {
170 QReadLocker locker(&lock);
171 locker.relock();
172 locker.unlock();
173
174 waitForTest();
175 }
176
177 waitForTest();
178 }
179 };
180
181 thread = new LockerStateThread;
182 thread->start();
183
184 waitForThread();
185 // even though we relock() after creating the QReadLocker, it shouldn't lock the lock more than once
186 QVERIFY(thread->lock.tryLockForWrite());
187 thread->lock.unlock();
188 releaseThread();
189
190 waitForThread();
191 // if we call QReadLocker::unlock(), its destructor should do nothing
192 QVERIFY(thread->lock.tryLockForWrite());
193 thread->lock.unlock();
194 releaseThread();
195
196 QVERIFY(thread->wait());
197
198 delete thread;
199 thread = 0;
200}
201
202QTEST_MAIN(tst_QReadLocker)
203#include "tst_qreadlocker.moc"
204

source code of qtbase/tests/auto/corelib/thread/qreadlocker/tst_qreadlocker.cpp