diff options
author | Thiago Macieira <thiago.macieira@nokia.com> | 2010-05-18 13:58:24 (GMT) |
---|---|---|
committer | Thiago Macieira <thiago.macieira@nokia.com> | 2010-05-24 19:09:31 (GMT) |
commit | fd256203708e79d64bad856e39bb5a43357bfd06 (patch) | |
tree | 7ec4edc7310b4a0724c3d6ffd3fce8a234f7c0c2 /src/dbus/qdbusintegrator.cpp | |
parent | 314a36895e1a31dd2b62de265d9160238d96e512 (diff) | |
download | Qt-fd256203708e79d64bad856e39bb5a43357bfd06.zip Qt-fd256203708e79d64bad856e39bb5a43357bfd06.tar.gz Qt-fd256203708e79d64bad856e39bb5a43357bfd06.tar.bz2 |
Fix a race condition with QtDBus blocking for replies.
If an auxiliary thread tried to block on waiting for a reply, and at
the same time the main thread handled the reply, there's room for a
race condition. So ensure only one thread is stopped at
dbus_pending_call_block().
The other thread(s) will be waiting on the QWaitCondition.
It's not a race condition for the main thread to process (and finish
processing) the reply while the auxiliary thread hasn't even started
to wait. The code will ensure that the reply is properly seen.
Task-Id: https://projects.maemo.org/bugzilla/show_bug.cgi?id=155306
Reviewed-By: Trust Me
Diffstat (limited to 'src/dbus/qdbusintegrator.cpp')
-rw-r--r-- | src/dbus/qdbusintegrator.cpp | 44 |
1 files changed, 30 insertions, 14 deletions
diff --git a/src/dbus/qdbusintegrator.cpp b/src/dbus/qdbusintegrator.cpp index 6354770..0f49dcc 100644 --- a/src/dbus/qdbusintegrator.cpp +++ b/src/dbus/qdbusintegrator.cpp @@ -1687,15 +1687,31 @@ static void qDBusResultReceived(DBusPendingCall *pending, void *user_data) void QDBusConnectionPrivate::waitForFinished(QDBusPendingCallPrivate *pcall) { Q_ASSERT(pcall->pending); - QDBusDispatchLocker locker(PendingCallBlockAction, this); - q_dbus_pending_call_block(pcall->pending); - // QDBusConnectionPrivate::processFinishedCall() is called automatically + Q_ASSERT(!pcall->autoDelete); + //Q_ASSERT(pcall->mutex.isLocked()); // there's no such function + + if (pcall->waitingForFinished) { + // another thread is already waiting + pcall->waitForFinishedCondition.wait(&pcall->mutex); + } else { + pcall->waitingForFinished = true; + pcall->mutex.unlock(); + + { + QDBusDispatchLocker locker(PendingCallBlockAction, this); + q_dbus_pending_call_block(pcall->pending); + // QDBusConnectionPrivate::processFinishedCall() is called automatically + } + pcall->mutex.lock(); + } } void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call) { QDBusConnectionPrivate *connection = const_cast<QDBusConnectionPrivate *>(call->connection); + QMutexLocker locker(&call->mutex); + QDBusMessage &msg = call->replyMessage; if (call->pending) { // decode the message @@ -1725,6 +1741,12 @@ void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call) qDBusDebug() << "Deliver failed!"; } + if (call->pending) + q_dbus_pending_call_unref(call->pending); + call->pending = 0; + + locker.unlock(); + // Are there any watchers? if (call->watcherHelper) call->watcherHelper->emitSignals(msg, call->sentMessage); @@ -1732,12 +1754,10 @@ void QDBusConnectionPrivate::processFinishedCall(QDBusPendingCallPrivate *call) if (msg.type() == QDBusMessage::ErrorMessage) emit connection->callWithCallbackFailed(QDBusError(msg), call->sentMessage); - if (call->pending) - q_dbus_pending_call_unref(call->pending); - call->pending = 0; - - if (call->autoDelete) + if (call->autoDelete) { + Q_ASSERT(!call->waitingForFinished); // can't wait on a call with autoDelete! delete call; + } } int QDBusConnectionPrivate::send(const QDBusMessage& message) @@ -1879,17 +1899,14 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM { if (isServiceRegisteredByThread(message.service())) { // special case for local calls - QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate; - pcall->sentMessage = message; + QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this); pcall->replyMessage = sendWithReplyLocal(message); - pcall->connection = this; return pcall; } checkThread(); - QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate; - pcall->sentMessage = message; + QDBusPendingCallPrivate *pcall = new QDBusPendingCallPrivate(message, this); pcall->ref = 0; QDBusError error; @@ -1913,7 +1930,6 @@ QDBusPendingCallPrivate *QDBusConnectionPrivate::sendWithReplyAsync(const QDBusM q_dbus_message_unref(msg); pcall->pending = pending; - pcall->connection = this; q_dbus_pending_call_set_notify(pending, qDBusResultReceived, pcall, 0); return pcall; |