diff options
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian.cpp | 125 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian_p.h | 34 |
2 files changed, 152 insertions, 7 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index fca2feb..ef331f6 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -59,6 +59,7 @@ QT_BEGIN_NAMESPACE #define WAKE_UP_PRIORITY CActive::EPriorityStandard #define TIMER_PRIORITY CActive::EPriorityHigh +#define COMPLETE_DEFERRED_ACTIVE_OBJECTS_PRIORITY CActive::EPriorityIdle class Incrementer { int &variable; @@ -140,17 +141,49 @@ private: }; /* - * This class can be used as a base class for Qt active objects. + * This class is designed to aid in implementing event handling in a more round robin fashion, + * when Qt active objects are used outside of QtRRActiveScheduler. + * We cannot change active objects that we do not own, but active objects that Qt owns may use + * this as a base class with convenience functions. + * + * 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. * Socket active objects can use it to defer their activity. */ QActiveObject::QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher) : CActive(priority), - m_dispatcher(dispatcher) + m_dispatcher(dispatcher), + m_hasAlreadyRun(false), + m_hasRunAgain(false), + m_iterationCount(1) { } QActiveObject::~QActiveObject() { + if (m_hasRunAgain) + m_dispatcher->removeDeferredActiveObject(this); +} + +bool QActiveObject::maybeQueueForLater() +{ + Q_ASSERT(!m_hasRunAgain); + + if (!m_hasAlreadyRun || m_dispatcher->iterationCount() != m_iterationCount) { + // First occurrence of this event in this iteration. + m_hasAlreadyRun = true; + m_iterationCount = m_dispatcher->iterationCount(); + return false; + } else { + // The event has already occurred. + m_dispatcher->addDeferredActiveObject(this); + m_hasRunAgain = true; + return true; + } } bool QActiveObject::maybeDeferSocketEvent() @@ -170,6 +203,9 @@ void QActiveObject::reactivateAndComplete() SetActive(); TRequestStatus *status = &iStatus; QEventDispatcherSymbian::RequestComplete(status, error); + + m_hasRunAgain = false; + m_hasAlreadyRun = false; } QWakeUpActiveObject::QWakeUpActiveObject(QEventDispatcherSymbian *dispatcher) @@ -212,8 +248,8 @@ void QWakeUpActiveObject::RunL() } QTimerActiveObject::QTimerActiveObject(QEventDispatcherSymbian *dispatcher, SymbianTimerInfo *timerInfo) - : CActive(TIMER_PRIORITY), - m_dispatcher(dispatcher), m_timerInfo(timerInfo), m_expectedTimeSinceLastEvent(0) + : QActiveObject(TIMER_PRIORITY, dispatcher), + m_timerInfo(timerInfo), m_expectedTimeSinceLastEvent(0) { // start the timeout timer to ensure initialisation m_timeoutTimer.start(); @@ -290,6 +326,9 @@ void QTimerActiveObject::Run() return; } + if (maybeQueueForLater()) + return; + if (m_timerInfo->interval > 0) { // Start a new timer immediately so that we don't lose time. m_timerInfo->msLeft = m_timerInfo->interval; @@ -341,6 +380,44 @@ SymbianTimerInfo::~SymbianTimerInfo() delete timerAO; } +QCompleteDeferredAOs::QCompleteDeferredAOs(QEventDispatcherSymbian *dispatcher) + : CActive(COMPLETE_DEFERRED_ACTIVE_OBJECTS_PRIORITY), + m_dispatcher(dispatcher) +{ + CActiveScheduler::Add(this); + iStatus = KRequestPending; + SetActive(); +} + +QCompleteDeferredAOs::~QCompleteDeferredAOs() +{ + Cancel(); +} + +void QCompleteDeferredAOs::complete() +{ + if (iStatus.Int() == KRequestPending) { + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } +} + +void QCompleteDeferredAOs::DoCancel() +{ + if (iStatus.Int() == KRequestPending) { + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } +} + +void QCompleteDeferredAOs::RunL() +{ + iStatus = KRequestPending; + SetActive(); + + QT_TRYCATCH_LEAVING(m_dispatcher->reactivateDeferredActiveObjects()); +} + QSelectThread::QSelectThread() : m_quit(false) { @@ -879,6 +956,7 @@ QEventDispatcherSymbian::QEventDispatcherSymbian(QObject *parent) m_selectThread(0), m_activeScheduler(0), m_wakeUpAO(0), + m_completeDeferredAOs(0), m_interrupt(false), m_wakeUpDone(0), m_iterationCount(0), @@ -903,6 +981,7 @@ void QEventDispatcherSymbian::startingUp() CActiveScheduler::Install(m_activeScheduler); } m_wakeUpAO = q_check_ptr(new QWakeUpActiveObject(this)); + m_completeDeferredAOs = q_check_ptr(new QCompleteDeferredAOs(this)); // We already might have posted events, wakeup once to process them wakeUp(); } @@ -921,6 +1000,7 @@ void QEventDispatcherSymbian::closingDown() delete m_selectThread; m_selectThread = 0; + delete m_completeDeferredAOs; delete m_wakeUpAO; if (m_activeScheduler) { delete m_activeScheduler; @@ -1153,6 +1233,35 @@ inline void QEventDispatcherSymbian::addDeferredSocketActiveObject(QActiveObject m_deferredSocketEvents.append(object); } +inline void QEventDispatcherSymbian::addDeferredActiveObject(QActiveObject *object) +{ + queueDeferredActiveObjectsCompletion(); + m_deferredActiveObjects.append(object); +} + +inline void QEventDispatcherSymbian::removeDeferredActiveObject(QActiveObject *object) +{ + m_deferredActiveObjects.removeAll(object); +} + +void QEventDispatcherSymbian::queueDeferredActiveObjectsCompletion() +{ + m_completeDeferredAOs->complete(); +} + +void QEventDispatcherSymbian::reactivateDeferredActiveObjects() +{ + while (!m_deferredActiveObjects.isEmpty()) { + QActiveObject *object = m_deferredActiveObjects.takeFirst(); + object->reactivateAndComplete(); + } + + // We do this because we want to return from processEvents. This is because + // each invocation of processEvents should only run each active object once. + // The active scheduler should run them continously, however. + m_interrupt = true; +} + bool QEventDispatcherSymbian::sendDeferredSocketEvents() { bool sentAnyEvents = false; @@ -1228,6 +1337,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 1b81599..01f5ab1 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian_p.h +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -84,10 +84,15 @@ public: ~QActiveObject(); bool maybeDeferSocketEvent(); - + bool maybeQueueForLater(); void reactivateAndComplete(); protected: QEventDispatcherSymbian *m_dispatcher; + +private: + bool m_hasAlreadyRun : 1; + bool m_hasRunAgain : 1; + int m_iterationCount; }; class QWakeUpActiveObject : public CActive @@ -124,7 +129,7 @@ struct SymbianTimerInfo : public QSharedData typedef QExplicitlySharedDataPointer<SymbianTimerInfo> SymbianTimerInfoPtr; // This is a bit of a proxy class. See comments in SetActive and Start for details. -class QTimerActiveObject : public CActive +class QTimerActiveObject : public QActiveObject { public: QTimerActiveObject(QEventDispatcherSymbian *dispatcher, SymbianTimerInfo *timerInfo); @@ -141,13 +146,28 @@ private: void StartTimer(); private: - QEventDispatcherSymbian *m_dispatcher; SymbianTimerInfo *m_timerInfo; QElapsedTimer m_timeoutTimer; int m_expectedTimeSinceLastEvent; RTimer m_rTimer; }; +class QCompleteDeferredAOs : public CActive +{ +public: + QCompleteDeferredAOs(QEventDispatcherSymbian *dispatcher); + ~QCompleteDeferredAOs(); + + void complete(); + +protected: + void DoCancel(); + void RunL(); + +private: + QEventDispatcherSymbian *m_dispatcher; +}; + class QSocketActiveObject : public QActiveObject { public: @@ -231,6 +251,11 @@ public: void wakeUpWasCalled(); void reactivateSocketNotifier(QSocketNotifier *notifier); + void addDeferredActiveObject(QActiveObject *object); + void removeDeferredActiveObject(QActiveObject *object); + void queueDeferredActiveObjectsCompletion(); + // Can be overridden to activate local active objects too, but do call baseclass! + virtual void reactivateDeferredActiveObjects(); inline int iterationCount() const { return m_iterationCount; } void addDeferredSocketActiveObject(QActiveObject *object); @@ -253,6 +278,7 @@ private: QHash<QSocketNotifier *, QSocketActiveObject *> m_notifiers; QWakeUpActiveObject *m_wakeUpAO; + QCompleteDeferredAOs *m_completeDeferredAOs; volatile bool m_interrupt; QAtomicInt m_wakeUpDone; @@ -263,6 +289,8 @@ private: //deferred until socket events are enabled QList<QActiveObject *> m_deferredSocketEvents; + QList<QActiveObject *> m_deferredActiveObjects; + int m_delay; int m_avgEventTime; QElapsedTimer m_lastIdleRequestTimer; |