diff options
author | axis <qt-info@nokia.com> | 2010-09-23 11:38:04 (GMT) |
---|---|---|
committer | axis <qt-info@nokia.com> | 2010-09-23 12:37:30 (GMT) |
commit | 8d8d147f1dd5d2922a4c61c43d378c8784224f13 (patch) | |
tree | 5a9570108c9af3b8e3697848eb05b7fb17390282 | |
parent | 5c29d5be5197b265f16c4895776e9be97db845d6 (diff) | |
download | Qt-8d8d147f1dd5d2922a4c61c43d378c8784224f13.zip Qt-8d8d147f1dd5d2922a4c61c43d378c8784224f13.tar.gz Qt-8d8d147f1dd5d2922a4c61c43d378c8784224f13.tar.bz2 |
Fixed event starvation on Symbian if timers were constantly recreated
If a timer event occurred, and inside its handler a new timer was
created that would also immediately occur, the events would execute
over and over and starve other events. This happened because the code
in Symbian that is supposed to detect when the same event happens
more than once does not work if it is always a new timer which
executes.
The bug was fixed by introducing a state variable which signals
whether we are currently inside the handler of a timer event, and
then pretending that newly created timers inside this handler have
already been executed once, thereby delaying their execution until
the next iteration.
Because we reset the state variable in processEvents, the behavior
will be slightly different if run directly under
CActiveScheduler::Start(). There, we have no way of resetting the
state on the next iteration, so all timers inside such a handler
(even if it recurses into a new CActiveScheduler::Start()) will be
delayed by one event iteration. However, this is considered
acceptable, since there is no real "iteration count" in the active
scheduler; the event will simply be run after the deferred queue is
reactivated (which will be immediately if there are no other events).
This is the same as what would have happened for a real timer that
executed once and then recursed into CActiveScheduler::Start() (it
would also be delayed by one iteration).
Task: QTBUG-13773
RevBy: mread
AutoTest: Passed
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian.cpp | 16 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian_p.h | 1 | ||||
-rw-r--r-- | tests/auto/qtimer/tst_qtimer.cpp | 4 |
3 files changed, 17 insertions, 4 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index 4ac500f..89012d1 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -724,6 +724,7 @@ QEventDispatcherSymbian::QEventDispatcherSymbian(QObject *parent) m_interrupt(false), m_wakeUpDone(0), m_iterationCount(0), + m_insideTimerEvent(false), m_noSocketEvents(false) { #ifdef QT_SYMBIAN_PRIORITY_DROP @@ -774,6 +775,9 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla { bool handledAnyEvent = false; bool oldNoSocketEventsValue = m_noSocketEvents; + bool oldInsideTimerEventValue = m_insideTimerEvent; + + m_insideTimerEvent = false; QT_TRY { Q_D(QAbstractEventDispatcher); @@ -864,6 +868,7 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla } m_noSocketEvents = oldNoSocketEventsValue; + m_insideTimerEvent = oldInsideTimerEventValue; return handledAnyEvent; } @@ -884,10 +889,13 @@ void QEventDispatcherSymbian::timerFired(int timerId) } timerInfo->inTimerEvent = true; + bool oldInsideTimerEventValue = m_insideTimerEvent; + m_insideTimerEvent = true; QTimerEvent event(timerInfo->timerId); QCoreApplication::sendEvent(timerInfo->receiver, &event); + m_insideTimerEvent = oldInsideTimerEventValue; timerInfo->inTimerEvent = false; return; @@ -1054,6 +1062,14 @@ void QEventDispatcherSymbian::registerTimer ( int timerId, int interval, QObject m_timerList.insert(timerId, timer); timer->timerAO->Start(); + + if (m_insideTimerEvent) + // If we are inside a timer event, we need to prevent event starvation + // by preventing newly created timers from running in the same event processing + // iteration. Do this by calling the okToRun() function to "fake" that we have + // already run once. This will cause the next run to be added to the deferred + // queue instead. + timer->timerAO->okToRun(); } bool QEventDispatcherSymbian::unregisterTimer ( int timerId ) diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h index 53afebe..8e20d56 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian_p.h +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -274,6 +274,7 @@ private: QAtomicInt m_wakeUpDone; unsigned char m_iterationCount; + bool m_insideTimerEvent; bool m_noSocketEvents; QList<QSocketActiveObject *> m_deferredSocketEvents; diff --git a/tests/auto/qtimer/tst_qtimer.cpp b/tests/auto/qtimer/tst_qtimer.cpp index 73179fd..102308e 100644 --- a/tests/auto/qtimer/tst_qtimer.cpp +++ b/tests/auto/qtimer/tst_qtimer.cpp @@ -719,10 +719,6 @@ void DontBlockEvents::paintEvent() void tst_QTimer::QTBUG13633_dontBlockEvents() { -#ifdef Q_OS_SYMBIAN - QEXPECT_FAIL("", "Expect failure because of QTBUG-13773", Abort); - QVERIFY2(false, "This test hangs on Symbian"); -#endif DontBlockEvents t; QTest::qWait(60); QVERIFY(t.total > 2); |