summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian.cpp33
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian_p.h2
-rw-r--r--tests/auto/qtimer/tst_qtimer.cpp12
3 files changed, 42 insertions, 5 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp
index b1c8734097..11a0da6b03 100644
--- a/src/corelib/kernel/qeventdispatcher_symbian.cpp
+++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp
@@ -231,15 +231,39 @@ void QTimerActiveObject::RunL()
}
}
+#define MAX_SYMBIAN_TIMEOUT_MS 2000000
+void QTimerActiveObject::StartTimer()
+{
+ if (m_timerInfo->msLeft > MAX_SYMBIAN_TIMEOUT_MS) {
+ //There is loss of accuracy anyway due to needing to restart the timer every 33 minutes,
+ //so the 1/64s res of After() is acceptable for these very long timers.
+ m_rTimer.After(iStatus, MAX_SYMBIAN_TIMEOUT_MS * 1000);
+ m_timerInfo->msLeft -= MAX_SYMBIAN_TIMEOUT_MS;
+ } else {
+ //HighRes gives the 1ms accuracy expected by Qt, the +1 is to ensure that
+ //"Timers will never time out earlier than the specified timeout value"
+ //condition is always met.
+ m_rTimer.HighRes(iStatus, (m_timerInfo->msLeft + 1) * 1000);
+ m_timerInfo->msLeft = 0;
+ }
+ SetActive();
+}
+
void QTimerActiveObject::Run()
{
+ //restart timer immediately, if the timeout has been split because it overflows max for platform.
+ if (m_timerInfo->msLeft > 0) {
+ StartTimer();
+ return;
+ }
+
if (!okToRun())
return;
if (m_timerInfo->interval > 0) {
// Start a new timer immediately so that we don't lose time.
- SetActive();
- m_rTimer.After(iStatus, m_timerInfo->interval*1000);
+ m_timerInfo->msLeft = m_timerInfo->interval;
+ StartTimer();
m_timerInfo->dispatcher->timerFired(m_timerInfo->timerId);
} else {
@@ -261,11 +285,10 @@ void QTimerActiveObject::Run()
void QTimerActiveObject::Start()
{
CActiveScheduler::Add(this);
+ m_timerInfo->msLeft = m_timerInfo->interval;
if (m_timerInfo->interval > 0) {
m_rTimer.CreateLocal();
- iStatus = KRequestPending;
- SetActive();
- m_rTimer.After(iStatus, m_timerInfo->interval*1000);
+ StartTimer();
} else {
iStatus = KRequestPending;
SetActive();
diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h
index 53f92a991a..fd0350d737 100644
--- a/src/corelib/kernel/qeventdispatcher_symbian_p.h
+++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h
@@ -117,6 +117,7 @@ struct SymbianTimerInfo : public QSharedData
int timerId;
int interval;
+ int msLeft;
bool inTimerEvent;
QObject *receiver;
QTimerActiveObject *timerAO;
@@ -140,6 +141,7 @@ protected:
private:
void Run();
+ void StartTimer();
private:
SymbianTimerInfo *m_timerInfo;
diff --git a/tests/auto/qtimer/tst_qtimer.cpp b/tests/auto/qtimer/tst_qtimer.cpp
index a55c1c63a5..0877500641 100644
--- a/tests/auto/qtimer/tst_qtimer.cpp
+++ b/tests/auto/qtimer/tst_qtimer.cpp
@@ -88,6 +88,7 @@ private slots:
void timerFiresOnlyOncePerProcessEvents_data();
void timerFiresOnlyOncePerProcessEvents();
void timerIdPersistsAfterThreadExit();
+ void cancelLongTimer();
};
class TimerHelper : public QObject
@@ -602,5 +603,16 @@ void tst_QTimer::timerIdPersistsAfterThreadExit()
QVERIFY((timerId & 0xffffff) != (thread.timerId & 0xffffff));
}
+void tst_QTimer::cancelLongTimer()
+{
+ QTimer timer;
+ timer.setSingleShot(true);
+ timer.start(1000 * 60 * 60); //set timer for 1 hour (which would overflow Symbian RTimer)
+ QCoreApplication::processEvents();
+ QVERIFY(timer.isActive()); //if the timer completes immediately with an error, then this will fail
+ timer.stop();
+ QVERIFY(!timer.isActive());
+}
+
QTEST_MAIN(tst_QTimer)
#include "tst_qtimer.moc"