FairMQ: Add static plugin mechanism

* Add skeleton for Take/ReleaseControl API
* Add skeleton for control_static builtin plugin
This commit is contained in:
Dennis Klein 2017-09-12 19:25:36 +02:00 committed by Mohammad Al-Turany
parent 17d7cd8ce4
commit 052ac8487d
11 changed files with 181 additions and 11 deletions

View File

@ -85,6 +85,8 @@ set(FAIRMQ_HEADER_FILES
Plugin.h Plugin.h
PluginManager.h PluginManager.h
PluginServices.h PluginServices.h
plugins/Builtin.h
plugins/ControlStatic.h
runFairMQDevice.h runFairMQDevice.h
shmem/FairMQMessageSHM.h shmem/FairMQMessageSHM.h
shmem/FairMQPollerSHM.h shmem/FairMQPollerSHM.h
@ -146,6 +148,7 @@ set(FAIRMQ_SOURCE_FILES
Plugin.cxx Plugin.cxx
PluginManager.cxx PluginManager.cxx
PluginServices.cxx PluginServices.cxx
plugins/ControlStatic.cxx
shmem/FairMQMessageSHM.cxx shmem/FairMQMessageSHM.cxx
shmem/FairMQPollerSHM.cxx shmem/FairMQPollerSHM.cxx
shmem/FairMQRegionSHM.cxx shmem/FairMQRegionSHM.cxx

View File

@ -70,6 +70,8 @@ class Plugin
auto ChangeDeviceState(const DeviceStateTransition next) -> void { fPluginServices->ChangeDeviceState(next); } auto ChangeDeviceState(const DeviceStateTransition next) -> void { fPluginServices->ChangeDeviceState(next); }
auto SubscribeToDeviceStateChange(std::function<void(DeviceState)> callback) -> void { fPluginServices->SubscribeToDeviceStateChange(fkName, callback); } auto SubscribeToDeviceStateChange(std::function<void(DeviceState)> callback) -> void { fPluginServices->SubscribeToDeviceStateChange(fkName, callback); }
auto UnsubscribeFromDeviceStateChange() -> void { fPluginServices->UnsubscribeFromDeviceStateChange(fkName); } auto UnsubscribeFromDeviceStateChange() -> void { fPluginServices->UnsubscribeFromDeviceStateChange(fkName); }
auto TakeControl() -> void { fPluginServices->TakeControl(fkName); };
auto ReleaseControl() -> void { fPluginServices->ReleaseControl(fkName); };
// device config API // device config API
// see <fairmq/PluginServices.h> for docs // see <fairmq/PluginServices.h> for docs
@ -97,7 +99,7 @@ class Plugin
} /* namespace fair */ } /* namespace fair */
#define REGISTER_FAIRMQ_PLUGIN(KLASS, NAME, VERSION, MAINTAINER, HOMEPAGE, PROGOPTIONS) \ #define REGISTER_FAIRMQ_PLUGIN(KLASS, NAME, VERSION, MAINTAINER, HOMEPAGE, PROGOPTIONS) \
static auto Make_##NAME##_Plugin(fair::mq::PluginServices* pluginServices) -> std::shared_ptr<KLASS> \ static auto Make_##NAME##_Plugin(fair::mq::PluginServices* pluginServices) -> std::shared_ptr<fair::mq::Plugin> \
{ \ { \
return std::make_shared<KLASS>(std::string{#NAME}, VERSION, std::string{MAINTAINER}, std::string{HOMEPAGE}, pluginServices); \ return std::make_shared<KLASS>(std::string{#NAME}, VERSION, std::string{MAINTAINER}, std::string{HOMEPAGE}, pluginServices); \
} \ } \

View File

@ -126,6 +126,11 @@ auto fair::mq::PluginManager::LoadPlugin(const string& pluginName) -> void
// Mechanism B: dynamic // Mechanism B: dynamic
LoadPluginDynamic(pluginName.substr(2)); LoadPluginDynamic(pluginName.substr(2));
} }
else if (pluginName.substr(0,2) == "s:")
{
// Mechanism C: static (builtin)
LoadPluginStatic(pluginName.substr(2));
}
else else
{ {
// Mechanism B: dynamic (default) // Mechanism B: dynamic (default)
@ -141,6 +146,7 @@ auto fair::mq::PluginManager::LoadPluginPrelinkedDynamic(const string& pluginNam
try try
{ {
LoadSymbols(pluginName, dll::program_location()); LoadSymbols(pluginName, dll::program_location());
fPluginOrder.push_back(pluginName);
} }
catch (boost::system::system_error& e) 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 auto fair::mq::PluginManager::InstantiatePlugin(const string& pluginName) -> void
{ {
if (fPlugins.find(pluginName) == fPlugins.end()) if (fPlugins.find(pluginName) == fPlugins.end())

View File

@ -11,6 +11,7 @@
#include <fairmq/Plugin.h> #include <fairmq/Plugin.h>
#include <fairmq/PluginServices.h> #include <fairmq/PluginServices.h>
#include <fairmq/plugins/Builtin.h>
#include <fairmq/Tools.h> #include <fairmq/Tools.h>
#include <FairMQDevice.h> #include <FairMQDevice.h>
#define BOOST_FILESYSTEM_VERSION 3 #define BOOST_FILESYSTEM_VERSION 3
@ -27,7 +28,6 @@
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <tuple> #include <tuple>
#include <tuple>
#include <vector> #include <vector>
namespace fair namespace fair
@ -43,6 +43,7 @@ namespace mq
* facilitates two plugin mechanisms: * facilitates two plugin mechanisms:
* A prelinked dynamic plugins (shared libraries) * A prelinked dynamic plugins (shared libraries)
* B dynamic plugins (shared libraries) * B dynamic plugins (shared libraries)
* C static plugins (builtin)
*/ */
class PluginManager class PluginManager
{ {
@ -82,6 +83,7 @@ class PluginManager
auto LoadPluginPrelinkedDynamic(const std::string& pluginName) -> void; auto LoadPluginPrelinkedDynamic(const std::string& pluginName) -> void;
auto LoadPluginDynamic(const std::string& pluginName) -> void; auto LoadPluginDynamic(const std::string& pluginName) -> void;
auto LoadPluginStatic(const std::string& pluginName) -> void;
template<typename... Args> template<typename... Args>
auto LoadSymbols(const std::string& pluginName, Args&&... args) -> void auto LoadSymbols(const std::string& pluginName, Args&&... args) -> void
{ {

View File

@ -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 /// @brief Unsubscribe from device state changes
/// @param subscriber id /// @param subscriber id
auto UnsubscribeFromDeviceStateChange(const std::string& subscriber) -> void { fDevice->UnsubscribeFromStateChange(subscriber); } auto UnsubscribeFromDeviceStateChange(const std::string& subscriber) -> void { fDevice->UnsubscribeFromStateChange(subscriber); }

11
fairmq/plugins/Builtin.h Normal file
View File

@ -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 <fairmq/plugins/ControlStatic.h>

View File

@ -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<std::string>("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<std::string>(), "Custom option.");
return plugin_options;
}
} /* namespace plugins */
} /* namespace mq */
} /* namespace fair */

View File

@ -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 <fairmq/Plugin.h>
#include <string>
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 <fairroot@gsi.de>", // Maintainer
"https://github.com/FairRootGroup/FairRoot", // Homepage
ControlStaticPluginProgramOptions // Free function which declares custom program options for the plugin
// signature: () -> boost::optional<boost::program_options::options_description>
)
} /* namespace plugins */
} /* namespace mq */
} /* namespace fair */
#endif /* FAIR_MQ_PLUGINS_CONTROLSTATIC */

View File

@ -122,10 +122,10 @@ add_testsuite(FairMQ.Plugins
TIMEOUT 10 TIMEOUT 10
) )
add_testsuite(FairMQ.PluginsStatic add_testsuite(FairMQ.PluginsPrelinked
SOURCES SOURCES
plugins/runner.cxx plugins/runner.cxx
plugins/_plugin_manager_static.cxx plugins/_plugin_manager_prelink.cxx
LINKS FairMQ FairMQPlugin_test_dummy FairMQPlugin_test_dummy2 LINKS FairMQ FairMQPlugin_test_dummy FairMQPlugin_test_dummy2
TIMEOUT 10 TIMEOUT 10

View File

@ -37,11 +37,11 @@ auto control(shared_ptr<FairMQDevice> device) -> void
} }
} }
TEST(PluginManager, LoadPlugin) TEST(PluginManager, LoadPluginDynamic)
{ {
FairMQProgOptions config{}; FairMQProgOptions config{};
auto device = make_shared<FairMQDevice>();
auto mgr = PluginManager{}; auto mgr = PluginManager{};
auto device = make_shared<FairMQDevice>();
mgr.EmplacePluginServices(&config, device); mgr.EmplacePluginServices(&config, device);
mgr.PrependSearchPath("./lib"); mgr.PrependSearchPath("./lib");
@ -65,6 +65,31 @@ TEST(PluginManager, LoadPlugin)
control(device); control(device);
} }
TEST(PluginManager, LoadPluginStatic)
{
FairMQProgOptions config{};
auto mgr = PluginManager{};
auto device = make_shared<FairMQDevice>();
mgr.EmplacePluginServices(&config, device);
ASSERT_NO_THROW(mgr.LoadPlugin("s:control_static"));
ASSERT_NO_THROW(mgr.InstantiatePlugins());
// check order
const auto expected = vector<string>{"control_static"};
auto actual = vector<string>{};
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) TEST(PluginManager, Factory)
{ {
const auto args = vector<string>{"-l", "debug", "--help", "-S", ">/lib", "</home/user/lib", "/usr/local/lib", "/usr/lib"}; const auto args = vector<string>{"-l", "debug", "--help", "-S", ">/lib", "</home/user/lib", "/usr/local/lib", "/usr/lib"};

View File

@ -8,10 +8,6 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <fairmq/PluginManager.h> #include <fairmq/PluginManager.h>
#include <FairMQDevice.h>
#include <options/FairMQProgOptions.h>
#include <FairMQLogger.h>
#include <vector>
namespace namespace
{ {
@ -19,7 +15,7 @@ namespace
using namespace fair::mq; using namespace fair::mq;
using namespace std; using namespace std;
TEST(PluginManager, LoadPluginStatic) TEST(PluginManager, LoadPluginPrelinkedDynamic)
{ {
auto mgr = PluginManager{}; auto mgr = PluginManager{};