Commit b3dbc4b4 authored by con's avatar con

Add flag to IPlugin::aboutToShutdown that allows asynchronous shutdown.

If a plugin requests asyncronous shutdown, the shutdown sequence does
not continue to deleting the plugins before it has sent a
asynchronousShutdownFinished signal. During that time an event loop
is running.
parent adf2c1b0
......@@ -306,6 +306,9 @@ int main(int argc, char **argv)
// Do this after the event loop has started
QTimer::singleShot(100, &pluginManager, SLOT(startTests()));
return app.exec();
int ret = app.exec();
pluginManager.shutdown();
return ret;
}
......@@ -217,36 +217,62 @@
/*!
\fn bool IPlugin::initialize(const QStringList &arguments, QString *errorString)
Called after the plugin has been loaded and the IPlugin instance
has been created. The initialize methods of plugins that depend
\brief Called after the plugin has been loaded and the IPlugin instance
has been created.
The initialize methods of plugins that depend
on this plugin are called after the initialize method of this plugin
has been called. Plugins should initialize their internal state in this
method. Returns if initialization of successful. If it wasn't successful,
the \a errorString should be set to a user-readable message
describing the reason.
\sa extensionsInitialized()
*/
/*!
\fn void IPlugin::extensionsInitialized()
Called after the IPlugin::initialize() method has been called,
\brief Called after the IPlugin::initialize() method has been called,
and after both the IPlugin::initialize() and IPlugin::extensionsInitialized()
methods of plugins that depend on this plugin have been called.
In this method, the plugin can assume that plugins that depend on
this plugin are fully 'up and running'. It is a good place to
look in the plugin manager's object pool for objects that have
been provided by dependent plugins.
\sa initialize()
*/
/*!
\fn void IPlugin::aboutToShutdown()
Called during a shutdown sequence in the same order as initialization
\fn IPlugin::ShutdownFlag IPlugin::aboutToShutdown()
\brief Called during a shutdown sequence in the same order as initialization
before the plugins get deleted in reverse order.
This method can be used to optimize the shutdown down, e.g. to
disconnect from the PluginManager::aboutToRemoveObject() signal
if getting the signal (and probably doing lots of stuff to update
the internal and visible state) doesn't make sense during shutdown.
This method should be used to disconnect from other plugins,
hide all UI, and optimize shutdown in general.
If a plugin needs to delay the real shutdown for a while, for example if
it needs to wait for external processes to finish for a clean shutdown,
the plugin can return IPlugin::AsynchronousShutdown from this method. This
will keep the main event loop running after the aboutToShutdown() sequence
has finished, until all plugins requesting AsynchronousShutdown have sent
the asynchronousShutdownFinished() signal.
The default implementation of this method does nothing and returns
IPlugin::SynchronousShutdown.
Returns IPlugin::AsynchronousShutdown if the plugin needs to perform
asynchonous actions before performing the shutdown.
\sa asynchronousShutdownFinished()
*/
/*!
\fn void IPlugin::asynchronousShutdownFinished()
Sent by the plugin implementation after a asynchronous shutdown
is ready to proceed with the shutdown sequence.
\sa aboutToShutdown()
*/
using namespace ExtensionSystem;
......
......@@ -49,12 +49,17 @@ class EXTENSIONSYSTEM_EXPORT IPlugin : public QObject
Q_OBJECT
public:
enum ShutdownFlag {
SynchronousShutdown,
AsynchronousShutdown
};
IPlugin();
virtual ~IPlugin();
virtual bool initialize(const QStringList &arguments, QString *errorString) = 0;
virtual void extensionsInitialized() = 0;
virtual void aboutToShutdown() { }
virtual ShutdownFlag aboutToShutdown() { return SynchronousShutdown; }
virtual void remoteCommand(const QStringList & /* options */, const QStringList & /* arguments */) { }
PluginSpec *pluginSpec() const;
......@@ -63,6 +68,9 @@ public:
void addAutoReleasedObject(QObject *obj);
void removeObject(QObject *obj);
signals:
void asynchronousShutdownFinished();
private:
Internal::IPluginPrivate *d;
......
......@@ -253,6 +253,16 @@ void PluginManager::loadPlugins()
return d->loadPlugins();
}
/*!
\fn void PluginManager::shutdown()
Shuts down and deletes all plugins.
*/
void PluginManager::shutdown()
{
d->shutdown();
}
/*!
\fn QStringList PluginManager::pluginPaths() const
The list of paths were the plugin manager searches for plugins.
......@@ -628,20 +638,21 @@ PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) :
{
}
/*!
\fn PluginManagerPrivate::~PluginManagerPrivate()
\internal
*/
PluginManagerPrivate::~PluginManagerPrivate()
{
stopAll();
qDeleteAll(pluginSpecs);
qDeleteAll(pluginCategories);
if (!allObjects.isEmpty()) {
qDebug() << "There are" << allObjects.size() << "objects left in the plugin manager pool: " << allObjects;
}
}
/*!
\fn void PluginManagerPrivate::writeSettings()
\internal
*/
void PluginManagerPrivate::writeSettings()
{
QSettings settings(QSettings::IniFormat, QSettings::UserScope,
......@@ -660,6 +671,10 @@ void PluginManagerPrivate::writeSettings()
settings.setValue(QLatin1String(C_FORCEENABLED_PLUGINS), tempForceEnabledPlugins);
}
/*!
\fn void PluginManagerPrivate::loadSettings()
\internal
*/
void PluginManagerPrivate::loadSettings()
{
const QSettings settings(QSettings::IniFormat, QSettings::UserScope,
......@@ -669,12 +684,25 @@ void PluginManagerPrivate::loadSettings()
forceEnabledPlugins = settings.value(QLatin1String(C_FORCEENABLED_PLUGINS)).toStringList();
}
/*!
\fn void PluginManagerPrivate::stopAll()
\internal
*/
void PluginManagerPrivate::stopAll()
{
QList<PluginSpec *> queue = loadQueue();
foreach (PluginSpec *spec, queue) {
loadPlugin(spec, PluginSpec::Stopped);
}
}
/*!
\fn void PluginManagerPrivate::deleteAll()
\internal
*/
void PluginManagerPrivate::deleteAll()
{
QList<PluginSpec *> queue = loadQueue();
QListIterator<PluginSpec *> it(queue);
it.toBack();
while (it.hasPrevious()) {
......@@ -759,6 +787,36 @@ void PluginManagerPrivate::loadPlugins()
emit q->pluginsChanged();
}
/*!
\fn void PluginManagerPrivate::shutdown()
\internal
*/
void PluginManagerPrivate::shutdown()
{
stopAll();
if (!asynchronousPlugins.isEmpty()) {
shutdownEventLoop = new QEventLoop;
shutdownEventLoop->exec();
}
deleteAll();
if (!allObjects.isEmpty()) {
qDebug() << "There are" << allObjects.size() << "objects left in the plugin manager pool: " << allObjects;
}
}
/*!
\fn void PluginManagerPrivate::asyncShutdownFinished()
\internal
*/
void PluginManagerPrivate::asyncShutdownFinished()
{
IPlugin *plugin = qobject_cast<IPlugin *>(sender());
Q_ASSERT(plugin);
asynchronousPlugins.removeAll(plugin->pluginSpec());
if (asynchronousPlugins.isEmpty())
shutdownEventLoop->exit();
}
/*!
\fn void PluginManagerPrivate::loadQueue()
\internal
......@@ -836,7 +894,9 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
profilingReport("<initializeExtensions", spec);
return;
case PluginSpec::Deleted:
profilingReport(">delete", spec);
spec->d->kill();
profilingReport("<delete", spec);
return;
default:
break;
......@@ -863,7 +923,11 @@ void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destSt
break;
case PluginSpec::Stopped:
profilingReport(">stop", spec);
spec->d->stop();
if (spec->d->stop() == IPlugin::AsynchronousShutdown) {
asynchronousPlugins << spec;
connect(spec->plugin(), SIGNAL(asynchronousShutdownFinished()),
this, SLOT(asyncShutdownFinished()));
}
profilingReport("<stop", spec);
break;
default:
......
......@@ -93,6 +93,7 @@ public:
// Plugin operations
QList<PluginSpec *> loadQueue();
void loadPlugins();
void shutdown();
QStringList pluginPaths() const;
void setPluginPaths(const QStringList &paths);
QList<PluginSpec *> plugins() const;
......
......@@ -37,6 +37,7 @@
#include <QtCore/QStringList>
#include <QtCore/QObject>
#include <QtCore/QScopedPointer>
#include <QtCore/QEventLoop>
QT_BEGIN_NAMESPACE
class QTime;
......@@ -51,8 +52,9 @@ namespace Internal {
class PluginSpecPrivate;
class EXTENSIONSYSTEM_EXPORT PluginManagerPrivate
class EXTENSIONSYSTEM_EXPORT PluginManagerPrivate : QObject
{
Q_OBJECT
public:
PluginManagerPrivate(PluginManager *pluginManager);
virtual ~PluginManagerPrivate();
......@@ -63,6 +65,7 @@ public:
// Plugin operations
void loadPlugins();
void shutdown();
void setPluginPaths(const QStringList &paths);
QList<PluginSpec *> loadQueue();
void loadPlugin(PluginSpec *spec, PluginSpec::State destState);
......@@ -81,6 +84,8 @@ public:
QList<QObject *> allObjects; // ### make this a QList<QPointer<QObject> > > ?
QStringList disabledPlugins;
QStringList forceEnabledPlugins;
QList<PluginSpec *> asynchronousPlugins; // plugins that have requested async shutdown
QEventLoop *shutdownEventLoop; // used for async shutdown
QStringList arguments;
QScopedPointer<QTime> m_profileTimer;
......@@ -94,6 +99,10 @@ public:
// used by tests
static PluginSpec *createSpec();
static PluginSpecPrivate *privateSpec(PluginSpec *spec);
private slots:
void asyncShutdownFinished();
private:
PluginCollection *defaultCollection;
PluginManager *q;
......@@ -103,6 +112,7 @@ private:
QList<PluginSpec *> &queue,
QList<PluginSpec *> &circularityCheckQueue);
void stopAll();
void deleteAll();
};
} // namespace Internal
......
......@@ -959,12 +959,12 @@ bool PluginSpecPrivate::initializeExtensions()
\fn bool PluginSpecPrivate::stop()
\internal
*/
void PluginSpecPrivate::stop()
IPlugin::ShutdownFlag PluginSpecPrivate::stop()
{
if (!plugin)
return;
plugin->aboutToShutdown();
return IPlugin::SynchronousShutdown;
state = PluginSpec::Stopped;
return plugin->aboutToShutdown();
}
/*!
......
......@@ -31,6 +31,7 @@
#define PLUGINSPEC_P_H
#include "pluginspec.h"
#include "iplugin.h"
#include <QtCore/QObject>
#include <QtCore/QStringList>
......@@ -56,7 +57,7 @@ public:
bool loadLibrary();
bool initializePlugin();
bool initializeExtensions();
void stop();
IPlugin::ShutdownFlag stop();
void kill();
QString name;
......
......@@ -108,9 +108,10 @@ void CorePlugin::fileOpenRequest(const QString &f)
remoteCommand(QStringList(), QStringList(f));
}
void CorePlugin::aboutToShutdown()
ExtensionSystem::IPlugin::ShutdownFlag CorePlugin::aboutToShutdown()
{
m_mainWindow->aboutToShutdown();
return SynchronousShutdown;
}
Q_EXPORT_PLUGIN(CorePlugin)
......@@ -49,7 +49,7 @@ public:
virtual bool initialize(const QStringList &arguments, QString *errorMessage = 0);
virtual void extensionsInitialized();
virtual void aboutToShutdown();
virtual ShutdownFlag aboutToShutdown();
virtual void remoteCommand(const QStringList & /* options */, const QStringList &args);
public slots:
......
......@@ -238,7 +238,6 @@ void MainWindow::setOverrideColor(const QColor &color)
MainWindow::~MainWindow()
{
hide();
ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
pm->removeObject(m_shortcutSettings);
pm->removeObject(m_generalSettings);
......@@ -1134,6 +1133,7 @@ void MainWindow::aboutToShutdown()
disconnect(QApplication::instance(), SIGNAL(focusChanged(QWidget*,QWidget*)),
this, SLOT(updateFocusWidget(QWidget*,QWidget*)));
m_activeContext = 0;
hide();
}
static const char *settingsGroup = "MainWindow";
......
......@@ -144,7 +144,7 @@ void CodepasterPlugin::extensionsInitialized()
{
}
void CodepasterPlugin::aboutToShutdown()
ExtensionSystem::IPlugin::ShutdownFlag CodepasterPlugin::aboutToShutdown()
{
// Delete temporary, fetched files
foreach(const QString &fetchedSnippet, m_fetchedSnippets) {
......@@ -152,6 +152,7 @@ void CodepasterPlugin::aboutToShutdown()
if (file.exists())
file.remove();
}
return SynchronousShutdown;
}
void CodepasterPlugin::postEditor()
......
......@@ -55,7 +55,7 @@ public:
virtual bool initialize(const QStringList &arguments, QString *error_message);
virtual void extensionsInitialized();
virtual void aboutToShutdown();
virtual ShutdownFlag aboutToShutdown();
public slots:
void postEditor();
......
......@@ -320,9 +320,10 @@ void CppPlugin::extensionsInitialized()
{
}
void CppPlugin::aboutToShutdown()
ExtensionSystem::IPlugin::ShutdownFlag CppPlugin::aboutToShutdown()
{
writeSettings();
return SynchronousShutdown;
}
void CppPlugin::switchDeclarationDefinition()
......
......@@ -60,7 +60,7 @@ public:
bool initialize(const QStringList &arguments, QString *error_message = 0);
void extensionsInitialized();
void aboutToShutdown();
ShutdownFlag aboutToShutdown();
// Connect editor to settings changed signals.
void initializeEditor(CPPEditor *editor);
......
......@@ -160,8 +160,9 @@ void CppToolsPlugin::extensionsInitialized()
m_modelManager->setHeaderSuffixes(mimeType.suffixes());
}
void CppToolsPlugin::aboutToShutdown()
ExtensionSystem::IPlugin::ShutdownFlag CppToolsPlugin::aboutToShutdown()
{
return SynchronousShutdown;
}
void CppToolsPlugin::switchHeaderSource()
......
......@@ -65,7 +65,7 @@ public:
bool initialize(const QStringList &arguments, QString *error_message);
void extensionsInitialized();
void aboutToShutdown();
ShutdownFlag aboutToShutdown();
CppModelManager *cppModelManager() { return m_modelManager; }
QString correspondingHeaderOrSource(const QString &fileName) const;
......
......@@ -2480,13 +2480,14 @@ void DebuggerPlugin::clearCppCodeModelSnapshot()
d->m_codeModelSnapshot = CPlusPlus::Snapshot();
}
void DebuggerPlugin::aboutToShutdown()
ExtensionSystem::IPlugin::ShutdownFlag DebuggerPlugin::aboutToShutdown()
{
writeSettings();
if (d->m_uiSwitcher)
d->m_uiSwitcher->aboutToShutdown();
//if (d->m_engine)
// d->m_engine->shutdown();
return SynchronousShutdown;
}
void DebuggerPlugin::showMessage(const QString &msg, int channel, int timeout)
......
......@@ -121,7 +121,7 @@ private:
friend class Internal::DebuggerListener
;
bool initialize(const QStringList &arguments, QString *errorMessage);
void aboutToShutdown();
ShutdownFlag aboutToShutdown();
void extensionsInitialized();
void remoteCommand(const QStringList &options, const QStringList &arguments);
......
......@@ -1175,9 +1175,10 @@ bool FakeVimPlugin::initialize(const QStringList &arguments, QString *errorMessa
return d->initialize();
}
void FakeVimPlugin::aboutToShutdown()
ExtensionSystem::IPlugin::ShutdownFlag FakeVimPlugin::aboutToShutdown()
{
d->aboutToShutdown();
return SynchronousShutdown;
}
void FakeVimPlugin::extensionsInitialized()
......
......@@ -50,7 +50,7 @@ public:
private:
// implementation of ExtensionSystem::IPlugin
bool initialize(const QStringList &arguments, QString *error_message);
void aboutToShutdown();
ShutdownFlag aboutToShutdown();
void extensionsInitialized();
private:
......
......@@ -143,12 +143,13 @@ void FindPlugin::extensionsInitialized()
readSettings();
}
void FindPlugin::aboutToShutdown()
ExtensionSystem::IPlugin::ShutdownFlag FindPlugin::aboutToShutdown()
{
d->m_findToolBar->setVisible(false);
d->m_findToolBar->setParent(0);
d->m_currentDocumentFind->removeConnections();
writeSettings();
return SynchronousShutdown;
}
void FindPlugin::filterChanged()
......
......@@ -67,7 +67,7 @@ public:
// IPlugin
bool initialize(const QStringList &arguments, QString *error_message);
void extensionsInitialized();
void aboutToShutdown();
ShutdownFlag aboutToShutdown();
QTextDocument::FindFlags findFlags() const;
void updateFindCompletion(const QString &text);
......
......@@ -338,10 +338,11 @@ void HelpPlugin::extensionsInitialized()
helpManager->registerDocumentation(filesToRegister);
}
void HelpPlugin::aboutToShutdown()
ExtensionSystem::IPlugin::ShutdownFlag HelpPlugin::aboutToShutdown()
{
if (m_sideBar)
m_sideBar->saveSettings(m_core->settings(), QLatin1String("HelpSideBar"));
return SynchronousShutdown;
}
void HelpPlugin::setupUi()
......
......@@ -70,7 +70,7 @@ public:
bool initialize(const QStringList &arguments, QString *error_message);
void extensionsInitialized();
void aboutToShutdown();
ShutdownFlag aboutToShutdown();
private slots:
void modeChanged(Core::IMode *mode);
......
......@@ -944,12 +944,13 @@ void ProjectExplorerPlugin::extensionsInitialized()
d->m_buildManager->extensionsInitialized();
}
void ProjectExplorerPlugin::aboutToShutdown()
ExtensionSystem::IPlugin::ShutdownFlag ProjectExplorerPlugin::aboutToShutdown()
{
d->m_proWindow->aboutToShutdown(); // disconnect from session
d->m_session->clear();
d->m_projectsMode = 0;
// d->m_proWindow->saveConfigChanges();
return SynchronousShutdown;
}
void ProjectExplorerPlugin::newProject()
......
......@@ -100,7 +100,7 @@ public:
//PluginInterface
bool initialize(const QStringList &arguments, QString *error_message);
void extensionsInitialized();
void aboutToShutdown();
ShutdownFlag aboutToShutdown();
void setProjectExplorerSettings(const Internal::ProjectExplorerSettings &pes);
Internal::ProjectExplorerSettings projectExplorerSettings() const;
......
......@@ -84,9 +84,10 @@ QmlInspectorPlugin::~QmlInspectorPlugin()
m_inspector = 0;
}
void QmlInspectorPlugin::aboutToShutdown()
ExtensionSystem::IPlugin::ShutdownFlag QmlInspectorPlugin::aboutToShutdown()
{
m_inspector->shutdown();
return SynchronousShutdown;
}
bool QmlInspectorPlugin::initialize(const QStringList &arguments, QString *errorString)
......
......@@ -58,7 +58,7 @@ public:
virtual bool initialize(const QStringList &arguments, QString *errorString);
virtual void extensionsInitialized();
virtual void aboutToShutdown();
virtual ShutdownFlag aboutToShutdown();
public slots:
void activateDebuggerForProject(ProjectExplorer::Project *project, const QString &runMode);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment