summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShane Kearns <shane.kearns@accenture.com>2011-01-07 15:57:28 (GMT)
committerJason McDonald <jason.mcdonald@nokia.com>2011-01-11 09:54:14 (GMT)
commit16e203e5de2aa984dadad2e4edd68d1c3446d9c1 (patch)
treeed88de0b963bfdb892133480d7b778452b71fbb8
parent497cd0564b2471354b1ac86f00c5ba90845aa2e1 (diff)
downloadQt-16e203e5de2aa984dadad2e4edd68d1c3446d9c1.zip
Qt-16e203e5de2aa984dadad2e4edd68d1c3446d9c1.tar.gz
Qt-16e203e5de2aa984dadad2e4edd68d1c3446d9c1.tar.bz2
Fix handle leak in symbian QTimer implementation
The timer handle was only being closed when a timer was cancelled, which resulted in a leak for one shot timers that have completed normally. Instead the timer is now closed in a destructor (closing null handles is safe, so it doesn't matter if the handle was never created - e.g. in the case of a zero timer) Also added a handle check before creating a timer to prevent a leak in case the start function is called twice in the backend. Task-number: QTBUG-16380 Reviewed-by: mread (cherry picked from commit 2b1b617664bfc78f6e95e53dc0f9749bd1f2d27a)
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian.cpp6
-rw-r--r--tests/auto/qtimer/tst_qtimer.cpp38
2 files changed, 42 insertions, 2 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp
index bb9bd01..99c4087 100644
--- a/src/corelib/kernel/qeventdispatcher_symbian.cpp
+++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp
@@ -217,13 +217,13 @@ QTimerActiveObject::QTimerActiveObject(QEventDispatcherSymbian *dispatcher, Symb
QTimerActiveObject::~QTimerActiveObject()
{
Cancel();
+ m_rTimer.Close(); //close of null handle is safe
}
void QTimerActiveObject::DoCancel()
{
if (m_timerInfo->interval > 0) {
m_rTimer.Cancel();
- m_rTimer.Close();
} else {
if (iStatus.Int() == KRequestPending) {
TRequestStatus *status = &iStatus;
@@ -302,7 +302,9 @@ void QTimerActiveObject::Start()
CActiveScheduler::Add(this);
m_timerInfo->msLeft = m_timerInfo->interval;
if (m_timerInfo->interval > 0) {
- m_rTimer.CreateLocal();
+ if (!m_rTimer.Handle()) {
+ qt_symbian_throwIfError(m_rTimer.CreateLocal());
+ }
StartTimer();
} else {
iStatus = KRequestPending;
diff --git a/tests/auto/qtimer/tst_qtimer.cpp b/tests/auto/qtimer/tst_qtimer.cpp
index 102308e..e964728 100644
--- a/tests/auto/qtimer/tst_qtimer.cpp
+++ b/tests/auto/qtimer/tst_qtimer.cpp
@@ -90,6 +90,9 @@ private slots:
void QTBUG13633_dontBlockEvents();
void postedEventsShouldNotStarveTimers();
+#ifdef Q_OS_SYMBIAN
+ void handleLeaks();
+#endif
};
class TimerHelper : public QObject
@@ -750,5 +753,40 @@ void tst_QTimer::postedEventsShouldNotStarveTimers()
QVERIFY(timerHelper.count > 5);
}
+#ifdef Q_OS_SYMBIAN
+void tst_QTimer::handleLeaks()
+{
+ const int timercount = 5;
+ int processhandles_start;
+ int threadhandles_start;
+ RThread().HandleCount(processhandles_start, threadhandles_start);
+ {
+ TimerHelper timerHelper;
+ QList<QTimer*> timers;
+ for (int i=0;i<timercount;i++) {
+ QTimer* timer = new QTimer;
+ timers.append(timer);
+ connect(timer, SIGNAL(timeout()), &timerHelper, SLOT(timeout()));
+ timer->setSingleShot(true);
+ timer->start(i); //test both zero and normal timeouts
+ }
+ int processhandles_mid;
+ int threadhandles_mid;
+ RThread().HandleCount(processhandles_mid, threadhandles_mid);
+ qDebug() << threadhandles_mid - threadhandles_start << "new thread owned handles";
+ QTest::qWait(100);
+ QCOMPARE(timerHelper.count, timercount);
+ qDeleteAll(timers);
+ }
+ int processhandles_end;
+ int threadhandles_end;
+ RThread().HandleCount(processhandles_end, threadhandles_end);
+ QCOMPARE(threadhandles_end, threadhandles_start); //RTimer::CreateLocal creates a thread owned handle
+ //Can not verify process handles because QObject::connect may create up to 2 mutexes
+ //from a QMutexPool (4 process owned handles with open C imp.)
+ //QCOMPARE(processhandles_end, processhandles_start);
+}
+#endif
+
QTEST_MAIN(tst_QTimer)
#include "tst_qtimer.moc"