1 /****************************************************************************
2 **
3 ** Copyright (C) 2015 The Qt Company Ltd.
4 ** Contact: http://www.qt.io/licensing/
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 The Qt Company. For licensing terms
14 ** and conditions see http://www.qt.io/terms-conditions. For further
15 ** information use the contact form at http://www.qt.io/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 or version 3 as published by the Free
20 ** Software Foundation and appearing in the file LICENSE.LGPLv21 and
21 ** LICENSE.LGPLv3 included in the packaging of this file. Please review the
22 ** following information to ensure the GNU Lesser General Public License
23 ** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
24 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25 **
26 ** As a special exception, The Qt Company gives you certain additional
27 ** rights. These rights are described in The Qt Company LGPL Exception
28 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29 **
30 ** GNU General Public License Usage
31 ** Alternatively, this file may be used under the terms of the GNU
32 ** General Public License version 3.0 as published by the Free Software
33 ** Foundation and appearing in the file LICENSE.GPL included in the
34 ** packaging of this file.  Please review the following information to
35 ** ensure the GNU General Public License version 3.0 requirements will be
36 ** met: http://www.gnu.org/copyleft/gpl.html.
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 
43 #include <QtTest/QtTest>
44 
45 #include <qcoreapplication.h>
46 #include <qmutex.h>
47 #include <qthread.h>
48 #include <qwaitcondition.h>
49 
50 #if defined(Q_OS_SYMBIAN)
51 // Symbian Open C has a bug that causes very short waits to fail sometimes
52 #define COND_WAIT_TIME 50
53 #else
54 #define COND_WAIT_TIME 1
55 #endif
56 
57 
58 //TESTED_CLASS=
59 //TESTED_FILES=
60 
61 class tst_QWaitCondition : public QObject
62 {
63     Q_OBJECT
64 
65 public:
66     tst_QWaitCondition();
67 
68 private slots:
69     void wait_QMutex();
70     void wait_QReadWriteLock();
71     void wakeOne();
72     void wakeAll();
73     void wait_RaceCondition();
74 };
75 
76 static const int iterations = 10;
77 
78 // Note: some tests rely on ThreadCount being multiple of 2
79 #if defined(Q_OS_SOLARIS) || ( defined(Q_OS_LINUX) && defined(QT_ARCH_ARMV6) )
80 static const int ThreadCount = 4;
81 #else
82 static const int ThreadCount = 10;
83 #endif
84 
tst_QWaitCondition()85 tst_QWaitCondition::tst_QWaitCondition()
86 
87 {
88 }
89 
90 class wait_QMutex_Thread_1 : public QThread
91 {
92 public:
93     QMutex mutex;
94     QWaitCondition cond;
95 
wait_QMutex_Thread_1()96     inline wait_QMutex_Thread_1()
97     { }
98 
run()99     void run()
100     {
101     mutex.lock();
102     cond.wakeOne();
103     cond.wait(&mutex);
104     mutex.unlock();
105     }
106 };
107 
108 class wait_QMutex_Thread_2 : public QThread
109 {
110 public:
111     QWaitCondition started;
112 
113     QMutex *mutex;
114     QWaitCondition *cond;
115 
wait_QMutex_Thread_2()116     inline wait_QMutex_Thread_2()
117     : mutex(0), cond(0)
118     { }
119 
run()120     void run()
121     {
122     mutex->lock();
123     started.wakeOne();
124     cond->wait(mutex);
125     mutex->unlock();
126     }
127 };
128 
129 class wait_QReadWriteLock_Thread_1 : public QThread
130 {
131 public:
132     QReadWriteLock readWriteLock;
133     QWaitCondition cond;
134 
wait_QReadWriteLock_Thread_1()135     inline wait_QReadWriteLock_Thread_1()
136     { }
137 
run()138     void run()
139     {
140     readWriteLock.lockForWrite();
141     cond.wakeOne();
142     cond.wait(&readWriteLock);
143     readWriteLock.unlock();
144     }
145 };
146 
147 class wait_QReadWriteLock_Thread_2 : public QThread
148 {
149 public:
150     QWaitCondition started;
151 
152     QReadWriteLock *readWriteLock;
153     QWaitCondition *cond;
154 
wait_QReadWriteLock_Thread_2()155     inline wait_QReadWriteLock_Thread_2()
156     : readWriteLock(0), cond(0)
157     { }
158 
run()159     void run()
160     {
161     readWriteLock->lockForRead();
162     started.wakeOne();
163     cond->wait(readWriteLock);
164     readWriteLock->unlock();
165     }
166 };
167 
wait_QMutex()168 void tst_QWaitCondition::wait_QMutex()
169 {
170     int x;
171     for (int i = 0; i < iterations; ++i) {
172     {
173         QMutex mutex;
174         QWaitCondition cond;
175 
176         mutex.lock();
177 
178         cond.wakeOne();
179         QVERIFY(!cond.wait(&mutex, 1));
180 
181         cond.wakeAll();
182         QVERIFY(!cond.wait(&mutex, 1));
183 
184         mutex.unlock();
185     }
186 
187     {
188         // test multiple threads waiting on separate wait conditions
189         wait_QMutex_Thread_1 thread[ThreadCount];
190 
191         for (x = 0; x < ThreadCount; ++x) {
192         thread[x].mutex.lock();
193         thread[x].start();
194         // wait for thread to start
195         QVERIFY(thread[x].cond.wait(&thread[x].mutex, 1000));
196         thread[x].mutex.unlock();
197         }
198 
199         for (x = 0; x < ThreadCount; ++x) {
200         QVERIFY(thread[x].isRunning());
201         QVERIFY(!thread[x].isFinished());
202         }
203 
204         for (x = 0; x < ThreadCount; ++x) {
205         thread[x].mutex.lock();
206         thread[x].cond.wakeOne();
207         thread[x].mutex.unlock();
208         }
209 
210         for (x = 0; x < ThreadCount; ++x) {
211         QVERIFY(thread[x].wait(1000));
212         }
213     }
214 
215     {
216         // test multiple threads waiting on a wait condition
217         QMutex mutex;
218         QWaitCondition cond1, cond2;
219         wait_QMutex_Thread_2 thread[ThreadCount];
220 
221         mutex.lock();
222         for (x = 0; x < ThreadCount; ++x) {
223         thread[x].mutex = &mutex;
224         thread[x].cond = (x < ThreadCount / 2) ? &cond1 : &cond2;
225         thread[x].start();
226         // wait for thread to start
227         QVERIFY(thread[x].started.wait(&mutex, 1000));
228         }
229         mutex.unlock();
230 
231         for (x = 0; x < ThreadCount; ++x) {
232         QVERIFY(thread[x].isRunning());
233         QVERIFY(!thread[x].isFinished());
234         }
235 
236         mutex.lock();
237         cond1.wakeAll();
238         cond2.wakeAll();
239         mutex.unlock();
240 
241         for (x = 0; x < ThreadCount; ++x) {
242         QVERIFY(thread[x].wait(1000));
243         }
244     }
245     }
246 }
247 
wait_QReadWriteLock()248 void tst_QWaitCondition::wait_QReadWriteLock()
249 {
250     {
251         QReadWriteLock readWriteLock(QReadWriteLock::Recursive);
252         QWaitCondition waitCondition;
253 
254         // ensure that the lockForRead is correctly restored
255         readWriteLock.lockForRead();
256 
257         QVERIFY(!waitCondition.wait(&readWriteLock, 1));
258 
259         QVERIFY(!readWriteLock.tryLockForWrite());
260         QVERIFY(readWriteLock.tryLockForRead());
261         readWriteLock.unlock();
262         QVERIFY(!readWriteLock.tryLockForWrite());
263         readWriteLock.unlock();
264 
265         QVERIFY(readWriteLock.tryLockForWrite());
266         readWriteLock.unlock();
267     }
268 
269     {
270         QReadWriteLock readWriteLock(QReadWriteLock::Recursive);
271         QWaitCondition waitCondition;
272 
273         // ensure that the lockForWrite is correctly restored
274         readWriteLock.lockForWrite();
275 
276         QVERIFY(!waitCondition.wait(&readWriteLock, 1));
277 
278         QVERIFY(!readWriteLock.tryLockForRead());
279         QVERIFY(readWriteLock.tryLockForWrite());
280         readWriteLock.unlock();
281         QVERIFY(!readWriteLock.tryLockForRead());
282         readWriteLock.unlock();
283 
284         QVERIFY(readWriteLock.tryLockForRead());
285         readWriteLock.unlock();
286     }
287 
288 
289     int x;
290     for (int i = 0; i < iterations; ++i) {
291     {
292         QReadWriteLock readWriteLock;
293         QWaitCondition waitCondition;
294 
295         readWriteLock.lockForRead();
296 
297         waitCondition.wakeOne();
298         QVERIFY(!waitCondition.wait(&readWriteLock, 1));
299 
300         waitCondition.wakeAll();
301         QVERIFY(!waitCondition.wait(&readWriteLock, 1));
302 
303         readWriteLock.unlock();
304     }
305 
306     {
307         QReadWriteLock readWriteLock;
308         QWaitCondition waitCondition;
309 
310         readWriteLock.lockForWrite();
311 
312         waitCondition.wakeOne();
313         QVERIFY(!waitCondition.wait(&readWriteLock, 1));
314 
315         waitCondition.wakeAll();
316         QVERIFY(!waitCondition.wait(&readWriteLock, 1));
317 
318         readWriteLock.unlock();
319     }
320 
321     {
322         // test multiple threads waiting on separate wait conditions
323         wait_QReadWriteLock_Thread_1 thread[ThreadCount];
324 
325         for (x = 0; x < ThreadCount; ++x) {
326         thread[x].readWriteLock.lockForRead();
327         thread[x].start();
328         // wait for thread to start
329 #if defined(Q_OS_SYMBIAN) && defined(Q_CC_WINSCW)
330         // Symbian emulator startup simultaneously with this thread causes additional delay
331         QVERIFY(thread[x].cond.wait(&thread[x].readWriteLock, 10000));
332 #else
333         QVERIFY(thread[x].cond.wait(&thread[x].readWriteLock, 1000));
334 #endif
335         thread[x].readWriteLock.unlock();
336         }
337 
338         for (x = 0; x < ThreadCount; ++x) {
339         QVERIFY(thread[x].isRunning());
340         QVERIFY(!thread[x].isFinished());
341         }
342 
343         for (x = 0; x < ThreadCount; ++x) {
344         thread[x].readWriteLock.lockForRead();
345         thread[x].cond.wakeOne();
346         thread[x].readWriteLock.unlock();
347         }
348 
349         for (x = 0; x < ThreadCount; ++x) {
350         QVERIFY(thread[x].wait(1000));
351         }
352     }
353 
354     {
355         // test multiple threads waiting on a wait condition
356         QReadWriteLock readWriteLock;
357         QWaitCondition cond1, cond2;
358         wait_QReadWriteLock_Thread_2 thread[ThreadCount];
359 
360         readWriteLock.lockForWrite();
361         for (x = 0; x < ThreadCount; ++x) {
362         thread[x].readWriteLock = &readWriteLock;
363         thread[x].cond = (x < ThreadCount / 2) ? &cond1 : &cond2;
364         thread[x].start();
365         // wait for thread to start
366         QVERIFY(thread[x].started.wait(&readWriteLock, 1000));
367         }
368         readWriteLock.unlock();
369 
370         for (x = 0; x < ThreadCount; ++x) {
371         QVERIFY(thread[x].isRunning());
372         QVERIFY(!thread[x].isFinished());
373         }
374 
375         readWriteLock.lockForWrite();
376         cond1.wakeAll();
377         cond2.wakeAll();
378         readWriteLock.unlock();
379 
380         for (x = 0; x < ThreadCount; ++x) {
381         QVERIFY(thread[x].wait(1000));
382         }
383     }
384     }
385 
386 }
387 
388 class wake_Thread : public QThread
389 {
390 public:
391     static int count;
392 
393     QWaitCondition started;
394     QWaitCondition dummy;
395 
396     QMutex *mutex;
397     QWaitCondition *cond;
398 
wake_Thread()399     inline wake_Thread()
400     : mutex(0), cond(0)
401     { }
402 
sleep(ulong s)403     static inline void sleep(ulong s)
404     { QThread::sleep(s); }
405 
run()406     void run()
407     {
408     mutex->lock();
409     ++count;
410         dummy.wakeOne(); // this wakeup should be lost
411            started.wakeOne();
412         dummy.wakeAll(); // this one too
413     cond->wait(mutex);
414         --count;
415     mutex->unlock();
416     }
417 };
418 
419 int wake_Thread::count = 0;
420 
421 class wake_Thread_2 : public QThread
422 {
423 public:
424     static int count;
425 
426     QWaitCondition started;
427     QWaitCondition dummy;
428 
429     QReadWriteLock *readWriteLock;
430     QWaitCondition *cond;
431 
wake_Thread_2()432     inline wake_Thread_2()
433     : readWriteLock(0), cond(0)
434     { }
435 
sleep(ulong s)436     static inline void sleep(ulong s)
437     { QThread::sleep(s); }
438 
run()439     void run()
440     {
441     readWriteLock->lockForWrite();
442     ++count;
443         dummy.wakeOne(); // this wakeup should be lost
444         started.wakeOne();
445         dummy.wakeAll(); // this one too
446     cond->wait(readWriteLock);
447         --count;
448     readWriteLock->unlock();
449     }
450 };
451 
452 int wake_Thread_2::count = 0;
453 
wakeOne()454 void tst_QWaitCondition::wakeOne()
455 {
456     int x;
457     // wake up threads, one at a time
458     for (int i = 0; i < iterations; ++i) {
459     QMutex mutex;
460     QWaitCondition cond;
461 
462     // QMutex
463     wake_Thread thread[ThreadCount];
464     bool thread_exited[ThreadCount];
465 
466     mutex.lock();
467     for (x = 0; x < ThreadCount; ++x) {
468         thread[x].mutex = &mutex;
469         thread[x].cond = &cond;
470         thread_exited[x] = FALSE;
471         thread[x].start();
472         // wait for thread to start
473         QVERIFY(thread[x].started.wait(&mutex, 1000));
474         // make sure wakeups are not queued... if nothing is
475         // waiting at the time of the wakeup, nothing happens
476         QVERIFY(!thread[x].dummy.wait(&mutex, 1));
477     }
478     mutex.unlock();
479 
480     QCOMPARE(wake_Thread::count, ThreadCount);
481 
482     // wake up threads one at a time
483     for (x = 0; x < ThreadCount; ++x) {
484         mutex.lock();
485         cond.wakeOne();
486         QVERIFY(!cond.wait(&mutex, COND_WAIT_TIME));
487         QVERIFY(!thread[x].dummy.wait(&mutex, 1));
488         mutex.unlock();
489 
490         int exited = 0;
491         for (int y = 0; y < ThreadCount; ++y) {
492             if (thread_exited[y])
493                         continue;
494             if (thread[y].wait(exited > 0 ? 3 : 1000)) {
495                 thread_exited[y] = TRUE;
496                 ++exited;
497             }
498         }
499 
500         QCOMPARE(exited, 1);
501         QCOMPARE(wake_Thread::count, ThreadCount - (x + 1));
502     }
503 
504     QCOMPARE(wake_Thread::count, 0);
505 
506     // QReadWriteLock
507     QReadWriteLock readWriteLock;
508     wake_Thread_2 rwthread[ThreadCount];
509 
510     readWriteLock.lockForWrite();
511     for (x = 0; x < ThreadCount; ++x) {
512         rwthread[x].readWriteLock = &readWriteLock;
513         rwthread[x].cond = &cond;
514         thread_exited[x] = FALSE;
515         rwthread[x].start();
516         // wait for thread to start
517         QVERIFY(rwthread[x].started.wait(&readWriteLock, 1000));
518         // make sure wakeups are not queued... if nothing is
519         // waiting at the time of the wakeup, nothing happens
520         QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1));
521     }
522     readWriteLock.unlock();
523 
524     QCOMPARE(wake_Thread_2::count, ThreadCount);
525 
526     // wake up threads one at a time
527     for (x = 0; x < ThreadCount; ++x) {
528         readWriteLock.lockForWrite();
529         cond.wakeOne();
530         QVERIFY(!cond.wait(&readWriteLock, COND_WAIT_TIME));
531         QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1));
532         readWriteLock.unlock();
533 
534         int exited = 0;
535         for (int y = 0; y < ThreadCount; ++y) {
536             if (thread_exited[y])
537                         continue;
538             if (rwthread[y].wait(exited > 0 ? 3 : 1000)) {
539                 thread_exited[y] = TRUE;
540                 ++exited;
541             }
542         }
543 
544         QCOMPARE(exited, 1);
545         QCOMPARE(wake_Thread_2::count, ThreadCount - (x + 1));
546     }
547 
548     QCOMPARE(wake_Thread_2::count, 0);
549     }
550 
551     // wake up threads, two at a time
552     for (int i = 0; i < iterations; ++i) {
553     QMutex mutex;
554     QWaitCondition cond;
555 
556         // QMutex
557     wake_Thread thread[ThreadCount];
558     bool thread_exited[ThreadCount];
559 
560     mutex.lock();
561     for (x = 0; x < ThreadCount; ++x) {
562         thread[x].mutex = &mutex;
563         thread[x].cond = &cond;
564         thread_exited[x] = FALSE;
565         thread[x].start();
566         // wait for thread to start
567         QVERIFY(thread[x].started.wait(&mutex, 1000));
568         // make sure wakeups are not queued... if nothing is
569         // waiting at the time of the wakeup, nothing happens
570         QVERIFY(!thread[x].dummy.wait(&mutex, 1));
571     }
572     mutex.unlock();
573 
574     QCOMPARE(wake_Thread::count, ThreadCount);
575 
576     // wake up threads one at a time
577     for (x = 0; x < ThreadCount; x += 2) {
578         mutex.lock();
579         cond.wakeOne();
580         cond.wakeOne();
581         QVERIFY(!cond.wait(&mutex, COND_WAIT_TIME));
582         QVERIFY(!thread[x].dummy.wait(&mutex, 1));
583         QVERIFY(!thread[x + 1].dummy.wait(&mutex, 1));
584         mutex.unlock();
585 
586         int exited = 0;
587         for (int y = 0; y < ThreadCount; ++y) {
588             if (thread_exited[y])
589                         continue;
590             if (thread[y].wait(exited > 0 ? 3 : 1000)) {
591                 thread_exited[y] = TRUE;
592                 ++exited;
593             }
594         }
595 
596         QCOMPARE(exited, 2);
597         QCOMPARE(wake_Thread::count, ThreadCount - (x + 2));
598     }
599 
600     QCOMPARE(wake_Thread::count, 0);
601 
602         // QReadWriteLock
603         QReadWriteLock readWriteLock;
604         wake_Thread_2 rwthread[ThreadCount];
605 
606     readWriteLock.lockForWrite();
607     for (x = 0; x < ThreadCount; ++x) {
608         rwthread[x].readWriteLock = &readWriteLock;
609         rwthread[x].cond = &cond;
610         thread_exited[x] = FALSE;
611         rwthread[x].start();
612         // wait for thread to start
613         QVERIFY(rwthread[x].started.wait(&readWriteLock, 1000));
614         // make sure wakeups are not queued... if nothing is
615         // waiting at the time of the wakeup, nothing happens
616         QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1));
617     }
618     readWriteLock.unlock();
619 
620     QCOMPARE(wake_Thread_2::count, ThreadCount);
621 
622     // wake up threads one at a time
623     for (x = 0; x < ThreadCount; x += 2) {
624         readWriteLock.lockForWrite();
625         cond.wakeOne();
626         cond.wakeOne();
627         QVERIFY(!cond.wait(&readWriteLock, COND_WAIT_TIME));
628         QVERIFY(!rwthread[x].dummy.wait(&readWriteLock, 1));
629         QVERIFY(!rwthread[x + 1].dummy.wait(&readWriteLock, 1));
630         readWriteLock.unlock();
631 
632         int exited = 0;
633         for (int y = 0; y < ThreadCount; ++y) {
634             if (thread_exited[y])
635                         continue;
636             if (rwthread[y].wait(exited > 0 ? 3 : 1000)) {
637                 thread_exited[y] = TRUE;
638                 ++exited;
639             }
640         }
641 
642         QCOMPARE(exited, 2);
643         QCOMPARE(wake_Thread_2::count, ThreadCount - (x + 2));
644     }
645 
646     QCOMPARE(wake_Thread_2::count, 0);
647 }
648 }
649 
wakeAll()650 void tst_QWaitCondition::wakeAll()
651 {
652     int x;
653     for (int i = 0; i < iterations; ++i) {
654     QMutex mutex;
655     QWaitCondition cond;
656 
657     // QMutex
658     wake_Thread thread[ThreadCount];
659 
660     mutex.lock();
661     for (x = 0; x < ThreadCount; ++x) {
662         thread[x].mutex = &mutex;
663         thread[x].cond = &cond;
664         thread[x].start();
665         // wait for thread to start
666         QVERIFY(thread[x].started.wait(&mutex, 1000));
667     }
668     mutex.unlock();
669 
670     QCOMPARE(wake_Thread::count, ThreadCount);
671 
672     // wake up all threads at once
673     mutex.lock();
674     cond.wakeAll();
675     QVERIFY(!cond.wait(&mutex, COND_WAIT_TIME));
676     mutex.unlock();
677 
678     int exited = 0;
679     for (x = 0; x < ThreadCount; ++x) {
680         if (thread[x].wait(1000))
681         ++exited;
682     }
683 
684     QCOMPARE(exited, ThreadCount);
685     QCOMPARE(wake_Thread::count, 0);
686 
687     // QReadWriteLock
688     QReadWriteLock readWriteLock;
689     wake_Thread_2 rwthread[ThreadCount];
690 
691     readWriteLock.lockForWrite();
692     for (x = 0; x < ThreadCount; ++x) {
693         rwthread[x].readWriteLock = &readWriteLock;
694         rwthread[x].cond = &cond;
695         rwthread[x].start();
696         // wait for thread to start
697         QVERIFY(rwthread[x].started.wait(&readWriteLock, 1000));
698     }
699     readWriteLock.unlock();
700 
701     QCOMPARE(wake_Thread_2::count, ThreadCount);
702 
703     // wake up all threads at once
704     readWriteLock.lockForWrite();
705     cond.wakeAll();
706     QVERIFY(!cond.wait(&readWriteLock, COND_WAIT_TIME));
707     readWriteLock.unlock();
708 
709     exited = 0;
710     for (x = 0; x < ThreadCount; ++x) {
711         if (rwthread[x].wait(1000))
712         ++exited;
713     }
714 
715     QCOMPARE(exited, ThreadCount);
716     QCOMPARE(wake_Thread_2::count, 0);
717     }
718 }
719 
720 class wait_RaceConditionThread : public QThread
721 {
722 public:
wait_RaceConditionThread(QMutex * mutex,QWaitCondition * startup,QWaitCondition * waitCondition,ulong timeout=ULONG_MAX)723     wait_RaceConditionThread(QMutex *mutex, QWaitCondition *startup, QWaitCondition *waitCondition,
724                              ulong timeout = ULONG_MAX)
725         : timeout(timeout), returnValue(false), ready(false),
726           mutex(mutex), startup(startup), waitCondition(waitCondition) {}
727 
728     unsigned long timeout;
729     bool returnValue;
730 
731     bool ready;
732 
733     QMutex *mutex;
734     QWaitCondition *startup;
735     QWaitCondition *waitCondition;
736 
run()737     void run() {
738         mutex->lock();
739 
740         ready = true;
741         startup->wakeOne();
742 
743         returnValue = waitCondition->wait(mutex, timeout);
744 
745         mutex->unlock();
746     }
747 };
748 
749 class wait_RaceConditionThread_2 : public QThread
750 {
751 public:
wait_RaceConditionThread_2(QReadWriteLock * readWriteLock,QWaitCondition * startup,QWaitCondition * waitCondition,ulong timeout=ULONG_MAX)752     wait_RaceConditionThread_2(QReadWriteLock *readWriteLock,
753                                QWaitCondition *startup,
754                                QWaitCondition *waitCondition,
755                                ulong timeout = ULONG_MAX)
756         : timeout(timeout), returnValue(false), ready(false),
757           readWriteLock(readWriteLock), startup(startup), waitCondition(waitCondition)
758     { }
759 
760     unsigned long timeout;
761     bool returnValue;
762 
763     bool ready;
764 
765     QReadWriteLock *readWriteLock;
766     QWaitCondition *startup;
767     QWaitCondition *waitCondition;
768 
run()769     void run() {
770         readWriteLock->lockForWrite();
771 
772         ready = true;
773         startup->wakeOne();
774 
775         returnValue = waitCondition->wait(readWriteLock, timeout);
776 
777         readWriteLock->unlock();
778     }
779 };
780 
wait_RaceCondition()781 void tst_QWaitCondition::wait_RaceCondition()
782 {
783     {
784         QMutex mutex;
785         QWaitCondition startup;
786         QWaitCondition waitCondition;
787 
788         wait_RaceConditionThread timeoutThread(&mutex, &startup, &waitCondition, 1000),
789             waitingThread1(&mutex, &startup, &waitCondition);
790 
791         timeoutThread.start();
792         waitingThread1.start();
793         mutex.lock();
794 
795         // wait for the threads to start up
796         while (!timeoutThread.ready
797                || !waitingThread1.ready) {
798             startup.wait(&mutex);
799         }
800 
801         QTest::qWait(2000);
802 
803         waitCondition.wakeOne();
804 
805         mutex.unlock();
806 
807         QVERIFY(timeoutThread.wait(5000));
808         QVERIFY(!timeoutThread.returnValue);
809         QVERIFY(waitingThread1.wait(5000));
810         QVERIFY(waitingThread1.returnValue);
811     }
812 
813     {
814         QReadWriteLock readWriteLock;
815         QWaitCondition startup;
816         QWaitCondition waitCondition;
817 
818         wait_RaceConditionThread_2 timeoutThread(&readWriteLock, &startup, &waitCondition, 1000),
819             waitingThread1(&readWriteLock, &startup, &waitCondition);
820 
821         timeoutThread.start();
822         waitingThread1.start();
823         readWriteLock.lockForRead();
824 
825         // wait for the threads to start up
826         while (!timeoutThread.ready
827                || !waitingThread1.ready) {
828             startup.wait(&readWriteLock);
829         }
830 
831         QTest::qWait(2000);
832 
833         waitCondition.wakeOne();
834 
835         readWriteLock.unlock();
836 
837         QVERIFY(timeoutThread.wait(5000));
838         QVERIFY(!timeoutThread.returnValue);
839         QVERIFY(waitingThread1.wait(5000));
840         QVERIFY(waitingThread1.returnValue);
841     }
842 }
843 
844 QTEST_MAIN(tst_QWaitCondition)
845 #include "tst_qwaitcondition.moc"
846