diff options
Diffstat (limited to 'src/dbus/qdbusintegrator.cpp')
-rw-r--r-- | src/dbus/qdbusintegrator.cpp | 108 |
1 files changed, 55 insertions, 53 deletions
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 010c076b7f..e5f3fbdc53 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -1830,7 +1830,6 @@ static void qDBusResultReceived(DBusPendingCall *pending, void *user_data) void QDBusConnectionPrivate::waitForFinished(QDBusPendingCallPrivate *pcall) { Q_ASSERT(pcall->pending); - Q_ASSERT(!pcall->autoDelete); //Q_ASSERT(pcall->mutex.isLocked()); // there's no such function if (pcall->waitingForFinished) { @@ -1846,17 +1845,16 @@ void QDBusConnectionPrivate::waitForFinished(QDBusPendingCallPrivate *pcall) // QDBusConnectionPrivate::processFinishedCall() is called automatically } pcall->mutex.lock(); + + if (pcall->pending) { + q_dbus_pending_call_unref(pcall->pending); + pcall->pending = 0; + } + pcall->waitForFinishedCondition.wakeAll(); } } -// this function is called only in a Q_ASSERT -static inline Q_DECL_UNUSED bool waitingForFinishedIsSet(QDBusPendingCallPrivate *call) -{ - const QMutexLocker locker(&call->mutex); - return call->waitingForFinished; -} - void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call) { QDBusConnectionPrivate *connection = const_cast<QDBusConnectionPrivate *>(call->connection); @@ -1892,9 +1890,10 @@ void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call) qDBusDebug() << "Deliver failed!"; } - if (call->pending) + if (call->pending && !call->waitingForFinished) { q_dbus_pending_call_unref(call->pending); - call->pending = 0; + call->pending = 0; + } locker.unlock(); @@ -1905,10 +1904,8 @@ void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call) if (msg.type() == QDBusMessage::ErrorMessage) emit connection->callWithCallbackFailed(QDBusError(msg), call->sentMessage); - if (call->autoDelete) { - Q_ASSERT(!waitingForFinishedIsSet(call)); // can't wait on a call with autoDelete! + if (!call->ref.deref()) delete call; - } } int QDBusConnectionPrivate::send(const QDBusMessage& message) @@ -1991,7 +1988,7 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message, return amsg; } else { // use the event loop - QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout); + QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, 0, 0, 0, timeout); Q_ASSERT(pcall); if (pcall->replyMessage.type() == QDBusMessage::InvalidMessage) { @@ -2007,6 +2004,10 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message, QDBusMessage reply = pcall->replyMessage; lastError = QDBusError(reply); // set or clear error + bool r = pcall->ref.deref(); + Q_ASSERT(!r); + Q_UNUSED(r); + delete pcall; return reply; } @@ -2046,19 +2047,55 @@ QDBusMessage QDBusConnectionPrivate::sendWithReplyLocal(const QDBusMessage &mess } QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, - int timeout) + QObject *receiver, const char *returnMethod, + const char *errorMethod, int timeout) { if (isServiceRegisteredByThread(message.service())) { // special case for local calls QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this); pcall->replyMessage = sendWithReplyLocal(message); + if (receiver && returnMethod) + pcall->setReplyCallback(receiver, returnMethod); + + if (errorMethod) { + pcall->watcherHelper = new QDBusPendingCallWatcherHelper; + connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod, + Qt::QueuedConnection); + pcall->watcherHelper->moveToThread(thread()); + } + if ((receiver && returnMethod) || errorMethod) { + // no one waiting, will delete pcall in processFinishedCall() + pcall->ref.store(1); + } else { + // set double ref to prevent race between processFinishedCall() and ref counting + // by QDBusPendingCall::QExplicitlySharedDataPointer<QDBusPendingCallPrivate> + pcall->ref.store(2); + } + processFinishedCall(pcall); return pcall; } checkThread(); QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this); - pcall->ref.store(0); + if (receiver && returnMethod) + pcall->setReplyCallback(receiver, returnMethod); + + if (errorMethod) { + pcall->watcherHelper = new QDBusPendingCallWatcherHelper; + connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod, + Qt::QueuedConnection); + pcall->watcherHelper->moveToThread(thread()); + } + + if ((receiver && returnMethod) || errorMethod) { + // no one waiting, will delete pcall in processFinishedCall() + pcall->ref.store(1); + } else { + // set double ref to prevent race between processFinishedCall() and ref counting + // by QDBusPendingCall::QExplicitlySharedDataPointer<QDBusPendingCallPrivate> + pcall->ref.store(2); + } QDBusError error; DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, capabilities, &error); @@ -2069,6 +2106,7 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM qPrintable(error.message())); pcall->replyMessage = QDBusMessage::createError(error); lastError = error; + processFinishedCall(pcall); return pcall; } @@ -2094,46 +2132,10 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM q_dbus_message_unref(msg); pcall->replyMessage = QDBusMessage::createError(error); + processFinishedCall(pcall); return pcall; } -int QDBusConnectionPrivate::sendWithReplyAsync(const QDBusMessage &message, QObject *receiver, - const char *returnMethod, const char *errorMethod, - int timeout) -{ - QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, timeout); - Q_ASSERT(pcall); - - // has it already finished with success (dispatched locally)? - if (pcall->replyMessage.type() == QDBusMessage::ReplyMessage) { - pcall->setReplyCallback(receiver, returnMethod); - processFinishedCall(pcall); - delete pcall; - return 1; - } - - // either it hasn't finished or it has finished with error - if (errorMethod) { - pcall->watcherHelper = new QDBusPendingCallWatcherHelper; - connect(pcall->watcherHelper, SIGNAL(error(QDBusError,QDBusMessage)), receiver, errorMethod, - Qt::QueuedConnection); - pcall->watcherHelper->moveToThread(thread()); - } - - // has it already finished and is an error reply message? - if (pcall->replyMessage.type() == QDBusMessage::ErrorMessage) { - processFinishedCall(pcall); - delete pcall; - return 1; - } - - pcall->autoDelete = true; - pcall->ref.ref(); - pcall->setReplyCallback(receiver, returnMethod); - - return 1; -} - bool QDBusConnectionPrivate::connectSignal(const QString &service, const QString &path, const QString &interface, const QString &name, const QStringList &argumentMatch, const QString &signature, |