diff options
author | mread <qt-info@nokia.com> | 2011-04-12 14:07:11 (GMT) |
---|---|---|
committer | mread <qt-info@nokia.com> | 2011-04-12 14:19:33 (GMT) |
commit | 6f1efe75dac53377b92d779818b43a34add92f02 (patch) | |
tree | c3db3804163d4e10b30f2fdea3694cba09eade5b /src | |
parent | 46163663e956b988719563eae18773a2dedd424e (diff) | |
download | Qt-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
Diffstat (limited to 'src')
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian.cpp | 10 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian_p.h | 3 | ||||
-rw-r--r-- | src/corelib/thread/qthread_symbian.cpp | 8 |
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; |