diff options
author | axis <qt-info@nokia.com> | 2010-09-23 13:21:31 (GMT) |
---|---|---|
committer | axis <qt-info@nokia.com> | 2010-09-23 13:21:31 (GMT) |
commit | fac1be47ea4ecc05c63e9ca6cae19ac67985c900 (patch) | |
tree | 0f7089a77ec1aa13b292faab39a242f7478b22ab | |
parent | 74f09c794d5fdcb8f4b547b1c55bcd512ef07b95 (diff) | |
parent | ecc7beca87bdfdad2e260f6b9621b77055cf313c (diff) | |
download | Qt-fac1be47ea4ecc05c63e9ca6cae19ac67985c900.zip Qt-fac1be47ea4ecc05c63e9ca6cae19ac67985c900.tar.gz Qt-fac1be47ea4ecc05c63e9ca6cae19ac67985c900.tar.bz2 |
Merge branch 'eventStarvationFixes' into 4.7-s60
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian.cpp | 38 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian_p.h | 8 | ||||
-rw-r--r-- | tests/auto/qapplication/test/test.pro | 2 | ||||
-rw-r--r-- | tests/auto/qtimer/tst_qtimer.cpp | 27 |
4 files changed, 59 insertions, 16 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index 5cc6ae3..d8cc344 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -127,9 +127,9 @@ private: * cannot change active objects that we do not own, but the active objects that Qt owns will use * this as a base class with convenience functions. * - * Here is how it works: On every RunL, the deriving class should call okToRun(). This will allow - * exactly one run of the active object, and mark it as such. If it is called again, it will return - * false, and add the object to a queue so it can be run later. + * Here is how it works: On every RunL, the deriving class should call maybeQueueForLater(). + * This will return whether the active object has been queued, or whether it should run immediately. + * Queued objects will run again after other events have been processed. * * The QCompleteDeferredAOs class is a special object that runs after all others, which will * reactivate the objects that were previously not run. @@ -149,7 +149,7 @@ QActiveObject::~QActiveObject() m_dispatcher->removeDeferredActiveObject(this); } -bool QActiveObject::okToRun() +bool QActiveObject::maybeQueueForLater() { Q_ASSERT(!m_hasRunAgain); @@ -157,12 +157,12 @@ bool QActiveObject::okToRun() // First occurrence of this event in this iteration. m_hasAlreadyRun = true; m_iterationCount = m_dispatcher->iterationCount(); - return true; + return false; } else { // The event has already occurred. m_dispatcher->addDeferredActiveObject(this); m_hasRunAgain = true; - return false; + return true; } } @@ -178,8 +178,7 @@ void QActiveObject::reactivateAndComplete() } QWakeUpActiveObject::QWakeUpActiveObject(QEventDispatcherSymbian *dispatcher) - : CActive(WAKE_UP_PRIORITY), - m_dispatcher(dispatcher) + : QActiveObject(WAKE_UP_PRIORITY, dispatcher) { CActiveScheduler::Add(this); iStatus = KRequestPending; @@ -201,6 +200,9 @@ void QWakeUpActiveObject::DoCancel() void QWakeUpActiveObject::RunL() { + if (maybeQueueForLater()) + return; + iStatus = KRequestPending; SetActive(); QT_TRYCATCH_LEAVING(m_dispatcher->wakeUpWasCalled()); @@ -270,7 +272,7 @@ void QTimerActiveObject::Run() return; } - if (!okToRun()) + if (maybeQueueForLater()) return; if (m_timerInfo->interval > 0) { @@ -630,7 +632,7 @@ void QSocketActiveObject::DoCancel() void QSocketActiveObject::RunL() { - if (!okToRun()) + if (maybeQueueForLater()) return; QT_TRYCATCH_LEAVING(m_dispatcher->socketFired(this)); @@ -722,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 @@ -772,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); @@ -862,6 +868,7 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla } m_noSocketEvents = oldNoSocketEventsValue; + m_insideTimerEvent = oldInsideTimerEventValue; return handledAnyEvent; } @@ -882,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; @@ -1052,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 maybeQueueForLater() 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->maybeQueueForLater(); } bool QEventDispatcherSymbian::unregisterTimer ( int timerId ) diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h index bc42753..1486db5 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian_p.h +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -82,7 +82,7 @@ public: QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher); ~QActiveObject(); - bool okToRun(); + bool maybeQueueForLater(); void reactivateAndComplete(); @@ -95,7 +95,7 @@ private: int m_iterationCount; }; -class QWakeUpActiveObject : public CActive +class QWakeUpActiveObject : public QActiveObject { public: QWakeUpActiveObject(QEventDispatcherSymbian *dispatcher); @@ -106,9 +106,6 @@ public: protected: void DoCancel(); void RunL(); - -private: - QEventDispatcherSymbian *m_dispatcher; }; struct SymbianTimerInfo : public QSharedData @@ -277,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/qapplication/test/test.pro b/tests/auto/qapplication/test/test.pro index 30eb751..2c54c37 100644 --- a/tests/auto/qapplication/test/test.pro +++ b/tests/auto/qapplication/test/test.pro @@ -12,7 +12,7 @@ wince* { } symbian: { - additional.sources = ../desktopsettingsaware/desktopsettingsaware.exe + additional.sources = $$OUT_PWD/../desktopsettingsaware/desktopsettingsaware.exe additional.path = desktopsettingsaware someTest.sources = test.pro someTest.path = test diff --git a/tests/auto/qtimer/tst_qtimer.cpp b/tests/auto/qtimer/tst_qtimer.cpp index f23d065..102308e 100644 --- a/tests/auto/qtimer/tst_qtimer.cpp +++ b/tests/auto/qtimer/tst_qtimer.cpp @@ -89,6 +89,7 @@ private slots: void recurseOnTimeoutAndStopTimer(); void QTBUG13633_dontBlockEvents(); + void postedEventsShouldNotStarveTimers(); }; class TimerHelper : public QObject @@ -723,5 +724,31 @@ void tst_QTimer::QTBUG13633_dontBlockEvents() QVERIFY(t.total > 2); } +class SlotRepeater : public QObject { + Q_OBJECT +public: + SlotRepeater() {} + +public slots: + void repeatThisSlot() + { + QMetaObject::invokeMethod(this, "repeatThisSlot", Qt::QueuedConnection); + } +}; + +void tst_QTimer::postedEventsShouldNotStarveTimers() +{ + TimerHelper timerHelper; + QTimer timer; + connect(&timer, SIGNAL(timeout()), &timerHelper, SLOT(timeout())); + timer.setInterval(0); + timer.setSingleShot(false); + timer.start(); + SlotRepeater slotRepeater; + slotRepeater.repeatThisSlot(); + QTest::qWait(100); + QVERIFY(timerHelper.count > 5); +} + QTEST_MAIN(tst_QTimer) #include "tst_qtimer.moc" |