summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoraxis <qt-info@nokia.com>2009-05-15 15:43:57 (GMT)
committeraxis <qt-info@nokia.com>2009-05-19 14:16:51 (GMT)
commitdbf64e86f37384a991153335ca4c1528cf44295a (patch)
tree7a156e75177e79f623efba9ee50b7e087bb312d8
parent1a1f4a8b3c8850d7abe4dda5b85b850094cf7a6a (diff)
downloadQt-dbf64e86f37384a991153335ca4c1528cf44295a.zip
Qt-dbf64e86f37384a991153335ca4c1528cf44295a.tar.gz
Qt-dbf64e86f37384a991153335ca4c1528cf44295a.tar.bz2
Changed the way that Qt handles active objects.
The change was done in order to get a more round-robin type of event handling, at least for Qt active objects. With this change, each object will only execute once within each call to processEvents, like other platforms. This is required for certain tests using Open C, because some of the function calls in that library take much longer than their desktop counterparts. Therefore the timer expires before the previous timer handler was finished and the test gets stuck executing the same timer over and over. By returning from processEvents after one iteration, we prevent this. RevBy: Aleksandar Sasha Babic AutoTest: Passed
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian.cpp143
-rw-r--r--src/corelib/kernel/qeventdispatcher_symbian_p.h44
-rw-r--r--tests/auto/qtimer/tst_qtimer.cpp3
3 files changed, 129 insertions, 61 deletions
diff --git a/src/corelib/kernel/qeventdispatcher_symbian.cpp b/src/corelib/kernel/qeventdispatcher_symbian.cpp
index 1581d9b..e1e3e0e 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,57 @@ 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)
+{
+}
+
+QActiveObject::~QActiveObject()
+{
+ if (m_hasRunAgain)
+ m_dispatcher->removeDeferredActiveObject(this);
+}
+
+bool QActiveObject::okToRun()
+{
+ Q_ASSERT(!m_hasRunAgain);
+
+ if (m_hasAlreadyRun) {
+ m_dispatcher->addDeferredActiveObject(this);
+ m_hasRunAgain = true;
+ return false;
+ } else {
+ m_hasAlreadyRun = true;
+ return true;
+ }
+}
+
+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 +162,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 +188,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 +209,8 @@ void QTimerActiveObject::RunL()
iStatus = KRequestPending;
SetActive();
- // We complete it when the QCompleteZeroTimersActiveObject is run.
+ TRequestStatus *status = &iStatus;
+ QEventDispatcherSymbian::RequestComplete(status, KErrNone);
}
}
@@ -180,33 +235,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 +265,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()
@@ -432,8 +481,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)
@@ -458,6 +506,9 @@ void QSocketActiveObject::DoCancel()
void QSocketActiveObject::RunL()
{
+ if (!okToRun())
+ return;
+
m_dispatcher->socketFired(this);
}
@@ -474,7 +525,7 @@ 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_noSocketEvents(false)
@@ -493,6 +544,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();
}
@@ -503,6 +555,7 @@ void QEventDispatcherSymbian::closingDown()
m_selectThread.stop();
}
+ delete m_completeDeferredAOs;
delete m_wakeUpAO;
if (m_activeScheduler) {
delete m_activeScheduler;
@@ -703,17 +756,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;
}
@@ -776,16 +840,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();
}
@@ -796,12 +853,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 8144472..3233fe4 100644
--- a/src/corelib/kernel/qeventdispatcher_symbian_p.h
+++ b/src/corelib/kernel/qeventdispatcher_symbian_p.h
@@ -45,6 +45,24 @@ 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;
+};
+
class QWakeUpActiveObject : public CActive
{
public:
@@ -76,10 +94,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 +111,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 +140,6 @@ protected:
void RunL();
private:
- QEventDispatcherSymbian *m_dispatcher;
QSocketNotifier *m_notifier;
bool m_inSocketEvent;
bool m_deleteLater;
@@ -187,7 +202,10 @@ public:
void socketFired(QSocketActiveObject *socketAO);
void wakeUpWasCalled();
void reactivateSocketNotifier(QSocketNotifier *notifier);
- void completeZeroTimers();
+
+ void addDeferredActiveObject(QActiveObject *object);
+ void removeDeferredActiveObject(QActiveObject *object);
+ void reactivateDeferredActiveObjects();
static void RequestComplete(TRequestStatus *&status, TInt reason);
static void RequestComplete(RThread &threadHandle, TRequestStatus *&status, TInt reason);
@@ -205,7 +223,7 @@ private:
QHash<QSocketNotifier *, QSocketActiveObject *> m_notifiers;
QWakeUpActiveObject *m_wakeUpAO;
- QCompleteZeroTimersActiveObject *m_completeZeroTimersAO;
+ QCompleteDeferredAOs *m_completeDeferredAOs;
volatile bool m_interrupt;
QAtomicInt m_wakeUpDone;
@@ -213,6 +231,8 @@ private:
bool m_noSocketEvents;
QList<QSocketActiveObject *> m_deferredSocketEvents;
+ QList<QActiveObject *> m_deferredActiveObjects;
+
RProcess m_processHandle;
};
diff --git a/tests/auto/qtimer/tst_qtimer.cpp b/tests/auto/qtimer/tst_qtimer.cpp
index 39144af..0051a9b 100644
--- a/tests/auto/qtimer/tst_qtimer.cpp
+++ b/tests/auto/qtimer/tst_qtimer.cpp
@@ -528,9 +528,6 @@ void tst_QTimer::timerFiresOnlyOncePerProcessEvents()
QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
}
-#ifdef Q_OS_SYMBIAN
- QEXPECT_FAIL("non-zero timer", "Will be fixed in next commit", Abort);
-#endif
QCOMPARE(longSlot.count, 1);
}