summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/thread/qthread.cpp5
-rw-r--r--tests/auto/qcoreapplication/tst_qcoreapplication.cpp45
-rw-r--r--tests/auto/qeventloop/tst_qeventloop.cpp41
-rw-r--r--tests/auto/qthread/tst_qthread.cpp191
4 files changed, 221 insertions, 61 deletions
diff --git a/src/corelib/thread/qthread.cpp b/src/corelib/thread/qthread.cpp
index f368192..f4bfa5d 100644
--- a/src/corelib/thread/qthread.cpp
+++ b/src/corelib/thread/qthread.cpp
@@ -482,10 +482,7 @@ int QThread::exec()
Q_D(QThread);
QMutexLocker locker(&d->mutex);
d->data->quitNow = false;
- if (d->exited) {
- d->exited = false;
- return d->returnCode;
- }
+ d->exited = false;
locker.unlock();
QEventLoop eventLoop;
diff --git a/tests/auto/qcoreapplication/tst_qcoreapplication.cpp b/tests/auto/qcoreapplication/tst_qcoreapplication.cpp
index 95055d1..bc69461 100644
--- a/tests/auto/qcoreapplication/tst_qcoreapplication.cpp
+++ b/tests/auto/qcoreapplication/tst_qcoreapplication.cpp
@@ -59,6 +59,9 @@ private slots:
void applicationPid();
void globalPostedEventsCount();
void processEventsAlwaysSendsPostedEvents();
+ void reexec();
+ void execAfterExit();
+ void eventLoopExecAfterExit();
};
class EventSpy : public QObject
@@ -524,5 +527,47 @@ void tst_QCoreApplication::processEventsAlwaysSendsPostedEvents()
} while (t.elapsed() < 3000);
}
+void tst_QCoreApplication::reexec()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QCoreApplication app(argc, argv);
+
+ // exec once
+ QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
+ QCOMPARE(app.exec(), 0);
+
+ // and again
+ QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
+ QCOMPARE(app.exec(), 0);
+}
+
+void tst_QCoreApplication::execAfterExit()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QCoreApplication app(argc, argv);
+
+ app.exit(1);
+ QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
+ QCOMPARE(app.exec(), 0);
+}
+
+void tst_QCoreApplication::eventLoopExecAfterExit()
+{
+ int argc = 1;
+ char *argv[] = { "tst_qcoreapplication" };
+ QCoreApplication app(argc, argv);
+
+ // exec once and exit
+ QMetaObject::invokeMethod(&app, "quit", Qt::QueuedConnection);
+ QCOMPARE(app.exec(), 0);
+
+ // and again, but this time using a QEventLoop
+ QEventLoop loop;
+ QMetaObject::invokeMethod(&loop, "quit", Qt::QueuedConnection);
+ QCOMPARE(loop.exec(), 0);
+}
+
QTEST_APPLESS_MAIN(tst_QCoreApplication)
#include "tst_qcoreapplication.moc"
diff --git a/tests/auto/qeventloop/tst_qeventloop.cpp b/tests/auto/qeventloop/tst_qeventloop.cpp
index 7af722f..6860f19 100644
--- a/tests/auto/qeventloop/tst_qeventloop.cpp
+++ b/tests/auto/qeventloop/tst_qeventloop.cpp
@@ -112,6 +112,10 @@ signals:
public:
QMutex mutex;
QWaitCondition cond;
+ volatile int result1;
+ volatile int result2;
+ MultipleExecThread() : result1(0xdead), result2(0xbeef) {}
+
void run()
{
QMutexLocker locker(&mutex);
@@ -124,13 +128,13 @@ public:
connect(&timer, SIGNAL(timeout()), SLOT(quit()), Qt::DirectConnection);
timer.setInterval(1000);
timer.start();
- (void) exec();
+ result1 = exec();
// this should return immediately, since exit() has been called
cond.wakeOne();
cond.wait(&mutex);
QEventLoop eventLoop;
- (void) eventLoop.exec();
+ result2 = eventLoop.exec();
}
};
@@ -197,7 +201,9 @@ private slots:
void symbianNestedActiveSchedulerLoop();
void processEvents();
void exec();
+ void reexec();
void exit();
+ void execAfterExit();
void wakeUp();
void quit();
void processEventsExcludeSocket();
@@ -398,7 +404,9 @@ void tst_QEventLoop::exec()
}
{
- // calling exec() after exit()/quit() should return immediately
+ // calling QEventLoop::exec() after a thread loop has exit()ed should return immediately
+ // Note: this behaviour differs from QCoreApplication and QEventLoop
+ // see tst_QCoreApplication::eventLoopExecAfterExit, tst_QEventLoop::reexec
MultipleExecThread thread;
// start thread and wait for checkpoint
@@ -411,6 +419,8 @@ void tst_QEventLoop::exec()
thread.cond.wakeOne();
thread.cond.wait(&thread.mutex);
QVERIFY(spy.count() > 0);
+ int v = thread.result1;
+ QCOMPARE(v, 0);
// exec should return immediately
spy.clear();
@@ -418,6 +428,8 @@ void tst_QEventLoop::exec()
thread.mutex.unlock();
thread.wait();
QCOMPARE(spy.count(), 0);
+ v = thread.result2;
+ QCOMPARE(v, -1);
}
{
@@ -462,9 +474,32 @@ void tst_QEventLoop::exec()
#endif
}
+void tst_QEventLoop::reexec()
+{
+ QEventLoop loop;
+
+ // exec once
+ QMetaObject::invokeMethod(&loop, "quit", Qt::QueuedConnection);
+ QCOMPARE(loop.exec(), 0);
+
+ // and again
+ QMetaObject::invokeMethod(&loop, "quit", Qt::QueuedConnection);
+ QCOMPARE(loop.exec(), 0);
+}
+
void tst_QEventLoop::exit()
{ DEPENDS_ON(exec()); }
+void tst_QEventLoop::execAfterExit()
+{
+ QEventLoop loop;
+ EventLoopExiter obj(&loop);
+
+ QMetaObject::invokeMethod(&obj, "exit", Qt::QueuedConnection);
+ loop.exit(1);
+ QCOMPARE(loop.exec(), 0);
+}
+
void tst_QEventLoop::wakeUp()
{
EventLoopThread thread;
diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp
index e6bf9ce..c7036e4 100644
--- a/tests/auto/qthread/tst_qthread.cpp
+++ b/tests/auto/qthread/tst_qthread.cpp
@@ -86,6 +86,7 @@ private slots:
void start();
void terminate();
void quit();
+ void execAfterQuit();
void wait();
void started();
void finished();
@@ -265,6 +266,34 @@ public:
}
};
+class ExecAfterQuitThreadHelper: public QObject
+{
+ Q_OBJECT
+ QThread *thr;
+public:
+ ExecAfterQuitThreadHelper(QThread *thr) : thr(thr) {}
+public slots:
+ void doIt() { thr->exit(0); }
+};
+
+class ExecAfterQuitThread: public QThread
+{
+public:
+ int returnValue;
+ void run()
+ {
+ ExecAfterQuitThreadHelper obj(this);
+
+ QMetaObject::invokeMethod(&obj, "doIt", Qt::QueuedConnection);
+ exit(1);
+
+ // returnValue will be either 0 or 1, depending on which of the two
+ // above take effect. The correct value is 0, since exit(1) before
+ // exec() should have no effect
+ returnValue = exec();
+ }
+};
+
tst_QThread::tst_QThread()
{
@@ -424,34 +453,52 @@ void tst_QThread::stackSize()
void tst_QThread::exit()
{
- Exit_Thread thread;
- thread.object = new Exit_Object;
- thread.object->moveToThread(&thread);
- thread.code = 42;
- thread.result = 0;
- QVERIFY(!thread.isFinished());
- QVERIFY(!thread.isRunning());
- QMutexLocker locker(&thread.mutex);
- thread.start();
- QVERIFY(thread.isRunning());
- QVERIFY(!thread.isFinished());
- thread.cond.wait(locker.mutex());
- QVERIFY(thread.wait(five_minutes));
- QVERIFY(thread.isFinished());
- QVERIFY(!thread.isRunning());
- QCOMPARE(thread.result, thread.code);
- delete thread.object;
+ {
+ Exit_Thread thread;
+ thread.object = new Exit_Object;
+ thread.object->moveToThread(&thread);
+ thread.code = 42;
+ thread.result = 0;
+ QVERIFY(!thread.isFinished());
+ QVERIFY(!thread.isRunning());
- Exit_Thread thread2;
- thread2.object = 0;
- thread2.code = 53;
- thread2.result = 0;
- QMutexLocker locker2(&thread2.mutex);
- thread2.start();
- thread2.exit(thread2.code);
- thread2.cond.wait(locker2.mutex());
- QVERIFY(thread2.wait(five_minutes));
- QCOMPARE(thread2.result, thread2.code);
+ QMutexLocker locker(&thread.mutex);
+ thread.start();
+ QVERIFY(thread.isRunning());
+ QVERIFY(!thread.isFinished());
+ // but the thread is not running the event loop yet (the mutex is locked)
+
+ // start the event loop
+ thread.cond.wait(locker.mutex());
+
+ // the Exit_Object above will cause the thread to exit
+ QVERIFY(thread.wait(five_minutes));
+ QVERIFY(thread.isFinished());
+ QVERIFY(!thread.isRunning());
+ QCOMPARE(thread.result, thread.code);
+ delete thread.object;
+ }
+
+ {
+ Exit_Thread thread2;
+ thread2.object = 0;
+ thread2.code = 53;
+ thread2.result = 0;
+ QMutexLocker locker2(&thread2.mutex);
+ thread2.start();
+
+ // the mutex is locked, so the thread has *not* started running the event loop yet
+ // this will do nothing:
+ thread2.exit(thread2.code);
+
+ // the thread will now start running
+ thread2.cond.wait(locker2.mutex());
+
+ // this will cause it to exit now
+ thread2.exit(++thread2.code);
+ QVERIFY(thread2.wait(five_minutes));
+ QCOMPARE(thread2.result, thread2.code);
+ }
}
void tst_QThread::start()
@@ -498,32 +545,59 @@ void tst_QThread::terminate()
void tst_QThread::quit()
{
- Quit_Thread thread;
- thread.object = new Quit_Object;
- thread.object->moveToThread(&thread);
- thread.result = -1;
- QVERIFY(!thread.isFinished());
- QVERIFY(!thread.isRunning());
- QMutexLocker locker(&thread.mutex);
- thread.start();
- QVERIFY(thread.isRunning());
- QVERIFY(!thread.isFinished());
- thread.cond.wait(locker.mutex());
- QVERIFY(thread.wait(five_minutes));
- QVERIFY(thread.isFinished());
- QVERIFY(!thread.isRunning());
- QCOMPARE(thread.result, 0);
- delete thread.object;
+ // very similar to exit() above
+ {
+ Quit_Thread thread;
+ thread.object = new Quit_Object;
+ thread.object->moveToThread(&thread);
+ thread.result = -1;
+ QVERIFY(!thread.isFinished());
+ QVERIFY(!thread.isRunning());
- Quit_Thread thread2;
- thread2.object = 0;
- thread2.result = -1;
- QMutexLocker locker2(&thread2.mutex);
- thread2.start();
- thread2.quit();
- thread2.cond.wait(locker2.mutex());
- QVERIFY(thread2.wait(five_minutes));
- QCOMPARE(thread2.result, 0);
+ // start the thread, but keep the event loop from starting
+ // (while the mutex is locked)
+ QMutexLocker locker(&thread.mutex);
+ thread.start();
+ QVERIFY(thread.isRunning());
+ QVERIFY(!thread.isFinished());
+
+ // unlock the mutex and let the event loop run
+ // the Quit_Object above will cause the thread to quit
+ thread.cond.wait(locker.mutex());
+ QVERIFY(thread.wait(five_minutes));
+ QVERIFY(thread.isFinished());
+ QVERIFY(!thread.isRunning());
+ QCOMPARE(thread.result, 0);
+ delete thread.object;
+ }
+
+ {
+ Quit_Thread thread2;
+ thread2.object = 0;
+ thread2.result = -1;
+
+ // start the thread, but keep the event loop from starting
+ // (while the mutex is locked)
+ QMutexLocker locker2(&thread2.mutex);
+ thread2.start();
+ thread2.quit(); // does nothing, the event loop is not running!
+
+ // unlock the mutex and let the event loop run
+ thread2.cond.wait(locker2.mutex());
+
+ // there's no Quit_Object so it won't quit on its own
+ thread2.quit();
+ QVERIFY(thread2.wait(five_minutes));
+ QCOMPARE(thread2.result, 0);
+ }
+}
+
+void tst_QThread::execAfterQuit()
+{
+ ExecAfterQuitThread thread;
+ thread.start();
+ QVERIFY(thread.wait());
+ QCOMPARE(thread.returnValue, 0);
}
void tst_QThread::wait()
@@ -994,8 +1068,17 @@ void tst_QThread::QTBUG15378_exitAndExec()
Thread thread;
thread.value = 0;
thread.start();
- thread.exit(556);
- thread.sem1.release(); //should exit the first loop
+ thread.exit(42); // will do nothing, this value should not appear
+ thread.sem1.release(); //should enter the first loop
+
+ Exit_Object *exit_object = new Exit_Object;
+ exit_object->code = 556;
+ exit_object->thread = &thread;
+ QMetaObject::invokeMethod(exit_object, "slot", Qt::QueuedConnection);
+ exit_object->deleteLater();
+ exit_object->moveToThread(&thread); // should exit the first loop
+ exit_object = 0;
+
thread.sem2.acquire();
int v = thread.value;
QCOMPARE(v, 556);