diff options
author | Shane Kearns <shane.kearns@sosco.com> | 2009-09-16 13:48:59 (GMT) |
---|---|---|
committer | Shane Kearns <shane.kearns@sosco.com> | 2009-09-16 13:48:59 (GMT) |
commit | 504dd08854a8f6519a0529014df2233938b82728 (patch) | |
tree | c96594b5b69bcd10d61b97fd9838505208eb7610 | |
parent | 314e5680c8276d539b596927874036a873966d8f (diff) | |
download | Qt-504dd08854a8f6519a0529014df2233938b82728.zip Qt-504dd08854a8f6519a0529014df2233938b82728.tar.gz Qt-504dd08854a8f6519a0529014df2233938b82728.tar.bz2 |
Fix QTimer overflow with interval > 35 minutes on symbian
For long intervals, restart the system timer every 2000 seconds
New autotest to verify long timers don't crash or complete immediately
Task-number: QT-651
Reviewed-by: axis
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian.cpp | 33 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian_p.h | 2 | ||||
-rw-r--r-- | tests/auto/qtimer/tst_qtimer.cpp | 12 |
3 files changed, 42 insertions, 5 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index b1c8734..11a0da6 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 53f92a9..fd0350d 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 a55c1c6..0877500 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" |