Skip to content

Commit

Permalink
PluginManager: make the global plugin storage file-local as well.
Browse files Browse the repository at this point in the history
This temporarily makes symbol duplication across static libs *slightly*
worse, but that will get fixed right away by the next commit.
  • Loading branch information
mosra committed Sep 1, 2019
1 parent ddd57b1 commit 491ff17
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 53 deletions.
83 changes: 45 additions & 38 deletions src/Corrade/PluginManager/AbstractManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,6 @@ struct AbstractManager::Plugin {
~Plugin() = default;
};

struct AbstractManager::GlobalPluginStorage {
/* Beware: having std::map<std::string, Containers::Pointer> is an
IMPOSSIBLE feat on GCC 4.7, as it will fails with tons of compiler
errors because std::pair is trying to copy itself. So calm down and
ignore those few delete calls. Please. Last tried: March 2018. */
std::map<std::string, Plugin*> plugins;
};

struct AbstractManager::State {
explicit State(std::string&& pluginInterface): pluginInterface{std::move(pluginInterface)} {}

Expand All @@ -146,21 +138,26 @@ struct {
Containers/Implementation/RawForwardList.h, look there for more info. */
Implementation::StaticPlugin* staticPlugins;

/* A map of plugins. Gets allocated by a manager on construction (if not
already), deallocated on manager destruction in case there are no
plugins left in it anymore.
Beware: having std::map<std::string, Containers::Pointer> is an
IMPOSSIBLE feat on GCC 4.7, as it will fails with tons of compiler
errors because std::pair is trying to copy itself. So calm down and
ignore those few delete calls. Please. Last tried: March 2018. */
std::map<std::string, AbstractManager::Plugin*>* plugins;

/* The value of this variable is guaranteed to be zero-filled even before any
static plugin initializers are executed, which means we don't hit any static
initialization order fiasco. */
} globals{nullptr};
} globals{nullptr, nullptr};

static_assert(std::is_pod<Implementation::StaticPlugin>::value,
"static plugins shouldn't cause any global initialization / finalization to happen on their own");

}

auto AbstractManager::initializeGlobalPluginStorage() -> GlobalPluginStorage& {
static GlobalPluginStorage* const plugins = new GlobalPluginStorage;
return *plugins;
}

#ifndef DOXYGEN_GENERATING_OUTPUT
void AbstractManager::importStaticPlugin(int version, Implementation::StaticPlugin& plugin) {
CORRADE_ASSERT(version == Version,
Expand All @@ -174,9 +171,12 @@ AbstractManager::AbstractManager(std::string pluginInterface, const std::vector<
#else
AbstractManager::AbstractManager(std::string pluginInterface):
#endif
_plugins(initializeGlobalPluginStorage()),
_state{Containers::InPlaceInit, std::move(pluginInterface)}
{
/* If the global storage doesn't exist yet, allocate it. This gets deleted
when it's fully empty again on manager destruction. */
if(!globals.plugins) globals.plugins = new std::map<std::string, AbstractManager::Plugin*>;

/* Add static plugins which have the same interface and don't have a
manager assigned to them (i.e, aren't in the map yet). */
for(const Implementation::StaticPlugin* staticPlugin = globals.staticPlugins; staticPlugin; staticPlugin = Containers::Implementation::forwardListNext(*staticPlugin)) {
Expand All @@ -185,7 +185,7 @@ AbstractManager::AbstractManager(std::string pluginInterface):

/* Attempt to insert the plugin into the global list. If it's
already there, it's owned by another plugin manager. Skip it. */
const auto inserted = _plugins.plugins.insert(std::make_pair(staticPlugin->plugin, nullptr));
const auto inserted = globals.plugins->insert(std::make_pair(staticPlugin->plugin, nullptr));
if(!inserted.second) continue;

/* Only allocate the Plugin in case the insertion happened. */
Expand Down Expand Up @@ -249,8 +249,8 @@ AbstractManager::AbstractManager(std::string pluginInterface):

AbstractManager::~AbstractManager() {
/* Unload all plugins associated with this plugin manager */
auto it = _plugins.plugins.begin();
while(it != _plugins.plugins.end()) {
auto it = globals.plugins->begin();
while(it != globals.plugins->end()) {
/* Plugin doesn't belong to this manager */
if(it->second->manager != this) {
++it;
Expand All @@ -271,14 +271,21 @@ AbstractManager::~AbstractManager() {
ones. The static ones get re-added next time a manager of matching
interface is instantiated. */
delete it->second;
it = _plugins.plugins.erase(it);
it = globals.plugins->erase(it);
}

/* If there's nothing left, deallocate the storage. If a manager needs it
again, it will allocate it on its own. */
if(globals.plugins->empty()) {
delete globals.plugins;
globals.plugins = nullptr;
}
}

#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
LoadState AbstractManager::unloadRecursive(const std::string& plugin) {
const auto found = _plugins.plugins.find(plugin);
CORRADE_INTERNAL_ASSERT(found != _plugins.plugins.end());
const auto found = globals.plugins->find(plugin);
CORRADE_INTERNAL_ASSERT(found != globals.plugins->end());
return unloadRecursiveInternal(*found->second);
}

Expand Down Expand Up @@ -325,11 +332,11 @@ void AbstractManager::setPluginDirectory(std::string directory) {
}

/* Remove all unloaded plugins from the container */
auto it = _plugins.plugins.cbegin();
while(it != _plugins.plugins.cend()) {
auto it = globals.plugins->cbegin();
while(it != globals.plugins->cend()) {
if(it->second->manager == this && it->second->loadState & (LoadState::NotLoaded|LoadState::WrongMetadataFile)) {
delete it->second;
it = _plugins.plugins.erase(it);
it = globals.plugins->erase(it);
} else ++it;
}

Expand All @@ -348,15 +355,15 @@ void AbstractManager::setPluginDirectory(std::string directory) {
const std::string name = filename.substr(0, filename.length() - sizeof(PLUGIN_FILENAME_SUFFIX) + 1);

/* Skip the plugin if it is among loaded */
if(_plugins.plugins.find(name) != _plugins.plugins.end()) continue;
if(globals.plugins->find(name) != globals.plugins->end()) continue;

registerDynamicPlugin(name, new Plugin{name, Directory::join(_state->pluginDirectory, name + ".conf"), this});
}

/* If some of the currently loaded plugins aliased plugins that werre in
the old plugin directory, these are no longer there. Refresh the alias
list with the new plugins. */
for(auto p: _plugins.plugins) {
for(auto p: *globals.plugins) {
if(p.second->manager != this) continue;

/* Add aliases to the list (only the ones that aren't already there are
Expand All @@ -383,8 +390,8 @@ void AbstractManager::setPreferredPlugins(const std::string& alias, const std::i

/* Replace the alias with the first candidate that exists */
for(const std::string& plugin: plugins) {
auto foundPlugin = _plugins.plugins.find(plugin);
if(foundPlugin == _plugins.plugins.end() || foundPlugin->second->manager != this)
auto foundPlugin = globals.plugins->find(plugin);
if(foundPlugin == globals.plugins->end() || foundPlugin->second->manager != this)
continue;

CORRADE_ASSERT(std::find(foundPlugin->second->metadata->provides().begin(), foundPlugin->second->metadata->provides().end(), alias) != foundPlugin->second->metadata->provides().end(),
Expand All @@ -397,7 +404,7 @@ void AbstractManager::setPreferredPlugins(const std::string& alias, const std::i

std::vector<std::string> AbstractManager::pluginList() const {
std::vector<std::string> names;
for(const std::pair<std::string, Plugin*>& plugin: _plugins.plugins) {
for(const std::pair<std::string, Plugin*>& plugin: *globals.plugins) {
/* Plugin doesn't belong to this manager */
if(plugin.second->manager != this) continue;

Expand Down Expand Up @@ -440,8 +447,8 @@ LoadState AbstractManager::load(const std::string& plugin) {
/* Dig plugin name from filename and verify it's not loaded at the moment */
const std::string filename = Utility::Directory::filename(plugin);
const std::string name = filename.substr(0, filename.length() - sizeof(PLUGIN_FILENAME_SUFFIX) + 1);
const auto found = _plugins.plugins.find(name);
if(found != _plugins.plugins.end() && (found->second->loadState & LoadState::Loaded)) {
const auto found = globals.plugins->find(name);
if(found != globals.plugins->end() && (found->second->loadState & LoadState::Loaded)) {
Error{} << "PluginManager::load():" << filename << "conflicts with currently loaded plugin of the same name";
return LoadState::Used;
}
Expand All @@ -454,7 +461,7 @@ LoadState AbstractManager::load(const std::string& plugin) {
if(state & LoadState::Loaded) {
/* Remove the potential plugin with the same name (we already
checked above that it's *not* loaded) */
if(found != _plugins.plugins.end()) {
if(found != globals.plugins->end()) {
/* Erase all aliases that reference this plugin, as they would
be dangling now. */
auto ait = _state->aliases.cbegin();
Expand All @@ -469,7 +476,7 @@ LoadState AbstractManager::load(const std::string& plugin) {
but since we were able to load the new plugin, everything
should be fine. */
delete found->second;
_plugins.plugins.erase(found);
globals.plugins->erase(found);
}

registerDynamicPlugin(name, data.release());
Expand Down Expand Up @@ -516,9 +523,9 @@ LoadState AbstractManager::loadInternal(Plugin& plugin, const std::string& filen
for(const std::string& dependency: plugin.metadata->_depends) {
/* Find manager which is associated to this plugin and load the plugin
with it */
const auto foundDependency = _plugins.plugins.find(dependency);
const auto foundDependency = globals.plugins->find(dependency);

if(foundDependency == _plugins.plugins.end() || !foundDependency->second->manager ||
if(foundDependency == globals.plugins->end() || !foundDependency->second->manager ||
!(foundDependency->second->manager->loadInternal(*foundDependency->second) & LoadState::Loaded))
{
Error() << "PluginManager::Manager::load(): unresolved dependency" << dependency << "of plugin" << plugin.metadata->_name;
Expand Down Expand Up @@ -684,8 +691,8 @@ LoadState AbstractManager::unloadInternal(Plugin& plugin) {

/* Remove this plugin from "used by" list of dependencies */
for(auto it = plugin.metadata->depends().cbegin(); it != plugin.metadata->depends().cend(); ++it) {
auto mit = _plugins.plugins.find(*it);
if(mit == _plugins.plugins.end()) continue;
auto mit = globals.plugins->find(*it);
if(mit == globals.plugins->end()) continue;

for(auto uit = mit->second->metadata->_usedBy.begin(); uit != mit->second->metadata->_usedBy.end(); ++uit) {
if(*uit != plugin.metadata->_name) continue;
Expand Down Expand Up @@ -726,7 +733,7 @@ LoadState AbstractManager::unloadInternal(Plugin& plugin) {

void AbstractManager::registerDynamicPlugin(const std::string& name, Plugin* const plugin) {
/* Insert plugin to list */
const auto result = _plugins.plugins.insert({name, plugin});
const auto result = globals.plugins->insert({name, plugin});
CORRADE_INTERNAL_ASSERT(result.second);

/* The plugin is the best version of itself. If there was already an
Expand Down
23 changes: 8 additions & 15 deletions src/Corrade/PluginManager/AbstractManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -205,11 +205,6 @@ class CORRADE_PLUGINMANAGER_EXPORT AbstractManager {
/** @brief Plugin version */
static const int Version;

#ifndef DOXYGEN_GENERATING_OUTPUT
typedef void* (*Instancer)(AbstractManager&, const std::string&);
static void importStaticPlugin(int version, Implementation::StaticPlugin& plugin);
#endif

/** @brief Copying is not allowed */
AbstractManager(const AbstractManager&) = delete;

Expand Down Expand Up @@ -379,25 +374,23 @@ class CORRADE_PLUGINMANAGER_EXPORT AbstractManager {
#ifdef DOXYGEN_GENERATING_OUTPUT
private:
#else
protected:
public:
#endif
struct CORRADE_PLUGINMANAGER_LOCAL Plugin;
struct CORRADE_PLUGINMANAGER_LOCAL GlobalPluginStorage;
typedef void* (*Instancer)(AbstractManager&, const std::string&);
static void importStaticPlugin(int version, Implementation::StaticPlugin& plugin);

#ifdef DOXYGEN_GENERATING_OUTPUT
private:
#else
protected:
#endif
#ifndef CORRADE_PLUGINMANAGER_NO_DYNAMIC_PLUGIN_SUPPORT
explicit AbstractManager(std::string pluginInterface, const std::vector<std::string>& pluginSearchPaths, std::string pluginDirectory);
#else
explicit AbstractManager(std::string pluginInterface);
#endif

/* Initialize global plugin map. On first run it creates the instance
and fills it with entries from staticPlugins(). The reference is
then in constructor stored in _plugins variable to avoid at least
some issues with duplicated static variables on static builds. */
static CORRADE_PLUGINMANAGER_LOCAL GlobalPluginStorage& initializeGlobalPluginStorage();

GlobalPluginStorage& _plugins;

Containers::Pointer<AbstractPlugin> instantiateInternal(const std::string& plugin);
Containers::Pointer<AbstractPlugin> loadAndInstantiateInternal(const std::string& plugin);

Expand Down

0 comments on commit 491ff17

Please sign in to comment.