summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormread <qt-info@nokia.com>2011-03-18 10:42:45 +0000
committermread <qt-info@nokia.com>2011-03-18 10:49:21 +0000
commita9cb2be8c14317001c0945da84f1a19e1d6ee6c6 (patch)
treed7d9f62fe53049e6c10afa5df2a18134d4b72e59
parentbbbe40631bac44489d35d7ae76a3ccd41b75fe6a (diff)
Making Symbian helper threads exit cleanly at app exit
The idle detector thread and the adopted thread monitor thread could keep an app alive unnecessarily after main had exited, if the app's main thread was no longer set "process permanent". The idle detector thread now exits when the QCoreApplication is destroyed. The adopted thread monitor thread now exits when there are no more adopted threads to monitor. Task-number: QTBUG-18073 Reviewed-by: Shane Kearns
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian.cpp50
-rw-r--r--src/corelib/thread/qthread_symbian.cpp36
2 files changed, 67 insertions, 19 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp
index 53796be7ba..4c01bdee6e 100644
--- a/src/corelib/kernel/qeventdispatcher_symbian.cpp
+++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp
@@ -43,6 +43,7 @@
#include <private/qthread_p.h>
#include <qcoreapplication.h>
#include <private/qcoreapplication_p.h>
+#include <qsemaphore.h>
#include <unistd.h>
#include <errno.h>
@@ -654,34 +655,54 @@ class QIdleDetectorThread
{
public:
QIdleDetectorThread()
- : m_state(STATE_RUN), m_stop(false)
+ : m_state(STATE_RUN), m_stop(false), m_running(false)
{
- qt_symbian_throwIfError(m_lock.CreateLocal(0));
+ start();
+ }
+
+ ~QIdleDetectorThread()
+ {
+ stop();
+ }
+
+ void start()
+ {
+ QMutexLocker lock(&m_mutex);
+ if (m_running)
+ return;
+ m_stop = false;
+ m_state = STATE_RUN;
TInt err = m_idleDetectorThread.Create(KNullDesC(), &idleDetectorThreadFunc, 1024, &User::Allocator(), this);
if (err != KErrNone)
- m_lock.Close();
- qt_symbian_throwIfError(err);
+ return; // Fail silently on error. Next kick will try again. Exception might stop the event being processed
m_idleDetectorThread.SetPriority(EPriorityAbsoluteBackgroundNormal);
m_idleDetectorThread.Resume();
+ m_running = true;
+ // get a callback from QCoreApplication destruction to stop this thread
+ qAddPostRoutine(StopIdleDetectorThread);
}
- ~QIdleDetectorThread()
+ void stop()
{
+ QMutexLocker lock(&m_mutex);
+ if (!m_running)
+ return;
// close down the idle thread because if corelib is loaded temporarily, this would leak threads into the host process
m_stop = true;
- m_lock.Signal();
+ m_kick.release();
m_idleDetectorThread.SetPriority(EPriorityNormal);
TRequestStatus s;
m_idleDetectorThread.Logon(s);
User::WaitForRequest(s);
m_idleDetectorThread.Close();
- m_lock.Close();
+ m_running = false;
}
void kick()
{
+ start();
m_state = STATE_KICKED;
- m_lock.Signal();
+ m_kick.release();
}
bool hasRun()
@@ -700,20 +721,29 @@ private:
void IdleLoop()
{
while (!m_stop) {
- m_lock.Wait();
+ m_kick.acquire();
m_state = STATE_RUN;
}
}
+ static void StopIdleDetectorThread();
+
private:
enum IdleStates {STATE_KICKED, STATE_RUN} m_state;
bool m_stop;
+ bool m_running;
RThread m_idleDetectorThread;
- RSemaphore m_lock;
+ QSemaphore m_kick;
+ QMutex m_mutex;
};
Q_GLOBAL_STATIC(QIdleDetectorThread, idleDetectorThread);
+void QIdleDetectorThread::StopIdleDetectorThread()
+{
+ idleDetectorThread()->stop();
+}
+
const int maxBusyTime = 2000; // maximum time we allow idle detector to be blocked before worrying, in milliseconds
const int baseDelay = 1000; // minimum delay time used when backing off to allow idling, in microseconds
#endif
diff --git a/src/corelib/thread/qthread_symbian.cpp b/src/corelib/thread/qthread_symbian.cpp
index 128124ffd7..75cb5eb699 100644
--- a/src/corelib/thread/qthread_symbian.cpp
+++ b/src/corelib/thread/qthread_symbian.cpp
@@ -131,11 +131,7 @@ public:
{
data->symbian_thread_handle.LogonCancel(iStatus);
}
- void RunL()
- {
- data->deref();
- delete this;
- }
+ void RunL();
private:
QThreadData* data;
};
@@ -177,6 +173,7 @@ public:
for (int i=threadsToAdd.size()-1; i>=0; i--) {
// Create an active object to monitor the thread
new (ELeave) QCAdoptedThreadMonitor(threadsToAdd[i]);
+ count++;
threadsToAdd.pop_back();
}
start();
@@ -193,6 +190,8 @@ public:
User::WaitForRequest(started);
monitorThread.Close();
}
+ if (RThread().Id() == adoptedThreadAdder->monitorThread.Id())
+ return;
adoptedThreadAdder->threadsToAdd.push_back(thread);
if (adoptedThreadAdder->stat) {
adoptedThreadAdder->monitorThread.RequestComplete(adoptedThreadAdder->stat, KErrNone);
@@ -204,15 +203,15 @@ public:
CleanupStack::PushL(scheduler);
CActiveScheduler::Install(scheduler);
- adoptedThreadAdder = new(ELeave) QCAddAdoptedThread();
+ adoptedThreadAdder = new(ELeave) QCAddAdoptedThread();
CleanupStack::PushL(adoptedThreadAdder);
adoptedThreadAdder->ConstructL();
+ QCAddAdoptedThread *adder = adoptedThreadAdder;
RThread::Rendezvous(KErrNone);
CActiveScheduler::Start();
- CleanupStack::PopAndDestroy(adoptedThreadAdder);
- adoptedThreadAdder = 0;
+ CleanupStack::PopAndDestroy(adder);
CleanupStack::PopAndDestroy(scheduler);
}
static int monitorThreadFunc(void *)
@@ -224,18 +223,37 @@ public:
delete cleanup;
return ret;
}
+ static void threadDied()
+ {
+ QMutexLocker adoptedThreadMonitorMutexlock(&adoptedThreadMonitorMutex);
+ if (adoptedThreadAdder) {
+ adoptedThreadAdder->count--;
+ if (adoptedThreadAdder->count <= 0 && adoptedThreadAdder->threadsToAdd.size() == 0) {
+ CActiveScheduler::Stop();
+ adoptedThreadAdder = 0;
+ }
+ }
+ }
private:
QVector<QThread*> threadsToAdd;
RThread monitorThread;
static QMutex adoptedThreadMonitorMutex;
- static QCAddAdoptedThread* adoptedThreadAdder;
+ static QCAddAdoptedThread *adoptedThreadAdder;
+ int count;
TRequestStatus *stat;
};
QMutex QCAddAdoptedThread::adoptedThreadMonitorMutex;
QCAddAdoptedThread* QCAddAdoptedThread::adoptedThreadAdder = 0;
+void QCAdoptedThreadMonitor::RunL()
+{
+ data->deref();
+ QCAddAdoptedThread::threadDied();
+ delete this;
+}
+
void QAdoptedThread::init()
{
Q_D(QThread);