summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormread <qt-info@nokia.com>2011-04-12 14:07:11 (GMT)
committermread <qt-info@nokia.com>2011-04-12 14:19:33 (GMT)
commit6f1efe75dac53377b92d779818b43a34add92f02 (patch)
treec3db3804163d4e10b30f2fdea3694cba09eade5b
parent46163663e956b988719563eae18773a2dedd424e (diff)
downloadQt-6f1efe75dac53377b92d779818b43a34add92f02.zip
Qt-6f1efe75dac53377b92d779818b43a34add92f02.tar.gz
Qt-6f1efe75dac53377b92d779818b43a34add92f02.tar.bz2
Applying the QTBUG-17986 fix to Symbian
This change takes the QTBUG-17986 fix, which deletes QThreadData for adopted threads that have created QEventLoops, and applies it to qthread_symbian.cpp, which didn't exist at the time of the original fix. One complication is that Symbian uses a separate thread to monitor adopted thread lifetime, as there is no API to intercept thread exit to have cleanup code run within the context of the thread. However the cleanup for the thread involes deleting active objects that were created in the adopted thread, not the monitor thread. If these active objects are completed but not run, their cancellation could deadlock. In particular the wake up active object in the event dispatcher is typically in this state. We deal with it by detecting the situation and re-completing/cancelling the active object in the adopted thread monitor thread, which prevents deadlock and allows correct operation of the monitor thread. It is possible for this problem to affect other active objects owned by the event dispatcher. They symptom would be that finished signals from adopted threads are not sent, or they arrive much later than they should. Task-number: QTBUG-18622 Reviewed-by: Shane Kearns
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian.cpp10
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian_p.h3
-rw-r--r--src/corelib/thread/qthread_symbian.cpp8
3 files changed, 21 insertions, 0 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp
index 79f2596..471028e 100644
--- a/src/corelib/kernel/qeventdispatcher_symbian.cpp
+++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp
@@ -194,6 +194,7 @@ void QActiveObject::reactivateAndComplete()
QWakeUpActiveObject::QWakeUpActiveObject(QEventDispatcherSymbian *dispatcher)
: QActiveObject(WAKE_UP_PRIORITY, dispatcher)
{
+ m_hostThreadId = RThread().Id();
CActiveScheduler::Add(this);
iStatus = KRequestPending;
SetActive();
@@ -209,6 +210,15 @@ void QWakeUpActiveObject::DoCancel()
if (iStatus.Int() == KRequestPending) {
TRequestStatus *status = &iStatus;
QEventDispatcherSymbian::RequestComplete(status, KErrNone);
+ } else if (IsActive() && m_hostThreadId != RThread().Id()) {
+ // This is being cancelled in the adopted monitor thread, which can happen if an adopted thread with
+ // an event loop has exited. The event loop creates an event dispatcher with this active object, which may be complete but not run on exit.
+ // We force a cancellation in this thread, because a) the object cannot be deleted while active and b) without a cancellation
+ // the thread semaphore will be one count down.
+ // It is possible for this problem to affect other active objects. They symptom would be that finished signals
+ // from adopted threads are not sent, or they arrive much later than they should.
+ TRequestStatus *status = &iStatus;
+ User::RequestComplete(status, KErrNone);
}
}
diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h
index e07d475..6e04bb1 100644
--- a/src/corelib/kernel/qeventdispatcher_symbian_p.h
+++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h
@@ -110,6 +110,9 @@ public:
protected:
void DoCancel();
void RunL();
+
+private:
+ TThreadId m_hostThreadId;
};
struct SymbianTimerInfo : public QSharedData
diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp
index 15e6898..5d8b5cb 100644
--- a/src/corelib/thread/qthread_symbian.cpp
+++ b/src/corelib/thread/qthread_symbian.cpp
@@ -113,6 +113,7 @@ QThreadData *QThreadData::current()
}
data->deref();
}
+ data->isAdopted = true;
data->threadId = QThread::currentThreadId();
if (!QCoreApplicationPrivate::theMainThread)
QCoreApplicationPrivate::theMainThread = data->thread;
@@ -257,6 +258,13 @@ QCAddAdoptedThread* QCAddAdoptedThread::adoptedThreadAdder = 0;
void QCAdoptedThreadMonitor::RunL()
{
+ if (data->isAdopted) {
+ QThread *thread = data->thread;
+ Q_ASSERT(thread);
+ QThreadPrivate *thread_p = static_cast<QThreadPrivate *>(QObjectPrivate::get(thread));
+ Q_ASSERT(!thread_p->finished);
+ thread_p->finish(thread);
+ }
data->deref();
QCAddAdoptedThread::threadDied();
delete this;