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