1
/****************************************************************************
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4
** Contact: http://www.qt-project.org/legal
6
** This file is part of the test suite of the Qt Toolkit.
8
** $QT_BEGIN_LICENSE:LGPL$
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 Digia. For licensing terms and
14
** conditions see http://qt.digia.com/licensing. For further information
15
** use the contact form at http://qt.digia.com/contact-us.
17
** GNU Lesser General Public License Usage
18
** Alternatively, this file may be used under the terms of the GNU Lesser
19
** General Public License version 2.1 as published by the Free Software
20
** Foundation and appearing in the file LICENSE.LGPL included in the
21
** packaging of this file. Please review the following information to
22
** ensure the GNU Lesser General Public License version 2.1 requirements
23
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25
** In addition, as a special exception, Digia gives you certain additional
26
** rights. These rights are described in the Digia Qt LGPL Exception
27
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29
** GNU General Public License Usage
30
** Alternatively, this file may be used under the terms of the GNU
31
** General Public License version 3.0 as published by the Free Software
32
** Foundation and appearing in the file LICENSE.GPL included in the
33
** packaging of this file. Please review the following information to
34
** ensure the GNU General Public License version 3.0 requirements will be
35
** met: http://www.gnu.org/copyleft/gpl.html.
40
****************************************************************************/
42
#include <QtCore/QtCore>
43
#include <QtTest/QtTest>
49
#if defined(Q_OS_UNIX)
50
#if !defined(USE_SEM_T)
53
typedef pthread_mutex_t NativeMutexType;
54
void NativeMutexInitialize(NativeMutexType *mutex)
56
pthread_mutex_init(mutex, NULL);
58
void NativeMutexDestroy(NativeMutexType *mutex)
60
pthread_mutex_destroy(mutex);
62
void NativeMutexLock(NativeMutexType *mutex)
64
pthread_mutex_lock(mutex);
66
void NativeMutexUnlock(NativeMutexType *mutex)
68
pthread_mutex_unlock(mutex);
71
# include <semaphore.h>
72
typedef sem_t NativeMutexType;
73
void NativeMutexInitialize(NativeMutexType *mutex)
75
sem_init(mutex, false, 1);
77
void NativeMutexDestroy(NativeMutexType *mutex)
81
void NativeMutexLock(NativeMutexType *mutex)
85
void NativeMutexUnlock(NativeMutexType *mutex)
90
#elif defined(Q_OS_WIN)
91
# define _WIN32_WINNT 0x0400
93
typedef CRITICAL_SECTION NativeMutexType;
94
void NativeMutexInitialize(NativeMutexType *mutex)
96
InitializeCriticalSection(mutex);
98
void NativeMutexDestroy(NativeMutexType *mutex)
100
DeleteCriticalSection(mutex);
102
void NativeMutexLock(NativeMutexType *mutex)
104
EnterCriticalSection(mutex);
106
void NativeMutexUnlock(NativeMutexType *mutex)
108
LeaveCriticalSection(mutex);
112
class tst_QMutex : public QObject
119
// barriers for the contended tests
120
static QSemaphore semaphore1, semaphore2, semaphore3, semaphore4;
124
// at least 2 threads, even on single cpu/core machines
125
threadCount = qMax(2, QThread::idealThreadCount());
126
qDebug("thread count: %d", threadCount);
130
void noThread_data();
133
void constructionNative();
134
void uncontendedNative();
135
void constructionQMutex();
136
void uncontendedQMutex();
137
void uncontendedQMutexLocker();
139
void contendedNative_data();
140
void contendedQMutex_data() { contendedNative_data(); }
141
void contendedQMutexLocker_data() { contendedNative_data(); }
143
void contendedNative();
144
void contendedQMutex();
145
void contendedQMutexLocker();
148
QSemaphore tst_QMutex::semaphore1;
149
QSemaphore tst_QMutex::semaphore2;
150
QSemaphore tst_QMutex::semaphore3;
151
QSemaphore tst_QMutex::semaphore4;
153
void tst_QMutex::noThread_data()
155
QTest::addColumn<int>("t");
157
QTest::newRow("noLock") << 1;
158
QTest::newRow("QMutex") << 3;
159
QTest::newRow("QMutexLocker") << 4;
162
void tst_QMutex::noThread()
164
volatile int count = 0;
165
const int N = 5000000;
173
for (int i = 0; i < N; i++) {
181
for (int i = 0; i < N; i++) {
191
for (int i = 0; i < N; i++) {
192
QMutexLocker locker(&mtx);
198
QCOMPARE(int(count), N);
201
void tst_QMutex::constructionNative()
204
NativeMutexType mutex;
205
NativeMutexInitialize(&mutex);
206
NativeMutexDestroy(&mutex);
210
void tst_QMutex::uncontendedNative()
212
NativeMutexType mutex;
213
NativeMutexInitialize(&mutex);
215
NativeMutexLock(&mutex);
216
NativeMutexUnlock(&mutex);
218
NativeMutexDestroy(&mutex);
221
void tst_QMutex::constructionQMutex()
229
void tst_QMutex::uncontendedQMutex()
238
void tst_QMutex::uncontendedQMutexLocker()
242
QMutexLocker locker(&mutex);
246
void tst_QMutex::contendedNative_data()
248
QTest::addColumn<int>("iterations");
249
QTest::addColumn<int>("msleepDuration");
250
QTest::addColumn<bool>("use2mutexes");
252
QTest::newRow("baseline") << 0 << -1 << false;
254
QTest::newRow("no msleep, 1 mutex") << 1000 << -1 << false;
255
QTest::newRow("no msleep, 2 mutexes") << 1000 << -1 << true;
256
QTest::newRow("msleep(0), 1 mutex") << 1000 << 0 << false;
257
QTest::newRow("msleep(0), 2 mutexes") << 1000 << 0 << true;
258
QTest::newRow("msleep(1), 1 mutex") << 10 << 1 << false;
259
QTest::newRow("msleep(1), 2 mutexes") << 10 << 1 << true;
260
QTest::newRow("msleep(2), 1 mutex") << 10 << 2 << false;
261
QTest::newRow("msleep(2), 2 mutexes") << 10 << 2 << true;
262
QTest::newRow("msleep(10), 1 mutex") << 10 << 10 << false;
263
QTest::newRow("msleep(10), 2 mutexes") << 10 << 10 << true;
266
class NativeMutexThread : public QThread
268
NativeMutexType *mutex1, *mutex2;
269
int iterations, msleepDuration;
273
NativeMutexThread(NativeMutexType *mutex1, NativeMutexType *mutex2, int iterations, int msleepDuration, bool use2mutexes)
274
: mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false)
278
tst_QMutex::semaphore1.release();
279
tst_QMutex::semaphore2.acquire();
282
for (int i = 0; i < iterations; ++i) {
283
NativeMutexLock(mutex1);
285
NativeMutexLock(mutex2);
286
if (msleepDuration >= 0)
287
msleep(msleepDuration);
289
NativeMutexUnlock(mutex2);
290
NativeMutexUnlock(mutex1);
292
QThread::yieldCurrentThread();
294
tst_QMutex::semaphore3.release();
295
tst_QMutex::semaphore4.acquire();
300
void tst_QMutex::contendedNative()
302
QFETCH(int, iterations);
303
QFETCH(int, msleepDuration);
304
QFETCH(bool, use2mutexes);
306
NativeMutexType mutex1, mutex2;
307
NativeMutexInitialize(&mutex1);
308
NativeMutexInitialize(&mutex2);
310
QVector<NativeMutexThread *> threads(threadCount);
311
for (int i = 0; i < threads.count(); ++i) {
312
threads[i] = new NativeMutexThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes);
317
semaphore1.acquire(threadCount);
318
semaphore2.release(threadCount);
319
semaphore3.acquire(threadCount);
320
semaphore4.release(threadCount);
323
for (int i = 0; i < threads.count(); ++i)
324
threads[i]->done = true;
325
semaphore1.acquire(threadCount);
326
semaphore2.release(threadCount);
327
for (int i = 0; i < threads.count(); ++i)
331
NativeMutexDestroy(&mutex1);
332
NativeMutexDestroy(&mutex2);
335
class QMutexThread : public QThread
337
QMutex *mutex1, *mutex2;
338
int iterations, msleepDuration;
342
QMutexThread(QMutex *mutex1, QMutex *mutex2, int iterations, int msleepDuration, bool use2mutexes)
343
: mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false)
347
tst_QMutex::semaphore1.release();
348
tst_QMutex::semaphore2.acquire();
351
for (int i = 0; i < iterations; ++i) {
355
if (msleepDuration >= 0)
356
msleep(msleepDuration);
361
QThread::yieldCurrentThread();
363
tst_QMutex::semaphore3.release();
364
tst_QMutex::semaphore4.acquire();
369
void tst_QMutex::contendedQMutex()
371
QFETCH(int, iterations);
372
QFETCH(int, msleepDuration);
373
QFETCH(bool, use2mutexes);
375
QMutex mutex1, mutex2;
377
QVector<QMutexThread *> threads(threadCount);
378
for (int i = 0; i < threads.count(); ++i) {
379
threads[i] = new QMutexThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes);
384
semaphore1.acquire(threadCount);
385
semaphore2.release(threadCount);
386
semaphore3.acquire(threadCount);
387
semaphore4.release(threadCount);
390
for (int i = 0; i < threads.count(); ++i)
391
threads[i]->done = true;
392
semaphore1.acquire(threadCount);
393
semaphore2.release(threadCount);
394
for (int i = 0; i < threads.count(); ++i)
399
class QMutexLockerThread : public QThread
401
QMutex *mutex1, *mutex2;
402
int iterations, msleepDuration;
406
QMutexLockerThread(QMutex *mutex1, QMutex *mutex2, int iterations, int msleepDuration, bool use2mutexes)
407
: mutex1(mutex1), mutex2(mutex2), iterations(iterations), msleepDuration(msleepDuration), use2mutexes(use2mutexes), done(false)
411
tst_QMutex::semaphore1.release();
412
tst_QMutex::semaphore2.acquire();
415
for (int i = 0; i < iterations; ++i) {
417
QMutexLocker locker1(mutex1);
418
QMutexLocker locker2(use2mutexes ? mutex2 : 0);
419
if (msleepDuration >= 0)
420
msleep(msleepDuration);
423
QThread::yieldCurrentThread();
425
tst_QMutex::semaphore3.release();
426
tst_QMutex::semaphore4.acquire();
431
void tst_QMutex::contendedQMutexLocker()
433
QFETCH(int, iterations);
434
QFETCH(int, msleepDuration);
435
QFETCH(bool, use2mutexes);
437
QMutex mutex1, mutex2;
439
QVector<QMutexLockerThread *> threads(threadCount);
440
for (int i = 0; i < threads.count(); ++i) {
441
threads[i] = new QMutexLockerThread(&mutex1, &mutex2, iterations, msleepDuration, use2mutexes);
446
semaphore1.acquire(threadCount);
447
semaphore2.release(threadCount);
448
semaphore3.acquire(threadCount);
449
semaphore4.release(threadCount);
452
for (int i = 0; i < threads.count(); ++i)
453
threads[i]->done = true;
454
semaphore1.acquire(threadCount);
455
semaphore2.release(threadCount);
456
for (int i = 0; i < threads.count(); ++i)
461
QTEST_MAIN(tst_QMutex)
462
#include "tst_qmutex.moc"