diff options
author | Qt Continuous Integration System <qt-info@nokia.com> | 2010-05-07 15:09:02 (GMT) |
---|---|---|
committer | Qt Continuous Integration System <qt-info@nokia.com> | 2010-05-07 15:09:02 (GMT) |
commit | a1f666b5f2b90e5cc1c7c53e322f515b888e24e2 (patch) | |
tree | 9b84f5e20ef4559ab398c52553af3221d14febf2 | |
parent | 00fb0a4d5254856423b05c742e6b1efd902be4d0 (diff) | |
parent | 62096261a9a07968eeaa77ef205f33a570913377 (diff) | |
download | Qt-a1f666b5f2b90e5cc1c7c53e322f515b888e24e2.zip Qt-a1f666b5f2b90e5cc1c7c53e322f515b888e24e2.tar.gz Qt-a1f666b5f2b90e5cc1c7c53e322f515b888e24e2.tar.bz2 |
Merge branch 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-2 into master-integration
* 'master' of scm.dev.nokia.troll.no:qt/oslo-staging-2:
Fix compilation of the tst_qmetaobject test
QObject: Optimize BlockingQueuedConnection connections
QMetaObject::invokeMethod using Qt::BlockingQueuedConnection can handle the return value.
-rw-r--r-- | src/corelib/kernel/qmetaobject.cpp | 53 | ||||
-rw-r--r-- | src/corelib/kernel/qobject.cpp | 65 | ||||
-rw-r--r-- | tests/auto/qmetaobject/tst_qmetaobject.cpp | 136 |
3 files changed, 186 insertions, 68 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..8a4304e 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(); @@ -2560,7 +2562,7 @@ bool QObject::connect(const QObject *sender, const char *signal, } int *types = 0; - if ((type == Qt::QueuedConnection || type == Qt::BlockingQueuedConnection) + if ((type == Qt::QueuedConnection) && !(types = queuedConnectionTypes(smeta->method(signal_absolute_index).parameterTypes()))) return false; @@ -3115,8 +3117,7 @@ void QMetaObject::connectSlotsByName(QObject *o) } } -static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, - void **argv, QSemaphore *semaphore = 0) +static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv) { if (!c->argumentTypes && c->argumentTypes != &DIRECT_CONNECTION_ONLY) { QMetaMethod m = sender->metaObject()->method(signal); @@ -3146,30 +3147,9 @@ static void queued_activate(QObject *sender, int signal, QObjectPrivate::Connect signal, nargs, types, - args, - semaphore)); + args)); } -static void blocking_activate(QObject *sender, int signal, QObjectPrivate::Connection *c, void **argv) -{ - if (QThread::currentThread() == c->receiver->thread()) { - qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: " - "Sender is %s(%p), receiver is %s(%p)", - sender->metaObject()->className(), sender, - c->receiver->metaObject()->className(), c->receiver); - } - -#ifdef QT_NO_THREAD - queued_activate(sender, signal, c, argv); -#else - QSemaphore semaphore; - queued_activate(sender, signal, c, argv, &semaphore); - QMutex *mutex = signalSlotLock(sender); - mutex->unlock(); - semaphore.acquire(); - mutex->lock(); -#endif -} /*!\internal \obsolete. @@ -3233,23 +3213,38 @@ void QMetaObject::activate(QObject *sender, const QMetaObject *m, int local_sign continue; QObject * const receiver = c->receiver; + const int method = c->method; + const bool receiverInSameThread = currentThreadData == receiver->d_func()->threadData; // determine if this connection should be sent immediately or // put into the event queue if ((c->connectionType == Qt::AutoConnection - && (currentThreadData != sender->d_func()->threadData + && (!receiverInSameThread || receiver->d_func()->threadData != sender->d_func()->threadData)) || (c->connectionType == Qt::QueuedConnection)) { queued_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv); continue; +#ifndef QT_NO_THREAD } else if (c->connectionType == Qt::BlockingQueuedConnection) { - blocking_activate(sender, signal_absolute_index, c, argv ? argv : empty_argv); + locker.unlock(); + if (receiverInSameThread) { + qWarning("Qt: Dead lock detected while activating a BlockingQueuedConnection: " + "Sender is %s(%p), receiver is %s(%p)", + sender->metaObject()->className(), sender, + receiver->metaObject()->className(), receiver); + } + QSemaphore semaphore; + QCoreApplication::postEvent(receiver, new QMetaCallEvent(method, + sender, signal_absolute_index, + 0, 0, + argv ? argv : empty_argv, + &semaphore)); + semaphore.acquire(); + locker.relock(); continue; +#endif } - - const int method = c->method; QObjectPrivate::Sender currentSender; - const bool receiverInSameThread = currentThreadData == receiver->d_func()->threadData; QObjectPrivate::Sender *previousSender = 0; if (receiverInSameThread) { currentSender.sender = sender; diff --git a/tests/auto/qmetaobject/tst_qmetaobject.cpp b/tests/auto/qmetaobject/tst_qmetaobject.cpp index c0b1303..370403e 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::currentThread()))); + t.quit(); + QVERIFY(t.wait()); + +} + + void tst_QMetaObject::qtMetaObjectInheritance() { |