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