forked from qt-creator/qt-creator
ProjectExplorer: Fix crashes on shutdown
Ensure that RunControls ramp down asynchronously. Since RunControls now ramp down asynchronously the plugin can only report synchronous shut down if no RunControl/OutputPane was present. Task-number: QTCREATORBUG-18605 Change-Id: Ib8d1f857f85c74d4f18ecb85db537121a2275668 Reviewed-by: Orgad Shaneh <orgads@gmail.com>
This commit is contained in:
@@ -247,11 +247,6 @@ AppOutputPane::AppOutputPane() :
|
|||||||
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
|
connect(ProjectExplorerPlugin::instance(), &ProjectExplorerPlugin::settingsChanged,
|
||||||
this, &AppOutputPane::updateFromSettings);
|
this, &AppOutputPane::updateFromSettings);
|
||||||
|
|
||||||
#ifdef Q_OS_WIN
|
|
||||||
connect(this, &AppOutputPane::allRunControlsFinished,
|
|
||||||
WinDebugInterface::instance(), &WinDebugInterface::stop);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
QSettings *settings = Core::ICore::settings();
|
QSettings *settings = Core::ICore::settings();
|
||||||
m_zoom = settings->value(QLatin1String(SETTINGS_KEY), 0).toFloat();
|
m_zoom = settings->value(QLatin1String(SETTINGS_KEY), 0).toFloat();
|
||||||
|
|
||||||
@@ -546,15 +541,10 @@ void AppOutputPane::stopRunControl()
|
|||||||
qDebug() << "OutputPane::stopRunControl " << rc;
|
qDebug() << "OutputPane::stopRunControl " << rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppOutputPane::closeTabs(CloseTabMode mode)
|
void AppOutputPane::closeTabs(CloseTabMode mode)
|
||||||
{
|
{
|
||||||
bool allClosed = true;
|
|
||||||
for (int t = m_tabWidget->count() - 1; t >= 0; t--)
|
for (int t = m_tabWidget->count() - 1; t >= 0; t--)
|
||||||
if (!closeTab(t, mode))
|
closeTab(t, mode);
|
||||||
allClosed = false;
|
|
||||||
if (debug)
|
|
||||||
qDebug() << "OutputPane::closeTabs() returns " << allClosed;
|
|
||||||
return allClosed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
QList<RunControl *> AppOutputPane::allRunControls() const
|
QList<RunControl *> AppOutputPane::allRunControls() const
|
||||||
@@ -564,48 +554,37 @@ QList<RunControl *> AppOutputPane::allRunControls() const
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppOutputPane::closeTab(int tabIndex, CloseTabMode closeTabMode)
|
void AppOutputPane::closeTab(int tabIndex, CloseTabMode closeTabMode)
|
||||||
{
|
{
|
||||||
int index = indexOf(m_tabWidget->widget(tabIndex));
|
int index = indexOf(m_tabWidget->widget(tabIndex));
|
||||||
QTC_ASSERT(index != -1, return true);
|
QTC_ASSERT(index != -1, return);
|
||||||
|
|
||||||
|
RunControl *runControl = m_runControlTabs[index].runControl;
|
||||||
|
Core::OutputWindow *window = m_runControlTabs[index].window;
|
||||||
if (debug)
|
if (debug)
|
||||||
qDebug() << "OutputPane::closeTab tab " << tabIndex << m_runControlTabs[index].runControl
|
qDebug() << "OutputPane::closeTab tab " << tabIndex << runControl << window;
|
||||||
<< m_runControlTabs[index].window;
|
|
||||||
// Prompt user to stop
|
// Prompt user to stop
|
||||||
if (m_runControlTabs[index].runControl->isRunning()) {
|
if (closeTabMode == CloseTabWithPrompt) {
|
||||||
switch (closeTabMode) {
|
QWidget *tabWidget = m_tabWidget->widget(tabIndex);
|
||||||
case CloseTabNoPrompt:
|
if (!runControl->promptToStop())
|
||||||
break;
|
return;
|
||||||
case CloseTabWithPrompt:
|
// The event loop has run, thus the ordering might have changed, a tab might
|
||||||
QWidget *tabWidget = m_tabWidget->widget(tabIndex);
|
// have been closed, so do some strange things...
|
||||||
if (!m_runControlTabs[index].runControl->promptToStop())
|
tabIndex = m_tabWidget->indexOf(tabWidget);
|
||||||
return false;
|
index = indexOf(tabWidget);
|
||||||
// The event loop has run, thus the ordering might have changed, a tab might
|
if (tabIndex == -1 || index == -1)
|
||||||
// have been closed, so do some strange things...
|
return;
|
||||||
tabIndex = m_tabWidget->indexOf(tabWidget);
|
|
||||||
index = indexOf(tabWidget);
|
|
||||||
if (tabIndex == -1 || index == -1)
|
|
||||||
return false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (m_runControlTabs[index].runControl->isRunning()) { // yes it might have stopped already, then just close
|
|
||||||
m_runControlTabs[index].runControl->initiateStop();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_tabWidget->removeTab(tabIndex);
|
m_tabWidget->removeTab(tabIndex);
|
||||||
delete m_runControlTabs[index].window;
|
delete window;
|
||||||
m_runControlTabs[index].runControl->initiateFinish(); // Will self-destruct.
|
|
||||||
m_runControlTabs[index].runControl = 0;
|
runControl->initiateFinish(); // Will self-destruct.
|
||||||
m_runControlTabs.removeAt(index);
|
m_runControlTabs.removeAt(index);
|
||||||
updateCloseActions();
|
updateCloseActions();
|
||||||
|
|
||||||
if (m_runControlTabs.isEmpty())
|
if (m_runControlTabs.isEmpty())
|
||||||
hide();
|
hide();
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppOutputPane::optionallyPromptToStop(RunControl *runControl)
|
bool AppOutputPane::optionallyPromptToStop(RunControl *runControl)
|
||||||
@@ -742,15 +721,14 @@ void AppOutputPane::slotRunControlFinished2(RunControl *sender)
|
|||||||
|
|
||||||
ProjectExplorerPlugin::instance()->updateRunActions();
|
ProjectExplorerPlugin::instance()->updateRunActions();
|
||||||
|
|
||||||
if (!isRunning())
|
#ifdef Q_OS_WIN
|
||||||
emit allRunControlsFinished();
|
const bool isRunning = Utils::anyOf(m_runControlTabs, [](const RunControlTab &rt) {
|
||||||
}
|
|
||||||
|
|
||||||
bool AppOutputPane::isRunning() const
|
|
||||||
{
|
|
||||||
return Utils::anyOf(m_runControlTabs, [](const RunControlTab &rt) {
|
|
||||||
return rt.runControl->isRunning();
|
return rt.runControl->isRunning();
|
||||||
});
|
});
|
||||||
|
if (!isRunning)
|
||||||
|
WinDebugInterface::instance()->stop();
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AppOutputPane::canNext() const
|
bool AppOutputPane::canNext() const
|
||||||
|
@@ -88,14 +88,10 @@ public:
|
|||||||
void setBehaviorOnOutput(RunControl *rc, BehaviorOnOutput mode);
|
void setBehaviorOnOutput(RunControl *rc, BehaviorOnOutput mode);
|
||||||
|
|
||||||
bool aboutToClose() const;
|
bool aboutToClose() const;
|
||||||
bool closeTabs(CloseTabMode mode);
|
void closeTabs(CloseTabMode mode);
|
||||||
|
|
||||||
QList<RunControl *> allRunControls() const;
|
QList<RunControl *> allRunControls() const;
|
||||||
|
|
||||||
signals:
|
|
||||||
void allRunControlsFinished();
|
|
||||||
|
|
||||||
public:
|
|
||||||
// ApplicationOutput specifics
|
// ApplicationOutput specifics
|
||||||
void projectRemoved();
|
void projectRemoved();
|
||||||
|
|
||||||
@@ -126,12 +122,11 @@ private:
|
|||||||
explicit RunControlTab(RunControl *runControl = nullptr,
|
explicit RunControlTab(RunControl *runControl = nullptr,
|
||||||
Core::OutputWindow *window = nullptr);
|
Core::OutputWindow *window = nullptr);
|
||||||
QPointer<RunControl> runControl;
|
QPointer<RunControl> runControl;
|
||||||
Core::OutputWindow *window;
|
QPointer<Core::OutputWindow> window;
|
||||||
BehaviorOnOutput behaviorOnOutput = Flash;
|
BehaviorOnOutput behaviorOnOutput = Flash;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool isRunning() const;
|
void closeTab(int index, CloseTabMode cm = CloseTabWithPrompt);
|
||||||
bool closeTab(int index, CloseTabMode cm = CloseTabWithPrompt);
|
|
||||||
bool optionallyPromptToStop(RunControl *runControl);
|
bool optionallyPromptToStop(RunControl *runControl);
|
||||||
|
|
||||||
int indexOf(const RunControl *) const;
|
int indexOf(const RunControl *) const;
|
||||||
@@ -148,6 +143,7 @@ private:
|
|||||||
QWidget *m_mainWidget;
|
QWidget *m_mainWidget;
|
||||||
TabWidget *m_tabWidget;
|
TabWidget *m_tabWidget;
|
||||||
QVector<RunControlTab> m_runControlTabs;
|
QVector<RunControlTab> m_runControlTabs;
|
||||||
|
int m_runControlCount = 0;
|
||||||
QAction *m_stopAction;
|
QAction *m_stopAction;
|
||||||
QAction *m_closeCurrentTabAction;
|
QAction *m_closeCurrentTabAction;
|
||||||
QAction *m_closeAllTabsAction;
|
QAction *m_closeAllTabsAction;
|
||||||
|
@@ -343,6 +343,9 @@ public:
|
|||||||
|
|
||||||
void runConfigurationConfigurationFinished();
|
void runConfigurationConfigurationFinished();
|
||||||
|
|
||||||
|
void checkForShutdown();
|
||||||
|
void timerEvent(QTimerEvent *) override;
|
||||||
|
|
||||||
QList<QPair<QString, QString> > recentProjects() const;
|
QList<QPair<QString, QString> > recentProjects() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -405,6 +408,8 @@ public:
|
|||||||
|
|
||||||
QStringList m_profileMimeTypes;
|
QStringList m_profileMimeTypes;
|
||||||
AppOutputPane *m_outputPane = nullptr;
|
AppOutputPane *m_outputPane = nullptr;
|
||||||
|
int m_activeRunControlCount = 0;
|
||||||
|
int m_shutdownWatchDogId = -1;
|
||||||
|
|
||||||
QHash<QString, std::function<Project *(const Utils::FileName &)>> m_projectCreators;
|
QHash<QString, std::function<Project *(const Utils::FileName &)>> m_projectCreators;
|
||||||
QList<QPair<QString, QString> > m_recentProjects; // pair of filename, displayname
|
QList<QPair<QString, QString> > m_recentProjects; // pair of filename, displayname
|
||||||
@@ -1632,10 +1637,12 @@ ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown()
|
|||||||
removeObject(dd->m_welcomePage);
|
removeObject(dd->m_welcomePage);
|
||||||
delete dd->m_welcomePage;
|
delete dd->m_welcomePage;
|
||||||
removeObject(this);
|
removeObject(this);
|
||||||
if (dd->m_outputPane->closeTabs(AppOutputPane::CloseTabNoPrompt /* No prompt any more */))
|
|
||||||
|
if (dd->m_activeRunControlCount == 0)
|
||||||
return SynchronousShutdown;
|
return SynchronousShutdown;
|
||||||
connect(dd->m_outputPane, &AppOutputPane::allRunControlsFinished,
|
|
||||||
this, &IPlugin::asynchronousShutdownFinished);
|
dd->m_outputPane->closeTabs(AppOutputPane::CloseTabNoPrompt /* No prompt any more */);
|
||||||
|
dd->m_shutdownWatchDogId = dd->startTimer(10 * 1000); // Make sure we shutdown *somehow*
|
||||||
return AsynchronousShutdown;
|
return AsynchronousShutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2032,10 +2039,27 @@ void ProjectExplorerPluginPrivate::startRunControl(RunControl *runControl)
|
|||||||
bool popup = (runMode == Constants::NORMAL_RUN_MODE && dd->m_projectExplorerSettings.showRunOutput)
|
bool popup = (runMode == Constants::NORMAL_RUN_MODE && dd->m_projectExplorerSettings.showRunOutput)
|
||||||
|| (runMode == Constants::DEBUG_RUN_MODE && m_projectExplorerSettings.showDebugOutput);
|
|| (runMode == Constants::DEBUG_RUN_MODE && m_projectExplorerSettings.showDebugOutput);
|
||||||
m_outputPane->setBehaviorOnOutput(runControl, popup ? AppOutputPane::Popup : AppOutputPane::Flash);
|
m_outputPane->setBehaviorOnOutput(runControl, popup ? AppOutputPane::Popup : AppOutputPane::Flash);
|
||||||
|
connect(runControl, &QObject::destroyed, this, &ProjectExplorerPluginPrivate::checkForShutdown,
|
||||||
|
Qt::QueuedConnection);
|
||||||
|
++m_activeRunControlCount;
|
||||||
runControl->initiateStart();
|
runControl->initiateStart();
|
||||||
emit m_instance->updateRunActions();
|
emit m_instance->updateRunActions();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ProjectExplorerPluginPrivate::checkForShutdown()
|
||||||
|
{
|
||||||
|
--m_activeRunControlCount;
|
||||||
|
QTC_ASSERT(m_activeRunControlCount >= 0, m_activeRunControlCount = 0);
|
||||||
|
if (m_shuttingDown && m_activeRunControlCount == 0)
|
||||||
|
m_instance->asynchronousShutdownFinished();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProjectExplorerPluginPrivate::timerEvent(QTimerEvent *ev)
|
||||||
|
{
|
||||||
|
if (m_shutdownWatchDogId == ev->timerId())
|
||||||
|
m_instance->asynchronousShutdownFinished();
|
||||||
|
}
|
||||||
|
|
||||||
void ProjectExplorerPlugin::initiateInlineRenaming()
|
void ProjectExplorerPlugin::initiateInlineRenaming()
|
||||||
{
|
{
|
||||||
dd->handleRenameFile();
|
dd->handleRenameFile();
|
||||||
|
@@ -674,7 +674,6 @@ RunControl::~RunControl()
|
|||||||
#ifdef WITH_JOURNALD
|
#ifdef WITH_JOURNALD
|
||||||
JournaldWatcher::instance()->unsubscribe(this);
|
JournaldWatcher::instance()->unsubscribe(this);
|
||||||
#endif
|
#endif
|
||||||
disconnect();
|
|
||||||
delete d;
|
delete d;
|
||||||
d = nullptr;
|
d = nullptr;
|
||||||
}
|
}
|
||||||
@@ -698,7 +697,7 @@ void RunControl::initiateStop()
|
|||||||
|
|
||||||
void RunControl::initiateFinish()
|
void RunControl::initiateFinish()
|
||||||
{
|
{
|
||||||
d->initiateFinish();
|
QTimer::singleShot(0, d, &RunControlPrivate::initiateFinish);
|
||||||
}
|
}
|
||||||
|
|
||||||
using WorkerCreators = QHash<Core::Id, RunControl::WorkerCreator>;
|
using WorkerCreators = QHash<Core::Id, RunControl::WorkerCreator>;
|
||||||
@@ -1277,7 +1276,7 @@ void RunControlPrivate::setState(RunControlState newState)
|
|||||||
case RunControlState::Finished:
|
case RunControlState::Finished:
|
||||||
emit q->finished();
|
emit q->finished();
|
||||||
debugMessage("All finished. Deleting myself");
|
debugMessage("All finished. Deleting myself");
|
||||||
deleteLater();
|
q->deleteLater();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
Reference in New Issue
Block a user