summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMurray Read <ext-murray.2.read@nokia.com>2012-02-06 11:33:07 +0000
committerPasi Pentikäinen <ext-pasi.a.pentikainen@nokia.com>2012-02-08 17:45:26 +0100
commit3c65a2e0af387c455fcc3a20323af7fc254fd4c2 (patch)
tree647442d8dac3d88c483fe7ab794d0e5e7adc5da3
parent201116ea7f0ee6e4a80166d3ca4ac2ad41e9d5bb (diff)
downloadqt4-tools-3c65a2e0af387c455fcc3a20323af7fc254fd4c2.tar.gz
Handling adopted thread death with active timers on Symbian
Timers are thread local objects on Symbian. When the adopted thread monitor tries to tidy up a thread, any existing qt timers will be cleaned up. But that has to be done very carefully without touching the underlying symbian timer objects. Checks are added to make sure the Symbian timers are only touched in the correct thread. Task-number: ou1cimx1#960478 Change-Id: If16750b455aa576aa9f2d93657a3627d18060272 Reviewed-by: Shane Kearns <ext-shane.2.kearns@nokia.com> (cherry picked from commit 4490850b9286d9b01fab9bc8900deb1598398f2e) Reviewed-by: Pasi Pentikäinen <ext-pasi.a.pentikainen@nokia.com>
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian.cpp28
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian_p.h1
-rw-r--r--tests/auto/qthread/tst_qthread.cpp27
3 files changed, 50 insertions, 6 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp
index 1052043034..3f44dddd0f 100644
--- a/src/corelib/kernel/qeventdispatcher_symbian.cpp
+++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp
@@ -157,6 +157,7 @@ private:
QActiveObject::QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher)
: CActive(priority),
m_dispatcher(dispatcher),
+ m_threadData(QThreadData::current()),
m_hasAlreadyRun(false),
m_hasRunAgain(false),
m_iterationCount(1)
@@ -258,18 +259,32 @@ QTimerActiveObject::QTimerActiveObject(QEventDispatcherSymbian *dispatcher, Symb
QTimerActiveObject::~QTimerActiveObject()
{
Cancel();
- m_rTimer.Close(); //close of null handle is safe
+ // deletion in the wrong thread (eg adoptedThreadMonitor thread) must avoid using the RTimer, which is local
+ // to the thread it was created in.
+ if (QThreadData::current() == m_threadData)
+ m_rTimer.Close(); //close of null handle is safe
}
void QTimerActiveObject::DoCancel()
{
- if (m_timerInfo->interval > 0) {
- m_rTimer.Cancel();
+ // RTimer is thread local and cannot be cancelled outside of the thread it was created in
+ if (QThreadData::current() == m_threadData) {
+ if (m_timerInfo->interval > 0) {
+ m_rTimer.Cancel();
+ } else {
+ if (iStatus.Int() == KRequestPending) {
+ TRequestStatus *status = &iStatus;
+ QEventDispatcherSymbian::RequestComplete(status, KErrNone);
+ }
+ }
} else {
- if (iStatus.Int() == KRequestPending) {
- TRequestStatus *status = &iStatus;
- QEventDispatcherSymbian::RequestComplete(status, KErrNone);
+ // Cancel requires a signal to continue, we're in the wrong thread to use the RTimer
+ if (m_threadData->symbian_thread_handle.ExitType() == EExitPending) {
+ // owner thread is still running, it will receive a stray event if the timer fires now.
+ qFatal("QTimerActiveObject cancelled from wrong thread");
}
+ TRequestStatus *status = &iStatus;
+ User::RequestComplete(status, KErrCancel);
}
}
@@ -358,6 +373,7 @@ void QTimerActiveObject::Start()
if (m_timerInfo->interval > 0) {
if (!m_rTimer.Handle()) {
qt_symbian_throwIfError(m_rTimer.CreateLocal());
+ m_threadData = QThreadData::current();
}
m_timeoutTimer.start();
m_expectedTimeSinceLastEvent = 0;
diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h
index 869fe31868..6fc62dd86c 100644
--- a/src/corelib/kernel/qeventdispatcher_symbian_p.h
+++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h
@@ -88,6 +88,7 @@ public:
void reactivateAndComplete();
protected:
QEventDispatcherSymbian *m_dispatcher;
+ QThreadData *m_threadData;
private:
bool m_hasAlreadyRun : 1;
diff --git a/tests/auto/qthread/tst_qthread.cpp b/tests/auto/qthread/tst_qthread.cpp
index 3c46212c16..a46f5aa6f7 100644
--- a/tests/auto/qthread/tst_qthread.cpp
+++ b/tests/auto/qthread/tst_qthread.cpp
@@ -102,6 +102,7 @@ private slots:
void adoptedThreadSetPriority();
void adoptedThreadExit();
void adoptedThreadExec();
+ void adoptThreadExitWithActiveTimer();
void adoptedThreadFinished();
void adoptedThreadExecFinished();
void adoptMultipleThreads();
@@ -1010,6 +1011,32 @@ void tst_QThread::adoptMultipleThreadsOverlap()
QVERIFY(!QTestEventLoop::instance().timeout());
QCOMPARE(int(recorder.activationCount), numThreads);
}
+
+void adoptedThreadActiveTimerFunction(void *)
+{
+ QThread * const adoptedThread = QThread::currentThread();
+ QEventLoop eventLoop(adoptedThread);
+
+ const int code = 1;
+ Exit_Object o;
+ o.thread = adoptedThread;
+ o.code = code;
+ QTimer::singleShot(100, &o, SLOT(slot()));
+
+ // create a timer that will still be active when the thread finishes
+ QTimer::singleShot(3000, &o, SLOT(slot()));
+
+ const int result = eventLoop.exec();
+ QCOMPARE(result, code);
+}
+
+void tst_QThread::adoptThreadExitWithActiveTimer()
+{
+ NativeThreadWrapper nativeThread;
+ nativeThread.start(adoptedThreadActiveTimerFunction);
+ nativeThread.join();
+}
+
void tst_QThread::stressTest()
{
#if defined(Q_OS_WINCE)