summaryrefslogtreecommitdiffstats
path: root/src/corelib
diff options
context:
space:
mode:
Diffstat (limited to 'src/corelib')
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian.cpp125
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian_p.h34
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;