summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOlivier Goffart <olivier.goffart@nokia.com>2010-05-06 16:46:49 (GMT)
committerOlivier Goffart <olivier.goffart@nokia.com>2010-05-07 09:37:19 (GMT)
commite248183fc443c0e2c133506dfb7c38560aee4948 (patch)
tree087d10e4d818d6e0d05d33d74444567f8cd387af
parent717e96cc790c173a4555077741d37f42a3dd6cba (diff)
downloadQt-e248183fc443c0e2c133506dfb7c38560aee4948.zip
Qt-e248183fc443c0e2c133506dfb7c38560aee4948.tar.gz
Qt-e248183fc443c0e2c133506dfb7c38560aee4948.tar.bz2
QMetaObject::invokeMethod using Qt::BlockingQueuedConnection can handle the return value.
When using Qt::BlockingQueuedConnection, we do not need to copy the arguments, and we can handle the return type. The argv we pass to the event is the param vector alocated on the stack. Since we don't need to destroy the argument, we can pass 0 for the types. The private QMetaCallEvent destructor is modified not to destroy the arguments if types_ is 0 Task-number: QTBUG-10440 Reviewed-by: Brad
-rw-r--r--src/corelib/kernel/qmetaobject.cpp53
-rw-r--r--src/corelib/kernel/qobject.cpp12
-rw-r--r--tests/auto/qmetaobject/tst_qmetaobject.cpp136
3 files changed, 163 insertions, 38 deletions
diff --git a/src/corelib/kernel/qmetaobject.cpp b/src/corelib/kernel/qmetaobject.cpp
index 4ad78fd..c2e12f8 100644
--- a/src/corelib/kernel/qmetaobject.cpp
+++ b/src/corelib/kernel/qmetaobject.cpp
@@ -1548,6 +1548,12 @@ bool QMetaMethod::invoke(QObject *object,
: Qt::QueuedConnection;
}
+#ifdef QT_NO_THREAD
+ if (connectionType == Qt::BlockingQueuedConnection) {
+ connectionType = Qt::DirectConnection;
+ }
+#endif
+
// invoke!
void *param[] = {
returnValue.data(),
@@ -1566,7 +1572,7 @@ bool QMetaMethod::invoke(QObject *object,
int methodIndex = ((handle - priv(mobj->d.data)->methodData) / 5) + mobj->methodOffset();
if (connectionType == Qt::DirectConnection) {
return QMetaObject::metacall(object, QMetaObject::InvokeMetaMethod, methodIndex, param) < 0;
- } else {
+ } else if (connectionType == Qt::QueuedConnection) {
if (returnValue.data()) {
qWarning("QMetaMethod::invoke: Unable to invoke methods with return values in "
"queued connections");
@@ -1599,40 +1605,21 @@ bool QMetaMethod::invoke(QObject *object,
}
}
- if (connectionType == Qt::QueuedConnection) {
- QCoreApplication::postEvent(object, new QMetaCallEvent(methodIndex,
- 0,
- -1,
- nargs,
- types,
- args));
- } else {
- if (currentThread == objectThread) {
- qWarning("QMetaMethod::invoke: Dead lock detected in "
- "BlockingQueuedConnection: Receiver is %s(%p)",
- mobj->className(), object);
- }
+ QCoreApplication::postEvent(object, new QMetaCallEvent(methodIndex,
+ 0, -1, nargs, types, args));
+ } else { // blocking queued connection
+#ifndef QT_NO_THREAD
+ if (currentThread == objectThread) {
+ qWarning("QMetaMethod::invoke: Dead lock detected in "
+ "BlockingQueuedConnection: Receiver is %s(%p)",
+ mobj->className(), object);
+ }
- // blocking queued connection
-#ifdef QT_NO_THREAD
- QCoreApplication::postEvent(object, new QMetaCallEvent(methodIndex,
- 0,
- -1,
- nargs,
- types,
- args));
-#else
- QSemaphore semaphore;
- QCoreApplication::postEvent(object, new QMetaCallEvent(methodIndex,
- 0,
- -1,
- nargs,
- types,
- args,
- &semaphore));
- semaphore.acquire();
+ QSemaphore semaphore;
+ QCoreApplication::postEvent(object, new QMetaCallEvent(methodIndex,
+ 0, -1, 0, 0, param, &semaphore));
+ semaphore.acquire();
#endif // QT_NO_THREAD
- }
}
return true;
}
diff --git a/src/corelib/kernel/qobject.cpp b/src/corelib/kernel/qobject.cpp
index 6a6db51..0f419bd 100644
--- a/src/corelib/kernel/qobject.cpp
+++ b/src/corelib/kernel/qobject.cpp
@@ -515,12 +515,14 @@ QMetaCallEvent::QMetaCallEvent(int id, const QObject *sender, int signalId,
*/
QMetaCallEvent::~QMetaCallEvent()
{
- for (int i = 0; i < nargs_; ++i) {
- if (types_[i] && args_[i])
- QMetaType::destroy(types_[i], args_[i]);
+ if (types_) {
+ for (int i = 0; i < nargs_; ++i) {
+ if (types_[i] && args_[i])
+ QMetaType::destroy(types_[i], args_[i]);
+ }
+ qFree(types_);
+ qFree(args_);
}
- if (types_) qFree(types_);
- if (args_) qFree(args_);
#ifndef QT_NO_THREAD
if (semaphore_)
semaphore_->release();
diff --git a/tests/auto/qmetaobject/tst_qmetaobject.cpp b/tests/auto/qmetaobject/tst_qmetaobject.cpp
index c0b1303..0ef452c 100644
--- a/tests/auto/qmetaobject/tst_qmetaobject.cpp
+++ b/tests/auto/qmetaobject/tst_qmetaobject.cpp
@@ -155,6 +155,7 @@ private slots:
void connectSlotsByName();
void invokeMetaMember();
void invokeQueuedMetaMember();
+ void invokeBlockingQueuedMetaMember();
void invokeCustomTypes();
void invokeMetaConstructor();
void invokeTypedefTypes();
@@ -334,6 +335,9 @@ public slots:
void testLongLong(qint64 ll1, quint64 ll2);
+ void moveToThread(QThread *t)
+ { QObject::moveToThread(t); }
+
signals:
void sig0();
QString sig1(QString s1);
@@ -581,6 +585,138 @@ void tst_QMetaObject::invokeQueuedMetaMember()
QCOMPARE(obj.slotResult, QString("testLongLong:-1,0"));
}
+void tst_QMetaObject::invokeBlockingQueuedMetaMember()
+{
+ QThread t;
+ t.start();
+ QtTestObject obj;
+ obj.moveToThread(&t);
+
+ QString t1("1"); QString t2("2"); QString t3("3"); QString t4("4"); QString t5("5");
+ QString t6("6"); QString t7("7"); QString t8("8"); QString t9("9"); QString t10("X");
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, Q_ARG(QString, t1)));
+ QCOMPARE(obj.slotResult, QString("sl1:1"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl2", Qt::BlockingQueuedConnection, Q_ARG(const QString, t1), Q_ARG(QString, t2)));
+ QCOMPARE(obj.slotResult, QString("sl2:12"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl3", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2), Q_ARG(QString, t3)));
+ QCOMPARE(obj.slotResult, QString("sl3:123"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl4", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2),
+ Q_ARG(QString, t3), Q_ARG(QString, t4)));
+ QCOMPARE(obj.slotResult, QString("sl4:1234"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl5", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2),
+ Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, "5")));
+ QCOMPARE(obj.slotResult, QString("sl5:12345"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl6", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2),
+ Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6)));
+ QCOMPARE(obj.slotResult, QString("sl6:123456"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl7", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2),
+ Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6),
+ Q_ARG(QString, t7)));
+ QCOMPARE(obj.slotResult, QString("sl7:1234567"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl8", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2),
+ Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6),
+ Q_ARG(QString, t7), Q_ARG(QString, t8)));
+ QCOMPARE(obj.slotResult, QString("sl8:12345678"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl9", Qt::BlockingQueuedConnection, Q_ARG(QString, t1), Q_ARG(QString, t2),
+ Q_ARG(QString, t3), Q_ARG(QString, t4), Q_ARG(QString, t5), Q_ARG(QString, t6),
+ Q_ARG(QString, t7), Q_ARG(QString, t8), Q_ARG(QString, t9)));
+ QCOMPARE(obj.slotResult, QString("sl9:123456789"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection));
+ QCOMPARE(obj.slotResult, QString("sl11"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "testSender", Qt::BlockingQueuedConnection));
+ QCOMPARE(obj.slotResult, QString("0x0"));
+
+ QString refStr("whatever");
+ QVERIFY(QMetaObject::invokeMethod(&obj, "testReference", Qt::BlockingQueuedConnection, QGenericArgument("QString&", &refStr)));
+ QCOMPARE(obj.slotResult, QString("testReference:whatever"));
+ QCOMPARE(refStr, QString("gotcha"));
+
+ qint64 ll1 = -1;
+ quint64 ll2 = 0;
+ QVERIFY(QMetaObject::invokeMethod(&obj,
+ "testLongLong",
+ Qt::BlockingQueuedConnection,
+ Q_ARG(qint64, ll1),
+ Q_ARG(quint64, ll2)));
+ QCOMPARE(obj.slotResult, QString("testLongLong:-1,0"));
+
+ QString exp;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, exp), Q_ARG(QString, "bubu")));
+ QCOMPARE(exp, QString("yessir"));
+ QCOMPARE(obj.slotResult, QString("sl1:bubu"));
+
+ QObject *ptr = 0;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QObject*,ptr)));
+ QCOMPARE(ptr, (QObject *)&obj);
+ QCOMPARE(obj.slotResult, QString("sl11"));
+ // try again with a space:
+ ptr = 0;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl11", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QObject * , ptr)));
+ QCOMPARE(ptr, (QObject *)&obj);
+ QCOMPARE(obj.slotResult, QString("sl11"));
+
+ const char *ptr2 = 0;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Qt::BlockingQueuedConnection, Q_RETURN_ARG(const char*, ptr2)));
+ QVERIFY(ptr2 != 0);
+ QCOMPARE(obj.slotResult, QString("sl12"));
+ // try again with a space:
+ ptr2 = 0;
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl12", Qt::BlockingQueuedConnection, Q_RETURN_ARG(char const * , ptr2)));
+ QVERIFY(ptr2 != 0);
+ QCOMPARE(obj.slotResult, QString("sl12"));
+
+ // test w/ template args
+ QList<QString> returnValue, argument;
+ argument << QString("one") << QString("two") << QString("three");
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sl13", Qt::BlockingQueuedConnection,
+ Q_RETURN_ARG(QList<QString>, returnValue),
+ Q_ARG(QList<QString>, argument)));
+ QCOMPARE(returnValue, argument);
+ QCOMPARE(obj.slotResult, QString("sl13"));
+
+ //test signals
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig0", Qt::BlockingQueuedConnection));
+ QCOMPARE(obj.slotResult, QString("sl0"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::BlockingQueuedConnection, Q_ARG(QString, "baba")));
+ QCOMPARE(obj.slotResult, QString("sl1:baba"));
+
+ exp.clear();
+ QVERIFY(QMetaObject::invokeMethod(&obj, "sig1", Qt::BlockingQueuedConnection, Q_RETURN_ARG(QString, exp), Q_ARG(QString, "hehe")));
+ QCOMPARE(exp, QString("yessir"));
+ QCOMPARE(obj.slotResult, QString("sl1:hehe"));
+
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::doesNotExist()");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "doesNotExist", Qt::BlockingQueuedConnection));
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString)(QString)");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1(QString)", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg")));
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl3(QString)");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "sl3", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg")));
+ QTest::ignoreMessage(QtWarningMsg, "QMetaObject::invokeMethod: No such method QtTestObject::sl1(QString,QString,QString)");
+ QVERIFY(!QMetaObject::invokeMethod(&obj, "sl1", Qt::BlockingQueuedConnection, Q_ARG(QString, "arg"), Q_ARG(QString, "arg"), Q_ARG(QString, "arg")));
+
+ //should not have changed since last test.
+ QCOMPARE(exp, QString("yessir"));
+ QCOMPARE(obj.slotResult, QString("sl1:hehe"));
+
+ QVERIFY(QMetaObject::invokeMethod(&obj, "moveToThread", Qt::BlockingQueuedConnection, Q_ARG(QThread*, QThread::current())));
+ t.quit();
+ QVERIFY(t.wait());
+
+}
+
+
void tst_QMetaObject::qtMetaObjectInheritance()
{