Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:steffens:branches:Application:Geo:qgis
libqt4-devel-doc
0005-Change-QDBusPendingCallPrivate-to-full-ref...
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File 0005-Change-QDBusPendingCallPrivate-to-full-reference-cou.patch of Package libqt4-devel-doc
From 8234f5171a20628d6384d10a45d0437a0ab791ee Mon Sep 17 00:00:00 2001 From: Peter Seiderer <ps.report@gmx.net> Date: Mon, 17 Jun 2013 22:44:30 +0200 Subject: [PATCH 5/6] Change QDBusPendingCallPrivate to full reference counting for deletion. Fixes race between QDBusConnectionPrivate::processFinishedCall() releasing the mutex before emitting signals (using various members of QDBusPendingCallPrivate) and deletion of the QDBusPendingCallPrivate object through QDBusPendingCall::d's destructor (a member of type QExplicitlySharedDataPointer<QDBusPendingCallPrivate>) leeds to segmentation fault with CrashTest example on slow/single core arm cpu). Task-number: QTBUG-27809 Change-Id: I3590d74d1cfa5816ede764b50b83a7008ec780ff (cherry-picked from qtbase commit 6c21f42657b494e24112c90d8b9fff719f1f8791) Reviewed-by: Peter Seiderer <ps.report@gmx.net> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> --- src/dbus/qdbusconnection.cpp | 3 +- src/dbus/qdbusconnection_p.h | 5 +-- src/dbus/qdbusintegrator.cpp | 87 ++++++++++++++++++++++++------------------- src/dbus/qdbuspendingcall.cpp | 6 +++ 4 files changed, 58 insertions(+), 43 deletions(-) diff --git a/src/dbus/qdbusconnection.cpp b/src/dbus/qdbusconnection.cpp index bb03c00..7ff09e9 100644 --- a/src/dbus/qdbusconnection.cpp +++ b/src/dbus/qdbusconnection.cpp @@ -53,6 +53,7 @@ #include "qdbusinterface_p.h" #include "qdbusutil_p.h" #include "qdbusconnectionmanager_p.h" +#include "qdbuspendingcall_p.h" #include "qdbusthreaddebug_p.h" @@ -625,7 +626,7 @@ QDBusPendingCall QDBusConnection::asyncCall(const QDBusMessage &message, int tim return QDBusPendingCall(0); // null pointer -> disconnected } - QDBusPendingCallPrivate *priv = d->sendWithReplyAsync(message, timeout); + QDBusPendingCallPrivate *priv = d->sendWithReplyAsync(message, 0, 0, 0, timeout); return QDBusPendingCall(priv); } diff --git a/src/dbus/qdbusconnection_p.h b/src/dbus/qdbusconnection_p.h index 04f22d3..e11997f 100644 --- a/src/dbus/qdbusconnection_p.h +++ b/src/dbus/qdbusconnection_p.h @@ -194,9 +194,8 @@ public: int send(const QDBusMessage &message); QDBusMessage sendWithReply(const QDBusMessage &message, int mode, int timeout = -1); QDBusMessage sendWithReplyLocal(const QDBusMessage &message); - QDBusPendingCallPrivate *sendWithReplyAsync(const QDBusMessage &message, int timeout = -1); - int sendWithReplyAsync(const QDBusMessage &message, QObject *receiver, - const char *returnMethod, const char *errorMethod, int timeout = -1); + QDBusPendingCallPrivate *sendWithReplyAsync(const QDBusMessage &message, QObject *receiver, + const char *returnMethod, const char *errorMethod,int timeout = -1); bool connectSignal(const QString &service, const QString &path, const QString& interface, const QString &name, const QStringList &argumentMatch, const QString &signature, QObject *receiver, const char *slot); diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index a91ba0e..081a947 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -1839,6 +1839,9 @@ void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call) if (msg.type() == QDBusMessage::ErrorMessage) emit connection->callWithCallbackFailed(QDBusError(msg), call->sentMessage); + + if (!call->ref.deref()) + delete call; } int QDBusConnectionPrivate::send(const QDBusMessage& message) @@ -1921,7 +1924,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) { @@ -1937,6 +1940,10 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message, QDBusMessage reply = pcall->replyMessage; lastError = reply; // set or clear error + bool r = pcall->ref.deref(); + Q_ASSERT(!r); + Q_UNUSED(r); + delete pcall; return reply; } @@ -1976,19 +1983,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 = 1; + } else { + // set double ref to prevent race between processFinishedCall() and ref counting + // by QDBusPendingCall::QExplicitlySharedDataPointer<QDBusPendingCallPrivate> + pcall->ref = 2; + } + processFinishedCall(pcall); return pcall; } checkThread(); QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this); - pcall->ref = 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 = 1; + } else { + // set double ref to prevent race between processFinishedCall() and ref counting + // by QDBusPendingCall::QExplicitlySharedDataPointer<QDBusPendingCallPrivate> + pcall->ref = 2; + } QDBusError error; DBusMessage *msg = QDBusMessagePrivate::toDBusMessage(message, capabilities, &error); @@ -1999,6 +2042,7 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM qPrintable(error.message())); pcall->replyMessage = QDBusMessage::createError(error); lastError = error; + processFinishedCall(pcall); return pcall; } @@ -2024,45 +2068,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->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, diff --git a/src/dbus/qdbuspendingcall.cpp b/src/dbus/qdbuspendingcall.cpp index 5485a4b..56cf45a 100644 --- a/src/dbus/qdbuspendingcall.cpp +++ b/src/dbus/qdbuspendingcall.cpp @@ -260,6 +260,11 @@ QDBusPendingCall::QDBusPendingCall(const QDBusPendingCall &other) QDBusPendingCall::QDBusPendingCall(QDBusPendingCallPrivate *dd) : d(dd) { + if (dd) { + bool r = dd->ref.deref(); + Q_ASSERT(r); + Q_UNUSED(r); + } } /*! @@ -465,6 +470,7 @@ QDBusPendingCall QDBusPendingCall::fromCompletedCall(const QDBusMessage &msg) msg.type() == QDBusMessage::ReplyMessage) { d = new QDBusPendingCallPrivate(QDBusMessage(), 0); d->replyMessage = msg; + d->ref = 1; } return QDBusPendingCall(d); -- 1.8.3.1
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor