diff options
Diffstat (limited to 'src/corelib')
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian.cpp | 155 | ||||
-rw-r--r-- | src/corelib/kernel/qeventdispatcher_symbian_p.h | 54 |
2 files changed, 144 insertions, 65 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp index 2f38a95..d745406 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian.cpp +++ b/src/corelib/kernel/qeventdispatcher_symbian.cpp @@ -22,7 +22,7 @@ QT_BEGIN_NAMESPACE #define WAKE_UP_PRIORITY CActive::EPriorityStandard #define TIMER_PRIORITY CActive::EPriorityLow -#define COMPLETE_ZERO_TIMERS_PRIORITY CActive::EPriorityIdle +#define COMPLETE_DEFERRED_ACTIVE_OBJECTS_PRIORITY CActive::EPriorityIdle static inline int qt_pipe_write(int socket, const char *data, qint64 len) { @@ -82,6 +82,61 @@ private: QMutex *m_mutex; }; +/* + * This class is designed to aid in implementing event handling in a more round robin fashion. We + * 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. + * + * The QCompleteDeferredAOs class is a special object that runs after all others, which will + * reactivate the objects that were previously not run. + */ +inline QActiveObject::QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher) + : CActive(priority), + m_dispatcher(dispatcher), + m_hasAlreadyRun(false), + m_hasRunAgain(false), + m_iterationCount(1) +{ +} + +QActiveObject::~QActiveObject() +{ + if (m_hasRunAgain) + m_dispatcher->removeDeferredActiveObject(this); +} + +bool QActiveObject::okToRun() +{ + 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 true; + } else { + // The event has already occurred. + m_dispatcher->addDeferredActiveObject(this); + m_hasRunAgain = true; + return false; + } +} + +void QActiveObject::reactivateAndComplete() +{ + iStatus = KRequestPending; + SetActive(); + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + + m_hasRunAgain = false; + m_hasAlreadyRun = false; +} + QWakeUpActiveObject::QWakeUpActiveObject(QEventDispatcherSymbian *dispatcher) : CActive(WAKE_UP_PRIORITY), m_dispatcher(dispatcher) @@ -111,8 +166,8 @@ void QWakeUpActiveObject::RunL() m_dispatcher->wakeUpWasCalled(); } -QTimerActiveObject::QTimerActiveObject(SymbianTimerInfo *timerInfo) - : CActive(TIMER_PRIORITY), +QTimerActiveObject::QTimerActiveObject(QEventDispatcherSymbian *dispatcher, SymbianTimerInfo *timerInfo) + : QActiveObject(TIMER_PRIORITY, dispatcher), m_timerInfo(timerInfo) { } @@ -137,6 +192,9 @@ void QTimerActiveObject::DoCancel() void QTimerActiveObject::RunL() { + if (!okToRun()) + return; + if (m_timerInfo->interval > 0) { // Start a new timer immediately so that we don't lose time. iStatus = KRequestPending; @@ -155,7 +213,8 @@ void QTimerActiveObject::RunL() iStatus = KRequestPending; SetActive(); - // We complete it after the processEvents is done. + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); } } @@ -180,33 +239,29 @@ SymbianTimerInfo::~SymbianTimerInfo() delete timerAO; } -QCompleteZeroTimersActiveObject::QCompleteZeroTimersActiveObject(QEventDispatcherSymbian *dispatcher) - : CActive(COMPLETE_ZERO_TIMERS_PRIORITY), +QCompleteDeferredAOs::QCompleteDeferredAOs(QEventDispatcherSymbian *dispatcher) + : CActive(COMPLETE_DEFERRED_ACTIVE_OBJECTS_PRIORITY), m_dispatcher(dispatcher) { CActiveScheduler::Add(this); iStatus = KRequestPending; SetActive(); - TRequestStatus *status = &iStatus; - QEventDispatcherSymbian::RequestComplete(status, KErrNone); } -QCompleteZeroTimersActiveObject::~QCompleteZeroTimersActiveObject() +QCompleteDeferredAOs::~QCompleteDeferredAOs() { Cancel(); } -bool QCompleteZeroTimersActiveObject::ref() +void QCompleteDeferredAOs::complete() { - return (++m_refCount != 0); -} - -bool QCompleteZeroTimersActiveObject::deref() -{ - return (--m_refCount != 0); + if (iStatus.Int() & KRequestPending) { + TRequestStatus *status = &iStatus; + QEventDispatcherSymbian::RequestComplete(status, KErrNone); + } } -void QCompleteZeroTimersActiveObject::DoCancel() +void QCompleteDeferredAOs::DoCancel() { if (iStatus.Int() & KRequestPending) { TRequestStatus *status = &iStatus; @@ -214,14 +269,12 @@ void QCompleteZeroTimersActiveObject::DoCancel() } } -void QCompleteZeroTimersActiveObject::RunL() +void QCompleteDeferredAOs::RunL() { - m_dispatcher->completeZeroTimers(); - iStatus = KRequestPending; SetActive(); - TRequestStatus *status = &iStatus; - QEventDispatcherSymbian::RequestComplete(status, KErrNone); + + m_dispatcher->reactivateDeferredActiveObjects(); } QSelectThread::QSelectThread() @@ -466,8 +519,7 @@ void QSelectThread::stop() } QSocketActiveObject::QSocketActiveObject(QEventDispatcherSymbian *dispatcher, QSocketNotifier *notifier) - : CActive(CActive::EPriorityStandard), - m_dispatcher(dispatcher), + : QActiveObject(CActive::EPriorityStandard, dispatcher), m_notifier(notifier), m_inSocketEvent(false), m_deleteLater(false) @@ -492,6 +544,9 @@ void QSocketActiveObject::DoCancel() void QSocketActiveObject::RunL() { + if (!okToRun()) + return; + m_dispatcher->socketFired(this); } @@ -508,9 +563,10 @@ QEventDispatcherSymbian::QEventDispatcherSymbian(QObject *parent) : QAbstractEventDispatcher(parent), m_activeScheduler(0), m_wakeUpAO(0), - m_completeZeroTimersAO(0), + m_completeDeferredAOs(0), m_interrupt(false), m_wakeUpDone(0), + m_iterationCount(0), m_noSocketEvents(false) { } @@ -527,6 +583,7 @@ void QEventDispatcherSymbian::startingUp() CActiveScheduler::Install(m_activeScheduler); } m_wakeUpAO = new(ELeave) QWakeUpActiveObject(this); + m_completeDeferredAOs = new(ELeave) QCompleteDeferredAOs(this); // We already might have posted events, wakeup once to process them wakeUp(); } @@ -537,6 +594,7 @@ void QEventDispatcherSymbian::closingDown() m_selectThread.stop(); } + delete m_completeDeferredAOs; delete m_wakeUpAO; if (m_activeScheduler) { delete m_activeScheduler; @@ -547,6 +605,10 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla { Q_D(QAbstractEventDispatcher); + // It is safe if this counter overflows. The main importance is that each + // iteration count is different from the last. + m_iterationCount++; + RThread &thread = d->threadData->symbian_thread_handle; bool block; @@ -633,9 +695,6 @@ bool QEventDispatcherSymbian::processEvents ( QEventLoop::ProcessEventsFlags fla timeState = SubsequentRun; }; - // Complete zero timers so that we get them next time. - completeZeroTimers(); - emit awake(); m_noSocketEvents = oldNoSocketEventsValue; @@ -740,17 +799,28 @@ bool QEventDispatcherSymbian::sendPostedEvents() //return false; } -void QEventDispatcherSymbian::completeZeroTimers() +inline void QEventDispatcherSymbian::addDeferredActiveObject(QActiveObject *object) { - for (QHash<int, SymbianTimerInfoPtr>::iterator i = m_timerList.begin(); i != m_timerList.end(); ++i) { - if ((*i)->interval == 0 && (*i)->timerAO->iStatus.Int() & KRequestPending) { - TRequestStatus *status = &(*i)->timerAO->iStatus; - QEventDispatcherSymbian::RequestComplete(status, KErrNone); - } + if (m_deferredActiveObjects.isEmpty()) { + m_completeDeferredAOs->complete(); + } + m_deferredActiveObjects.append(object); +} + +inline void QEventDispatcherSymbian::removeDeferredActiveObject(QActiveObject *object) +{ + m_deferredActiveObjects.removeAll(object); +} + +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 zero timer once. + // each invocation of processEvents should only run each active object once. // The active scheduler should run them continously, however. m_interrupt = true; } @@ -813,16 +883,9 @@ void QEventDispatcherSymbian::registerTimer ( int timerId, int interval, QObject timer->inTimerEvent = false; timer->receiver = object; timer->dispatcher = this; - timer->timerAO = new(ELeave) QTimerActiveObject(timer.data()); + timer->timerAO = new(ELeave) QTimerActiveObject(this, timer.data()); m_timerList.insert(timerId, timer); - if (interval == 0) { - if (!m_completeZeroTimersAO) { - m_completeZeroTimersAO = new (ELeave) QCompleteZeroTimersActiveObject(this); - } - m_completeZeroTimersAO->ref(); - } - timer->timerAO->Start(); } @@ -833,12 +896,6 @@ bool QEventDispatcherSymbian::unregisterTimer ( int timerId ) } SymbianTimerInfoPtr timerInfo = m_timerList.take(timerId); - if (timerInfo->interval == 0) { - if (!m_completeZeroTimersAO->deref()) { - delete m_completeZeroTimersAO; - m_completeZeroTimersAO = 0; - } - } return true; } diff --git a/src/corelib/kernel/qeventdispatcher_symbian_p.h b/src/corelib/kernel/qeventdispatcher_symbian_p.h index b5ce868..393749f 100644 --- a/src/corelib/kernel/qeventdispatcher_symbian_p.h +++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h @@ -45,6 +45,25 @@ QT_BEGIN_NAMESPACE class QEventDispatcherSymbian; class QTimerActiveObject; +class QActiveObject : public CActive +{ +public: + QActiveObject(TInt priority, QEventDispatcherSymbian *dispatcher); + ~QActiveObject(); + + bool okToRun(); + + void reactivateAndComplete(); + +protected: + QEventDispatcherSymbian *m_dispatcher; + +private: + bool m_hasAlreadyRun : 1; + bool m_hasRunAgain : 1; + int m_iterationCount; +}; + class QWakeUpActiveObject : public CActive { public: @@ -76,10 +95,10 @@ 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(SymbianTimerInfo *timerInfo); + QTimerActiveObject(QEventDispatcherSymbian *dispatcher, SymbianTimerInfo *timerInfo); ~QTimerActiveObject(); void Start(); @@ -93,25 +112,23 @@ private: RTimer m_rTimer; }; -class QCompleteZeroTimersActiveObject : public CActive +class QCompleteDeferredAOs : public CActive { public: - QCompleteZeroTimersActiveObject(QEventDispatcherSymbian *dispatcher); - ~QCompleteZeroTimersActiveObject(); + QCompleteDeferredAOs(QEventDispatcherSymbian *dispatcher); + ~QCompleteDeferredAOs(); - bool ref(); - bool deref(); + void complete(); protected: void DoCancel(); void RunL(); private: - int m_refCount; QEventDispatcherSymbian *m_dispatcher; }; -class QSocketActiveObject : public CActive +class QSocketActiveObject : public QActiveObject { public: QSocketActiveObject(QEventDispatcherSymbian *dispatcher, QSocketNotifier *notifier); @@ -124,7 +141,6 @@ protected: void RunL(); private: - QEventDispatcherSymbian *m_dispatcher; QSocketNotifier *m_notifier; bool m_inSocketEvent; bool m_deleteLater; @@ -187,7 +203,12 @@ public: void socketFired(QSocketActiveObject *socketAO); void wakeUpWasCalled(); void reactivateSocketNotifier(QSocketNotifier *notifier); - void completeZeroTimers(); + + void addDeferredActiveObject(QActiveObject *object); + void removeDeferredActiveObject(QActiveObject *object); + void reactivateDeferredActiveObjects(); + + inline int iterationCount() const { return m_iterationCount; } static void RequestComplete(TRequestStatus *&status, TInt reason); static void RequestComplete(RThread &threadHandle, TRequestStatus *&status, TInt reason); @@ -205,20 +226,21 @@ private: QHash<QSocketNotifier *, QSocketActiveObject *> m_notifiers; QWakeUpActiveObject *m_wakeUpAO; - QCompleteZeroTimersActiveObject *m_completeZeroTimersAO; + QCompleteDeferredAOs *m_completeDeferredAOs; volatile bool m_interrupt; QAtomicInt m_wakeUpDone; + unsigned char m_iterationCount; bool m_noSocketEvents; QList<QSocketActiveObject *> m_deferredSocketEvents; + QList<QActiveObject *> m_deferredActiveObjects; + RProcess m_processHandle; }; -#define DEBUG_REQUEST_COMPLETE - -#ifdef DEBUG_REQUEST_COMPLETE +#ifdef QT_DEBUG // EActive is defined to 1 and ERequestPending to 2, but they are both private. // A little dangerous to rely on, but it is only for debugging. # define REQUEST_STATUS_ACTIVE_AND_PENDING 3 @@ -230,7 +252,7 @@ private: #endif // Convenience functions for doing some sanity checking on our own complete code. -// Unless you define DEBUG_REQUEST_COMPLETE, it is exactly equivalent to the Symbian version. +// Unless QT_DEBUG is defined, it is exactly equivalent to the Symbian version. inline void QEventDispatcherSymbian::RequestComplete(TRequestStatus *&status, TInt reason) { VERIFY_PENDING_REQUEST_STATUS |