From ad0f050c996eb6abe82cbde32fa6991e7079d65c Mon Sep 17 00:00:00 2001 From: Dennis Klein Date: Thu, 29 Jun 2017 22:53:44 +0200 Subject: [PATCH] FairMQ: Implement PluginServices - Config --- fairmq/CMakeLists.txt | 1 + fairmq/FairMQStateMachine.cxx | 8 +- fairmq/FairMQStateMachine.h | 47 ++----- fairmq/Plugin.h | 17 ++- fairmq/PluginManager.cxx | 2 +- fairmq/PluginManager.h | 7 +- fairmq/PluginServices.cxx | 78 ++++++++++- fairmq/PluginServices.h | 193 +++++++++++++------------- fairmq/options/FairMQEventManager.h | 13 +- fairmq/options/FairMQProgOptions.h | 42 +++++- fairmq/options/FairProgOptions.cxx | 6 +- fairmq/options/FairProgOptions.h | 6 +- fairmq/runFairMQDevice.h | 8 +- fairmq/test/helper/plugins/dummy.h.in | 6 +- 14 files changed, 265 insertions(+), 169 deletions(-) diff --git a/fairmq/CMakeLists.txt b/fairmq/CMakeLists.txt index 3f610633..52cc8fce 100644 --- a/fairmq/CMakeLists.txt +++ b/fairmq/CMakeLists.txt @@ -94,6 +94,7 @@ set(FAIRMQ_HEADER_FILES tools/CppSTL.h tools/Network.h tools/runSimpleMQStateMachine.h + tools/Strings.h zeromq/FairMQMessageZMQ.h zeromq/FairMQPollerZMQ.h zeromq/FairMQSocketZMQ.h diff --git a/fairmq/FairMQStateMachine.cxx b/fairmq/FairMQStateMachine.cxx index c9ca76db..3779e317 100644 --- a/fairmq/FairMQStateMachine.cxx +++ b/fairmq/FairMQStateMachine.cxx @@ -226,13 +226,13 @@ bool FairMQStateMachine::WaitForEndOfStateForMs(std::string event, int durationI return WaitForEndOfStateForMs(GetEventNumber(event), durationInMs); } -void FairMQStateMachine::OnStateChange(const std::string& key, std::function callback) +void FairMQStateMachine::SubscribeToStateChange(const std::string& key, std::function callback) { - fStateChangeCallbacksMap.insert({key, fStateChangeCallback.connect(callback)}); + fStateChangeCallbacks.insert({key, fStateChangeCallback.connect(callback)}); } void FairMQStateMachine::UnsubscribeFromStateChange(const std::string& key) { - fStateChangeCallbacksMap.at(key).disconnect(); - //fStateChangeCallbacksMap.erase(key); + fStateChangeCallbacks.at(key).disconnect(); + fStateChangeCallbacks.erase(key); } diff --git a/fairmq/FairMQStateMachine.h b/fairmq/FairMQStateMachine.h index 9aee47d0..2d5e07ca 100644 --- a/fairmq/FairMQStateMachine.h +++ b/fairmq/FairMQStateMachine.h @@ -86,7 +86,7 @@ struct FairMQFSM_ : public msmf::state_machine_def , fState() , fChangeStateMutex() , fStateChangeCallback() - , fStateChangeCallbacksMap() + , fStateChangeCallbacks() {} // Destructor @@ -134,7 +134,7 @@ struct FairMQFSM_ : public msmf::state_machine_def { LOG(STATE) << "Entering IDLE state"; fsm.fState = IDLE; - if (!fsm.fStateChangeCallback.empty()) + if (!fsm.fStateChangeCallbacks.empty()) { fsm.fStateChangeCallback(IDLE); } @@ -519,39 +519,10 @@ struct FairMQFSM_ : public msmf::state_machine_def } } - std::string GetCurrentStateName() const - { - return GetStateName(fState); - } - - int GetCurrentState() const - { - return fState; - } - - bool CheckCurrentState(int state) const - { - if (state == fState) - { - return true; - } - else - { - return false; - } - } - - bool CheckCurrentState(std::string state) const - { - if (state == GetCurrentStateName()) - { - return true; - } - else - { - return false; - } - } + std::string GetCurrentStateName() const { return GetStateName(fState); } + int GetCurrentState() const { return fState; } + bool CheckCurrentState(int state) const { return state == fState; } + bool CheckCurrentState(std::string state) const { return state == GetCurrentStateName(); } // this is to run certain functions in a separate thread std::thread fWorkerThread; @@ -570,7 +541,7 @@ struct FairMQFSM_ : public msmf::state_machine_def std::mutex fChangeStateMutex; boost::signals2::signal fStateChangeCallback; - std::unordered_map fStateChangeCallbacksMap; + std::unordered_map fStateChangeCallbacks; }; // reactivate the warning for non-virtual destructor @@ -619,8 +590,8 @@ class FairMQStateMachine : public FairMQFSM::FairMQFSM bool WaitForEndOfStateForMs(int state, int durationInMs); bool WaitForEndOfStateForMs(std::string state, int durationInMs); - void OnStateChange(const std::string&, std::function callback); - void UnsubscribeFromStateChange(const std::string&); + void SubscribeToStateChange(const std::string& key, std::function callback); + void UnsubscribeFromStateChange(const std::string& key); }; #endif /* FAIRMQSTATEMACHINE_H_ */ diff --git a/fairmq/Plugin.h b/fairmq/Plugin.h index 9519653d..b1cdb928 100644 --- a/fairmq/Plugin.h +++ b/fairmq/Plugin.h @@ -36,6 +36,8 @@ class Plugin { public: + using ProgOptions = boost::optional; + struct Version { const int fkMajor, fkMinor, fkPatch; @@ -67,9 +69,10 @@ class Plugin << "maintainer '" << p.GetMaintainer() << "', " << "homepage '" << p.GetHomepage() << "'"; } - static auto NoProgramOptions() -> const boost::optional { return boost::none; } + static auto NoProgramOptions() -> ProgOptions { return boost::none; } // device control API + // see for docs using DeviceState = fair::mq::PluginServices::DeviceState; using DeviceStateTransition = fair::mq::PluginServices::DeviceStateTransition; auto ToDeviceState(const std::string& state) const -> fair::mq::PluginServices::DeviceState { return fPluginServices.ToDeviceState(state); } @@ -79,6 +82,18 @@ class Plugin auto SubscribeToDeviceStateChange(std::function callback) -> void { fPluginServices.SubscribeToDeviceStateChange(fkName, callback); } auto UnsubscribeFromDeviceStateChange() -> void { fPluginServices.UnsubscribeFromDeviceStateChange(fkName); } + // device config API + // see for docs + template + auto SetProperty(const std::string& key, T val) -> void { fPluginServices.SetProperty(key, val); } + template + auto GetProperty(const std::string& key) const -> T { return fPluginServices.GetProperty(key); } + auto GetPropertyAsString(const std::string& key) const -> std::string { return fPluginServices.GetPropertyAsString(key); } + template + auto SubscribeToPropertyChange(std::function callback) const -> void { fPluginServices.SubscribeToPropertyChange(fkName, callback); } + template + auto UnsubscribeFromPropertyChange() -> void { fPluginServices.UnsubscribeFromPropertyChange(fkName); } + private: const std::string fkName; diff --git a/fairmq/PluginManager.cxx b/fairmq/PluginManager.cxx index fc8fc7cc..393ec12a 100644 --- a/fairmq/PluginManager.cxx +++ b/fairmq/PluginManager.cxx @@ -57,7 +57,7 @@ auto fair::mq::PluginManager::PrependSearchPath(const fs::path& path) -> void fSearchPaths.insert(begin(fSearchPaths), path); } -auto fair::mq::PluginManager::ProgramOptions() -> const po::options_description +auto fair::mq::PluginManager::ProgramOptions() -> po::options_description { auto plugin_options = po::options_description{"Plugin Manager"}; plugin_options.add_options() diff --git a/fairmq/PluginManager.h b/fairmq/PluginManager.h index 610c440e..d5b5294d 100644 --- a/fairmq/PluginManager.h +++ b/fairmq/PluginManager.h @@ -49,7 +49,6 @@ class PluginManager public: using PluginFactory = std::shared_ptr(PluginServices&); - using PluginProgOptions = const boost::optional(); PluginManager(); @@ -65,14 +64,14 @@ class PluginManager auto InstantiatePlugins() -> void; struct PluginInstantiationError : std::runtime_error { using std::runtime_error::runtime_error; }; - static auto ProgramOptions() -> const boost::program_options::options_description; + static auto ProgramOptions() -> boost::program_options::options_description; static auto MakeFromCommandLineOptions(const std::vector) -> std::shared_ptr; struct ProgramOptionsParseError : std::runtime_error { using std::runtime_error::runtime_error; }; static auto LibPrefix() -> const std::string& { return fgkLibPrefix; } auto ForEachPlugin(std::function func) -> void { for(const auto& p : fPluginOrder) { func(*fPlugins[p]); } } - auto ForEachPluginProgOptions(std::function func) const -> void { for(const auto& pair : fPluginProgOptions) { func(pair.second); } } + auto ForEachPluginProgOptions(std::function func) const -> void { for(const auto& pair : fPluginProgOptions) { func(pair.second); } } template auto EmplacePluginServices(Args&&... args) -> void { fPluginServices = fair::mq::tools::make_unique(std::forward(args)...); }; @@ -100,7 +99,7 @@ class PluginManager { fPluginProgOptions.insert({ pluginName, - lib.get_alias(ToString("get_", pluginName, "_plugin_progoptions"))().value() + lib.get_alias(ToString("get_", pluginName, "_plugin_progoptions"))().value() }); } catch (const boost::bad_optional_access& e) { /* just ignore, if no prog options are declared */ } diff --git a/fairmq/PluginServices.cxx b/fairmq/PluginServices.cxx index d5568b0f..619a0f17 100644 --- a/fairmq/PluginServices.cxx +++ b/fairmq/PluginServices.cxx @@ -8,4 +8,80 @@ #include -using namespace std; +using fair::mq::PluginServices; + +const std::unordered_map PluginServices::fkDeviceStateStrMap = { + {"OK", DeviceState::Ok}, + {"ERROR", DeviceState::Error}, + {"IDLE", DeviceState::Idle}, + {"INITIALIZING DEVICE", DeviceState::InitializingDevice}, + {"DEVICE READY", DeviceState::DeviceReady}, + {"INITIALIZING TASK", DeviceState::InitializingTask}, + {"READY", DeviceState::Ready}, + {"RUNNING", DeviceState::Running}, + {"PAUSED", DeviceState::Paused}, + {"RESETTING TASK", DeviceState::ResettingTask}, + {"RESETTING DEVICE", DeviceState::ResettingDevice}, + {"EXITING", DeviceState::Exiting} +}; +const std::unordered_map PluginServices::fkStrDeviceStateMap = { + {DeviceState::Ok, "OK"}, + {DeviceState::Error, "ERROR"}, + {DeviceState::Idle, "IDLE"}, + {DeviceState::InitializingDevice, "INITIALIZING DEVICE"}, + {DeviceState::DeviceReady, "DEVICE READY"}, + {DeviceState::InitializingTask, "INITIALIZING TASK"}, + {DeviceState::Ready, "READY"}, + {DeviceState::Running, "RUNNING"}, + {DeviceState::Paused, "PAUSED"}, + {DeviceState::ResettingTask, "RESETTING TASK"}, + {DeviceState::ResettingDevice, "RESETTING DEVICE"}, + {DeviceState::Exiting, "EXITING"} +}; +const std::unordered_map PluginServices::fkDeviceStateTransitionStrMap = { + {"INIT DEVICE", DeviceStateTransition::InitDevice}, + {"INIT TASK", DeviceStateTransition::InitTask}, + {"RUN", DeviceStateTransition::Run}, + {"PAUSE", DeviceStateTransition::Pause}, + {"STOP", DeviceStateTransition::Stop}, + {"RESET TASK", DeviceStateTransition::ResetTask}, + {"RESET DEVICE", DeviceStateTransition::ResetDevice}, + {"END", DeviceStateTransition::End}, + {"ERROR FOUND", DeviceStateTransition::ErrorFound}, +}; +const std::unordered_map PluginServices::fkStrDeviceStateTransitionMap = { + {DeviceStateTransition::InitDevice, "INIT DEVICE"}, + {DeviceStateTransition::InitTask, "INIT TASK"}, + {DeviceStateTransition::Run, "RUN"}, + {DeviceStateTransition::Pause, "PAUSE"}, + {DeviceStateTransition::Stop, "STOP"}, + {DeviceStateTransition::ResetTask, "RESET TASK"}, + {DeviceStateTransition::ResetDevice, "RESET DEVICE"}, + {DeviceStateTransition::End, "END"}, + {DeviceStateTransition::ErrorFound, "ERROR FOUND"}, +}; +const std::unordered_map PluginServices::fkDeviceStateMap = { + {FairMQDevice::OK, DeviceState::Ok}, + {FairMQDevice::ERROR, DeviceState::Error}, + {FairMQDevice::IDLE, DeviceState::Idle}, + {FairMQDevice::INITIALIZING_DEVICE, DeviceState::InitializingDevice}, + {FairMQDevice::DEVICE_READY, DeviceState::DeviceReady}, + {FairMQDevice::INITIALIZING_TASK, DeviceState::InitializingTask}, + {FairMQDevice::READY, DeviceState::Ready}, + {FairMQDevice::RUNNING, DeviceState::Running}, + {FairMQDevice::PAUSED, DeviceState::Paused}, + {FairMQDevice::RESETTING_TASK, DeviceState::ResettingTask}, + {FairMQDevice::RESETTING_DEVICE, DeviceState::ResettingDevice}, + {FairMQDevice::EXITING, DeviceState::Exiting} +}; +const std::unordered_map PluginServices::fkDeviceStateTransitionMap = { + {DeviceStateTransition::InitDevice, FairMQDevice::INIT_DEVICE}, + {DeviceStateTransition::InitTask, FairMQDevice::INIT_TASK}, + {DeviceStateTransition::Run, FairMQDevice::RUN}, + {DeviceStateTransition::Pause, FairMQDevice::PAUSE}, + {DeviceStateTransition::Stop, FairMQDevice::STOP}, + {DeviceStateTransition::ResetTask, FairMQDevice::RESET_TASK}, + {DeviceStateTransition::ResetDevice, FairMQDevice::RESET_DEVICE}, + {DeviceStateTransition::End, FairMQDevice::END}, + {DeviceStateTransition::ErrorFound, FairMQDevice::ERROR_FOUND} +}; diff --git a/fairmq/PluginServices.h b/fairmq/PluginServices.h index 07d0fd73..cb7d781b 100644 --- a/fairmq/PluginServices.h +++ b/fairmq/PluginServices.h @@ -9,9 +9,9 @@ #ifndef FAIR_MQ_PLUGINSERVICES_H #define FAIR_MQ_PLUGINSERVICES_H +#include #include #include -#include #include #include #include @@ -65,144 +65,141 @@ class PluginServices PluginServices(FairMQProgOptions& config, FairMQDevice& device) : fDevice{device} , fConfig{config} - , fConfigEnabled{false} - , fkDeviceStateStrMap{ - {"Ok", DeviceState::Ok}, - {"Error", DeviceState::Error}, - {"Idle", DeviceState::Idle}, - {"InitializingDevice", DeviceState::InitializingDevice}, - {"DeviceReady", DeviceState::DeviceReady}, - {"InitializingTask", DeviceState::InitializingTask}, - {"Ready", DeviceState::Ready}, - {"Running", DeviceState::Running}, - {"Paused", DeviceState::Paused}, - {"ResettingTask", DeviceState::ResettingTask}, - {"ResettingDevice", DeviceState::ResettingDevice}, - {"Exiting", DeviceState::Exiting} - } - , fkStrDeviceStateMap{ - {DeviceState::Ok, "Ok"}, - {DeviceState::Error, "Error"}, - {DeviceState::Idle, "Idle"}, - {DeviceState::InitializingDevice, "InitializingDevice"}, - {DeviceState::DeviceReady, "DeviceReady"}, - {DeviceState::InitializingTask, "InitializingTask"}, - {DeviceState::Ready, "Ready"}, - {DeviceState::Running, "Running"}, - {DeviceState::Paused, "Paused"}, - {DeviceState::ResettingTask, "ResettingTask"}, - {DeviceState::ResettingDevice, "ResettingDevice"}, - {DeviceState::Exiting, "Exiting"} - } - , fkDeviceStateMap{ - {FairMQDevice::OK, DeviceState::Ok}, - {FairMQDevice::ERROR, DeviceState::Error}, - {FairMQDevice::IDLE, DeviceState::Idle}, - {FairMQDevice::INITIALIZING_DEVICE, DeviceState::InitializingDevice}, - {FairMQDevice::DEVICE_READY, DeviceState::DeviceReady}, - {FairMQDevice::INITIALIZING_TASK, DeviceState::InitializingTask}, - {FairMQDevice::READY, DeviceState::Ready}, - {FairMQDevice::RUNNING, DeviceState::Running}, - {FairMQDevice::PAUSED, DeviceState::Paused}, - {FairMQDevice::RESETTING_TASK, DeviceState::ResettingTask}, - {FairMQDevice::RESETTING_DEVICE, DeviceState::ResettingDevice}, - {FairMQDevice::EXITING, DeviceState::Exiting} - } - , fkDeviceStateTransitionMap{ - {DeviceStateTransition::InitDevice, FairMQDevice::INIT_DEVICE}, - {DeviceStateTransition::InitTask, FairMQDevice::INIT_TASK}, - {DeviceStateTransition::Run, FairMQDevice::RUN}, - {DeviceStateTransition::Pause, FairMQDevice::PAUSE}, - {DeviceStateTransition::Stop, FairMQDevice::STOP}, - {DeviceStateTransition::ResetTask, FairMQDevice::RESET_TASK}, - {DeviceStateTransition::ResetDevice, FairMQDevice::RESET_DEVICE}, - {DeviceStateTransition::End, FairMQDevice::END}, - {DeviceStateTransition::ErrorFound, FairMQDevice::ERROR_FOUND} - } { } - // Control + // Control API /// @brief Convert string to DeviceState /// @param state to convert /// @return DeviceState enum entry /// @throw std::out_of_range if a string cannot be resolved to a DeviceState - auto ToDeviceState(const std::string& state) const -> DeviceState - { - return fkDeviceStateStrMap.at(state); - } + static auto ToDeviceState(const std::string& state) -> DeviceState { return fkDeviceStateStrMap.at(state); } + + /// @brief Convert string to DeviceStateTransition + /// @param transition to convert + /// @return DeviceStateTransition enum entry + /// @throw std::out_of_range if a string cannot be resolved to a DeviceStateTransition + static auto ToDeviceStateTransition(const std::string& transition) -> DeviceStateTransition { return fkDeviceStateTransitionStrMap.at(transition); } /// @brief Convert DeviceState to string - /// @param string to convert + /// @param state to convert /// @return string representation of DeviceState enum entry - auto ToStr(DeviceState state) const -> std::string - { - return fkStrDeviceStateMap.at(state); - } + static auto ToStr(DeviceState state) -> std::string { return fkStrDeviceStateMap.at(state); } + friend auto operator<<(std::ostream& os, const DeviceState& state) -> std::ostream& { return os << ToStr(state); } + + /// @brief Convert DeviceStateTransition to string + /// @param transition to convert + /// @return string representation of DeviceStateTransition enum entry + static auto ToStr(DeviceStateTransition transition) -> std::string { return fkStrDeviceStateTransitionMap.at(transition); } + friend auto operator<<(std::ostream& os, const DeviceStateTransition& transition) -> std::ostream& { return os << ToStr(transition); } /// @return current device state - auto GetCurrentDeviceState() const -> DeviceState - { - return fkDeviceStateMap.at(static_cast(fDevice.GetCurrentState())); - } + auto GetCurrentDeviceState() const -> DeviceState { return fkDeviceStateMap.at(static_cast(fDevice.GetCurrentState())); } - /// @brief Trigger a device state transition + /// @brief Request a device state transition /// @param next state transition /// /// The state transition may not happen immediately, but when the current state evaluates the /// pending transition event and terminates. In other words, the device states are scheduled cooperatively. - auto ChangeDeviceState(const DeviceStateTransition next) -> void - { - fDevice.ChangeState(fkDeviceStateTransitionMap.at(next)); - } + auto ChangeDeviceState(const DeviceStateTransition next) -> void { fDevice.ChangeState(fkDeviceStateTransitionMap.at(next)); } /// @brief Subscribe with a callback to device state changes - /// @param InputMsgCallback + /// @param subscriber id + /// @param callback /// /// The callback will be called at the beginning of a new state. The callback is called from the thread /// the state is running in. - auto SubscribeToDeviceStateChange(const std::string& key, std::function callback) -> void + auto SubscribeToDeviceStateChange(const std::string& subscriber, std::function callback) -> void { - fDevice.OnStateChange(key, [&,callback](FairMQDevice::State newState){ + fDevice.SubscribeToStateChange(subscriber, [&,callback](FairMQDevice::State newState){ callback(fkDeviceStateMap.at(newState)); }); } - auto UnsubscribeFromDeviceStateChange(const std::string& key) -> void + /// @brief Unsubscribe from device state changes + /// @param subscriber id + auto UnsubscribeFromDeviceStateChange(const std::string& subscriber) -> void { fDevice.UnsubscribeFromStateChange(subscriber); } + + + // Config API + + /// @brief Set config property + /// @param key + /// @param val + /// @throws fair::mq::PluginServices::InvalidStateError if method is called in unsupported device states + /// + /// Setting a config property will store the value in the FairMQ internal config store and notify any subscribers about the update. + /// It is property dependent, if the call to this method will have an immediate, delayed or any effect at all. + template + auto SetProperty(const std::string& key, T val) -> void { - fDevice.UnsubscribeFromStateChange(key); + auto currentState = GetCurrentDeviceState(); + if (currentState == DeviceState::InitializingDevice) + { + fConfig.SetValue(key, val); + } + else + { + throw InvalidStateError{tools::ToString("PluginServices::SetProperty is not supported in device state ", currentState, ". Supported state is ", DeviceState::InitializingDevice, ".")}; + } } + struct InvalidStateError : std::runtime_error { using std::runtime_error::runtime_error; }; + /// @brief Read config property + /// @param key + /// @return config property value + /// + /// TODO Currently, if a non-existing key is requested and a default constructed object is returned. + /// This behaviour will be changed in the future to throw an exception in that case to provide a proper sentinel. + template + auto GetProperty(const std::string& key) const -> T { return fConfig.GetValue(key); } - //// Configuration + /// @brief Read config property as string + /// @param key + /// @return config property value converted to string + /// + /// If a type is not supported, the user can provide support by overloading the ostream operator for this type + auto GetPropertyAsString(const std::string& key) const -> std::string { return fConfig.GetStringValue(key); } - //// Writing only works during Initializing_device state - //template - //auto SetProperty(const std::string& key, T val) -> void; + /// @brief Subscribe to property updates of type T + /// @param subscriber + /// @param callback function + /// + /// While PluginServices provides the SetProperty method which can update properties only during certain device states, there are + /// other methods in a FairMQ device that can update properties at any time. Therefore, the callback implementation should expect to be called in any + /// device state. + // template + // auto SubscribeToPropertyChange( + // const std::string& subscriber, + // std::functionkey*/, const T /*newValue<])> callback + // ) const -> void + // { + // fConfig.Subscribe(subscriber, callback); + // } + // + // /// @brief Unsubscribe from property updates of type T + // /// @param subscriber + // template + // auto UnsubscribeFromPropertyChange(const std::string& subscriber) -> void { fConfig.Unsubscribe(subscriber); } + // + // TODO Fix property subscription + // TODO Property iterator - //template - //auto GetProperty(const std::string& key) const -> T; - //auto GetPropertyAsString(const std::string& key) const -> std::string; - - //template - //auto SubscribeToPropertyChange( - //const std::string& key, - //std::functionkey*/, const T /*newValue<])> callback - //) const -> void; - //auto UnsubscribeFromPropertyChange(const std::string& key) -> void; + static const std::unordered_map fkDeviceStateStrMap; + static const std::unordered_map fkStrDeviceStateMap; + static const std::unordered_map fkDeviceStateTransitionStrMap; + static const std::unordered_map fkStrDeviceStateTransitionMap; + static const std::unordered_map fkDeviceStateMap; + static const std::unordered_map fkDeviceStateTransitionMap; private: FairMQProgOptions& fConfig; FairMQDevice& fDevice; - std::atomic fConfigEnabled; - const std::unordered_map fkDeviceStateStrMap; - const std::unordered_map fkStrDeviceStateMap; - const std::unordered_map fkDeviceStateMap; - const std::unordered_map fkDeviceStateTransitionMap; }; /* class PluginServices */ + } /* namespace mq */ } /* namespace fair */ diff --git a/fairmq/options/FairMQEventManager.h b/fairmq/options/FairMQEventManager.h index c1f9e695..a1e4629a 100644 --- a/fairmq/options/FairMQEventManager.h +++ b/fairmq/options/FairMQEventManager.h @@ -16,6 +16,8 @@ #ifndef FAIRMQEVENTMANAGER_H #define FAIRMQEVENTMANAGER_H +#include + #include #include #include @@ -97,7 +99,7 @@ class FairMQEventManager } template - void Disonnect(const std::string& key) + void Disconnect(const std::string& key) { GetSlot(key).disconnect(); } @@ -111,14 +113,7 @@ class FairMQEventManager template bool EventKeyFound(const std::string& key) { - if (fEventMap.find(std::pair(event, key)) != fEventMap.end()) - { - return true; - } - else - { - return false; - } + return fEventMap.find(std::pair(event, key)) != fEventMap.end(); } private: diff --git a/fairmq/options/FairMQProgOptions.h b/fairmq/options/FairMQProgOptions.h index 6a61e3ba..26cdc705 100644 --- a/fairmq/options/FairMQProgOptions.h +++ b/fairmq/options/FairMQProgOptions.h @@ -205,6 +205,37 @@ class FairMQProgOptions : public FairProgOptions , public FairMQEventManager return 0; } + template + int SetValue(const std::string& key, T val) + { + std::unique_lock lock(fConfigMutex); + + // update variable map + UpdateVarMap::type>(key, val); + + // update FairMQChannel map, check first if data are int or string + if (std::is_same::value || std::is_same::value) + { + if (fMQKeyMap.count(key)) + { + std::string channelName; + int index = 0; + std::string member; + std::tie(channelName, index, member) = fMQKeyMap.at(key); + UpdateChannelMap(channelName, index, member, val); + } + } + + // execute stored function of a given key if exist + //if (std::is_same::value || std::is_same::value)//if one wants to restrict type + if (EventKeyFound(key)) + { + EmitUpdate::type>(key, val); + } + + return 0; + } + template void Subscribe(const std::string& key, F&& func) const { @@ -215,10 +246,19 @@ class FairMQProgOptions : public FairProgOptions , public FairMQEventManager if (fVarMap.count(key)) { - FairMQEventManager::Connect(key, std::forward(func)); + Connect(key, std::forward(func)); } } + template + void Unsubscribe(const std::string& key) const + { + std::unique_lock lock(fConfigMutex); + + Disconnect(key); + } + + /* template void Subscribe(const std::string& key, F&& func) diff --git a/fairmq/options/FairProgOptions.cxx b/fairmq/options/FairProgOptions.cxx index 67f5619c..7d36985a 100644 --- a/fairmq/options/FairProgOptions.cxx +++ b/fairmq/options/FairProgOptions.cxx @@ -59,7 +59,7 @@ FairProgOptions::~FairProgOptions() /// ////////////////////////////////////////////////////////////////////////////////////////////////////// /// Add option descriptions -int FairProgOptions::AddToCmdLineOptions(const po::options_description& optDesc, bool visible) +int FairProgOptions::AddToCmdLineOptions(const po::options_description optDesc, bool visible) { fCmdLineOptions.add(optDesc); if (visible) @@ -69,7 +69,7 @@ int FairProgOptions::AddToCmdLineOptions(const po::options_description& optDesc, return 0; } -int FairProgOptions::AddToCfgFileOptions(const po::options_description& optDesc, bool visible) +int FairProgOptions::AddToCfgFileOptions(const po::options_description optDesc, bool visible) { //if UseConfigFile() not yet called, then enable it with required file name to be provided by command line if (!fUseConfigFile) @@ -100,7 +100,7 @@ po::options_description& FairProgOptions::GetEnvironmentOptions() return fEnvironmentDesc; } -int FairProgOptions::AddToEnvironmentOptions(const po::options_description& optDesc) +int FairProgOptions::AddToEnvironmentOptions(const po::options_description optDesc) { fEnvironmentDesc.add(optDesc); return 0; diff --git a/fairmq/options/FairProgOptions.h b/fairmq/options/FairProgOptions.h index 5e9a0d9a..006931b2 100644 --- a/fairmq/options/FairProgOptions.h +++ b/fairmq/options/FairProgOptions.h @@ -65,9 +65,9 @@ class FairProgOptions virtual ~FairProgOptions(); // add options_description - int AddToCmdLineOptions(const po::options_description& optDesc, bool visible = true); - int AddToCfgFileOptions(const po::options_description& optDesc, bool visible = true); - int AddToEnvironmentOptions(const po::options_description& optDesc); + int AddToCmdLineOptions(const po::options_description optDesc, bool visible = true); + int AddToCfgFileOptions(const po::options_description optDesc, bool visible = true); + int AddToEnvironmentOptions(const po::options_description optDesc); po::options_description& GetCmdLineOptions(); po::options_description& GetCfgFileOptions(); po::options_description& GetEnvironmentOptions(); diff --git a/fairmq/runFairMQDevice.h b/fairmq/runFairMQDevice.h index 990b9e5b..861023c1 100644 --- a/fairmq/runFairMQDevice.h +++ b/fairmq/runFairMQDevice.h @@ -47,14 +47,16 @@ int main(int argc, const char** argv) boost::program_options::options_description customOptions("Custom options"); addCustomOptions(customOptions); + // Plugin manager needs to be destroyed after config ! + // TODO Investigate, why + auto pluginManager = fair::mq::PluginManager::MakeFromCommandLineOptions(fair::mq::tools::ToStrVector(argc, argv)); FairMQProgOptions config; config.AddToCmdLineOptions(customOptions); - auto pluginManager = fair::mq::PluginManager::MakeFromCommandLineOptions(fair::mq::tools::ToStrVector(argc, argv)); - config.AddToCmdLineOptions(pluginManager->ProgramOptions()); - pluginManager->ForEachPluginProgOptions([&config](const boost::program_options::options_description& options){ + pluginManager->ForEachPluginProgOptions([&config](boost::program_options::options_description options){ config.AddToCmdLineOptions(options); }); + config.AddToCmdLineOptions(pluginManager->ProgramOptions()); config.ParseAll(argc, argv, true); diff --git a/fairmq/test/helper/plugins/dummy.h.in b/fairmq/test/helper/plugins/dummy.h.in index 335c87a6..0bbf34aa 100644 --- a/fairmq/test/helper/plugins/dummy.h.in +++ b/fairmq/test/helper/plugins/dummy.h.in @@ -47,12 +47,12 @@ class DummyPlugin : public fair::mq::Plugin } }; /* class DummyPlugin */ -auto DummyPluginProgramOptions() -> const boost::optional +auto DummyPluginProgramOptions() -> Plugin::ProgOptions { auto plugin_options = boost::program_options::options_description{"Dummy Plugin"}; plugin_options.add_options() - ("custom-dummy-option", value(), "Cool custom option."); - ("custom-dummy-option2", value(), "Another cool custom option."); + ("custom-dummy-option", boost::program_options::value(), "Cool custom option."); + ("custom-dummy-option2", boost::program_options::value(), "Another cool custom option."); return plugin_options; }