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 <QMutexLocker>
33#include <QSemaphore>
34#include <QThread>
35
36class tst_QMutexLockerThread : public QThread
37{
38public:
39 QRecursiveMutex mutex;
40 QSemaphore semaphore, testSemaphore;
41
42 void waitForTest()
43 {
44 semaphore.release();
45 testSemaphore.acquire();
46 }
47
48};
49
50class tst_QMutexLocker : public QObject
51{
52 Q_OBJECT
53
54public:
55 tst_QMutexLockerThread *thread;
56
57 void waitForThread()
58 {
59 thread->semaphore.acquire();
60 }
61 void releaseThread()
62 {
63 thread->testSemaphore.release();
64 }
65
66private slots:
67 void scopeTest();
68 void unlockAndRelockTest();
69 void lockerStateTest();
70};
71
72void tst_QMutexLocker::scopeTest()
73{
74 class ScopeTestThread : public tst_QMutexLockerThread
75 {
76 public:
77 void run()
78 {
79 waitForTest();
80
81 {
82 QMutexLocker locker(&mutex);
83 waitForTest();
84 }
85
86 waitForTest();
87 }
88 };
89
90 thread = new ScopeTestThread;
91 thread->start();
92
93 waitForThread();
94 // mutex should be unlocked before entering the scope that creates the QMutexLocker
95 QVERIFY(thread->mutex.tryLock());
96 thread->mutex.unlock();
97 releaseThread();
98
99 waitForThread();
100 // mutex should be locked by the QMutexLocker
101 QVERIFY(!thread->mutex.tryLock());
102 releaseThread();
103
104 waitForThread();
105 // mutex should be unlocked when the QMutexLocker goes out of scope
106 QVERIFY(thread->mutex.tryLock());
107 thread->mutex.unlock();
108 releaseThread();
109
110 QVERIFY(thread->wait());
111
112 delete thread;
113 thread = 0;
114}
115
116
117void tst_QMutexLocker::unlockAndRelockTest()
118{
119 class UnlockAndRelockThread : public tst_QMutexLockerThread
120 {
121 public:
122 void run()
123 {
124 QMutexLocker locker(&mutex);
125
126 waitForTest();
127
128 locker.unlock();
129
130 waitForTest();
131
132 locker.relock();
133
134 waitForTest();
135 }
136 };
137
138 thread = new UnlockAndRelockThread;
139 thread->start();
140
141 waitForThread();
142 // mutex should be locked by the QMutexLocker
143 QVERIFY(!thread->mutex.tryLock());
144 releaseThread();
145
146 waitForThread();
147 // mutex has been explicitly unlocked via QMutexLocker
148 QVERIFY(thread->mutex.tryLock());
149 thread->mutex.unlock();
150 releaseThread();
151
152 waitForThread();
153 // mutex has been explicitly relocked via QMutexLocker
154 QVERIFY(!thread->mutex.tryLock());
155 releaseThread();
156
157 QVERIFY(thread->wait());
158
159 delete thread;
160 thread = 0;
161}
162
163void tst_QMutexLocker::lockerStateTest()
164{
165 class LockerStateThread : public tst_QMutexLockerThread
166 {
167 public:
168 void run()
169 {
170 {
171 QMutexLocker locker(&mutex);
172 locker.relock();
173 locker.unlock();
174
175 waitForTest();
176 }
177
178 waitForTest();
179 }
180 };
181
182 thread = new LockerStateThread;
183 thread->start();
184
185 waitForThread();
186 // even though we relock() after creating the QMutexLocker, it shouldn't lock the mutex more than once
187 QVERIFY(thread->mutex.tryLock());
188 thread->mutex.unlock();
189 releaseThread();
190
191 waitForThread();
192 // if we call QMutexLocker::unlock(), its destructor should do nothing
193 QVERIFY(thread->mutex.tryLock());
194 thread->mutex.unlock();
195 releaseThread();
196
197 QVERIFY(thread->wait());
198
199 delete thread;
200 thread = 0;
201}
202
203QTEST_MAIN(tst_QMutexLocker)
204#include "tst_qmutexlocker.moc"
205

source code of qtbase/tests/auto/corelib/thread/qmutexlocker/tst_qmutexlocker.cpp