forked from qt-creator/qt-creator
RemoteLinux: Do not announce connection attempts from non-UI threads
This can lead to a deadlock. Example scenario: - Have a kit with an unreachable device as the build device. - Open a project with a .user file not matching the current QtC. - The target setup page will open, showing a candidate widget for each kit. These widgets contains path choosers, which nowadays start a dedicated thread to validate their input. - The path validation thread for the Linux kit arrives at setupShell() and tries to announce the connection attempt. To that end, it invokes a method of Core::ICore::infoBar, using Qt::BlockingQueuedConnection, as otherwise the call would either not be tread-safe or arrive too late. - As the InfoBar lives in the main thread, control is now passed back to that one, and the target setup page continues its work, which is to gather candidates for importing a build from. This involves perusing potential build directories for all kits. In case of the Linux kit, QDirIterator is backed by a remote call to find(), which triggers a call to runInShell(), which tries to acquire the mutex that is already held by the path validation thread, which in turn is waiting for the UI thread. - Qt Creator now hangs indefinitely. Skipping the announcements for non-UI threads limits the usefulness of this feature, but I don't see a better way. Change-Id: I816c83358f543aa9a6e6e97eee7fa8ad95e66ea8 Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
This commit is contained in:
@@ -1231,25 +1231,20 @@ RunResult LinuxDevicePrivate::runInShell(const CommandLine &cmd, const QByteArra
|
|||||||
|
|
||||||
void LinuxDevicePrivate::announceConnectionAttempt()
|
void LinuxDevicePrivate::announceConnectionAttempt()
|
||||||
{
|
{
|
||||||
const auto announce = [id = announceId(), name = q->displayName()] {
|
const QString message = Tr::tr("Establishing initial connection to device \"%1\". "
|
||||||
Core::ICore::infoBar()->addInfo(
|
"This might take a moment.").arg(q->displayName());
|
||||||
InfoBarEntry(id,
|
qCDebug(linuxDeviceLog) << message;
|
||||||
Tr::tr("Establishing initial connection to device \"%1\". "
|
if (isMainThread()) {
|
||||||
"This might take a moment.")
|
Core::ICore::infoBar()->addInfo(InfoBarEntry(announceId(), message));
|
||||||
.arg(name)));
|
|
||||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents);
|
||||||
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); // Yes, twice.
|
QCoreApplication::processEvents(QEventLoop::ExcludeUserInputEvents); // Yes, twice.
|
||||||
};
|
}
|
||||||
if (QThread::currentThread() == qApp->thread())
|
|
||||||
announce();
|
|
||||||
else
|
|
||||||
QMetaObject::invokeMethod(Core::ICore::infoBar(), announce, Qt::BlockingQueuedConnection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinuxDevicePrivate::unannounceConnectionAttempt()
|
void LinuxDevicePrivate::unannounceConnectionAttempt()
|
||||||
{
|
{
|
||||||
QMetaObject::invokeMethod(Core::ICore::infoBar(),
|
if (isMainThread())
|
||||||
[id = announceId()] { Core::ICore::infoBar()->removeInfo(id); });
|
Core::ICore::infoBar()->removeInfo(announceId());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LinuxDevicePrivate::checkDisconnectedWithWarning()
|
bool LinuxDevicePrivate::checkDisconnectedWithWarning()
|
||||||
|
Reference in New Issue
Block a user