forked from qt-creator/qt-creator
UicCodeModel: Make process killing more robust
One possible cause for the crash reported in QTCREATORBUG-15672 is that uic is in the process of getting killed while somebody else already starts a new instance. So this patch makes that more robust by using a new QProcess instance for each uic run. Task-number: QTCREATORBUG-15672 Change-Id: Ibf4feda4fd783fbcadbdbbed30edeb0ff3c85871 Reviewed-by: Eike Ziller <eike.ziller@theqtcompany.com>
This commit is contained in:
@@ -75,31 +75,26 @@ UiCodeModelSupport::UiCodeModelSupport(CppTools::CppModelManager *modelmanager,
|
|||||||
: CppTools::AbstractEditorSupport(modelmanager),
|
: CppTools::AbstractEditorSupport(modelmanager),
|
||||||
m_project(project),
|
m_project(project),
|
||||||
m_uiFileName(uiFile),
|
m_uiFileName(uiFile),
|
||||||
m_headerFileName(uiHeaderFile),
|
m_headerFileName(uiHeaderFile)
|
||||||
m_state(BARE)
|
|
||||||
{
|
{
|
||||||
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
||||||
qCDebug(log) << "ctor UiCodeModelSupport for" << m_uiFileName << uiHeaderFile;
|
qCDebug(log) << "ctor UiCodeModelSupport for" << m_uiFileName << uiHeaderFile;
|
||||||
connect(&m_process, SIGNAL(finished(int)),
|
|
||||||
this, SLOT(finishProcess()));
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
UiCodeModelSupport::~UiCodeModelSupport()
|
UiCodeModelSupport::~UiCodeModelSupport()
|
||||||
{
|
{
|
||||||
disconnect(&m_process, SIGNAL(finished(int)),
|
cleanUpProcess();
|
||||||
this, SLOT(finishProcess()));
|
|
||||||
m_process.kill();
|
|
||||||
CppTools::CppModelManager::instance()->emitAbstractEditorSupportRemoved(m_headerFileName);
|
CppTools::CppModelManager::instance()->emitAbstractEditorSupportRemoved(m_headerFileName);
|
||||||
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
||||||
qCDebug(log) << "dtor ~UiCodeModelSupport for" << m_uiFileName;
|
qCDebug(log) << "dtor ~UiCodeModelSupport for" << m_uiFileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UiCodeModelSupport::init() const
|
void UiCodeModelSupport::init()
|
||||||
{
|
{
|
||||||
|
QTC_ASSERT(!m_process, return);
|
||||||
|
|
||||||
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
||||||
if (m_state != BARE)
|
|
||||||
return;
|
|
||||||
QDateTime sourceTime = QFileInfo(m_uiFileName).lastModified();
|
QDateTime sourceTime = QFileInfo(m_uiFileName).lastModified();
|
||||||
QFileInfo uiHeaderFileInfo(m_headerFileName);
|
QFileInfo uiHeaderFileInfo(m_headerFileName);
|
||||||
QDateTime uiHeaderTime = uiHeaderFileInfo.exists() ? uiHeaderFileInfo.lastModified() : QDateTime();
|
QDateTime uiHeaderTime = uiHeaderFileInfo.exists() ? uiHeaderFileInfo.lastModified() : QDateTime();
|
||||||
@@ -110,7 +105,6 @@ void UiCodeModelSupport::init() const
|
|||||||
QTextStream stream(&file);
|
QTextStream stream(&file);
|
||||||
m_contents = stream.readAll().toUtf8();
|
m_contents = stream.readAll().toUtf8();
|
||||||
m_cacheTime = uiHeaderTime;
|
m_cacheTime = uiHeaderTime;
|
||||||
m_state = FINISHED;
|
|
||||||
notifyAboutUpdatedContents();
|
notifyAboutUpdatedContents();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -129,14 +123,12 @@ void UiCodeModelSupport::init() const
|
|||||||
qCDebug(log) << "uic run wasn't succesfull";
|
qCDebug(log) << "uic run wasn't succesfull";
|
||||||
m_cacheTime = QDateTime ();
|
m_cacheTime = QDateTime ();
|
||||||
m_contents.clear();
|
m_contents.clear();
|
||||||
m_state = FINISHED;
|
|
||||||
notifyAboutUpdatedContents();
|
notifyAboutUpdatedContents();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
qCDebug(log) << "Could not open " << m_uiFileName << "needed for the cpp model";
|
qCDebug(log) << "Could not open " << m_uiFileName << "needed for the cpp model";
|
||||||
m_contents.clear();
|
m_contents.clear();
|
||||||
m_state = FINISHED;
|
|
||||||
notifyAboutUpdatedContents();
|
notifyAboutUpdatedContents();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -161,11 +153,7 @@ void UiCodeModelSupport::setHeaderFileName(const QString &name)
|
|||||||
if (m_headerFileName == name && m_cacheTime.isValid())
|
if (m_headerFileName == name && m_cacheTime.isValid())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_state == RUNNING) {
|
cleanUpProcess();
|
||||||
m_state = ABORTING;
|
|
||||||
m_process.kill();
|
|
||||||
m_process.waitForFinished(3000);
|
|
||||||
}
|
|
||||||
|
|
||||||
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
||||||
qCDebug(log) << "UiCodeModelSupport::setFileName" << name;
|
qCDebug(log) << "UiCodeModelSupport::setFileName" << name;
|
||||||
@@ -173,45 +161,57 @@ void UiCodeModelSupport::setHeaderFileName(const QString &name)
|
|||||||
m_headerFileName = name;
|
m_headerFileName = name;
|
||||||
m_contents.clear();
|
m_contents.clear();
|
||||||
m_cacheTime = QDateTime();
|
m_cacheTime = QDateTime();
|
||||||
m_state = BARE;
|
|
||||||
init();
|
init();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UiCodeModelSupport::runUic(const QString &ui) const
|
bool UiCodeModelSupport::runUic(const QString &ui)
|
||||||
{
|
{
|
||||||
|
QTC_ASSERT(!m_process, return false);
|
||||||
|
|
||||||
const QString uic = uicCommand();
|
const QString uic = uicCommand();
|
||||||
if (uic.isEmpty())
|
if (uic.isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
||||||
m_process.setEnvironment(environment());
|
m_process = new QProcess(this);
|
||||||
|
connect(m_process, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
|
||||||
|
this, &UiCodeModelSupport::finishProcess);
|
||||||
|
connect(m_process, &QProcess::started, this, [this, ui]() { startProcess(ui); });
|
||||||
|
#if QT_VERSION < QT_VERSION_CHECK(5, 6, 0) // ### fixme: Remove once 5.6 is the minimum Qt version required
|
||||||
|
# define QPROCESS_ERROR_SIGNAL static_cast<void (QProcess::*)(QProcess::ProcessError)>(&QProcess::error)
|
||||||
|
#else
|
||||||
|
# define QPROCESS_ERROR_SIGNAL &QProcess::errorOccurred
|
||||||
|
#endif
|
||||||
|
connect(m_process, QPROCESS_ERROR_SIGNAL, this, &UiCodeModelSupport::errorProcess);
|
||||||
|
#undef QPROCESS_ERROR_SIGNAL
|
||||||
|
|
||||||
qCDebug(log) << " UiCodeModelSupport::runUic " << uic << " on " << ui.size() << " bytes";
|
qCDebug(log) << " UiCodeModelSupport::runUic " << uic << " on " << ui.size() << " bytes";
|
||||||
m_process.start(uic, QStringList(), QIODevice::ReadWrite);
|
m_process->setEnvironment(environment());
|
||||||
if (!m_process.waitForStarted())
|
m_process->start(uic, QStringList(), QIODevice::ReadWrite);
|
||||||
return false;
|
|
||||||
m_process.write(ui.toUtf8());
|
|
||||||
if (!m_process.waitForBytesWritten(3000))
|
|
||||||
goto error;
|
|
||||||
m_process.closeWriteChannel();
|
|
||||||
m_state = RUNNING;
|
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
error:
|
void UiCodeModelSupport::cleanUpProcess()
|
||||||
qCDebug(log) << "failed" << m_process.readAllStandardError();
|
{
|
||||||
m_process.kill();
|
if (!m_process)
|
||||||
m_state = FINISHED;
|
return;
|
||||||
return false;
|
|
||||||
|
disconnect(m_process);
|
||||||
|
if (m_process->state() == QProcess::Running) {
|
||||||
|
connect(m_process, static_cast<void (QProcess::*)(int)>(&QProcess::finished),
|
||||||
|
m_process, &QProcess::deleteLater);
|
||||||
|
m_process->kill();
|
||||||
|
} else {
|
||||||
|
m_process->deleteLater();
|
||||||
|
}
|
||||||
|
m_process = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UiCodeModelSupport::updateFromEditor(const QString &formEditorContents)
|
void UiCodeModelSupport::updateFromEditor(const QString &formEditorContents)
|
||||||
{
|
{
|
||||||
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
||||||
qCDebug(log) << "updating from editor" << m_uiFileName;
|
qCDebug(log) << "updating from editor" << m_uiFileName;
|
||||||
if (m_state == RUNNING) {
|
cleanUpProcess();
|
||||||
m_state = ABORTING;
|
|
||||||
m_process.kill();
|
|
||||||
m_process.waitForFinished(3000);
|
|
||||||
}
|
|
||||||
runUic(formEditorContents);
|
runUic(formEditorContents);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -273,31 +273,39 @@ QStringList UiCodeModelSupport::environment() const
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UiCodeModelSupport::finishProcess()
|
void UiCodeModelSupport::startProcess(const QString &ui)
|
||||||
{
|
{
|
||||||
if (m_state != RUNNING)
|
QTC_ASSERT(m_process, return);
|
||||||
return false;
|
m_process->write(ui.toUtf8());
|
||||||
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
m_process->closeWriteChannel();
|
||||||
if (!m_process.waitForFinished(3000)
|
|
||||||
&& m_process.exitStatus() != QProcess::NormalExit
|
|
||||||
&& m_process.exitCode() != 0) {
|
|
||||||
|
|
||||||
qCDebug(log) << "finish process: failed" << m_process.readAllStandardError();
|
|
||||||
m_process.kill();
|
|
||||||
m_state = FINISHED;
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UiCodeModelSupport::errorProcess()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_process, return);
|
||||||
|
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
||||||
|
qCDebug(log) << "failed" << m_process->readAllStandardError();
|
||||||
|
cleanUpProcess();
|
||||||
|
}
|
||||||
|
|
||||||
|
void UiCodeModelSupport::finishProcess()
|
||||||
|
{
|
||||||
|
QTC_ASSERT(m_process, return);
|
||||||
|
QLoggingCategory log("qtc.qtsupport.uicodemodelsupport");
|
||||||
|
|
||||||
|
if (m_process->exitStatus() == QProcess::NormalExit && m_process->exitCode() == 0) {
|
||||||
// As far as I can discover in the UIC sources, it writes out local 8-bit encoding. The
|
// As far as I can discover in the UIC sources, it writes out local 8-bit encoding. The
|
||||||
// conversion below is to normalize both the encoding, and the line terminators.
|
// conversion below is to normalize both the encoding, and the line terminators.
|
||||||
QString normalized = QString::fromLocal8Bit(m_process.readAllStandardOutput());
|
const QString normalized = QString::fromLocal8Bit(m_process->readAllStandardOutput());
|
||||||
m_contents = normalized.toUtf8();
|
m_contents = normalized.toUtf8();
|
||||||
m_cacheTime = QDateTime::currentDateTime();
|
m_cacheTime = QDateTime::currentDateTime();
|
||||||
qCDebug(log) << "finish process: ok" << m_contents.size() << "bytes.";
|
qCDebug(log) << "finish process: ok" << m_contents.size() << "bytes.";
|
||||||
m_state = FINISHED;
|
|
||||||
notifyAboutUpdatedContents();
|
notifyAboutUpdatedContents();
|
||||||
updateDocument();
|
updateDocument();
|
||||||
return true;
|
}
|
||||||
|
cleanUpProcess();
|
||||||
}
|
}
|
||||||
|
|
||||||
UiCodeModelManager *UiCodeModelManager::m_instance = 0;
|
UiCodeModelManager *UiCodeModelManager::m_instance = 0;
|
||||||
|
@@ -72,22 +72,21 @@ private:
|
|||||||
QString uicCommand() const;
|
QString uicCommand() const;
|
||||||
QStringList environment() const;
|
QStringList environment() const;
|
||||||
|
|
||||||
private slots:
|
|
||||||
bool finishProcess();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void startProcess(const QString &ui);
|
||||||
|
void errorProcess();
|
||||||
|
void finishProcess();
|
||||||
ProjectExplorer::Project *m_project;
|
ProjectExplorer::Project *m_project;
|
||||||
enum State { BARE, RUNNING, FINISHED, ABORTING };
|
|
||||||
|
|
||||||
void init() const;
|
void init();
|
||||||
bool runUic(const QString &ui) const;
|
bool runUic(const QString &ui);
|
||||||
mutable QProcess m_process;
|
void cleanUpProcess();
|
||||||
|
|
||||||
|
QProcess *m_process = nullptr;
|
||||||
QString m_uiFileName;
|
QString m_uiFileName;
|
||||||
QString m_headerFileName;
|
QString m_headerFileName;
|
||||||
mutable State m_state;
|
QByteArray m_contents;
|
||||||
mutable QByteArray m_contents;
|
QDateTime m_cacheTime;
|
||||||
mutable QDateTime m_cacheTime;
|
|
||||||
static QList<UiCodeModelSupport *> m_waitingForStart;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class QTSUPPORT_EXPORT UiCodeModelManager : public QObject
|
class QTSUPPORT_EXPORT UiCodeModelManager : public QObject
|
||||||
|
Reference in New Issue
Block a user