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,
|
||||
this, &AppOutputPane::updateFromSettings);
|
||||
|
||||
#ifdef Q_OS_WIN
|
||||
connect(this, &AppOutputPane::allRunControlsFinished,
|
||||
WinDebugInterface::instance(), &WinDebugInterface::stop);
|
||||
#endif
|
||||
|
||||
QSettings *settings = Core::ICore::settings();
|
||||
m_zoom = settings->value(QLatin1String(SETTINGS_KEY), 0).toFloat();
|
||||
|
||||
@@ -546,15 +541,10 @@ void AppOutputPane::stopRunControl()
|
||||
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--)
|
||||
if (!closeTab(t, mode))
|
||||
allClosed = false;
|
||||
if (debug)
|
||||
qDebug() << "OutputPane::closeTabs() returns " << allClosed;
|
||||
return allClosed;
|
||||
closeTab(t, mode);
|
||||
}
|
||||
|
||||
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));
|
||||
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)
|
||||
qDebug() << "OutputPane::closeTab tab " << tabIndex << m_runControlTabs[index].runControl
|
||||
<< m_runControlTabs[index].window;
|
||||
qDebug() << "OutputPane::closeTab tab " << tabIndex << runControl << window;
|
||||
// Prompt user to stop
|
||||
if (m_runControlTabs[index].runControl->isRunning()) {
|
||||
switch (closeTabMode) {
|
||||
case CloseTabNoPrompt:
|
||||
break;
|
||||
case CloseTabWithPrompt:
|
||||
QWidget *tabWidget = m_tabWidget->widget(tabIndex);
|
||||
if (!m_runControlTabs[index].runControl->promptToStop())
|
||||
return false;
|
||||
// The event loop has run, thus the ordering might have changed, a tab might
|
||||
// have been closed, so do some strange things...
|
||||
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;
|
||||
}
|
||||
if (closeTabMode == CloseTabWithPrompt) {
|
||||
QWidget *tabWidget = m_tabWidget->widget(tabIndex);
|
||||
if (!runControl->promptToStop())
|
||||
return;
|
||||
// The event loop has run, thus the ordering might have changed, a tab might
|
||||
// have been closed, so do some strange things...
|
||||
tabIndex = m_tabWidget->indexOf(tabWidget);
|
||||
index = indexOf(tabWidget);
|
||||
if (tabIndex == -1 || index == -1)
|
||||
return;
|
||||
}
|
||||
|
||||
m_tabWidget->removeTab(tabIndex);
|
||||
delete m_runControlTabs[index].window;
|
||||
m_runControlTabs[index].runControl->initiateFinish(); // Will self-destruct.
|
||||
m_runControlTabs[index].runControl = 0;
|
||||
delete window;
|
||||
|
||||
runControl->initiateFinish(); // Will self-destruct.
|
||||
m_runControlTabs.removeAt(index);
|
||||
updateCloseActions();
|
||||
|
||||
if (m_runControlTabs.isEmpty())
|
||||
hide();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AppOutputPane::optionallyPromptToStop(RunControl *runControl)
|
||||
@@ -742,15 +721,14 @@ void AppOutputPane::slotRunControlFinished2(RunControl *sender)
|
||||
|
||||
ProjectExplorerPlugin::instance()->updateRunActions();
|
||||
|
||||
if (!isRunning())
|
||||
emit allRunControlsFinished();
|
||||
}
|
||||
|
||||
bool AppOutputPane::isRunning() const
|
||||
{
|
||||
return Utils::anyOf(m_runControlTabs, [](const RunControlTab &rt) {
|
||||
#ifdef Q_OS_WIN
|
||||
const bool isRunning = Utils::anyOf(m_runControlTabs, [](const RunControlTab &rt) {
|
||||
return rt.runControl->isRunning();
|
||||
});
|
||||
if (!isRunning)
|
||||
WinDebugInterface::instance()->stop();
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
bool AppOutputPane::canNext() const
|
||||
|
@@ -88,14 +88,10 @@ public:
|
||||
void setBehaviorOnOutput(RunControl *rc, BehaviorOnOutput mode);
|
||||
|
||||
bool aboutToClose() const;
|
||||
bool closeTabs(CloseTabMode mode);
|
||||
void closeTabs(CloseTabMode mode);
|
||||
|
||||
QList<RunControl *> allRunControls() const;
|
||||
|
||||
signals:
|
||||
void allRunControlsFinished();
|
||||
|
||||
public:
|
||||
// ApplicationOutput specifics
|
||||
void projectRemoved();
|
||||
|
||||
@@ -126,12 +122,11 @@ private:
|
||||
explicit RunControlTab(RunControl *runControl = nullptr,
|
||||
Core::OutputWindow *window = nullptr);
|
||||
QPointer<RunControl> runControl;
|
||||
Core::OutputWindow *window;
|
||||
QPointer<Core::OutputWindow> window;
|
||||
BehaviorOnOutput behaviorOnOutput = Flash;
|
||||
};
|
||||
|
||||
bool isRunning() const;
|
||||
bool closeTab(int index, CloseTabMode cm = CloseTabWithPrompt);
|
||||
void closeTab(int index, CloseTabMode cm = CloseTabWithPrompt);
|
||||
bool optionallyPromptToStop(RunControl *runControl);
|
||||
|
||||
int indexOf(const RunControl *) const;
|
||||
@@ -148,6 +143,7 @@ private:
|
||||
QWidget *m_mainWidget;
|
||||
TabWidget *m_tabWidget;
|
||||
QVector<RunControlTab> m_runControlTabs;
|
||||
int m_runControlCount = 0;
|
||||
QAction *m_stopAction;
|
||||
QAction *m_closeCurrentTabAction;
|
||||
QAction *m_closeAllTabsAction;
|
||||
|
@@ -343,6 +343,9 @@ public:
|
||||
|
||||
void runConfigurationConfigurationFinished();
|
||||
|
||||
void checkForShutdown();
|
||||
void timerEvent(QTimerEvent *) override;
|
||||
|
||||
QList<QPair<QString, QString> > recentProjects() const;
|
||||
|
||||
public:
|
||||
@@ -405,6 +408,8 @@ public:
|
||||
|
||||
QStringList m_profileMimeTypes;
|
||||
AppOutputPane *m_outputPane = nullptr;
|
||||
int m_activeRunControlCount = 0;
|
||||
int m_shutdownWatchDogId = -1;
|
||||
|
||||
QHash<QString, std::function<Project *(const Utils::FileName &)>> m_projectCreators;
|
||||
QList<QPair<QString, QString> > m_recentProjects; // pair of filename, displayname
|
||||
@@ -1632,10 +1637,12 @@ ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown()
|
||||
removeObject(dd->m_welcomePage);
|
||||
delete dd->m_welcomePage;
|
||||
removeObject(this);
|
||||
if (dd->m_outputPane->closeTabs(AppOutputPane::CloseTabNoPrompt /* No prompt any more */))
|
||||
|
||||
if (dd->m_activeRunControlCount == 0)
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -2032,10 +2039,27 @@ void ProjectExplorerPluginPrivate::startRunControl(RunControl *runControl)
|
||||
bool popup = (runMode == Constants::NORMAL_RUN_MODE && dd->m_projectExplorerSettings.showRunOutput)
|
||||
|| (runMode == Constants::DEBUG_RUN_MODE && m_projectExplorerSettings.showDebugOutput);
|
||||
m_outputPane->setBehaviorOnOutput(runControl, popup ? AppOutputPane::Popup : AppOutputPane::Flash);
|
||||
connect(runControl, &QObject::destroyed, this, &ProjectExplorerPluginPrivate::checkForShutdown,
|
||||
Qt::QueuedConnection);
|
||||
++m_activeRunControlCount;
|
||||
runControl->initiateStart();
|
||||
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()
|
||||
{
|
||||
dd->handleRenameFile();
|
||||
|
@@ -674,7 +674,6 @@ RunControl::~RunControl()
|
||||
#ifdef WITH_JOURNALD
|
||||
JournaldWatcher::instance()->unsubscribe(this);
|
||||
#endif
|
||||
disconnect();
|
||||
delete d;
|
||||
d = nullptr;
|
||||
}
|
||||
@@ -698,7 +697,7 @@ void RunControl::initiateStop()
|
||||
|
||||
void RunControl::initiateFinish()
|
||||
{
|
||||
d->initiateFinish();
|
||||
QTimer::singleShot(0, d, &RunControlPrivate::initiateFinish);
|
||||
}
|
||||
|
||||
using WorkerCreators = QHash<Core::Id, RunControl::WorkerCreator>;
|
||||
@@ -1277,7 +1276,7 @@ void RunControlPrivate::setState(RunControlState newState)
|
||||
case RunControlState::Finished:
|
||||
emit q->finished();
|
||||
debugMessage("All finished. Deleting myself");
|
||||
deleteLater();
|
||||
q->deleteLater();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
Reference in New Issue
Block a user