Details
-
Bug
-
Resolution: Unresolved
-
P4: Low
-
None
-
5.9
-
None
Description
when use qdbus, like this
myQDBusInterface->call(QDBus::BlockWithGui, ......)
I encountered such a problem that the functions call never returns,and it should be timeout but it doesn't.
finally, I found what's wrong it is. the core logic of the function "QDBusAbstractInterface::call" like this,
// send thread // QDBusConnectionManager thread
QDBusConnectionPrivate::sendWithReply
QDBusConnectionPrivate::sendWithReplyAsync
emit messageNeedsSending ----> QDBusConnectionPrivate::sendInternal
create QDBusPendingCallWatcherHelper q_dbus_connection_send_with_reply
Qeventloop.exec q_dbus_pending_call_set_notify
send dbus message、register result callback and call the callback function for reply message are all in QDBusConnectionManager thread, and create QDBusPendingCallWatcherHelper and wating in Qeventloop is in send thread. when reply message returned, the QDBusPendingCallWatcherHelper will be used to sigal the send thread to quit Qeventloop.
If the reply message returned is earlier than QDBusPendingCallWatcherHelper created, the send thread will never quit Qeventloop.
For reproduce this case, we can force the send thread to sleep a short time to make the reply message returned earlier.
QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message, int sendMode, int timeout){ QDBusBlockingCallWatcher watcher(message); QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, 0, 0, 0, timeout); Q_ASSERT(pcall); if (pcall->replyMessage.type() == QDBusMessage::InvalidMessage) { QThread::msleep(100); // need to wait for the reply if (sendMode == QDBus::BlockWithGui) { pcall->watcherHelper = new QDBusPendingCallWatcherHelper;
And I fixed the problem like this:
@@ -2046,15 +2050,15 @@ QDBusMessage QDBusConnectionPrivate::sendWithReply(const QDBusMessage &message, QDBusPendingCallPrivate *pcall = sendWithReplyAsync(message, 0, 0, 0, timeout); Q_ASSERT(pcall);+ QEventLoop loop; + if (sendMode == QDBus::BlockWithGui) { + pcall->watcherHelper = new QDBusPendingCallWatcherHelper; + loop.connect(pcall->watcherHelper, &QDBusPendingCallWatcherHelper::reply, &loop, &QEventLoop::quit); + loop.connect(pcall->watcherHelper, &QDBusPendingCallWatcherHelper::error, &loop, &QEventLoop::quit); + } + if (pcall->replyMessage.type() == QDBusMessage::InvalidMessage) { - // need to wait for the reply if (sendMode == QDBus::BlockWithGui) { - pcall->watcherHelper = new QDBusPendingCallWatcherHelper; - QEventLoop loop; - loop.connect(pcall->watcherHelper, &QDBusPendingCallWatcherHelper::reply, &loop, &QEventLoop::quit); - loop.connect(pcall->watcherHelper, &QDBusPendingCallWatcherHelper::error, &loop, &QEventLoop::quit); - - // enter the event loop and wait for a reply loop.exec(QEventLoop::ExcludeUserInputEvents | QEventLoop::WaitForMoreEvents); } else { pcall->waitForFinished();