From 052ac8487d2eda1a1890d00f95692814ff3596c6 Mon Sep 17 00:00:00 2001 From: Dennis Klein Date: Tue, 12 Sep 2017 19:25:36 +0200 Subject: [PATCH] FairMQ: Add static plugin mechanism * Add skeleton for Take/ReleaseControl API * Add skeleton for control_static builtin plugin --- fairmq/CMakeLists.txt | 3 ++ fairmq/Plugin.h | 4 +- fairmq/PluginManager.cxx | 23 ++++++++ fairmq/PluginManager.h | 4 +- fairmq/PluginServices.h | 3 ++ fairmq/plugins/Builtin.h | 11 ++++ fairmq/plugins/ControlStatic.cxx | 54 +++++++++++++++++++ fairmq/plugins/ControlStatic.h | 51 ++++++++++++++++++ fairmq/test/CMakeLists.txt | 4 +- fairmq/test/plugins/_plugin_manager.cxx | 29 +++++++++- ...static.cxx => _plugin_manager_prelink.cxx} | 6 +-- 11 files changed, 181 insertions(+), 11 deletions(-) create mode 100644 fairmq/plugins/Builtin.h create mode 100644 fairmq/plugins/ControlStatic.cxx create mode 100644 fairmq/plugins/ControlStatic.h rename fairmq/test/plugins/{_plugin_manager_static.cxx => _plugin_manager_prelink.cxx} (85%) diff --git a/fairmq/CMakeLists.txt b/fairmq/CMakeLists.txt index 248acaf0..e7a48676 100644 --- a/fairmq/CMakeLists.txt +++ b/fairmq/CMakeLists.txt @@ -85,6 +85,8 @@ set(FAIRMQ_HEADER_FILES Plugin.h PluginManager.h PluginServices.h + plugins/Builtin.h + plugins/ControlStatic.h runFairMQDevice.h shmem/FairMQMessageSHM.h shmem/FairMQPollerSHM.h @@ -146,6 +148,7 @@ set(FAIRMQ_SOURCE_FILES Plugin.cxx PluginManager.cxx PluginServices.cxx + plugins/ControlStatic.cxx shmem/FairMQMessageSHM.cxx shmem/FairMQPollerSHM.cxx shmem/FairMQRegionSHM.cxx diff --git a/fairmq/Plugin.h b/fairmq/Plugin.h index f2ba0bd2..85f329f7 100644 --- a/fairmq/Plugin.h +++ b/fairmq/Plugin.h @@ -70,6 +70,8 @@ class Plugin auto ChangeDeviceState(const DeviceStateTransition next) -> void { fPluginServices->ChangeDeviceState(next); } auto SubscribeToDeviceStateChange(std::function callback) -> void { fPluginServices->SubscribeToDeviceStateChange(fkName, callback); } auto UnsubscribeFromDeviceStateChange() -> void { fPluginServices->UnsubscribeFromDeviceStateChange(fkName); } + auto TakeControl() -> void { fPluginServices->TakeControl(fkName); }; + auto ReleaseControl() -> void { fPluginServices->ReleaseControl(fkName); }; // device config API // see for docs @@ -97,7 +99,7 @@ class Plugin } /* namespace fair */ #define REGISTER_FAIRMQ_PLUGIN(KLASS, NAME, VERSION, MAINTAINER, HOMEPAGE, PROGOPTIONS) \ -static auto Make_##NAME##_Plugin(fair::mq::PluginServices* pluginServices) -> std::shared_ptr \ +static auto Make_##NAME##_Plugin(fair::mq::PluginServices* pluginServices) -> std::shared_ptr \ { \ return std::make_shared(std::string{#NAME}, VERSION, std::string{MAINTAINER}, std::string{HOMEPAGE}, pluginServices); \ } \ diff --git a/fairmq/PluginManager.cxx b/fairmq/PluginManager.cxx index 393ec12a..128c6efe 100644 --- a/fairmq/PluginManager.cxx +++ b/fairmq/PluginManager.cxx @@ -126,6 +126,11 @@ auto fair::mq::PluginManager::LoadPlugin(const string& pluginName) -> void // Mechanism B: dynamic LoadPluginDynamic(pluginName.substr(2)); } + else if (pluginName.substr(0,2) == "s:") + { + // Mechanism C: static (builtin) + LoadPluginStatic(pluginName.substr(2)); + } else { // Mechanism B: dynamic (default) @@ -141,6 +146,7 @@ auto fair::mq::PluginManager::LoadPluginPrelinkedDynamic(const string& pluginNam try { LoadSymbols(pluginName, dll::program_location()); + fPluginOrder.push_back(pluginName); } catch (boost::system::system_error& e) { @@ -181,6 +187,23 @@ auto fair::mq::PluginManager::LoadPluginDynamic(const string& pluginName) -> voi } } +auto fair::mq::PluginManager::LoadPluginStatic(const string& pluginName) -> void +{ + // Load symbol + if (fPluginFactories.find(pluginName) == fPluginFactories.end()) + { + try + { + LoadSymbols(pluginName, dll::program_location()); + fPluginOrder.push_back(pluginName); + } + catch (boost::system::system_error& e) + { + throw PluginLoadError(ToString("An error occurred while loading static plugin ", pluginName, ": ", e.what())); + } + } +} + auto fair::mq::PluginManager::InstantiatePlugin(const string& pluginName) -> void { if (fPlugins.find(pluginName) == fPlugins.end()) diff --git a/fairmq/PluginManager.h b/fairmq/PluginManager.h index d5b5294d..f93233ca 100644 --- a/fairmq/PluginManager.h +++ b/fairmq/PluginManager.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #define BOOST_FILESYSTEM_VERSION 3 @@ -27,7 +28,6 @@ #include #include #include -#include #include namespace fair @@ -43,6 +43,7 @@ namespace mq * facilitates two plugin mechanisms: * A prelinked dynamic plugins (shared libraries) * B dynamic plugins (shared libraries) + * C static plugins (builtin) */ class PluginManager { @@ -82,6 +83,7 @@ class PluginManager auto LoadPluginPrelinkedDynamic(const std::string& pluginName) -> void; auto LoadPluginDynamic(const std::string& pluginName) -> void; + auto LoadPluginStatic(const std::string& pluginName) -> void; template auto LoadSymbols(const std::string& pluginName, Args&&... args) -> void { diff --git a/fairmq/PluginServices.h b/fairmq/PluginServices.h index c183f111..c58c9a15 100644 --- a/fairmq/PluginServices.h +++ b/fairmq/PluginServices.h @@ -119,6 +119,9 @@ class PluginServices }); } + auto TakeControl(const std::string& controller) -> void { }; + auto ReleaseControl(const std::string& controller) -> void { }; + /// @brief Unsubscribe from device state changes /// @param subscriber id auto UnsubscribeFromDeviceStateChange(const std::string& subscriber) -> void { fDevice->UnsubscribeFromStateChange(subscriber); } diff --git a/fairmq/plugins/Builtin.h b/fairmq/plugins/Builtin.h new file mode 100644 index 00000000..987573ae --- /dev/null +++ b/fairmq/plugins/Builtin.h @@ -0,0 +1,11 @@ +/******************************************************************************** + * Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ + +// List of all builtin plugin headers (the ones which call REGISTER_FAIRMQ_PLUGIN macro) + +#include diff --git a/fairmq/plugins/ControlStatic.cxx b/fairmq/plugins/ControlStatic.cxx new file mode 100644 index 00000000..eece3993 --- /dev/null +++ b/fairmq/plugins/ControlStatic.cxx @@ -0,0 +1,54 @@ +/******************************************************************************** + * Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ + +#include "ControlStatic.h" + +namespace fair +{ +namespace mq +{ +namespace plugins +{ + +ControlStatic::ControlStatic( + const std::string name, + const Plugin::Version version, + const std::string maintainer, + const std::string homepage, + PluginServices* pluginServices) +: Plugin(name, version, maintainer, homepage, pluginServices) +{ + SubscribeToDeviceStateChange( + [&](DeviceState newState){ + LOG(WARN) << newState; + switch (newState) + { + case DeviceState::InitializingDevice: + LOG(WARN) << GetPropertyAsString("custom-example-option"); + SetProperty("custom-example-option", std::string{"new value"}); + break; + case DeviceState::Exiting: + LOG(WARN) << GetProperty("custom-example-option"); + UnsubscribeFromDeviceStateChange(); + break; + } + } + ); +} + +auto ControlStaticPluginProgramOptions() -> Plugin::ProgOptions +{ + auto plugin_options = boost::program_options::options_description{"Control Static Plugin"}; + plugin_options.add_options() + ("custom-example-option", boost::program_options::value(), "Custom option."); + return plugin_options; +} + +} /* namespace plugins */ +} /* namespace mq */ +} /* namespace fair */ diff --git a/fairmq/plugins/ControlStatic.h b/fairmq/plugins/ControlStatic.h new file mode 100644 index 00000000..e51e965c --- /dev/null +++ b/fairmq/plugins/ControlStatic.h @@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (C) 2017 GSI Helmholtzzentrum fuer Schwerionenforschung GmbH * + * * + * This software is distributed under the terms of the * + * GNU Lesser General Public Licence (LGPL) version 3, * + * copied verbatim in the file "LICENSE" * + ********************************************************************************/ + +#ifndef FAIR_MQ_PLUGINS_CONTROLSTATIC +#define FAIR_MQ_PLUGINS_CONTROLSTATIC + +#include +#include + +namespace fair +{ +namespace mq +{ +namespace plugins +{ + +class ControlStatic : public Plugin +{ + public: + + ControlStatic( + const std::string name, + const Plugin::Version version, + const std::string maintainer, + const std::string homepage, + PluginServices* pluginServices + ); +}; /* class ControlStatic */ + +auto ControlStaticPluginProgramOptions() -> Plugin::ProgOptions; + +REGISTER_FAIRMQ_PLUGIN( + ControlStatic, // Class name + control_static, // Plugin name (string, lower case chars only) + (Plugin::Version{1,0,0}), // Version + "FairRootGroup ", // Maintainer + "https://github.com/FairRootGroup/FairRoot", // Homepage + ControlStaticPluginProgramOptions // Free function which declares custom program options for the plugin + // signature: () -> boost::optional +) + +} /* namespace plugins */ +} /* namespace mq */ +} /* namespace fair */ + +#endif /* FAIR_MQ_PLUGINS_CONTROLSTATIC */ diff --git a/fairmq/test/CMakeLists.txt b/fairmq/test/CMakeLists.txt index 2462fc96..b5f955f6 100644 --- a/fairmq/test/CMakeLists.txt +++ b/fairmq/test/CMakeLists.txt @@ -122,10 +122,10 @@ add_testsuite(FairMQ.Plugins TIMEOUT 10 ) -add_testsuite(FairMQ.PluginsStatic +add_testsuite(FairMQ.PluginsPrelinked SOURCES plugins/runner.cxx - plugins/_plugin_manager_static.cxx + plugins/_plugin_manager_prelink.cxx LINKS FairMQ FairMQPlugin_test_dummy FairMQPlugin_test_dummy2 TIMEOUT 10 diff --git a/fairmq/test/plugins/_plugin_manager.cxx b/fairmq/test/plugins/_plugin_manager.cxx index c1cdefc2..6311e422 100644 --- a/fairmq/test/plugins/_plugin_manager.cxx +++ b/fairmq/test/plugins/_plugin_manager.cxx @@ -37,11 +37,11 @@ auto control(shared_ptr device) -> void } } -TEST(PluginManager, LoadPlugin) +TEST(PluginManager, LoadPluginDynamic) { FairMQProgOptions config{}; - auto device = make_shared(); auto mgr = PluginManager{}; + auto device = make_shared(); mgr.EmplacePluginServices(&config, device); mgr.PrependSearchPath("./lib"); @@ -65,6 +65,31 @@ TEST(PluginManager, LoadPlugin) control(device); } +TEST(PluginManager, LoadPluginStatic) +{ + FairMQProgOptions config{}; + auto mgr = PluginManager{}; + auto device = make_shared(); + mgr.EmplacePluginServices(&config, device); + + ASSERT_NO_THROW(mgr.LoadPlugin("s:control_static")); + + ASSERT_NO_THROW(mgr.InstantiatePlugins()); + + // check order + const auto expected = vector{"control_static"}; + auto actual = vector{}; + mgr.ForEachPlugin([&](Plugin& plugin){ actual.push_back(plugin.GetName()); }); + ASSERT_TRUE(actual == expected); + + // program options + auto count = 0; + mgr.ForEachPluginProgOptions([&count](const options_description& d){ ++count; }); + ASSERT_EQ(count, 1); + + control(device); +} + TEST(PluginManager, Factory) { const auto args = vector{"-l", "debug", "--help", "-S", ">/lib", " #include -#include -#include -#include -#include namespace { @@ -19,7 +15,7 @@ namespace using namespace fair::mq; using namespace std; -TEST(PluginManager, LoadPluginStatic) +TEST(PluginManager, LoadPluginPrelinkedDynamic) { auto mgr = PluginManager{};