1/****************************************************************************
2**
3** Copyright (C) 2021 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.h>
32#include <qelapsedtimer.h>
33#include <qmutex.h>
34#include <qthread.h>
35#include <qtimer.h>
36#include <qwaitcondition.h>
37#include <qdebug.h>
38#include <qmetaobject.h>
39#include <qscopeguard.h>
40
41#ifdef Q_OS_UNIX
42#include <pthread.h>
43#endif
44#if defined(Q_OS_WIN)
45#include <windows.h>
46#if defined(Q_OS_WIN32)
47#include <process.h>
48#endif
49#endif
50
51#ifndef QT_NO_EXCEPTIONS
52#include <exception>
53#endif
54
55#include "emulationdetector.h"
56
57class tst_QThread : public QObject
58{
59 Q_OBJECT
60private slots:
61 void currentThreadId();
62 void currentThread();
63 void idealThreadCount();
64 void isFinished();
65 void isRunning();
66 void setPriority();
67 void setStackSize();
68 void exit();
69 void start();
70 void terminate();
71 void quit();
72 void started();
73 void finished();
74 void terminated(); // Named after a signal that was removed in Qt 5.0
75 void exec();
76 void sleep();
77 void msleep();
78 void usleep();
79
80 void nativeThreadAdoption();
81 void adoptedThreadAffinity();
82 void adoptedThreadSetPriority();
83 void adoptedThreadExit();
84 void adoptedThreadExec();
85 void adoptedThreadFinished();
86 void adoptedThreadExecFinished();
87 void adoptMultipleThreads();
88 void adoptMultipleThreadsOverlap();
89
90 void exitAndStart();
91 void exitAndExec();
92
93 void connectThreadFinishedSignalToObjectDeleteLaterSlot();
94 void wait2();
95 void wait3_slowDestructor();
96 void destroyFinishRace();
97 void startFinishRace();
98 void startAndQuitCustomEventLoop();
99 void isRunningInFinished();
100
101 void customEventDispatcher();
102
103 void requestTermination();
104
105 void stressTest();
106
107 void quitLock();
108
109 void create();
110 void threadIdReuse();
111};
112
113enum { one_minute = 60 * 1000, five_minutes = 5 * one_minute };
114
115template <class Int>
116static QString msgElapsed(Int elapsed)
117{
118 return QString::fromLatin1(str: "elapsed: %1").arg(elapsed);
119}
120
121class SignalRecorder : public QObject
122{
123 Q_OBJECT
124public:
125 QAtomicInt activationCount;
126
127 inline SignalRecorder()
128 : activationCount(0)
129 { }
130
131 bool wasActivated()
132 { return activationCount.loadRelaxed() > 0; }
133
134public slots:
135 void slot();
136};
137
138void SignalRecorder::slot()
139{ activationCount.ref(); }
140
141class Current_Thread : public QThread
142{
143public:
144 Qt::HANDLE id;
145 QThread *thread;
146
147 void run()
148 {
149 id = QThread::currentThreadId();
150 thread = QThread::currentThread();
151 }
152};
153
154class Simple_Thread : public QThread
155{
156public:
157 QMutex mutex;
158 QWaitCondition cond;
159
160 void run()
161 {
162 QMutexLocker locker(&mutex);
163 cond.wakeOne();
164 }
165};
166
167class Exit_Object : public QObject
168{
169 Q_OBJECT
170public:
171 QThread *thread;
172 int code;
173public slots:
174 void slot()
175 { thread->exit(retcode: code); }
176};
177
178class Exit_Thread : public Simple_Thread
179{
180public:
181 Exit_Object *object;
182 int code;
183 int result;
184
185 void run()
186 {
187 Simple_Thread::run();
188 if (object) {
189 object->thread = this;
190 object->code = code;
191 QTimer::singleShot(msec: 100, receiver: object, SLOT(slot()));
192 }
193 result = exec();
194 }
195};
196
197class Terminate_Thread : public Simple_Thread
198{
199public:
200 void run()
201 {
202 setTerminationEnabled(false);
203 {
204 QMutexLocker locker(&mutex);
205 cond.wakeOne();
206 cond.wait(lockedMutex: &mutex, time: five_minutes);
207 }
208 setTerminationEnabled(true);
209 qFatal(msg: "tst_QThread: test case hung");
210 }
211};
212
213class Quit_Object : public QObject
214{
215 Q_OBJECT
216public:
217 QThread *thread;
218public slots:
219 void slot()
220 { thread->quit(); }
221};
222
223class Quit_Thread : public Simple_Thread
224{
225public:
226 Quit_Object *object;
227 int result;
228
229 void run()
230 {
231 Simple_Thread::run();
232 if (object) {
233 object->thread = this;
234 QTimer::singleShot(msec: 100, receiver: object, SLOT(slot()));
235 }
236 result = exec();
237 }
238};
239
240class Sleep_Thread : public Simple_Thread
241{
242public:
243 enum SleepType { Second, Millisecond, Microsecond };
244
245 SleepType sleepType;
246 int interval;
247
248 int elapsed; // result, in *MILLISECONDS*
249
250 void run()
251 {
252 QMutexLocker locker(&mutex);
253
254 elapsed = 0;
255 QElapsedTimer timer;
256 timer.start();
257 switch (sleepType) {
258 case Second:
259 sleep(interval);
260 break;
261 case Millisecond:
262 msleep(interval);
263 break;
264 case Microsecond:
265 usleep(interval);
266 break;
267 }
268 elapsed = timer.elapsed();
269
270 cond.wakeOne();
271 }
272};
273
274void tst_QThread::currentThreadId()
275{
276 Current_Thread thread;
277 thread.id = 0;
278 thread.thread = 0;
279 thread.start();
280 QVERIFY(thread.wait(five_minutes));
281 QVERIFY(thread.id != 0);
282 QVERIFY(thread.id != QThread::currentThreadId());
283}
284
285void tst_QThread::currentThread()
286{
287 QVERIFY(QThread::currentThread() != 0);
288 QCOMPARE(QThread::currentThread(), thread());
289
290 Current_Thread thread;
291 thread.id = 0;
292 thread.thread = 0;
293 thread.start();
294 QVERIFY(thread.wait(five_minutes));
295 QCOMPARE(thread.thread, (QThread *)&thread);
296}
297
298void tst_QThread::idealThreadCount()
299{
300 QVERIFY(QThread::idealThreadCount() > 0);
301 qDebug() << "Ideal thread count:" << QThread::idealThreadCount();
302}
303
304void tst_QThread::isFinished()
305{
306 Simple_Thread thread;
307 QVERIFY(!thread.isFinished());
308 QMutexLocker locker(&thread.mutex);
309 thread.start();
310 QVERIFY(!thread.isFinished());
311 thread.cond.wait(lockedMutex: locker.mutex());
312 QVERIFY(thread.wait(five_minutes));
313 QVERIFY(thread.isFinished());
314}
315
316void tst_QThread::isRunning()
317{
318 Simple_Thread thread;
319 QVERIFY(!thread.isRunning());
320 QMutexLocker locker(&thread.mutex);
321 thread.start();
322 QVERIFY(thread.isRunning());
323 thread.cond.wait(lockedMutex: locker.mutex());
324 QVERIFY(thread.wait(five_minutes));
325 QVERIFY(!thread.isRunning());
326}
327
328void tst_QThread::setPriority()
329{
330 Simple_Thread thread;
331
332 // cannot change the priority, since the thread is not running
333 QCOMPARE(thread.priority(), QThread::InheritPriority);
334 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
335 thread.setPriority(QThread::IdlePriority);
336 QCOMPARE(thread.priority(), QThread::InheritPriority);
337 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
338 thread.setPriority(QThread::LowestPriority);
339 QCOMPARE(thread.priority(), QThread::InheritPriority);
340 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
341 thread.setPriority(QThread::LowPriority);
342 QCOMPARE(thread.priority(), QThread::InheritPriority);
343 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
344 thread.setPriority(QThread::NormalPriority);
345 QCOMPARE(thread.priority(), QThread::InheritPriority);
346 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
347 thread.setPriority(QThread::HighPriority);
348 QCOMPARE(thread.priority(), QThread::InheritPriority);
349 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
350 thread.setPriority(QThread::HighestPriority);
351 QCOMPARE(thread.priority(), QThread::InheritPriority);
352 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
353 thread.setPriority(QThread::TimeCriticalPriority);
354 QCOMPARE(thread.priority(), QThread::InheritPriority);
355
356 QCOMPARE(thread.priority(), QThread::InheritPriority);
357 QMutexLocker locker(&thread.mutex);
358 thread.start();
359
360 // change the priority of a running thread
361 QCOMPARE(thread.priority(), QThread::InheritPriority);
362 thread.setPriority(QThread::IdlePriority);
363 QCOMPARE(thread.priority(), QThread::IdlePriority);
364 thread.setPriority(QThread::LowestPriority);
365 QCOMPARE(thread.priority(), QThread::LowestPriority);
366 thread.setPriority(QThread::LowPriority);
367 QCOMPARE(thread.priority(), QThread::LowPriority);
368 thread.setPriority(QThread::NormalPriority);
369 QCOMPARE(thread.priority(), QThread::NormalPriority);
370 thread.setPriority(QThread::HighPriority);
371 QCOMPARE(thread.priority(), QThread::HighPriority);
372 thread.setPriority(QThread::HighestPriority);
373 QCOMPARE(thread.priority(), QThread::HighestPriority);
374 thread.setPriority(QThread::TimeCriticalPriority);
375 QCOMPARE(thread.priority(), QThread::TimeCriticalPriority);
376 thread.cond.wait(lockedMutex: locker.mutex());
377 QVERIFY(thread.wait(five_minutes));
378
379 QCOMPARE(thread.priority(), QThread::InheritPriority);
380 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
381 thread.setPriority(QThread::IdlePriority);
382 QCOMPARE(thread.priority(), QThread::InheritPriority);
383 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
384 thread.setPriority(QThread::LowestPriority);
385 QCOMPARE(thread.priority(), QThread::InheritPriority);
386 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
387 thread.setPriority(QThread::LowPriority);
388 QCOMPARE(thread.priority(), QThread::InheritPriority);
389 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
390 thread.setPriority(QThread::NormalPriority);
391 QCOMPARE(thread.priority(), QThread::InheritPriority);
392 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
393 thread.setPriority(QThread::HighPriority);
394 QCOMPARE(thread.priority(), QThread::InheritPriority);
395 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
396 thread.setPriority(QThread::HighestPriority);
397 QCOMPARE(thread.priority(), QThread::InheritPriority);
398 QTest::ignoreMessage(type: QtWarningMsg, message: "QThread::setPriority: Cannot set priority, thread is not running");
399 thread.setPriority(QThread::TimeCriticalPriority);
400 QCOMPARE(thread.priority(), QThread::InheritPriority);
401}
402
403void tst_QThread::setStackSize()
404{
405 Simple_Thread thread;
406 QCOMPARE(thread.stackSize(), 0u);
407 thread.setStackSize(8192u);
408 QCOMPARE(thread.stackSize(), 8192u);
409 thread.setStackSize(0u);
410 QCOMPARE(thread.stackSize(), 0u);
411}
412
413void tst_QThread::exit()
414{
415 Exit_Thread thread;
416 thread.object = new Exit_Object;
417 thread.object->moveToThread(thread: &thread);
418 thread.code = 42;
419 thread.result = 0;
420 QVERIFY(!thread.isFinished());
421 QVERIFY(!thread.isRunning());
422 QMutexLocker locker(&thread.mutex);
423 thread.start();
424 QVERIFY(thread.isRunning());
425 QVERIFY(!thread.isFinished());
426 thread.cond.wait(lockedMutex: locker.mutex());
427 QVERIFY(thread.wait(five_minutes));
428 QVERIFY(thread.isFinished());
429 QVERIFY(!thread.isRunning());
430 QCOMPARE(thread.result, thread.code);
431 delete thread.object;
432
433 Exit_Thread thread2;
434 thread2.object = 0;
435 thread2.code = 53;
436 thread2.result = 0;
437 QMutexLocker locker2(&thread2.mutex);
438 thread2.start();
439 thread2.exit(retcode: thread2.code);
440 thread2.cond.wait(lockedMutex: locker2.mutex());
441 QVERIFY(thread2.wait(five_minutes));
442 QCOMPARE(thread2.result, thread2.code);
443}
444
445void tst_QThread::start()
446{
447 QThread::Priority priorities[] = {
448 QThread::IdlePriority,
449 QThread::LowestPriority,
450 QThread::LowPriority,
451 QThread::NormalPriority,
452 QThread::HighPriority,
453 QThread::HighestPriority,
454 QThread::TimeCriticalPriority,
455 QThread::InheritPriority
456 };
457 const int prio_count = sizeof(priorities) / sizeof(QThread::Priority);
458
459 for (int i = 0; i < prio_count; ++i) {
460 Simple_Thread thread;
461 QVERIFY(!thread.isFinished());
462 QVERIFY(!thread.isRunning());
463 QMutexLocker locker(&thread.mutex);
464 thread.start(priorities[i]);
465 QVERIFY(thread.isRunning());
466 QVERIFY(!thread.isFinished());
467 thread.cond.wait(lockedMutex: locker.mutex());
468 QVERIFY(thread.wait(five_minutes));
469 QVERIFY(thread.isFinished());
470 QVERIFY(!thread.isRunning());
471 }
472}
473
474void tst_QThread::terminate()
475{
476#if defined(Q_OS_WINRT) || defined(Q_OS_ANDROID)
477 QSKIP("Thread termination is not supported on WinRT or Android.");
478#endif
479 Terminate_Thread thread;
480 {
481 QMutexLocker locker(&thread.mutex);
482 thread.start();
483 QVERIFY(thread.cond.wait(locker.mutex(), five_minutes));
484 thread.terminate();
485 thread.cond.wakeOne();
486 }
487 QVERIFY(thread.wait(five_minutes));
488}
489
490void tst_QThread::quit()
491{
492 Quit_Thread thread;
493 thread.object = new Quit_Object;
494 thread.object->moveToThread(thread: &thread);
495 thread.result = -1;
496 QVERIFY(!thread.isFinished());
497 QVERIFY(!thread.isRunning());
498 QMutexLocker locker(&thread.mutex);
499 thread.start();
500 QVERIFY(thread.isRunning());
501 QVERIFY(!thread.isFinished());
502 thread.cond.wait(lockedMutex: locker.mutex());
503 QVERIFY(thread.wait(five_minutes));
504 QVERIFY(thread.isFinished());
505 QVERIFY(!thread.isRunning());
506 QCOMPARE(thread.result, 0);
507 delete thread.object;
508
509 Quit_Thread thread2;
510 thread2.object = 0;
511 thread2.result = -1;
512 QMutexLocker locker2(&thread2.mutex);
513 thread2.start();
514 thread2.quit();
515 thread2.cond.wait(lockedMutex: locker2.mutex());
516 QVERIFY(thread2.wait(five_minutes));
517 QCOMPARE(thread2.result, 0);
518}
519
520void tst_QThread::started()
521{
522 SignalRecorder recorder;
523 Simple_Thread thread;
524 connect(sender: &thread, SIGNAL(started()), receiver: &recorder, SLOT(slot()), Qt::DirectConnection);
525 thread.start();
526 QVERIFY(thread.wait(five_minutes));
527 QVERIFY(recorder.wasActivated());
528}
529
530void tst_QThread::finished()
531{
532 SignalRecorder recorder;
533 Simple_Thread thread;
534 connect(sender: &thread, SIGNAL(finished()), receiver: &recorder, SLOT(slot()), Qt::DirectConnection);
535 thread.start();
536 QVERIFY(thread.wait(five_minutes));
537 QVERIFY(recorder.wasActivated());
538}
539
540void tst_QThread::terminated()
541{
542#if defined(Q_OS_WINRT) || defined(Q_OS_ANDROID)
543 QSKIP("Thread termination is not supported on WinRT or Android.");
544#endif
545 SignalRecorder recorder;
546 Terminate_Thread thread;
547 connect(sender: &thread, SIGNAL(finished()), receiver: &recorder, SLOT(slot()), Qt::DirectConnection);
548 {
549 QMutexLocker locker(&thread.mutex);
550 thread.start();
551 thread.cond.wait(lockedMutex: locker.mutex());
552 thread.terminate();
553 thread.cond.wakeOne();
554 }
555 QVERIFY(thread.wait(five_minutes));
556 QVERIFY(recorder.wasActivated());
557}
558
559void tst_QThread::exec()
560{
561 class MultipleExecThread : public QThread
562 {
563 public:
564 int res1, res2;
565
566 MultipleExecThread() : res1(-2), res2(-2) { }
567
568 void run()
569 {
570 {
571 Exit_Object o;
572 o.thread = this;
573 o.code = 1;
574 QTimer::singleShot(msec: 100, receiver: &o, SLOT(slot()));
575 res1 = exec();
576 }
577 {
578 Exit_Object o;
579 o.thread = this;
580 o.code = 2;
581 QTimer::singleShot(msec: 100, receiver: &o, SLOT(slot()));
582 res2 = exec();
583 }
584 }
585 };
586
587 MultipleExecThread thread;
588 thread.start();
589 QVERIFY(thread.wait());
590
591 QCOMPARE(thread.res1, 1);
592 QCOMPARE(thread.res2, 2);
593}
594
595void tst_QThread::sleep()
596{
597 Sleep_Thread thread;
598 thread.sleepType = Sleep_Thread::Second;
599 thread.interval = 2;
600 thread.start();
601 QVERIFY(thread.wait(five_minutes));
602 QVERIFY2(thread.elapsed >= 2000, qPrintable(msgElapsed(thread.elapsed)));
603}
604
605void tst_QThread::msleep()
606{
607 Sleep_Thread thread;
608 thread.sleepType = Sleep_Thread::Millisecond;
609 thread.interval = 120;
610 thread.start();
611 QVERIFY(thread.wait(five_minutes));
612#if defined (Q_OS_WIN) // May no longer be needed
613 QVERIFY2(thread.elapsed >= 100, qPrintable(msgElapsed(thread.elapsed)));
614#else
615 QVERIFY2(thread.elapsed >= 120, qPrintable(msgElapsed(thread.elapsed)));
616#endif
617}
618
619void tst_QThread::usleep()
620{
621 Sleep_Thread thread;
622 thread.sleepType = Sleep_Thread::Microsecond;
623 thread.interval = 120000;
624 thread.start();
625 QVERIFY(thread.wait(five_minutes));
626#if defined (Q_OS_WIN) // May no longer be needed
627 QVERIFY2(thread.elapsed >= 100, qPrintable(msgElapsed(thread.elapsed)));
628#else
629 QVERIFY2(thread.elapsed >= 120, qPrintable(msgElapsed(thread.elapsed)));
630#endif
631}
632
633typedef void (*FunctionPointer)(void *);
634void noop(void*) { }
635
636#if defined Q_OS_UNIX
637 typedef pthread_t ThreadHandle;
638#elif defined Q_OS_WIN
639 typedef HANDLE ThreadHandle;
640#endif
641
642#ifdef Q_OS_WIN
643#define WIN_FIX_STDCALL __stdcall
644#else
645#define WIN_FIX_STDCALL
646#endif
647
648class NativeThreadWrapper
649{
650public:
651 NativeThreadWrapper() : qthread(0), waitForStop(false) {}
652 void start(FunctionPointer functionPointer = noop, void *data = 0);
653 void startAndWait(FunctionPointer functionPointer = noop, void *data = 0);
654 void join();
655 void setWaitForStop() { waitForStop = true; }
656 void stop();
657
658 ThreadHandle nativeThreadHandle;
659 QThread *qthread;
660 QWaitCondition startCondition;
661 QMutex mutex;
662 bool waitForStop;
663 QWaitCondition stopCondition;
664protected:
665 static void *runUnix(void *data);
666 static unsigned WIN_FIX_STDCALL runWin(void *data);
667
668 FunctionPointer functionPointer;
669 void *data;
670};
671
672void NativeThreadWrapper::start(FunctionPointer functionPointer, void *data)
673{
674 this->functionPointer = functionPointer;
675 this->data = data;
676#if defined Q_OS_UNIX
677 const int state = pthread_create(newthread: &nativeThreadHandle, attr: 0, start_routine: NativeThreadWrapper::runUnix, arg: this);
678 Q_UNUSED(state);
679#elif defined(Q_OS_WINRT)
680 nativeThreadHandle = CreateThread(NULL, 0 , (LPTHREAD_START_ROUTINE)NativeThreadWrapper::runWin , this, 0, NULL);
681#elif defined Q_OS_WIN
682 unsigned thrdid = 0;
683 nativeThreadHandle = (Qt::HANDLE) _beginthreadex(NULL, 0, NativeThreadWrapper::runWin, this, 0, &thrdid);
684#endif
685}
686
687void NativeThreadWrapper::startAndWait(FunctionPointer functionPointer, void *data)
688{
689 QMutexLocker locker(&mutex);
690 start(functionPointer, data);
691 startCondition.wait(lockedMutex: locker.mutex());
692}
693
694void NativeThreadWrapper::join()
695{
696#if defined Q_OS_UNIX
697 pthread_join(th: nativeThreadHandle, thread_return: 0);
698#elif defined Q_OS_WIN
699 WaitForSingleObjectEx(nativeThreadHandle, INFINITE, FALSE);
700 CloseHandle(nativeThreadHandle);
701#endif
702}
703
704void *NativeThreadWrapper::runUnix(void *that)
705{
706 NativeThreadWrapper *nativeThreadWrapper = reinterpret_cast<NativeThreadWrapper*>(that);
707
708 // Adopt thread, create QThread object.
709 nativeThreadWrapper->qthread = QThread::currentThread();
710
711 // Release main thread.
712 {
713 QMutexLocker lock(&nativeThreadWrapper->mutex);
714 nativeThreadWrapper->startCondition.wakeOne();
715 }
716
717 // Run function.
718 nativeThreadWrapper->functionPointer(nativeThreadWrapper->data);
719
720 // Wait for stop.
721 {
722 QMutexLocker lock(&nativeThreadWrapper->mutex);
723 if (nativeThreadWrapper->waitForStop)
724 nativeThreadWrapper->stopCondition.wait(lockedMutex: lock.mutex());
725 }
726
727 return 0;
728}
729
730unsigned WIN_FIX_STDCALL NativeThreadWrapper::runWin(void *data)
731{
732 runUnix(that: data);
733 return 0;
734}
735
736void NativeThreadWrapper::stop()
737{
738 QMutexLocker lock(&mutex);
739 waitForStop = false;
740 stopCondition.wakeOne();
741}
742
743bool threadAdoptedOk = false;
744QThread *mainThread;
745void testNativeThreadAdoption(void *)
746{
747 threadAdoptedOk = (QThread::currentThreadId() != 0
748 && QThread::currentThread() != 0
749 && QThread::currentThread() != mainThread);
750}
751void tst_QThread::nativeThreadAdoption()
752{
753 threadAdoptedOk = false;
754 mainThread = QThread::currentThread();
755 NativeThreadWrapper nativeThread;
756 nativeThread.setWaitForStop();
757 nativeThread.startAndWait(functionPointer: testNativeThreadAdoption);
758 QVERIFY(nativeThread.qthread);
759
760 nativeThread.stop();
761 nativeThread.join();
762
763 QVERIFY(threadAdoptedOk);
764}
765
766void adoptedThreadAffinityFunction(void *arg)
767{
768 QThread **affinity = reinterpret_cast<QThread **>(arg);
769 QThread *current = QThread::currentThread();
770 affinity[0] = current;
771 affinity[1] = current->thread();
772}
773
774void tst_QThread::adoptedThreadAffinity()
775{
776 QThread *affinity[2] = { 0, 0 };
777
778 NativeThreadWrapper thread;
779 thread.startAndWait(functionPointer: adoptedThreadAffinityFunction, data: affinity);
780 thread.join();
781
782 // adopted thread should have affinity to itself
783 QCOMPARE(affinity[0], affinity[1]);
784}
785
786void tst_QThread::adoptedThreadSetPriority()
787{
788 NativeThreadWrapper nativeThread;
789 nativeThread.setWaitForStop();
790 nativeThread.startAndWait();
791
792 // change the priority of a running thread
793 QCOMPARE(nativeThread.qthread->priority(), QThread::InheritPriority);
794 nativeThread.qthread->setPriority(QThread::IdlePriority);
795 QCOMPARE(nativeThread.qthread->priority(), QThread::IdlePriority);
796 nativeThread.qthread->setPriority(QThread::LowestPriority);
797 QCOMPARE(nativeThread.qthread->priority(), QThread::LowestPriority);
798 nativeThread.qthread->setPriority(QThread::LowPriority);
799 QCOMPARE(nativeThread.qthread->priority(), QThread::LowPriority);
800 nativeThread.qthread->setPriority(QThread::NormalPriority);
801 QCOMPARE(nativeThread.qthread->priority(), QThread::NormalPriority);
802 nativeThread.qthread->setPriority(QThread::HighPriority);
803 QCOMPARE(nativeThread.qthread->priority(), QThread::HighPriority);
804 nativeThread.qthread->setPriority(QThread::HighestPriority);
805 QCOMPARE(nativeThread.qthread->priority(), QThread::HighestPriority);
806 nativeThread.qthread->setPriority(QThread::TimeCriticalPriority);
807 QCOMPARE(nativeThread.qthread->priority(), QThread::TimeCriticalPriority);
808
809 nativeThread.stop();
810 nativeThread.join();
811}
812
813void tst_QThread::adoptedThreadExit()
814{
815 NativeThreadWrapper nativeThread;
816 nativeThread.setWaitForStop();
817
818 nativeThread.startAndWait();
819 QVERIFY(nativeThread.qthread);
820 QVERIFY(nativeThread.qthread->isRunning());
821 QVERIFY(!nativeThread.qthread->isFinished());
822
823 nativeThread.stop();
824 nativeThread.join();
825}
826
827void adoptedThreadExecFunction(void *)
828{
829 QThread * const adoptedThread = QThread::currentThread();
830 QEventLoop eventLoop(adoptedThread);
831
832 const int code = 1;
833 Exit_Object o;
834 o.thread = adoptedThread;
835 o.code = code;
836 QTimer::singleShot(msec: 100, receiver: &o, SLOT(slot()));
837
838 const int result = eventLoop.exec();
839 QCOMPARE(result, code);
840}
841
842void tst_QThread::adoptedThreadExec()
843{
844 NativeThreadWrapper nativeThread;
845 nativeThread.start(functionPointer: adoptedThreadExecFunction);
846 nativeThread.join();
847}
848
849/*
850 Test that you get the finished signal when an adopted thread exits.
851*/
852void tst_QThread::adoptedThreadFinished()
853{
854 NativeThreadWrapper nativeThread;
855 nativeThread.setWaitForStop();
856 nativeThread.startAndWait();
857
858 QObject::connect(sender: nativeThread.qthread, SIGNAL(finished()), receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
859
860 nativeThread.stop();
861 nativeThread.join();
862
863 QTestEventLoop::instance().enterLoop(secs: 5);
864 QVERIFY(!QTestEventLoop::instance().timeout());
865}
866
867void tst_QThread::adoptedThreadExecFinished()
868{
869 NativeThreadWrapper nativeThread;
870 nativeThread.setWaitForStop();
871 nativeThread.startAndWait(functionPointer: adoptedThreadExecFunction);
872
873 QObject::connect(sender: nativeThread.qthread, SIGNAL(finished()), receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
874
875 nativeThread.stop();
876 nativeThread.join();
877
878 QTestEventLoop::instance().enterLoop(secs: 5);
879 QVERIFY(!QTestEventLoop::instance().timeout());
880}
881
882void tst_QThread::adoptMultipleThreads()
883{
884#if defined(Q_OS_WIN)
885 // need to test lots of threads, so that we exceed MAXIMUM_WAIT_OBJECTS in qt_adopted_thread_watcher()
886 const int numThreads = 200;
887#else
888 const int numThreads = 5;
889#endif
890 QVector<NativeThreadWrapper*> nativeThreads;
891
892 SignalRecorder recorder;
893
894 for (int i = 0; i < numThreads; ++i) {
895 nativeThreads.append(t: new NativeThreadWrapper());
896 nativeThreads.at(i)->setWaitForStop();
897 nativeThreads.at(i)->startAndWait();
898 QObject::connect(sender: nativeThreads.at(i)->qthread, SIGNAL(finished()), receiver: &recorder, SLOT(slot()));
899 }
900
901 QObject::connect(sender: nativeThreads.at(i: numThreads - 1)->qthread, SIGNAL(finished()), receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
902
903 for (int i = 0; i < numThreads; ++i) {
904 nativeThreads.at(i)->stop();
905 nativeThreads.at(i)->join();
906 delete nativeThreads.at(i);
907 }
908
909 QTestEventLoop::instance().enterLoop(secs: 5);
910 QVERIFY(!QTestEventLoop::instance().timeout());
911 QCOMPARE(recorder.activationCount.loadRelaxed(), numThreads);
912}
913
914void tst_QThread::adoptMultipleThreadsOverlap()
915{
916#if defined(Q_OS_WIN)
917 // need to test lots of threads, so that we exceed MAXIMUM_WAIT_OBJECTS in qt_adopted_thread_watcher()
918 const int numThreads = 200;
919#else
920 const int numThreads = 5;
921#endif
922 QVector<NativeThreadWrapper*> nativeThreads;
923
924 SignalRecorder recorder;
925
926 for (int i = 0; i < numThreads; ++i) {
927 nativeThreads.append(t: new NativeThreadWrapper());
928 nativeThreads.at(i)->setWaitForStop();
929 nativeThreads.at(i)->mutex.lock();
930 nativeThreads.at(i)->start();
931 }
932 for (int i = 0; i < numThreads; ++i) {
933 nativeThreads.at(i)->startCondition.wait(lockedMutex: &nativeThreads.at(i)->mutex);
934 QObject::connect(sender: nativeThreads.at(i)->qthread, SIGNAL(finished()), receiver: &recorder, SLOT(slot()));
935 nativeThreads.at(i)->mutex.unlock();
936 }
937
938 QObject::connect(sender: nativeThreads.at(i: numThreads - 1)->qthread, SIGNAL(finished()), receiver: &QTestEventLoop::instance(), SLOT(exitLoop()));
939
940 for (int i = 0; i < numThreads; ++i) {
941 nativeThreads.at(i)->stop();
942 nativeThreads.at(i)->join();
943 delete nativeThreads.at(i);
944 }
945
946 QTestEventLoop::instance().enterLoop(secs: 5);
947 QVERIFY(!QTestEventLoop::instance().timeout());
948 QCOMPARE(recorder.activationCount.loadRelaxed(), numThreads);
949}
950
951// Disconnects on WinCE
952void tst_QThread::stressTest()
953{
954 if (EmulationDetector::isRunningArmOnX86())
955 QSKIP("Qemu uses too much memory for each thread. Test would run out of memory.");
956
957 QElapsedTimer timer;
958 timer.start();
959 while (timer.elapsed() < one_minute) {
960 Current_Thread t;
961 t.start();
962 t.wait(time: one_minute);
963 }
964}
965
966class Syncronizer : public QObject
967{ Q_OBJECT
968public slots:
969 void setProp(int p) {
970 if(m_prop != p) {
971 m_prop = p;
972 emit propChanged(p);
973 }
974 }
975signals:
976 void propChanged(int);
977public:
978 Syncronizer() : m_prop(42) {}
979 int m_prop;
980};
981
982void tst_QThread::exitAndStart()
983{
984 QThread thread;
985 thread.exit(retcode: 555); //should do nothing
986
987 thread.start();
988
989 //test that the thread is running by executing queued connected signal there
990 Syncronizer sync1;
991 sync1.moveToThread(thread: &thread);
992 Syncronizer sync2;
993 sync2.moveToThread(thread: &thread);
994 connect(sender: &sync2, SIGNAL(propChanged(int)), receiver: &sync1, SLOT(setProp(int)), Qt::QueuedConnection);
995 connect(sender: &sync1, SIGNAL(propChanged(int)), receiver: &thread, SLOT(quit()), Qt::QueuedConnection);
996 QMetaObject::invokeMethod(obj: &sync2, member: "setProp", type: Qt::QueuedConnection , Q_ARG(int, 89));
997 QTRY_VERIFY(thread.wait(10));
998 QCOMPARE(sync2.m_prop, 89);
999 QCOMPARE(sync1.m_prop, 89);
1000}
1001
1002void tst_QThread::exitAndExec()
1003{
1004 class Thread : public QThread {
1005 public:
1006 QSemaphore sem1;
1007 QSemaphore sem2;
1008 volatile int value;
1009 void run() {
1010 sem1.acquire();
1011 value = exec(); //First entrence
1012 sem2.release();
1013 value = exec(); // Second loop
1014 }
1015 };
1016 Thread thread;
1017 thread.value = 0;
1018 thread.start();
1019 thread.exit(retcode: 556);
1020 thread.sem1.release(); //should exit the first loop
1021 thread.sem2.acquire();
1022 int v = thread.value;
1023 QCOMPARE(v, 556);
1024
1025 //test that the thread is running by executing queued connected signal there
1026 Syncronizer sync1;
1027 sync1.moveToThread(thread: &thread);
1028 Syncronizer sync2;
1029 sync2.moveToThread(thread: &thread);
1030 connect(sender: &sync2, SIGNAL(propChanged(int)), receiver: &sync1, SLOT(setProp(int)), Qt::QueuedConnection);
1031 connect(sender: &sync1, SIGNAL(propChanged(int)), receiver: &thread, SLOT(quit()), Qt::QueuedConnection);
1032 QMetaObject::invokeMethod(obj: &sync2, member: "setProp", type: Qt::QueuedConnection , Q_ARG(int, 89));
1033 QTRY_VERIFY(thread.wait(10));
1034 QCOMPARE(sync2.m_prop, 89);
1035 QCOMPARE(sync1.m_prop, 89);
1036}
1037
1038void tst_QThread::connectThreadFinishedSignalToObjectDeleteLaterSlot()
1039{
1040 QThread thread;
1041 QObject *object = new QObject;
1042 QPointer<QObject> p = object;
1043 QVERIFY(!p.isNull());
1044 connect(sender: &thread, SIGNAL(started()), receiver: &thread, SLOT(quit()), Qt::DirectConnection);
1045 connect(sender: &thread, SIGNAL(finished()), receiver: object, SLOT(deleteLater()));
1046 object->moveToThread(thread: &thread);
1047 thread.start();
1048 QVERIFY(thread.wait(30000));
1049 QVERIFY(p.isNull());
1050}
1051
1052class Waiting_Thread : public QThread
1053{
1054public:
1055 enum { WaitTime = 800 };
1056 QMutex mutex;
1057 QWaitCondition cond1;
1058 QWaitCondition cond2;
1059
1060 void run()
1061 {
1062 QMutexLocker locker(&mutex);
1063 cond1.wait(lockedMutex: &mutex);
1064 cond2.wait(lockedMutex: &mutex, time: WaitTime);
1065 }
1066};
1067
1068void tst_QThread::wait2()
1069{
1070 QElapsedTimer timer;
1071 Waiting_Thread thread;
1072 thread.start();
1073 timer.start();
1074 QVERIFY(!thread.wait(Waiting_Thread::WaitTime));
1075 qint64 elapsed = timer.elapsed(); // On Windows, we sometimes get (WaitTime - 9).
1076 QVERIFY2(elapsed >= Waiting_Thread::WaitTime - 10,
1077 qPrintable(msgElapsed(elapsed)));
1078
1079 timer.start();
1080 thread.cond1.wakeOne();
1081 QVERIFY(thread.wait(/*Waiting_Thread::WaitTime * 1.4*/));
1082 elapsed = timer.elapsed();
1083 QVERIFY2(elapsed - Waiting_Thread::WaitTime >= -1,
1084 qPrintable(msgElapsed(elapsed)));
1085}
1086
1087class SlowSlotObject : public QObject
1088{
1089 Q_OBJECT
1090public:
1091 QMutex mutex;
1092 QWaitCondition cond;
1093public slots:
1094 void slowSlot() {
1095 QMutexLocker locker(&mutex);
1096 cond.wait(lockedMutex: &mutex);
1097 }
1098};
1099
1100void tst_QThread::wait3_slowDestructor()
1101{
1102 SlowSlotObject slow;
1103 QThread thread;
1104 QObject::connect(sender: &thread, signal: &QThread::finished,
1105 receiver: &slow, slot: &SlowSlotObject::slowSlot, type: Qt::DirectConnection);
1106 QElapsedTimer timer;
1107
1108 thread.start();
1109 thread.quit();
1110 // Calling quit() will cause the thread to finish and enter the blocking slowSlot().
1111
1112 timer.start();
1113 {
1114 // Ensure thread finishes quickly after the checks - regardless of success:
1115 const auto wakeSlow = qScopeGuard(f: [&slow]() -> void { slow.cond.wakeOne(); });
1116 QVERIFY(!thread.wait(Waiting_Thread::WaitTime));
1117 const qint64 elapsed = timer.elapsed();
1118 QVERIFY2(elapsed >= Waiting_Thread::WaitTime - 1,
1119 qPrintable(QString::fromLatin1("elapsed: %1").arg(elapsed)));
1120 }
1121 QVERIFY(thread.wait(one_minute));
1122}
1123
1124void tst_QThread::destroyFinishRace()
1125{
1126 class Thread : public QThread { void run() {} };
1127 for (int i = 0; i < 15; i++) {
1128 Thread *thr = new Thread;
1129 connect(sender: thr, SIGNAL(finished()), receiver: thr, SLOT(deleteLater()));
1130 QPointer<QThread> weak(static_cast<QThread*>(thr));
1131 thr->start();
1132 while (weak) {
1133 qApp->processEvents();
1134 qApp->processEvents();
1135 qApp->processEvents();
1136 qApp->processEvents();
1137 }
1138 }
1139}
1140
1141void tst_QThread::startFinishRace()
1142{
1143 class Thread : public QThread {
1144 public:
1145 Thread() : i (50) {}
1146 void run() {
1147 i--;
1148 if (!i) disconnect(sender: this, SIGNAL(finished()), receiver: 0, member: 0);
1149 }
1150 int i;
1151 };
1152 for (int i = 0; i < 15; i++) {
1153 Thread thr;
1154 connect(sender: &thr, SIGNAL(finished()), receiver: &thr, SLOT(start()));
1155 thr.start();
1156 while (!thr.isFinished() || thr.i != 0) {
1157 qApp->processEvents();
1158 qApp->processEvents();
1159 qApp->processEvents();
1160 qApp->processEvents();
1161 }
1162 QCOMPARE(thr.i, 0);
1163 }
1164}
1165
1166void tst_QThread::startAndQuitCustomEventLoop()
1167{
1168 struct Thread : QThread {
1169 void run() { QEventLoop().exec(); }
1170 };
1171
1172 for (int i = 0; i < 5; i++) {
1173 Thread t;
1174 t.start();
1175 t.quit();
1176 t.wait();
1177 }
1178}
1179
1180class FinishedTestObject : public QObject {
1181 Q_OBJECT
1182public:
1183 FinishedTestObject() : ok(false) {}
1184 bool ok;
1185public slots:
1186 void slotFinished() {
1187 QThread *t = qobject_cast<QThread *>(object: sender());
1188 ok = t && t->isFinished() && !t->isRunning();
1189 }
1190};
1191
1192void tst_QThread::isRunningInFinished()
1193{
1194 for (int i = 0; i < 15; i++) {
1195 QThread thread;
1196 thread.start();
1197 FinishedTestObject localObject;
1198 FinishedTestObject inThreadObject;
1199 localObject.setObjectName("...");
1200 inThreadObject.moveToThread(thread: &thread);
1201 connect(sender: &thread, SIGNAL(finished()), receiver: &localObject, SLOT(slotFinished()));
1202 connect(sender: &thread, SIGNAL(finished()), receiver: &inThreadObject, SLOT(slotFinished()));
1203 QEventLoop loop;
1204 connect(sender: &thread, SIGNAL(finished()), receiver: &loop, SLOT(quit()));
1205 QMetaObject::invokeMethod(obj: &thread, member: "quit", type: Qt::QueuedConnection);
1206 loop.exec();
1207 QVERIFY(!thread.isRunning());
1208 QVERIFY(thread.isFinished());
1209 QVERIFY(localObject.ok);
1210 QVERIFY(inThreadObject.ok);
1211 }
1212}
1213
1214QT_BEGIN_NAMESPACE
1215Q_CORE_EXPORT uint qGlobalPostedEventsCount();
1216QT_END_NAMESPACE
1217
1218class DummyEventDispatcher : public QAbstractEventDispatcher {
1219public:
1220 DummyEventDispatcher() : QAbstractEventDispatcher() {}
1221 bool processEvents(QEventLoop::ProcessEventsFlags) {
1222 visited.storeRelaxed(newValue: true);
1223 emit awake();
1224 QCoreApplication::sendPostedEvents();
1225 return false;
1226 }
1227 bool hasPendingEvents() {
1228 return qGlobalPostedEventsCount();
1229 }
1230 void registerSocketNotifier(QSocketNotifier *) {}
1231 void unregisterSocketNotifier(QSocketNotifier *) {}
1232 void registerTimer(int, int, Qt::TimerType, QObject *) {}
1233 bool unregisterTimer(int ) { return false; }
1234 bool unregisterTimers(QObject *) { return false; }
1235 QList<TimerInfo> registeredTimers(QObject *) const { return QList<TimerInfo>(); }
1236 int remainingTime(int) { return 0; }
1237 void wakeUp() {}
1238 void interrupt() {}
1239 void flush() {}
1240
1241#ifdef Q_OS_WIN
1242 bool registerEventNotifier(QWinEventNotifier *) { return false; }
1243 void unregisterEventNotifier(QWinEventNotifier *) { }
1244#endif
1245
1246 QBasicAtomicInt visited; // bool
1247};
1248
1249class ThreadObj : public QObject
1250{
1251 Q_OBJECT
1252public slots:
1253 void visit() {
1254 emit visited();
1255 }
1256signals:
1257 void visited();
1258};
1259
1260void tst_QThread::customEventDispatcher()
1261{
1262 QThread thr;
1263 // there should be no ED yet
1264 QVERIFY(!thr.eventDispatcher());
1265 DummyEventDispatcher *ed = new DummyEventDispatcher;
1266 thr.setEventDispatcher(ed);
1267 // the new ED should be set
1268 QCOMPARE(thr.eventDispatcher(), ed);
1269 // test the alternative API of QAbstractEventDispatcher
1270 QCOMPARE(QAbstractEventDispatcher::instance(&thr), ed);
1271 thr.start();
1272 // start() should not overwrite the ED
1273 QCOMPARE(thr.eventDispatcher(), ed);
1274
1275 ThreadObj obj;
1276 obj.moveToThread(thread: &thr);
1277 // move was successful?
1278 QCOMPARE(obj.thread(), &thr);
1279 QEventLoop loop;
1280 connect(sender: &obj, SIGNAL(visited()), receiver: &loop, SLOT(quit()), Qt::QueuedConnection);
1281 QMetaObject::invokeMethod(obj: &obj, member: "visit", type: Qt::QueuedConnection);
1282 loop.exec();
1283 // test that the ED has really been used
1284 QVERIFY(ed->visited.loadRelaxed());
1285
1286 QPointer<DummyEventDispatcher> weak_ed(ed);
1287 QVERIFY(!weak_ed.isNull());
1288 thr.quit();
1289 // wait for thread to be stopped
1290 QVERIFY(thr.wait(30000));
1291 // test that ED has been deleted
1292 QVERIFY(weak_ed.isNull());
1293}
1294
1295class Job : public QObject
1296{
1297 Q_OBJECT
1298public:
1299 Job(QThread *thread, int deleteDelay, bool *flag, QObject *parent = 0)
1300 : QObject(parent), quitLocker(thread), exitThreadCalled(*flag)
1301 {
1302 exitThreadCalled = false;
1303 moveToThread(thread);
1304 QTimer::singleShot(msec: deleteDelay, receiver: this, SLOT(deleteLater()));
1305 QTimer::singleShot(msec: 1000, receiver: this, SLOT(exitThread()));
1306 }
1307
1308private slots:
1309 void exitThread()
1310 {
1311 exitThreadCalled = true;
1312 thread()->exit(retcode: 1);
1313 }
1314
1315private:
1316 QEventLoopLocker quitLocker;
1317public:
1318 bool &exitThreadCalled;
1319};
1320
1321void tst_QThread::quitLock()
1322{
1323 QThread thread;
1324 bool exitThreadCalled;
1325
1326 QEventLoop loop;
1327 connect(sender: &thread, SIGNAL(finished()), receiver: &loop, SLOT(quit()));
1328
1329 Job *job;
1330
1331 thread.start();
1332 job = new Job(&thread, 500, &exitThreadCalled);
1333 QCOMPARE(job->thread(), &thread);
1334 loop.exec();
1335 QVERIFY(!exitThreadCalled);
1336
1337 thread.start();
1338 job = new Job(&thread, 2500, &exitThreadCalled);
1339 QCOMPARE(job->thread(), &thread);
1340 loop.exec();
1341 QVERIFY(exitThreadCalled);
1342
1343 delete job;
1344}
1345
1346void tst_QThread::create()
1347{
1348#if !QT_CONFIG(cxx11_future)
1349 QSKIP("This test requires QThread::create");
1350#else
1351 {
1352 const auto &function = [](){};
1353 QScopedPointer<QThread> thread(QThread::create(f: function));
1354 QVERIFY(thread);
1355 QVERIFY(!thread->isRunning());
1356 thread->start();
1357 QVERIFY(thread->wait());
1358 }
1359
1360 {
1361 // no side effects before starting
1362 int i = 0;
1363 const auto &function = [&i]() { i = 42; };
1364 QScopedPointer<QThread> thread(QThread::create(f: function));
1365 QVERIFY(thread);
1366 QVERIFY(!thread->isRunning());
1367 QCOMPARE(i, 0);
1368 thread->start();
1369 QVERIFY(thread->wait());
1370 QCOMPARE(i, 42);
1371 }
1372
1373 {
1374 // control thread progress
1375 QSemaphore semaphore1;
1376 QSemaphore semaphore2;
1377
1378 const auto &function = [&semaphore1, &semaphore2]() -> void
1379 {
1380 semaphore1.acquire();
1381 semaphore2.release();
1382 };
1383
1384 QScopedPointer<QThread> thread(QThread::create(f: function));
1385
1386 QVERIFY(thread);
1387 thread->start();
1388 QTRY_VERIFY(thread->isRunning());
1389 semaphore1.release();
1390 semaphore2.acquire();
1391 QVERIFY(thread->wait());
1392 QVERIFY(!thread->isRunning());
1393 }
1394
1395 {
1396 // ignore return values
1397 const auto &function = []() { return 42; };
1398 QScopedPointer<QThread> thread(QThread::create(f: function));
1399 QVERIFY(thread);
1400 QVERIFY(!thread->isRunning());
1401 thread->start();
1402 QVERIFY(thread->wait());
1403 }
1404
1405 {
1406 // return value of create
1407 QScopedPointer<QThread> thread;
1408 QSemaphore s;
1409 const auto &function = [&thread, &s]() -> void
1410 {
1411 s.acquire();
1412 QCOMPARE(thread.data(), QThread::currentThread());
1413 };
1414
1415 thread.reset(other: QThread::create(f: function));
1416 QVERIFY(thread);
1417 thread->start();
1418 QTRY_VERIFY(thread->isRunning());
1419 s.release();
1420 QVERIFY(thread->wait());
1421 }
1422
1423 {
1424 // move-only parameters
1425 struct MoveOnlyValue {
1426 explicit MoveOnlyValue(int v) : v(v) {}
1427 ~MoveOnlyValue() = default;
1428 MoveOnlyValue(const MoveOnlyValue &) = delete;
1429 MoveOnlyValue(MoveOnlyValue &&) = default;
1430 MoveOnlyValue &operator=(const MoveOnlyValue &) = delete;
1431 MoveOnlyValue &operator=(MoveOnlyValue &&) = default;
1432 int v;
1433 };
1434
1435 struct MoveOnlyFunctor {
1436 explicit MoveOnlyFunctor(int *i) : i(i) {}
1437 ~MoveOnlyFunctor() = default;
1438 MoveOnlyFunctor(const MoveOnlyFunctor &) = delete;
1439 MoveOnlyFunctor(MoveOnlyFunctor &&) = default;
1440 MoveOnlyFunctor &operator=(const MoveOnlyFunctor &) = delete;
1441 MoveOnlyFunctor &operator=(MoveOnlyFunctor &&) = default;
1442 int operator()() { return (*i = 42); }
1443 int *i;
1444 };
1445
1446 {
1447 int i = 0;
1448 MoveOnlyFunctor f(&i);
1449 QScopedPointer<QThread> thread(QThread::create(f: std::move(f)));
1450 QVERIFY(thread);
1451 QVERIFY(!thread->isRunning());
1452 thread->start();
1453 QVERIFY(thread->wait());
1454 QCOMPARE(i, 42);
1455 }
1456
1457#if defined(__cpp_init_captures) && __cpp_init_captures >= 201304
1458 {
1459 int i = 0;
1460 MoveOnlyValue mo(123);
1461 auto moveOnlyFunction = [&i, mo = std::move(mo)]() { i = mo.v; };
1462 QScopedPointer<QThread> thread(QThread::create(f: std::move(moveOnlyFunction)));
1463 QVERIFY(thread);
1464 QVERIFY(!thread->isRunning());
1465 thread->start();
1466 QVERIFY(thread->wait());
1467 QCOMPARE(i, 123);
1468 }
1469#endif // __cpp_init_captures
1470
1471#ifdef QTHREAD_HAS_VARIADIC_CREATE
1472 {
1473 int i = 0;
1474 const auto &function = [&i](MoveOnlyValue &&mo) { i = mo.v; };
1475 QScopedPointer<QThread> thread(QThread::create(f: function, args: MoveOnlyValue(123)));
1476 QVERIFY(thread);
1477 QVERIFY(!thread->isRunning());
1478 thread->start();
1479 QVERIFY(thread->wait());
1480 QCOMPARE(i, 123);
1481 }
1482
1483 {
1484 int i = 0;
1485 const auto &function = [&i](MoveOnlyValue &&mo) { i = mo.v; };
1486 MoveOnlyValue mo(-1);
1487 QScopedPointer<QThread> thread(QThread::create(f: function, args: std::move(mo)));
1488 QVERIFY(thread);
1489 QVERIFY(!thread->isRunning());
1490 thread->start();
1491 QVERIFY(thread->wait());
1492 QCOMPARE(i, -1);
1493 }
1494#endif // QTHREAD_HAS_VARIADIC_CREATE
1495 }
1496
1497#ifdef QTHREAD_HAS_VARIADIC_CREATE
1498 {
1499 // simple parameter passing
1500 int i = 0;
1501 const auto &function = [&i](int j, int k) { i = j * k; };
1502 QScopedPointer<QThread> thread(QThread::create(f: function, args: 3, args: 4));
1503 QVERIFY(thread);
1504 QVERIFY(!thread->isRunning());
1505 QCOMPARE(i, 0);
1506 thread->start();
1507 QVERIFY(thread->wait());
1508 QCOMPARE(i, 12);
1509 }
1510
1511 {
1512 // ignore return values (with parameters)
1513 const auto &function = [](double d) { return d * 2.0; };
1514 QScopedPointer<QThread> thread(QThread::create(f: function, args: 3.14));
1515 QVERIFY(thread);
1516 QVERIFY(!thread->isRunning());
1517 thread->start();
1518 QVERIFY(thread->wait());
1519 }
1520
1521 {
1522 // handling of pointers to member functions, std::ref, etc.
1523 struct S {
1524 S() : v(0) {}
1525 void doSomething() { ++v; }
1526 int v;
1527 };
1528
1529 S object;
1530
1531 QCOMPARE(object.v, 0);
1532
1533 QScopedPointer<QThread> thread;
1534 thread.reset(other: QThread::create(f: &S::doSomething, args&: object));
1535 QVERIFY(thread);
1536 QVERIFY(!thread->isRunning());
1537 thread->start();
1538 QVERIFY(thread->wait());
1539
1540 QCOMPARE(object.v, 0); // a copy was passed, this should still be 0
1541
1542 thread.reset(other: QThread::create(f: &S::doSomething, args: std::ref(t&: object)));
1543 QVERIFY(thread);
1544 QVERIFY(!thread->isRunning());
1545 thread->start();
1546 QVERIFY(thread->wait());
1547
1548 QCOMPARE(object.v, 1);
1549
1550 thread.reset(other: QThread::create(f: &S::doSomething, args: &object));
1551 QVERIFY(thread);
1552 QVERIFY(!thread->isRunning());
1553 thread->start();
1554 QVERIFY(thread->wait());
1555
1556 QCOMPARE(object.v, 2);
1557 }
1558
1559 {
1560 // std::ref into ordinary reference
1561 int i = 42;
1562 const auto &function = [](int &i) { i *= 2; };
1563 QScopedPointer<QThread> thread(QThread::create(f: function, args: std::ref(t&: i)));
1564 QVERIFY(thread);
1565 thread->start();
1566 QVERIFY(thread->wait());
1567 QCOMPARE(i, 84);
1568 }
1569
1570#ifndef QT_NO_EXCEPTIONS
1571 {
1572 // exceptions when copying/decaying the arguments are thrown at build side and won't terminate
1573 class ThreadException : public std::exception
1574 {
1575 };
1576
1577 struct ThrowWhenCopying
1578 {
1579 ThrowWhenCopying() = default;
1580 ThrowWhenCopying(const ThrowWhenCopying &)
1581 {
1582 throw ThreadException();
1583 }
1584 ~ThrowWhenCopying() = default;
1585 ThrowWhenCopying &operator=(const ThrowWhenCopying &) = default;
1586 };
1587
1588 const auto &function = [](const ThrowWhenCopying &){};
1589 QScopedPointer<QThread> thread;
1590 ThrowWhenCopying t;
1591 QVERIFY_EXCEPTION_THROWN(thread.reset(QThread::create(function, t)), ThreadException);
1592 QVERIFY(!thread);
1593 }
1594#endif // QT_NO_EXCEPTIONS
1595#endif // QTHREAD_HAS_VARIADIC_CREATE
1596#endif // QT_CONFIG(cxx11_future)
1597}
1598
1599class StopableJob : public QObject
1600{
1601 Q_OBJECT
1602public:
1603 StopableJob (QSemaphore &sem) : sem(sem) {}
1604 QSemaphore &sem;
1605public Q_SLOTS:
1606 void run() {
1607 sem.release();
1608 while (!thread()->isInterruptionRequested())
1609 QTest::qSleep(ms: 10);
1610 sem.release();
1611 Q_EMIT finished();
1612 }
1613Q_SIGNALS:
1614 void finished();
1615};
1616
1617void tst_QThread::requestTermination()
1618{
1619 QThread thread;
1620 QVERIFY(!thread.isInterruptionRequested());
1621 QSemaphore sem;
1622 StopableJob *j = new StopableJob(sem);
1623 j->moveToThread(thread: &thread);
1624 connect(sender: &thread, signal: &QThread::started, receiver: j, slot: &StopableJob::run);
1625 connect(sender: j, signal: &StopableJob::finished, receiver: &thread, slot: &QThread::quit, type: Qt::DirectConnection);
1626 connect(sender: &thread, signal: &QThread::finished, receiver: j, slot: &QObject::deleteLater);
1627 thread.start();
1628 QVERIFY(!thread.isInterruptionRequested());
1629 sem.acquire();
1630 QVERIFY(!thread.wait(1000));
1631 thread.requestInterruption();
1632 sem.acquire();
1633 QVERIFY(thread.wait(1000));
1634 QVERIFY(!thread.isInterruptionRequested());
1635}
1636
1637/*
1638 This is a regression test for QTBUG-96846.
1639
1640 Incorrect system thread ID cleanup can cause QThread::wait() to report that
1641 a thread is trying to wait for itself.
1642*/
1643void tst_QThread::threadIdReuse()
1644{
1645 class Thread1 : public QThread {
1646 public:
1647 // It's important that those thread ID's are not accessed concurrently
1648 Qt::HANDLE savedThreadId;
1649
1650 void run() override { savedThreadId = QThread::currentThreadId(); }
1651 };
1652
1653 class Thread2 : public Thread1 {
1654 public:
1655 bool waitOk;
1656 Thread2(QThread *otherThread) : Thread1(), waitOk(false), otherThread(otherThread) {}
1657
1658 void run() override {
1659 Thread1::run();
1660 waitOk = otherThread->wait();
1661 }
1662
1663 private:
1664 QThread *const otherThread;
1665 };
1666
1667 Thread1 thread1;
1668 thread1.start();
1669 QVERIFY(thread1.wait());
1670
1671 // If the system thread allocated for thread1 is destroyed before thread2 is
1672 // started, at least on some versions of Linux the system thread ID for
1673 // thread2 would be the same as one that was used for thread1.
1674
1675 // The system thread may be alive for some time after returning from
1676 // QThread::wait() because the implementation is using detachable threads, so
1677 // some additional time is required for the system thread to terminate. Not
1678 // waiting long enough here would result in a new system thread ID being
1679 // allocated for thread2 and this test passing even without a fix for
1680 // QTBUG-96846.
1681 bool threadIdReused = false;
1682
1683 for (int i = 0; i < 42; i++) {
1684 QThread::msleep(1);
1685
1686 Thread2 thread2(&thread1);
1687 thread2.start();
1688 QVERIFY(thread2.wait());
1689 QVERIFY(thread2.waitOk);
1690
1691 if (thread1.savedThreadId == thread2.savedThreadId) {
1692 qDebug(msg: "Thread ID reused at iteration %d", i);
1693 threadIdReused = true;
1694 break;
1695 }
1696 }
1697
1698 if (!threadIdReused) {
1699 QSKIP("Thread ID was not reused");
1700 }
1701}
1702
1703QTEST_MAIN(tst_QThread)
1704#include "tst_qthread.moc"
1705

source code of qtbase/tests/auto/corelib/thread/qthread/tst_qthread.cpp