tests/auto/qthread/tst_qthread.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
-1:000000000000 0:1918ee327afb
       
     1 /****************************************************************************
       
     2 **
       
     3 ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       
     4 ** All rights reserved.
       
     5 ** Contact: Nokia Corporation (qt-info@nokia.com)
       
     6 **
       
     7 ** This file is part of the test suite of the Qt Toolkit.
       
     8 **
       
     9 ** $QT_BEGIN_LICENSE:LGPL$
       
    10 ** No Commercial Usage
       
    11 ** This file contains pre-release code and may not be distributed.
       
    12 ** You may use this file in accordance with the terms and conditions
       
    13 ** contained in the Technology Preview License Agreement accompanying
       
    14 ** this package.
       
    15 **
       
    16 ** GNU Lesser General Public License Usage
       
    17 ** Alternatively, this file may be used under the terms of the GNU Lesser
       
    18 ** General Public License version 2.1 as published by the Free Software
       
    19 ** Foundation and appearing in the file LICENSE.LGPL included in the
       
    20 ** packaging of this file.  Please review the following information to
       
    21 ** ensure the GNU Lesser General Public License version 2.1 requirements
       
    22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
       
    23 **
       
    24 ** In addition, as a special exception, Nokia gives you certain additional
       
    25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
       
    26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
       
    27 **
       
    28 ** If you have questions regarding the use of this file, please contact
       
    29 ** Nokia at qt-info@nokia.com.
       
    30 **
       
    31 **
       
    32 **
       
    33 **
       
    34 **
       
    35 **
       
    36 **
       
    37 **
       
    38 ** $QT_END_LICENSE$
       
    39 **
       
    40 ****************************************************************************/
       
    41 
       
    42 
       
    43 #include <QtTest/QtTest>
       
    44 
       
    45 #include <qcoreapplication.h>
       
    46 #include <qdatetime.h>
       
    47 #include <qmutex.h>
       
    48 #include <qthread.h>
       
    49 #include <qtimer.h>
       
    50 #include <qwaitcondition.h>
       
    51 #include <qdebug.h>
       
    52 
       
    53 #ifdef Q_OS_UNIX
       
    54 #include <pthread.h>
       
    55 #endif
       
    56 #if defined(Q_OS_WINCE)
       
    57 #include <windows.h>
       
    58 #elif defined(Q_OS_WIN)
       
    59 #include <process.h>
       
    60 #include <windows.h>
       
    61 #endif
       
    62 
       
    63 //TESTED_CLASS=
       
    64 //TESTED_FILES=
       
    65 
       
    66 class tst_QThread : public QObject
       
    67 {
       
    68     Q_OBJECT
       
    69 
       
    70 public:
       
    71     tst_QThread();
       
    72     virtual ~tst_QThread();
       
    73 
       
    74 private slots:
       
    75     void currentThreadId();
       
    76     void currentThread();
       
    77     void idealThreadCount();
       
    78     void isFinished();
       
    79     void isRunning();
       
    80     void setPriority();
       
    81     void priority();
       
    82     void setStackSize();
       
    83     void stackSize();
       
    84     void exit();
       
    85     void start();
       
    86     void terminate();
       
    87     void quit();
       
    88     void wait();
       
    89     void started();
       
    90     void finished();
       
    91     void terminated();
       
    92     void run();
       
    93     void exec();
       
    94     void setTerminationEnabled();
       
    95     void sleep();
       
    96     void msleep();
       
    97     void usleep();
       
    98 
       
    99     void nativeThreadAdoption();
       
   100     void adoptedThreadAffinity();
       
   101     void adoptedThreadSetPriority();
       
   102     void adoptedThreadExit();
       
   103     void adoptedThreadExec();
       
   104     void adoptedThreadFinished();
       
   105     void adoptMultipleThreads();
       
   106 
       
   107     void stressTest();
       
   108 };
       
   109 
       
   110 enum { one_minute = 60 * 1000, five_minutes = 5 * one_minute };
       
   111 
       
   112 class SignalRecorder : public QObject
       
   113 {
       
   114     Q_OBJECT
       
   115 public:
       
   116     QAtomicInt activationCount;
       
   117 
       
   118     inline SignalRecorder()
       
   119     { activationCount = 0; }
       
   120 
       
   121     bool wasActivated()
       
   122     { return activationCount > 0; }
       
   123 
       
   124 public slots:
       
   125     void slot();
       
   126 };
       
   127 
       
   128 void SignalRecorder::slot()
       
   129 { activationCount.ref(); }
       
   130 
       
   131 class Current_Thread : public QThread
       
   132 {
       
   133 public:
       
   134     Qt::HANDLE id;
       
   135     QThread *thread;
       
   136 
       
   137     void run()
       
   138     {
       
   139         id = QThread::currentThreadId();
       
   140         thread = QThread::currentThread();
       
   141     }
       
   142 };
       
   143 
       
   144 class Simple_Thread : public QThread
       
   145 {
       
   146 public:
       
   147     QMutex mutex;
       
   148     QWaitCondition cond;
       
   149 
       
   150     void run()
       
   151     {
       
   152         QMutexLocker locker(&mutex);
       
   153         cond.wakeOne();
       
   154     }
       
   155 };
       
   156 
       
   157 class Exit_Object : public QObject
       
   158 {
       
   159     Q_OBJECT
       
   160 public:
       
   161     QThread *thread;
       
   162     int code;
       
   163 public slots:
       
   164     void slot()
       
   165     { thread->exit(code); }
       
   166 };
       
   167 
       
   168 class Exit_Thread : public Simple_Thread
       
   169 {
       
   170 public:
       
   171     int code;
       
   172     int result;
       
   173 
       
   174     void run()
       
   175     {
       
   176         Simple_Thread::run();
       
   177         Exit_Object o;
       
   178         o.thread = this;
       
   179         o.code = code;
       
   180         QTimer::singleShot(100, &o, SLOT(slot()));
       
   181         result = exec();
       
   182     }
       
   183 };
       
   184 
       
   185 class Terminate_Thread : public Simple_Thread
       
   186 {
       
   187 public:
       
   188     void run()
       
   189     {
       
   190         setTerminationEnabled(false);
       
   191         {
       
   192             QMutexLocker locker(&mutex);
       
   193             cond.wakeOne();
       
   194             cond.wait(&mutex, five_minutes);
       
   195         }
       
   196         setTerminationEnabled(true);
       
   197         Q_ASSERT_X(false, "tst_QThread", "test case hung");
       
   198     }
       
   199 };
       
   200 
       
   201 class Quit_Object : public QObject
       
   202 {
       
   203     Q_OBJECT
       
   204 public:
       
   205     QThread *thread;
       
   206 public slots:
       
   207     void slot()
       
   208     { thread->quit(); }
       
   209 };
       
   210 
       
   211 class Quit_Thread : public Simple_Thread
       
   212 {
       
   213 public:
       
   214     int result;
       
   215 
       
   216     void run()
       
   217     {
       
   218         {
       
   219             QMutexLocker locker(&mutex);
       
   220             cond.wakeOne();
       
   221         }
       
   222         Quit_Object o;
       
   223         o.thread = this;
       
   224         QTimer::singleShot(100, &o, SLOT(slot()));
       
   225         result = exec();
       
   226     }
       
   227 };
       
   228 
       
   229 class Sleep_Thread : public Simple_Thread
       
   230 {
       
   231 public:
       
   232     enum SleepType { Second, Millisecond, Microsecond };
       
   233 
       
   234     SleepType sleepType;
       
   235     int interval;
       
   236 
       
   237     int elapsed; // result, in *MILLISECONDS*
       
   238 
       
   239     void run()
       
   240     {
       
   241         QMutexLocker locker(&mutex);
       
   242 
       
   243         elapsed = 0;
       
   244         QTime time;
       
   245         time.start();
       
   246         switch (sleepType) {
       
   247         case Second:
       
   248             sleep(interval);
       
   249             break;
       
   250         case Millisecond:
       
   251             msleep(interval);
       
   252             break;
       
   253         case Microsecond:
       
   254             usleep(interval);
       
   255             break;
       
   256         }
       
   257         elapsed = time.elapsed();
       
   258 
       
   259         cond.wakeOne();
       
   260     }
       
   261 };
       
   262 
       
   263 tst_QThread::tst_QThread()
       
   264 
       
   265 {
       
   266 }
       
   267 
       
   268 tst_QThread::~tst_QThread()
       
   269 {
       
   270 
       
   271 }
       
   272 
       
   273 void tst_QThread::currentThreadId()
       
   274 {
       
   275     Current_Thread thread;
       
   276     thread.id = 0;
       
   277     thread.thread = 0;
       
   278     thread.start();
       
   279     QVERIFY(thread.wait(five_minutes));
       
   280     QVERIFY(thread.id != 0);
       
   281     QVERIFY(thread.id != QThread::currentThreadId());
       
   282 }
       
   283 
       
   284 void tst_QThread::currentThread()
       
   285 {
       
   286     QVERIFY(QThread::currentThread() != 0);
       
   287     QCOMPARE(QThread::currentThread(), thread());
       
   288 
       
   289     Current_Thread thread;
       
   290     thread.id = 0;
       
   291     thread.thread = 0;
       
   292     thread.start();
       
   293     QVERIFY(thread.wait(five_minutes));
       
   294     QCOMPARE(thread.thread, (QThread *)&thread);
       
   295 }
       
   296 
       
   297 void tst_QThread::idealThreadCount()
       
   298 {
       
   299     QVERIFY(QThread::idealThreadCount() > 0);
       
   300     qDebug() << "Available cpu cores:" << QThread::idealThreadCount();
       
   301 }
       
   302 
       
   303 void tst_QThread::isFinished()
       
   304 {
       
   305     Simple_Thread thread;
       
   306     QVERIFY(!thread.isFinished());
       
   307     QMutexLocker locker(&thread.mutex);
       
   308     thread.start();
       
   309     QVERIFY(!thread.isFinished());
       
   310     thread.cond.wait(locker.mutex());
       
   311     QVERIFY(thread.wait(five_minutes));
       
   312     QVERIFY(thread.isFinished());
       
   313 }
       
   314 
       
   315 void tst_QThread::isRunning()
       
   316 {
       
   317     Simple_Thread thread;
       
   318     QVERIFY(!thread.isRunning());
       
   319     QMutexLocker locker(&thread.mutex);
       
   320     thread.start();
       
   321     QVERIFY(thread.isRunning());
       
   322     thread.cond.wait(locker.mutex());
       
   323     QVERIFY(thread.wait(five_minutes));
       
   324     QVERIFY(!thread.isRunning());
       
   325 }
       
   326 
       
   327 void tst_QThread::setPriority()
       
   328 {
       
   329     Simple_Thread thread;
       
   330 
       
   331     // cannot change the priority, since the thread is not running
       
   332     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   333     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   334     thread.setPriority(QThread::IdlePriority);
       
   335     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   336     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   337     thread.setPriority(QThread::LowestPriority);
       
   338     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   339     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   340     thread.setPriority(QThread::LowPriority);
       
   341     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   342     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   343     thread.setPriority(QThread::NormalPriority);
       
   344     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   345     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   346     thread.setPriority(QThread::HighPriority);
       
   347     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   348     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   349     thread.setPriority(QThread::HighestPriority);
       
   350     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   351     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   352     thread.setPriority(QThread::TimeCriticalPriority);
       
   353     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   354 
       
   355     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   356     QMutexLocker locker(&thread.mutex);
       
   357     thread.start();
       
   358 
       
   359     // change the priority of a running thread
       
   360     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   361     thread.setPriority(QThread::IdlePriority);
       
   362     QCOMPARE(thread.priority(), QThread::IdlePriority);
       
   363     thread.setPriority(QThread::LowestPriority);
       
   364     QCOMPARE(thread.priority(), QThread::LowestPriority);
       
   365     thread.setPriority(QThread::LowPriority);
       
   366     QCOMPARE(thread.priority(), QThread::LowPriority);
       
   367     thread.setPriority(QThread::NormalPriority);
       
   368     QCOMPARE(thread.priority(), QThread::NormalPriority);
       
   369     thread.setPriority(QThread::HighPriority);
       
   370     QCOMPARE(thread.priority(), QThread::HighPriority);
       
   371     thread.setPriority(QThread::HighestPriority);
       
   372     QCOMPARE(thread.priority(), QThread::HighestPriority);
       
   373     thread.setPriority(QThread::TimeCriticalPriority);
       
   374     QCOMPARE(thread.priority(), QThread::TimeCriticalPriority);
       
   375     thread.cond.wait(locker.mutex());
       
   376     QVERIFY(thread.wait(five_minutes));
       
   377 
       
   378     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   379     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   380     thread.setPriority(QThread::IdlePriority);
       
   381     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   382     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   383     thread.setPriority(QThread::LowestPriority);
       
   384     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   385     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   386     thread.setPriority(QThread::LowPriority);
       
   387     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   388     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   389     thread.setPriority(QThread::NormalPriority);
       
   390     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   391     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   392     thread.setPriority(QThread::HighPriority);
       
   393     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   394     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   395     thread.setPriority(QThread::HighestPriority);
       
   396     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   397     QTest::ignoreMessage(QtWarningMsg, "QThread::setPriority: Cannot set priority, thread is not running");
       
   398     thread.setPriority(QThread::TimeCriticalPriority);
       
   399     QCOMPARE(thread.priority(), QThread::InheritPriority);
       
   400 }
       
   401 
       
   402 void tst_QThread::priority()
       
   403 { DEPENDS_ON("setPriority"); }
       
   404 
       
   405 void tst_QThread::setStackSize()
       
   406 {
       
   407     Simple_Thread thread;
       
   408     QCOMPARE(thread.stackSize(), 0u);
       
   409     thread.setStackSize(8192u);
       
   410     QCOMPARE(thread.stackSize(), 8192u);
       
   411     thread.setStackSize(0u);
       
   412     QCOMPARE(thread.stackSize(), 0u);
       
   413 }
       
   414 
       
   415 void tst_QThread::stackSize()
       
   416 {
       
   417     DEPENDS_ON("setStackSize");
       
   418 }
       
   419 
       
   420 void tst_QThread::exit()
       
   421 {
       
   422     Exit_Thread thread;
       
   423     thread.code = 42;
       
   424     thread.result = 0;
       
   425     QVERIFY(!thread.isFinished());
       
   426     QVERIFY(!thread.isRunning());
       
   427     QMutexLocker locker(&thread.mutex);
       
   428     thread.start();
       
   429     QVERIFY(thread.isRunning());
       
   430     QVERIFY(!thread.isFinished());
       
   431     thread.cond.wait(locker.mutex());
       
   432     QVERIFY(thread.wait(five_minutes));
       
   433     QVERIFY(thread.isFinished());
       
   434     QVERIFY(!thread.isRunning());
       
   435     QCOMPARE(thread.result, thread.code);
       
   436 }
       
   437 
       
   438 void tst_QThread::start()
       
   439 {
       
   440     QThread::Priority priorities[] = {
       
   441 	QThread::IdlePriority,
       
   442 	QThread::LowestPriority,
       
   443 	QThread::LowPriority,
       
   444 	QThread::NormalPriority,
       
   445 	QThread::HighPriority,
       
   446 	QThread::HighestPriority,
       
   447 	QThread::TimeCriticalPriority,
       
   448 	QThread::InheritPriority
       
   449     };
       
   450     const int prio_count = sizeof(priorities) / sizeof(QThread::Priority);
       
   451 
       
   452     for (int i = 0; i < prio_count; ++i) {
       
   453         Simple_Thread thread;
       
   454         QVERIFY(!thread.isFinished());
       
   455         QVERIFY(!thread.isRunning());
       
   456         QMutexLocker locker(&thread.mutex);
       
   457         thread.start(priorities[i]);
       
   458         QVERIFY(thread.isRunning());
       
   459         QVERIFY(!thread.isFinished());
       
   460         thread.cond.wait(locker.mutex());
       
   461         QVERIFY(thread.wait(five_minutes));
       
   462         QVERIFY(thread.isFinished());
       
   463         QVERIFY(!thread.isRunning());
       
   464     }
       
   465 }
       
   466 
       
   467 void tst_QThread::terminate()
       
   468 {
       
   469     Terminate_Thread thread;
       
   470     {
       
   471         QMutexLocker locker(&thread.mutex);
       
   472         thread.start();
       
   473         QVERIFY(thread.cond.wait(locker.mutex(), five_minutes));
       
   474         thread.terminate();
       
   475         thread.cond.wakeOne();
       
   476     }
       
   477     QVERIFY(thread.wait(five_minutes));
       
   478 }
       
   479 
       
   480 void tst_QThread::quit()
       
   481 {
       
   482     Quit_Thread thread;
       
   483     QVERIFY(!thread.isFinished());
       
   484     QVERIFY(!thread.isRunning());
       
   485     QMutexLocker locker(&thread.mutex);
       
   486     thread.start();
       
   487     QVERIFY(thread.isRunning());
       
   488     QVERIFY(!thread.isFinished());
       
   489     thread.cond.wait(locker.mutex());
       
   490     QVERIFY(thread.wait(five_minutes));
       
   491     QVERIFY(thread.isFinished());
       
   492     QVERIFY(!thread.isRunning());
       
   493     QCOMPARE(thread.result, 0);
       
   494 }
       
   495 
       
   496 void tst_QThread::wait()
       
   497 {
       
   498     DEPENDS_ON("isRunning");
       
   499     DEPENDS_ON("isFinished");
       
   500 }
       
   501 
       
   502 void tst_QThread::started()
       
   503 {
       
   504     SignalRecorder recorder;
       
   505     Simple_Thread thread;
       
   506     connect(&thread, SIGNAL(started()), &recorder, SLOT(slot()), Qt::DirectConnection);
       
   507     thread.start();
       
   508     QVERIFY(thread.wait(five_minutes));
       
   509     QVERIFY(recorder.wasActivated());
       
   510 }
       
   511 
       
   512 void tst_QThread::finished()
       
   513 {
       
   514     SignalRecorder recorder;
       
   515     Simple_Thread thread;
       
   516     connect(&thread, SIGNAL(finished()), &recorder, SLOT(slot()), Qt::DirectConnection);
       
   517     thread.start();
       
   518     QVERIFY(thread.wait(five_minutes));
       
   519     QVERIFY(recorder.wasActivated());
       
   520 }
       
   521 
       
   522 void tst_QThread::terminated()
       
   523 {
       
   524     SignalRecorder recorder;
       
   525     Terminate_Thread thread;
       
   526     connect(&thread, SIGNAL(terminated()), &recorder, SLOT(slot()), Qt::DirectConnection);
       
   527     {
       
   528         QMutexLocker locker(&thread.mutex);
       
   529         thread.start();
       
   530         thread.cond.wait(locker.mutex());
       
   531         thread.terminate();
       
   532         thread.cond.wakeOne();
       
   533     }
       
   534     QVERIFY(thread.wait(five_minutes));
       
   535     QVERIFY(recorder.wasActivated());
       
   536 }
       
   537 
       
   538 void tst_QThread::run()
       
   539 { DEPENDS_ON("wait()"); }
       
   540 
       
   541 void tst_QThread::exec()
       
   542 {
       
   543     DEPENDS_ON("exit()");
       
   544     DEPENDS_ON("quit()");
       
   545 
       
   546     class MultipleExecThread : public QThread
       
   547     {
       
   548     public:
       
   549         int res1, res2;
       
   550 
       
   551         MultipleExecThread() : res1(-2), res2(-2) { }
       
   552 
       
   553         void run()
       
   554         {
       
   555             {
       
   556                 Exit_Object o;
       
   557                 o.thread = this;
       
   558                 o.code = 1;
       
   559                 QTimer::singleShot(100, &o, SLOT(slot()));
       
   560                 res1 = exec();
       
   561             }
       
   562             {
       
   563                 Exit_Object o;
       
   564                 o.thread = this;
       
   565                 o.code = 2;
       
   566                 QTimer::singleShot(100, &o, SLOT(slot()));
       
   567                 res2 = exec();
       
   568             }
       
   569         }
       
   570     };
       
   571 
       
   572     MultipleExecThread thread;
       
   573     thread.start();
       
   574     QVERIFY(thread.wait());
       
   575 
       
   576     QCOMPARE(thread.res1, 1);
       
   577     QCOMPARE(thread.res2, 2);
       
   578 }
       
   579 
       
   580 void tst_QThread::setTerminationEnabled()
       
   581 { DEPENDS_ON("terminate"); }
       
   582 
       
   583 void tst_QThread::sleep()
       
   584 {
       
   585     Sleep_Thread thread;
       
   586     thread.sleepType = Sleep_Thread::Second;
       
   587     thread.interval = 2;
       
   588     thread.start();
       
   589     QVERIFY(thread.wait(five_minutes));
       
   590     QVERIFY(thread.elapsed >= 2000);
       
   591 }
       
   592 
       
   593 void tst_QThread::msleep()
       
   594 {
       
   595     Sleep_Thread thread;
       
   596     thread.sleepType = Sleep_Thread::Millisecond;
       
   597     thread.interval = 120;
       
   598     thread.start();
       
   599     QVERIFY(thread.wait(five_minutes));
       
   600 #if defined (Q_OS_WIN)
       
   601     // Since the resolution of QTime is so coarse...
       
   602     QVERIFY(thread.elapsed >= 100);
       
   603 #else
       
   604     QVERIFY(thread.elapsed >= 120);
       
   605 #endif
       
   606 }
       
   607 
       
   608 void tst_QThread::usleep()
       
   609 {
       
   610     Sleep_Thread thread;
       
   611     thread.sleepType = Sleep_Thread::Microsecond;
       
   612     thread.interval = 120000;
       
   613     thread.start();
       
   614     QVERIFY(thread.wait(five_minutes));
       
   615 #if defined (Q_OS_WIN)
       
   616     // Since the resolution of QTime is so coarse...
       
   617     QVERIFY(thread.elapsed >= 100);
       
   618 #else
       
   619     QVERIFY(thread.elapsed >= 120);
       
   620 #endif
       
   621 }
       
   622 
       
   623 typedef void (*FunctionPointer)(void *);
       
   624 void noop(void*) { }
       
   625 
       
   626 #ifdef Q_OS_UNIX
       
   627     typedef pthread_t ThreadHandle;
       
   628 #elif defined Q_OS_WIN
       
   629     typedef HANDLE ThreadHandle;
       
   630 #endif
       
   631 
       
   632 #ifdef Q_OS_WIN
       
   633 #define WIN_FIX_STDCALL __stdcall
       
   634 #else
       
   635 #define WIN_FIX_STDCALL
       
   636 #endif
       
   637 
       
   638 class NativeThreadWrapper
       
   639 {
       
   640 public:
       
   641     NativeThreadWrapper() : qthread(0), waitForStop(false) {}
       
   642     void start(FunctionPointer functionPointer = noop, void *data = 0);
       
   643     void startAndWait(FunctionPointer functionPointer = noop, void *data = 0);
       
   644     void join();
       
   645     void setWaitForStop() { waitForStop = true; }
       
   646     void stop();
       
   647 
       
   648     ThreadHandle nativeThreadHandle;
       
   649     QThread *qthread;
       
   650     QWaitCondition startCondition;
       
   651     QMutex mutex;
       
   652     bool waitForStop;
       
   653     QWaitCondition stopCondition;
       
   654 protected:
       
   655     static void *runUnix(void *data);
       
   656     static unsigned WIN_FIX_STDCALL runWin(void *data);
       
   657 
       
   658     FunctionPointer functionPointer;
       
   659     void *data;
       
   660 };
       
   661 
       
   662 void NativeThreadWrapper::start(FunctionPointer functionPointer, void *data)
       
   663 {
       
   664     this->functionPointer = functionPointer;
       
   665     this->data = data;
       
   666 #ifdef Q_OS_UNIX
       
   667     const int state = pthread_create(&nativeThreadHandle, 0, NativeThreadWrapper::runUnix, this);
       
   668     Q_UNUSED(state);
       
   669 #elif defined(Q_OS_WINCE)
       
   670 	nativeThreadHandle = CreateThread(NULL, 0 , (LPTHREAD_START_ROUTINE)NativeThreadWrapper::runWin , this, 0, NULL);
       
   671 #elif defined Q_OS_WIN
       
   672     unsigned thrdid = 0;
       
   673     nativeThreadHandle = (Qt::HANDLE) _beginthreadex(NULL, 0, NativeThreadWrapper::runWin, this, 0, &thrdid);
       
   674 #endif
       
   675 }
       
   676 
       
   677 void NativeThreadWrapper::startAndWait(FunctionPointer functionPointer, void *data)
       
   678 {
       
   679     QMutexLocker locker(&mutex);
       
   680     start(functionPointer, data);
       
   681     startCondition.wait(locker.mutex());
       
   682 }
       
   683 
       
   684 void NativeThreadWrapper::join()
       
   685 {
       
   686 #ifdef Q_OS_UNIX
       
   687     pthread_join(nativeThreadHandle, 0);
       
   688 #elif defined Q_OS_WIN
       
   689     WaitForSingleObject(nativeThreadHandle, INFINITE);
       
   690     CloseHandle(nativeThreadHandle);
       
   691 #endif
       
   692 }
       
   693 
       
   694 void *NativeThreadWrapper::runUnix(void *that)
       
   695 {
       
   696     NativeThreadWrapper *nativeThreadWrapper = reinterpret_cast<NativeThreadWrapper*>(that);
       
   697 
       
   698     // Adopt thread, create QThread object.
       
   699     nativeThreadWrapper->qthread = QThread::currentThread();
       
   700 
       
   701     // Release main thread.
       
   702     {
       
   703         QMutexLocker lock(&nativeThreadWrapper->mutex);
       
   704         nativeThreadWrapper->startCondition.wakeOne();
       
   705     }
       
   706 
       
   707     // Run function.
       
   708     nativeThreadWrapper->functionPointer(nativeThreadWrapper->data);
       
   709 
       
   710     // Wait for stop.
       
   711     {
       
   712         QMutexLocker lock(&nativeThreadWrapper->mutex);
       
   713         if (nativeThreadWrapper->waitForStop)
       
   714             nativeThreadWrapper->stopCondition.wait(lock.mutex());
       
   715     }
       
   716 
       
   717     return 0;
       
   718 }
       
   719 
       
   720 unsigned WIN_FIX_STDCALL NativeThreadWrapper::runWin(void *data)
       
   721 {
       
   722     runUnix(data);
       
   723     return 0;
       
   724 }
       
   725 
       
   726 void NativeThreadWrapper::stop()
       
   727 {
       
   728     QMutexLocker lock(&mutex);
       
   729     waitForStop = false;
       
   730     stopCondition.wakeOne();
       
   731 }
       
   732 
       
   733 bool threadAdoptedOk = false;
       
   734 QThread *mainThread;
       
   735 void testNativeThreadAdoption(void *)
       
   736 {
       
   737     threadAdoptedOk = (QThread::currentThreadId() != 0
       
   738                        && QThread::currentThread() != 0
       
   739                        && QThread::currentThread() != mainThread);
       
   740 }
       
   741 void tst_QThread::nativeThreadAdoption()
       
   742 {
       
   743     threadAdoptedOk = false;
       
   744     mainThread = QThread::currentThread();
       
   745     NativeThreadWrapper nativeThread;
       
   746     nativeThread.setWaitForStop();
       
   747     nativeThread.startAndWait(testNativeThreadAdoption);
       
   748     QVERIFY(nativeThread.qthread);
       
   749 
       
   750     nativeThread.stop();
       
   751     nativeThread.join();
       
   752 
       
   753     QVERIFY(threadAdoptedOk);
       
   754 }
       
   755 
       
   756 void adoptedThreadAffinityFunction(void *arg)
       
   757 {
       
   758     QThread **affinity = reinterpret_cast<QThread **>(arg);
       
   759     QThread *current = QThread::currentThread();
       
   760     affinity[0] = current;
       
   761     affinity[1] = current->thread();
       
   762 }
       
   763 
       
   764 void tst_QThread::adoptedThreadAffinity()
       
   765 {
       
   766     QThread *affinity[2] = { 0, 0 };
       
   767 
       
   768     NativeThreadWrapper thread;
       
   769     thread.startAndWait(adoptedThreadAffinityFunction, affinity);
       
   770     thread.join();
       
   771 
       
   772     // adopted thread should have affinity to itself
       
   773     QCOMPARE(affinity[0], affinity[1]);
       
   774 }
       
   775 
       
   776 void tst_QThread::adoptedThreadSetPriority()
       
   777 {
       
   778 
       
   779     NativeThreadWrapper nativeThread;
       
   780     nativeThread.setWaitForStop();
       
   781     nativeThread.startAndWait();
       
   782 
       
   783     // change the priority of a running thread
       
   784     QCOMPARE(nativeThread.qthread->priority(), QThread::InheritPriority);
       
   785     nativeThread.qthread->setPriority(QThread::IdlePriority);
       
   786     QCOMPARE(nativeThread.qthread->priority(), QThread::IdlePriority);
       
   787     nativeThread.qthread->setPriority(QThread::LowestPriority);
       
   788     QCOMPARE(nativeThread.qthread->priority(), QThread::LowestPriority);
       
   789     nativeThread.qthread->setPriority(QThread::LowPriority);
       
   790     QCOMPARE(nativeThread.qthread->priority(), QThread::LowPriority);
       
   791     nativeThread.qthread->setPriority(QThread::NormalPriority);
       
   792     QCOMPARE(nativeThread.qthread->priority(), QThread::NormalPriority);
       
   793     nativeThread.qthread->setPriority(QThread::HighPriority);
       
   794     QCOMPARE(nativeThread.qthread->priority(), QThread::HighPriority);
       
   795     nativeThread.qthread->setPriority(QThread::HighestPriority);
       
   796     QCOMPARE(nativeThread.qthread->priority(), QThread::HighestPriority);
       
   797     nativeThread.qthread->setPriority(QThread::TimeCriticalPriority);
       
   798     QCOMPARE(nativeThread.qthread->priority(), QThread::TimeCriticalPriority);
       
   799 
       
   800     nativeThread.stop();
       
   801     nativeThread.join();
       
   802 }
       
   803 
       
   804 void tst_QThread::adoptedThreadExit()
       
   805 {
       
   806     NativeThreadWrapper nativeThread;
       
   807     nativeThread.setWaitForStop();
       
   808 
       
   809     nativeThread.startAndWait();
       
   810     QVERIFY(nativeThread.qthread);
       
   811     QVERIFY(nativeThread.qthread->isRunning());
       
   812     QVERIFY(!nativeThread.qthread->isFinished());
       
   813 
       
   814     nativeThread.stop();
       
   815     nativeThread.join();
       
   816 }
       
   817 
       
   818 void adoptedThreadExecFunction(void *)
       
   819 {
       
   820     QThread  * const adoptedThread = QThread::currentThread();
       
   821     QEventLoop eventLoop(adoptedThread);
       
   822 
       
   823     const int code = 1;
       
   824     Exit_Object o;
       
   825     o.thread = adoptedThread;
       
   826     o.code = code;
       
   827     QTimer::singleShot(100, &o, SLOT(slot()));
       
   828 
       
   829     const int result = eventLoop.exec();
       
   830     QCOMPARE(result, code);
       
   831 }
       
   832 
       
   833 void tst_QThread::adoptedThreadExec()
       
   834 {
       
   835     NativeThreadWrapper nativeThread;
       
   836     nativeThread.start(adoptedThreadExecFunction);
       
   837     nativeThread.join();
       
   838 }
       
   839 
       
   840 /*
       
   841     Test that you get the finished signal when an adopted thread exits.
       
   842 */
       
   843 void tst_QThread::adoptedThreadFinished()
       
   844 {
       
   845     NativeThreadWrapper nativeThread;
       
   846     nativeThread.setWaitForStop();
       
   847     nativeThread.startAndWait();
       
   848 
       
   849     QObject::connect(nativeThread.qthread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
   850 
       
   851     nativeThread.stop();
       
   852     nativeThread.join();
       
   853 
       
   854     QTestEventLoop::instance().enterLoop(5);
       
   855     QVERIFY(!QTestEventLoop::instance().timeout());
       
   856 }
       
   857 
       
   858 void tst_QThread::adoptMultipleThreads()
       
   859 {
       
   860 #if defined(Q_OS_WIN)
       
   861     // Windows CE is not capable of handling that many threads. On the emulator it is dead with 26 threads already.
       
   862 #  if defined(Q_OS_WINCE)
       
   863     const int numThreads = 20;
       
   864 #  else
       
   865     // need to test lots of threads, so that we exceed MAXIMUM_WAIT_OBJECTS in qt_adopted_thread_watcher()
       
   866     const int numThreads = 200;
       
   867 #  endif
       
   868 #else
       
   869     const int numThreads = 5;
       
   870 #endif
       
   871     QVector<NativeThreadWrapper*> nativeThreads;
       
   872 
       
   873     SignalRecorder recorder;
       
   874 
       
   875     for (int i = 0; i < numThreads; ++i) {
       
   876         nativeThreads.append(new NativeThreadWrapper());
       
   877         nativeThreads.at(i)->setWaitForStop();
       
   878         nativeThreads.at(i)->startAndWait();
       
   879         QObject::connect(nativeThreads.at(i)->qthread, SIGNAL(finished()), &recorder, SLOT(slot()));
       
   880     }
       
   881 
       
   882     QObject::connect(nativeThreads.at(numThreads - 1)->qthread, SIGNAL(finished()), &QTestEventLoop::instance(), SLOT(exitLoop()));
       
   883 
       
   884     for (int i = 0; i < numThreads; ++i) {
       
   885         nativeThreads.at(i)->stop();
       
   886         nativeThreads.at(i)->join();
       
   887     }
       
   888 
       
   889     QTestEventLoop::instance().enterLoop(5);
       
   890     QVERIFY(!QTestEventLoop::instance().timeout());
       
   891     QCOMPARE(int(recorder.activationCount), numThreads);
       
   892 }
       
   893 
       
   894 void tst_QThread::stressTest()
       
   895 {
       
   896 #if defined(Q_OS_WINCE)
       
   897     QSKIP("Disconnects on WinCE, skipping...", SkipAll);
       
   898 #endif
       
   899     QTime t;
       
   900     t.start();
       
   901     while (t.elapsed() < one_minute) {
       
   902         Current_Thread t;
       
   903         t.start();
       
   904         t.wait(one_minute);
       
   905     }
       
   906 }
       
   907 
       
   908 
       
   909 QTEST_MAIN(tst_QThread)
       
   910 #include "tst_qthread.moc"