~ubuntu-branches/ubuntu/wily/qtbase-opensource-src/wily

« back to all changes in this revision

Viewing changes to tests/auto/corelib/thread/qmutex/tst_qmutex.cpp

  • Committer: Package Import Robot
  • Author(s): Timo Jyrinki
  • Date: 2013-02-05 12:46:17 UTC
  • Revision ID: package-import@ubuntu.com-20130205124617-c8jouts182j002fx
Tags: upstream-5.0.1+dfsg
ImportĀ upstreamĀ versionĀ 5.0.1+dfsg

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/****************************************************************************
 
2
**
 
3
** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
 
4
** Contact: http://www.qt-project.org/legal
 
5
**
 
6
** This file is part of the test suite of the Qt Toolkit.
 
7
**
 
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.
 
16
**
 
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.
 
24
**
 
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.
 
28
**
 
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.
 
36
**
 
37
**
 
38
** $QT_END_LICENSE$
 
39
**
 
40
****************************************************************************/
 
41
 
 
42
#include <QtTest/QtTest>
 
43
 
 
44
#include <qatomic.h>
 
45
#include <qcoreapplication.h>
 
46
#include <qdatetime.h>
 
47
#include <qmutex.h>
 
48
#include <qthread.h>
 
49
#include <qwaitcondition.h>
 
50
 
 
51
class tst_QMutex : public QObject
 
52
{
 
53
    Q_OBJECT
 
54
private slots:
 
55
    void tryLock();
 
56
    void lock_unlock_locked_tryLock();
 
57
    void stressTest();
 
58
    void tryLockRace();
 
59
    void tryLockDeadlock();
 
60
    void tryLockNegative_data();
 
61
    void tryLockNegative();
 
62
    void moreStress();
 
63
};
 
64
 
 
65
static const int iterations = 100;
 
66
 
 
67
QAtomicInt lockCount(0);
 
68
QMutex normalMutex, recursiveMutex(QMutex::Recursive);
 
69
QSemaphore testsTurn;
 
70
QSemaphore threadsTurn;
 
71
 
 
72
enum { waitTime = 100 };
 
73
 
 
74
void tst_QMutex::tryLock()
 
75
{
 
76
    // test non-recursive mutex
 
77
    {
 
78
        class Thread : public QThread
 
79
        {
 
80
        public:
 
81
            void run()
 
82
            {
 
83
                testsTurn.release();
 
84
 
 
85
                // TEST 1: thread can't acquire lock
 
86
                threadsTurn.acquire();
 
87
                QVERIFY(!normalMutex.tryLock());
 
88
                testsTurn.release();
 
89
 
 
90
                // TEST 2: thread can acquire lock
 
91
                threadsTurn.acquire();
 
92
                QVERIFY(normalMutex.tryLock());
 
93
                QVERIFY(lockCount.testAndSetRelaxed(0, 1));
 
94
                QVERIFY(!normalMutex.tryLock());
 
95
                QVERIFY(lockCount.testAndSetRelaxed(1, 0));
 
96
                normalMutex.unlock();
 
97
                testsTurn.release();
 
98
 
 
99
                // TEST 3: thread can't acquire lock, timeout = waitTime
 
100
                threadsTurn.acquire();
 
101
                QTime timer;
 
102
                timer.start();
 
103
                QVERIFY(!normalMutex.tryLock(waitTime));
 
104
                QVERIFY(timer.elapsed() >= waitTime);
 
105
                testsTurn.release();
 
106
 
 
107
                // TEST 4: thread can acquire lock, timeout = waitTime
 
108
                threadsTurn.acquire();
 
109
                timer.start();
 
110
                QVERIFY(normalMutex.tryLock(waitTime));
 
111
                QVERIFY(timer.elapsed() <= waitTime);
 
112
                QVERIFY(lockCount.testAndSetRelaxed(0, 1));
 
113
                timer.start();
 
114
                // it's non-recursive, so the following lock needs to fail
 
115
                QVERIFY(!normalMutex.tryLock(waitTime));
 
116
                QVERIFY(timer.elapsed() >= waitTime);
 
117
                QVERIFY(lockCount.testAndSetRelaxed(1, 0));
 
118
                normalMutex.unlock();
 
119
                testsTurn.release();
 
120
 
 
121
                // TEST 5: thread can't acquire lock, timeout = 0
 
122
                threadsTurn.acquire();
 
123
                QVERIFY(!normalMutex.tryLock(0));
 
124
                testsTurn.release();
 
125
 
 
126
                // TEST 6: thread can acquire lock, timeout = 0
 
127
                threadsTurn.acquire();
 
128
                timer.start();
 
129
                QVERIFY(normalMutex.tryLock(0));
 
130
                QVERIFY(timer.elapsed() < waitTime);
 
131
                QVERIFY(lockCount.testAndSetRelaxed(0, 1));
 
132
                QVERIFY(!normalMutex.tryLock(0));
 
133
                QVERIFY(lockCount.testAndSetRelaxed(1, 0));
 
134
                normalMutex.unlock();
 
135
                testsTurn.release();
 
136
 
 
137
                // TEST 7 overflow: thread can acquire lock, timeout = 3000 (QTBUG-24795)
 
138
                threadsTurn.acquire();
 
139
                timer.start();
 
140
                QVERIFY(normalMutex.tryLock(3000));
 
141
                QVERIFY(timer.elapsed() < 3000);
 
142
                normalMutex.unlock();
 
143
                testsTurn.release();
 
144
 
 
145
                threadsTurn.acquire();
 
146
            }
 
147
        };
 
148
 
 
149
        Thread thread;
 
150
        thread.start();
 
151
 
 
152
        // TEST 1: thread can't acquire lock
 
153
        testsTurn.acquire();
 
154
        normalMutex.lock();
 
155
        QVERIFY(lockCount.testAndSetRelaxed(0, 1));
 
156
        threadsTurn.release();
 
157
 
 
158
        // TEST 2: thread can acquire lock
 
159
        testsTurn.acquire();
 
160
        QVERIFY(lockCount.testAndSetRelaxed(1, 0));
 
161
        normalMutex.unlock();
 
162
        threadsTurn.release();
 
163
 
 
164
        // TEST 3: thread can't acquire lock, timeout = waitTime
 
165
        testsTurn.acquire();
 
166
        normalMutex.lock();
 
167
        QVERIFY(lockCount.testAndSetRelaxed(0, 1));
 
168
        threadsTurn.release();
 
169
 
 
170
        // TEST 4: thread can acquire lock, timeout = waitTime
 
171
        testsTurn.acquire();
 
172
        QVERIFY(lockCount.testAndSetRelaxed(1, 0));
 
173
        normalMutex.unlock();
 
174
        threadsTurn.release();
 
175
 
 
176
        // TEST 5: thread can't acquire lock, timeout = 0
 
177
        testsTurn.acquire();
 
178
        normalMutex.lock();
 
179
        QVERIFY(lockCount.testAndSetRelaxed(0, 1));
 
180
        threadsTurn.release();
 
181
 
 
182
        // TEST 6: thread can acquire lock, timeout = 0
 
183
        testsTurn.acquire();
 
184
        QVERIFY(lockCount.testAndSetRelaxed(1, 0));
 
185
        normalMutex.unlock();
 
186
        threadsTurn.release();
 
187
 
 
188
        // TEST 7: thread can acquire lock, timeout = 3000   (QTBUG-24795)
 
189
        testsTurn.acquire();
 
190
        normalMutex.lock();
 
191
        threadsTurn.release();
 
192
        QThread::msleep(100);
 
193
        normalMutex.unlock();
 
194
 
 
195
        // wait for thread to finish
 
196
        testsTurn.acquire();
 
197
        threadsTurn.release();
 
198
        thread.wait();
 
199
    }
 
200
 
 
201
    // test recursive mutex
 
202
    {
 
203
        class Thread : public QThread
 
204
        {
 
205
        public:
 
206
            void run()
 
207
            {
 
208
                testsTurn.release();
 
209
 
 
210
                threadsTurn.acquire();
 
211
                QVERIFY(!recursiveMutex.tryLock());
 
212
                testsTurn.release();
 
213
 
 
214
                threadsTurn.acquire();
 
215
                QVERIFY(recursiveMutex.tryLock());
 
216
                QVERIFY(lockCount.testAndSetRelaxed(0, 1));
 
217
                QVERIFY(recursiveMutex.tryLock());
 
218
                QVERIFY(lockCount.testAndSetRelaxed(1, 2));
 
219
                QVERIFY(lockCount.testAndSetRelaxed(2, 1));
 
220
                recursiveMutex.unlock();
 
221
                QVERIFY(lockCount.testAndSetRelaxed(1, 0));
 
222
                recursiveMutex.unlock();
 
223
                testsTurn.release();
 
224
 
 
225
                threadsTurn.acquire();
 
226
                QTime timer;
 
227
                timer.start();
 
228
                QVERIFY(!recursiveMutex.tryLock(waitTime));
 
229
                QVERIFY(timer.elapsed() >= waitTime);
 
230
                QVERIFY(!recursiveMutex.tryLock(0));
 
231
                testsTurn.release();
 
232
 
 
233
                threadsTurn.acquire();
 
234
                timer.start();
 
235
                QVERIFY(recursiveMutex.tryLock(waitTime));
 
236
                QVERIFY(timer.elapsed() <= waitTime);
 
237
                QVERIFY(lockCount.testAndSetRelaxed(0, 1));
 
238
                QVERIFY(recursiveMutex.tryLock(waitTime));
 
239
                QVERIFY(lockCount.testAndSetRelaxed(1, 2));
 
240
                QVERIFY(lockCount.testAndSetRelaxed(2, 1));
 
241
                recursiveMutex.unlock();
 
242
                QVERIFY(lockCount.testAndSetRelaxed(1, 0));
 
243
                recursiveMutex.unlock();
 
244
                testsTurn.release();
 
245
 
 
246
                threadsTurn.acquire();
 
247
                QVERIFY(!recursiveMutex.tryLock(0));
 
248
                QVERIFY(!recursiveMutex.tryLock(0));
 
249
                testsTurn.release();
 
250
 
 
251
                threadsTurn.acquire();
 
252
                timer.start();
 
253
                QVERIFY(recursiveMutex.tryLock(0));
 
254
                QVERIFY(timer.elapsed() < waitTime);
 
255
                QVERIFY(lockCount.testAndSetRelaxed(0, 1));
 
256
                QVERIFY(recursiveMutex.tryLock(0));
 
257
                QVERIFY(lockCount.testAndSetRelaxed(1, 2));
 
258
                QVERIFY(lockCount.testAndSetRelaxed(2, 1));
 
259
                recursiveMutex.unlock();
 
260
                QVERIFY(lockCount.testAndSetRelaxed(1, 0));
 
261
                recursiveMutex.unlock();
 
262
                testsTurn.release();
 
263
 
 
264
                threadsTurn.acquire();
 
265
            }
 
266
        };
 
267
 
 
268
        Thread thread;
 
269
        thread.start();
 
270
 
 
271
        // thread can't acquire lock
 
272
        testsTurn.acquire();
 
273
        recursiveMutex.lock();
 
274
        QVERIFY(lockCount.testAndSetRelaxed(0, 1));
 
275
        recursiveMutex.lock();
 
276
        QVERIFY(lockCount.testAndSetRelaxed(1, 2));
 
277
        threadsTurn.release();
 
278
 
 
279
        // thread can acquire lock
 
280
        testsTurn.acquire();
 
281
        QVERIFY(lockCount.testAndSetRelaxed(2, 1));
 
282
        recursiveMutex.unlock();
 
283
        QVERIFY(lockCount.testAndSetRelaxed(1, 0));
 
284
        recursiveMutex.unlock();
 
285
        threadsTurn.release();
 
286
 
 
287
        // thread can't acquire lock, timeout = waitTime
 
288
        testsTurn.acquire();
 
289
        recursiveMutex.lock();
 
290
        QVERIFY(lockCount.testAndSetRelaxed(0, 1));
 
291
        recursiveMutex.lock();
 
292
        QVERIFY(lockCount.testAndSetRelaxed(1, 2));
 
293
        threadsTurn.release();
 
294
 
 
295
        // thread can acquire lock, timeout = waitTime
 
296
        testsTurn.acquire();
 
297
        QVERIFY(lockCount.testAndSetRelaxed(2, 1));
 
298
        recursiveMutex.unlock();
 
299
        QVERIFY(lockCount.testAndSetRelaxed(1, 0));
 
300
        recursiveMutex.unlock();
 
301
        threadsTurn.release();
 
302
 
 
303
        // thread can't acquire lock, timeout = 0
 
304
        testsTurn.acquire();
 
305
        recursiveMutex.lock();
 
306
        QVERIFY(lockCount.testAndSetRelaxed(0, 1));
 
307
        recursiveMutex.lock();
 
308
        QVERIFY(lockCount.testAndSetRelaxed(1, 2));
 
309
        threadsTurn.release();
 
310
 
 
311
        // thread can acquire lock, timeout = 0
 
312
        testsTurn.acquire();
 
313
        QVERIFY(lockCount.testAndSetRelaxed(2, 1));
 
314
        recursiveMutex.unlock();
 
315
        QVERIFY(lockCount.testAndSetRelaxed(1, 0));
 
316
        recursiveMutex.unlock();
 
317
        threadsTurn.release();
 
318
 
 
319
        // stop thread
 
320
        testsTurn.acquire();
 
321
        threadsTurn.release();
 
322
        thread.wait();
 
323
    }
 
324
}
 
325
 
 
326
class mutex_Thread : public QThread
 
327
{
 
328
public:
 
329
    QMutex mutex;
 
330
    QWaitCondition cond;
 
331
 
 
332
    QMutex &test_mutex;
 
333
 
 
334
    inline mutex_Thread(QMutex &m) : test_mutex(m) { }
 
335
 
 
336
    void run()
 
337
    {
 
338
        test_mutex.lock();
 
339
 
 
340
        mutex.lock();
 
341
        for (int i = 0; i < iterations; ++i) {
 
342
            cond.wakeOne();
 
343
            cond.wait(&mutex);
 
344
        }
 
345
        mutex.unlock();
 
346
 
 
347
        test_mutex.unlock();
 
348
    }
 
349
};
 
350
 
 
351
class rmutex_Thread : public QThread
 
352
{
 
353
public:
 
354
    QMutex mutex;
 
355
    QWaitCondition cond;
 
356
 
 
357
    QMutex &test_mutex;
 
358
 
 
359
    inline rmutex_Thread(QMutex &m) : test_mutex(m) { }
 
360
 
 
361
    void run()
 
362
    {
 
363
        test_mutex.lock();
 
364
        test_mutex.lock();
 
365
        test_mutex.lock();
 
366
        test_mutex.lock();
 
367
 
 
368
        mutex.lock();
 
369
        for (int i = 0; i < iterations; ++i) {
 
370
            cond.wakeOne();
 
371
            cond.wait(&mutex);
 
372
        }
 
373
        mutex.unlock();
 
374
 
 
375
        test_mutex.unlock();
 
376
        test_mutex.unlock();
 
377
        test_mutex.unlock();
 
378
        test_mutex.unlock();
 
379
    }
 
380
};
 
381
 
 
382
void tst_QMutex::lock_unlock_locked_tryLock()
 
383
{
 
384
    // normal mutex
 
385
    QMutex mutex;
 
386
    mutex_Thread thread(mutex);
 
387
 
 
388
    QMutex rmutex(QMutex::Recursive);
 
389
    rmutex_Thread rthread(rmutex);
 
390
 
 
391
    for (int i = 0; i < iterations; ++i) {
 
392
        // normal mutex
 
393
        QVERIFY(mutex.tryLock());
 
394
        mutex.unlock();
 
395
 
 
396
        thread.mutex.lock();
 
397
        thread.start();
 
398
 
 
399
        for (int j = 0; j < iterations; ++j) {
 
400
            QVERIFY(thread.cond.wait(&thread.mutex, 10000));
 
401
            QVERIFY(!mutex.tryLock());
 
402
 
 
403
            thread.cond.wakeOne();
 
404
        }
 
405
 
 
406
        thread.mutex.unlock();
 
407
 
 
408
        QVERIFY(thread.wait(10000));
 
409
        QVERIFY(mutex.tryLock());
 
410
 
 
411
        mutex.unlock();
 
412
 
 
413
        // recursive mutex
 
414
        QVERIFY(rmutex.tryLock());
 
415
        QVERIFY(rmutex.tryLock());
 
416
        QVERIFY(rmutex.tryLock());
 
417
        QVERIFY(rmutex.tryLock());
 
418
 
 
419
        rmutex.unlock();
 
420
        rmutex.unlock();
 
421
        rmutex.unlock();
 
422
        rmutex.unlock();
 
423
 
 
424
        rthread.mutex.lock();
 
425
        rthread.start();
 
426
 
 
427
        for (int k = 0; k < iterations; ++k) {
 
428
            QVERIFY(rthread.cond.wait(&rthread.mutex, 10000));
 
429
            QVERIFY(!rmutex.tryLock());
 
430
 
 
431
            rthread.cond.wakeOne();
 
432
        }
 
433
 
 
434
        rthread.mutex.unlock();
 
435
 
 
436
        QVERIFY(rthread.wait(10000));
 
437
        QVERIFY(rmutex.tryLock());
 
438
        QVERIFY(rmutex.tryLock());
 
439
        QVERIFY(rmutex.tryLock());
 
440
        QVERIFY(rmutex.tryLock());
 
441
 
 
442
        rmutex.unlock();
 
443
        rmutex.unlock();
 
444
        rmutex.unlock();
 
445
        rmutex.unlock();
 
446
    }
 
447
}
 
448
 
 
449
enum { one_minute = 6 * 1000, //not really one minute, but else it is too long.
 
450
       threadCount = 10 };
 
451
 
 
452
class StressTestThread : public QThread
 
453
{
 
454
    QTime t;
 
455
public:
 
456
    static QBasicAtomicInt lockCount;
 
457
    static QBasicAtomicInt sentinel;
 
458
    static QMutex mutex;
 
459
    static int errorCount;
 
460
    void start()
 
461
    {
 
462
        t.start();
 
463
        QThread::start();
 
464
    }
 
465
    void run()
 
466
    {
 
467
        while (t.elapsed() < one_minute) {
 
468
            mutex.lock();
 
469
            if (sentinel.ref()) ++errorCount;
 
470
            if (!sentinel.deref()) ++errorCount;
 
471
            lockCount.ref();
 
472
            mutex.unlock();
 
473
            if (mutex.tryLock()) {
 
474
                if (sentinel.ref()) ++errorCount;
 
475
                if (!sentinel.deref()) ++errorCount;
 
476
                lockCount.ref();
 
477
                mutex.unlock();
 
478
            }
 
479
        }
 
480
    }
 
481
};
 
482
QMutex StressTestThread::mutex;
 
483
QBasicAtomicInt StressTestThread::lockCount = Q_BASIC_ATOMIC_INITIALIZER(0);
 
484
QBasicAtomicInt StressTestThread::sentinel = Q_BASIC_ATOMIC_INITIALIZER(-1);
 
485
int StressTestThread::errorCount = 0;
 
486
 
 
487
void tst_QMutex::stressTest()
 
488
{
 
489
    StressTestThread threads[threadCount];
 
490
    for (int i = 0; i < threadCount; ++i)
 
491
        threads[i].start();
 
492
    QVERIFY(threads[0].wait(one_minute + 10000));
 
493
    for (int i = 1; i < threadCount; ++i)
 
494
        QVERIFY(threads[i].wait(10000));
 
495
    QCOMPARE(StressTestThread::errorCount, 0);
 
496
    qDebug("locked %d times", int(StressTestThread::lockCount.load()));
 
497
}
 
498
 
 
499
class TryLockRaceThread : public QThread
 
500
{
 
501
public:
 
502
    static QMutex mutex;
 
503
 
 
504
    void run()
 
505
    {
 
506
        QTime t;
 
507
        t.start();
 
508
        do {
 
509
            if (mutex.tryLock())
 
510
                mutex.unlock();
 
511
        } while (t.elapsed() < one_minute/2);
 
512
    }
 
513
};
 
514
QMutex TryLockRaceThread::mutex;
 
515
 
 
516
void tst_QMutex::tryLockRace()
 
517
{
 
518
    // mutex not in use, should be able to lock it
 
519
    QVERIFY(TryLockRaceThread::mutex.tryLock());
 
520
    TryLockRaceThread::mutex.unlock();
 
521
 
 
522
    // try to break tryLock
 
523
    TryLockRaceThread thread[threadCount];
 
524
    for (int i = 0; i < threadCount; ++i)
 
525
        thread[i].start();
 
526
    for (int i = 0; i < threadCount; ++i)
 
527
        QVERIFY(thread[i].wait());
 
528
 
 
529
    // mutex not in use, should be able to lock it
 
530
    QVERIFY(TryLockRaceThread::mutex.tryLock());
 
531
    TryLockRaceThread::mutex.unlock();
 
532
}
 
533
 
 
534
// The following is a regression test for QTBUG-16115, where QMutex could
 
535
// deadlock after calling tryLock repeatedly.
 
536
 
 
537
// Variable that will be protected by the mutex. Volatile so that the
 
538
// the optimiser doesn't mess with it based on the increment-then-decrement
 
539
// usage pattern.
 
540
static volatile int tryLockDeadlockCounter;
 
541
// Counter for how many times the protected variable has an incorrect value.
 
542
static int tryLockDeadlockFailureCount = 0;
 
543
 
 
544
void tst_QMutex::tryLockDeadlock()
 
545
{
 
546
    //Used to deadlock on unix
 
547
    struct TrylockThread : QThread {
 
548
        TrylockThread(QMutex &mut) : mut(mut) {}
 
549
        QMutex &mut;
 
550
        void run() {
 
551
            for (int i = 0; i < 100000; ++i) {
 
552
                if (mut.tryLock(0)) {
 
553
                    if ((++tryLockDeadlockCounter) != 1)
 
554
                        ++tryLockDeadlockFailureCount;
 
555
                    if ((--tryLockDeadlockCounter) != 0)
 
556
                        ++tryLockDeadlockFailureCount;
 
557
                    mut.unlock();
 
558
                }
 
559
            }
 
560
        }
 
561
    };
 
562
    QMutex mut;
 
563
    TrylockThread t1(mut);
 
564
    TrylockThread t2(mut);
 
565
    TrylockThread t3(mut);
 
566
    t1.start();
 
567
    t2.start();
 
568
    t3.start();
 
569
 
 
570
    for (int i = 0; i < 100000; ++i) {
 
571
        mut.lock();
 
572
        if ((++tryLockDeadlockCounter) != 1)
 
573
            ++tryLockDeadlockFailureCount;
 
574
        if ((--tryLockDeadlockCounter) != 0)
 
575
            ++tryLockDeadlockFailureCount;
 
576
        mut.unlock();
 
577
    }
 
578
    t1.wait();
 
579
    t2.wait();
 
580
    t3.wait();
 
581
    QCOMPARE(tryLockDeadlockFailureCount, 0);
 
582
}
 
583
 
 
584
void tst_QMutex::tryLockNegative_data()
 
585
{
 
586
    QTest::addColumn<int>("timeout");
 
587
    QTest::newRow("-1") << -1;
 
588
    QTest::newRow("-2") << -2;
 
589
    QTest::newRow("INT_MIN/2") << INT_MIN/2;
 
590
    QTest::newRow("INT_MIN") << INT_MIN;
 
591
}
 
592
 
 
593
void tst_QMutex::tryLockNegative()
 
594
{
 
595
    // the documentation says tryLock() with a negative number is the same as lock()
 
596
    struct TrylockThread : QThread {
 
597
        TrylockThread(QMutex &mut, int timeout)
 
598
            : mut(mut), timeout(timeout), tryLockResult(-1)
 
599
        {}
 
600
        QMutex &mut;
 
601
        int timeout;
 
602
        int tryLockResult;
 
603
        void run() {
 
604
            tryLockResult = mut.tryLock(timeout);
 
605
            mut.unlock();
 
606
        }
 
607
    };
 
608
 
 
609
    QFETCH(int, timeout);
 
610
 
 
611
    QMutex mutex;
 
612
    TrylockThread thr(mutex, timeout);
 
613
    QSignalSpy spy(&thr, SIGNAL(started()));
 
614
    mutex.lock();
 
615
    thr.start();
 
616
 
 
617
    // the thread should have stopped in tryLock(), waiting for us to unlock
 
618
    // the mutex. The following test can be falsely positive due to timing:
 
619
    // tryLock may still fail but hasn't failed yet. But it certainly cannot be
 
620
    // a false negative: if wait() returns, tryLock failed.
 
621
    QVERIFY(!thr.wait(200));
 
622
 
 
623
    // after we unlock the mutex, the thread should succeed in locking, then
 
624
    // unlock and exit. Do this before more tests to avoid deadlocking due to
 
625
    // ~QThread waiting forever on a thread that won't exit.
 
626
    mutex.unlock();
 
627
 
 
628
    QCOMPARE(spy.count(), 1);
 
629
    QVERIFY(thr.wait());
 
630
    QCOMPARE(thr.tryLockResult, 1);
 
631
}
 
632
 
 
633
 
 
634
class MoreStressTestThread : public QThread
 
635
{
 
636
    QTime t;
 
637
public:
 
638
    static QAtomicInt lockCount;
 
639
    static QAtomicInt sentinel[threadCount];
 
640
    static QMutex mutex[threadCount];
 
641
    static QAtomicInt errorCount;
 
642
    void start()
 
643
    {
 
644
        t.start();
 
645
        QThread::start();
 
646
    }
 
647
    void run()
 
648
    {
 
649
        quint64 i = 0;
 
650
        while (t.elapsed() < one_minute) {
 
651
            i++;
 
652
            uint nb = (i * 9 + lockCount.load() * 13) % threadCount;
 
653
            QMutexLocker locker(&mutex[nb]);
 
654
            if (sentinel[nb].load()) errorCount.ref();
 
655
            if (sentinel[nb].fetchAndAddRelaxed(5)) errorCount.ref();
 
656
            if (!sentinel[nb].testAndSetRelaxed(5, 0)) errorCount.ref();
 
657
            if (sentinel[nb].load()) errorCount.ref();
 
658
            lockCount.ref();
 
659
            nb = (nb * 17 + i * 5 + lockCount.load() * 3) % threadCount;
 
660
            if (mutex[nb].tryLock()) {
 
661
                if (sentinel[nb].load()) errorCount.ref();
 
662
                if (sentinel[nb].fetchAndAddRelaxed(16)) errorCount.ref();
 
663
                if (!sentinel[nb].testAndSetRelaxed(16, 0)) errorCount.ref();
 
664
                if (sentinel[nb].load()) errorCount.ref();
 
665
                lockCount.ref();
 
666
                mutex[nb].unlock();
 
667
            }
 
668
            nb = (nb * 15 + i * 47 + lockCount.load() * 31) % threadCount;
 
669
            if (mutex[nb].tryLock(2)) {
 
670
                if (sentinel[nb].load()) errorCount.ref();
 
671
                if (sentinel[nb].fetchAndAddRelaxed(53)) errorCount.ref();
 
672
                if (!sentinel[nb].testAndSetRelaxed(53, 0)) errorCount.ref();
 
673
                if (sentinel[nb].load()) errorCount.ref();
 
674
                lockCount.ref();
 
675
                mutex[nb].unlock();
 
676
            }
 
677
        }
 
678
    }
 
679
};
 
680
QMutex MoreStressTestThread::mutex[threadCount];
 
681
QAtomicInt MoreStressTestThread::lockCount;
 
682
QAtomicInt MoreStressTestThread::sentinel[threadCount];
 
683
QAtomicInt MoreStressTestThread::errorCount = 0;
 
684
 
 
685
void tst_QMutex::moreStress()
 
686
{
 
687
    MoreStressTestThread threads[threadCount];
 
688
    for (int i = 0; i < threadCount; ++i)
 
689
        threads[i].start();
 
690
    QVERIFY(threads[0].wait(one_minute + 10000));
 
691
    for (int i = 1; i < threadCount; ++i)
 
692
        QVERIFY(threads[i].wait(10000));
 
693
    qDebug("locked %d times", MoreStressTestThread::lockCount.load());
 
694
    QCOMPARE(MoreStressTestThread::errorCount.load(), 0);
 
695
}
 
696
 
 
697
 
 
698
QTEST_MAIN(tst_QMutex)
 
699
#include "tst_qmutex.moc"