summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/corelib/kernel/qcoreapplication.cpp17
-rw-r--r--src/corelib/kernel/qobject.cpp2
-rw-r--r--src/corelib/thread/qthread_p.h21
-rw-r--r--src/gui/kernel/qapplication.cpp4
-rw-r--r--tests/auto/qeventloop/tst_qeventloop.cpp75
5 files changed, 101 insertions, 18 deletions
diff --git a/src/corelib/kernel/qcoreapplication.cpp b/src/corelib/kernel/qcoreapplication.cpp
index a8c40c5180..cc1b1812e5 100644
--- a/src/corelib/kernel/qcoreapplication.cpp
+++ b/src/corelib/kernel/qcoreapplication.cpp
@@ -1272,20 +1272,7 @@ void QCoreApplication::postEvent(QObject *receiver, QEvent *event, int priority)
// delete the event on exceptions to protect against memory leaks till the event is
// properly owned in the postEventList
QScopedPointer<QEvent> eventDeleter(event);
- if (data->postEventList.isEmpty() || data->postEventList.last().priority >= priority) {
- // optimization: we can simply append if the last event in
- // the queue has higher or equal priority
- data->postEventList.append(QPostEvent(receiver, event, priority));
- } else {
- // insert event in descending priority order, using upper
- // bound for a given priority (to ensure proper ordering
- // of events with the same priority)
- QPostEventList::iterator begin = data->postEventList.begin()
- + data->postEventList.insertionOffset,
- end = data->postEventList.end();
- QPostEventList::iterator at = qUpperBound(begin, end, priority);
- data->postEventList.insert(at, QPostEvent(receiver, event, priority));
- }
+ data->postEventList.addEvent(QPostEvent(receiver, event, priority));
eventDeleter.take();
event->posted = true;
++receiver->d_func()->postedEvents;
@@ -1445,7 +1432,7 @@ void QCoreApplicationPrivate::sendPostedEvents(QObject *receiver, int event_type
// cannot send deferred delete
if (!event_type && !receiver) {
// don't lose the event
- data->postEventList.append(pe);
+ data->postEventList.addEvent(pe);
const_cast<QPostEvent &>(pe).event = 0;
}
continue;
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index b88643df5c..88618c3c87 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -1482,7 +1482,7 @@ void QObjectPrivate::setThreadData_helper(QThreadData *currentData, QThreadData
continue;
if (pe.receiver == q) {
// move this post event to the targetList
- targetData->postEventList.append(pe);
+ targetData->postEventList.addEvent(pe);
const_cast<QPostEvent &>(pe).event = 0;
++eventsMoved;
}
diff --git a/src/corelib/thread/qthread_p.h b/src/corelib/thread/qthread_p.h
index 13df3e6fea..461d93dd50 100644
--- a/src/corelib/thread/qthread_p.h
+++ b/src/corelib/thread/qthread_p.h
@@ -93,6 +93,8 @@ inline bool operator<(const QPostEvent &pe, int priority)
return priority < pe.priority;
}
+// This class holds the list of posted events.
+// The list has to be kept sorted by priority
class QPostEventList : public QList<QPostEvent>
{
public:
@@ -109,6 +111,25 @@ public:
inline QPostEventList()
: QList<QPostEvent>(), recursion(0), startOffset(0), insertionOffset(0)
{ }
+
+ void addEvent(const QPostEvent &ev) {
+ int priority = ev.priority;
+ if (isEmpty() || last().priority >= priority) {
+ // optimization: we can simply append if the last event in
+ // the queue has higher or equal priority
+ append(ev);
+ } else {
+ // insert event in descending priority order, using upper
+ // bound for a given priority (to ensure proper ordering
+ // of events with the same priority)
+ QPostEventList::iterator at = qUpperBound(begin() + insertionOffset, end(), priority);
+ insert(at, ev);
+ }
+ }
+private:
+ //hides because they do not keep that list sorted. addEvent must be used
+ using QList<QPostEvent>::append;
+ using QList<QPostEvent>::insert;
};
#ifndef QT_NO_THREAD
diff --git a/src/gui/kernel/qapplication.cpp b/src/gui/kernel/qapplication.cpp
index 38035997fe..361ec6ddec 100644
--- a/src/gui/kernel/qapplication.cpp
+++ b/src/gui/kernel/qapplication.cpp
@@ -1288,8 +1288,8 @@ bool QApplication::compressEvent(QEvent *event, QObject *receiver, QPostEventLis
|| event->type() == QEvent::LanguageChange
|| event->type() == QEvent::UpdateSoftKeys
|| event->type() == QEvent::InputMethod)) {
- for (int i = 0; i < postedEvents->size(); ++i) {
- const QPostEvent &cur = postedEvents->at(i);
+ for (QPostEventList::const_iterator it = postedEvents->constBegin(); it != postedEvents->constEnd(); ++it) {
+ const QPostEvent &cur = *it;
if (cur.receiver != receiver || cur.event == 0 || cur.event->type() != event->type())
continue;
if (cur.event->type() == QEvent::LayoutRequest
diff --git a/tests/auto/qeventloop/tst_qeventloop.cpp b/tests/auto/qeventloop/tst_qeventloop.cpp
index b31f8cd76c..942daa9ca8 100644
--- a/tests/auto/qeventloop/tst_qeventloop.cpp
+++ b/tests/auto/qeventloop/tst_qeventloop.cpp
@@ -59,6 +59,8 @@
#include <unistd.h>
#endif
+#include "../../shared/util.h"
+
//TESTED_CLASS=
//TESTED_FILES=
@@ -208,6 +210,7 @@ private slots:
void quit();
void processEventsExcludeSocket();
void processEventsExcludeTimers();
+ void deliverInDefinedOrder_QTBUG19637();
// keep this test last:
void nestedLoops();
@@ -837,5 +840,77 @@ void tst_QEventLoop::symbianNestedActiveSchedulerLoop()
#endif
}
+Q_DECLARE_METATYPE(QThread*)
+
+namespace DeliverInDefinedOrder_QTBUG19637 {
+ enum { NbThread = 3, NbObject = 500, NbEventQueue = 5, NbEvent = 50 };
+
+ struct CustomEvent : public QEvent {
+ CustomEvent(int q, int v) : QEvent(Type(User + q)), value(v) {}
+ int value;
+ };
+
+ struct Object : public QObject {
+ Q_OBJECT
+ public:
+ Object() : count(0) {
+ for (int i = 0; i < NbEventQueue; i++)
+ lastReceived[i] = -1;
+ }
+ int lastReceived[NbEventQueue];
+ int count;
+ virtual void customEvent(QEvent* e) {
+ QVERIFY(e->type() >= QEvent::User);
+ QVERIFY(e->type() < QEvent::User + 5);
+ uint idx = e->type() - QEvent::User;
+ int value = static_cast<CustomEvent *>(e)->value;
+ QVERIFY(lastReceived[idx] < value);
+ lastReceived[idx] = value;
+ count++;
+ }
+
+ public slots:
+ void moveToThread(QThread *t) {
+ QObject::moveToThread(t);
+ }
+ };
+
+}
+
+void tst_QEventLoop::deliverInDefinedOrder_QTBUG19637()
+{
+ using namespace DeliverInDefinedOrder_QTBUG19637;
+ qMetaTypeId<QThread*>();
+ QThread threads[NbThread];
+ Object objects[NbObject];
+ for (int t = 0; t < NbThread; t++) {
+ threads[t].start();
+ }
+
+ int event = 0;
+
+ for (int o = 0; o < NbObject; o++) {
+ objects[o].moveToThread(&threads[o % NbThread]);
+ for (int e = 0; e < NbEvent; e++) {
+ int q = e % NbEventQueue;
+ QCoreApplication::postEvent(&objects[o], new CustomEvent(q, ++event) , q);
+ if (e % 7)
+ QMetaObject::invokeMethod(&objects[o], "moveToThread", Qt::QueuedConnection, Q_ARG(QThread*, &threads[(e+o)%NbThread]));
+ }
+ }
+
+ QTest::qWait(30);
+ for (int o = 0; o < NbObject; o++) {
+ QTRY_COMPARE(objects[o].count, int(NbEvent));
+ }
+
+ for (int t = 0; t < NbThread; t++) {
+ threads[t].quit();
+ threads[t].wait();
+ }
+
+}
+
+
QTEST_MAIN(tst_QEventLoop)
#include "tst_qeventloop.moc"