diff options
-rw-r--r-- | include/gras/CMakeLists.txt | 2 | ||||
-rw-r--r-- | include/gras/block.hpp | 75 | ||||
-rw-r--r-- | include/gras/detail/block.hpp | 35 | ||||
-rw-r--r-- | include/gras/detail/property.hpp | 54 | ||||
-rw-r--r-- | lib/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/block_props.cpp | 87 | ||||
-rw-r--r-- | lib/gras_impl/block_actor.hpp | 7 | ||||
-rw-r--r-- | lib/gras_impl/messages.hpp | 9 | ||||
-rw-r--r-- | lib/register_messages.cpp | 1 |
9 files changed, 271 insertions, 0 deletions
diff --git a/include/gras/CMakeLists.txt b/include/gras/CMakeLists.txt index 301f96a..462b0ff 100644 --- a/include/gras/CMakeLists.txt +++ b/include/gras/CMakeLists.txt @@ -28,6 +28,8 @@ install(FILES install(FILES + detail/block.hpp + detail/property.hpp detail/sbuffer.hpp detail/work_buffer.hpp diff --git a/include/gras/block.hpp b/include/gras/block.hpp index 1c6516d..d3e9848 100644 --- a/include/gras/block.hpp +++ b/include/gras/block.hpp @@ -9,6 +9,7 @@ #include <gras/tags.hpp> #include <gras/work_buffer.hpp> #include <gras/buffer_queue.hpp> +#include <gras/detail/property.hpp> #include <vector> #include <string> @@ -214,6 +215,71 @@ struct GRAS_API Block : Element PMCC pop_input_msg(const size_t which_input); /******************************************************************* + * The property interface: + * Provides polymorphic, thread-safe access to block properties. + ******************************************************************/ + + /*! + * Register property get and set methods into the property interface. + * Call register_property() from the contructor of the block. + * + * Note: It is safe for the user to register a NULL function if the user + * wishes to not register a getter or setter for a particular property. + * + * Example register usage: + * this->register_property("foo", &MyBlock::get_foo, &MyBlock::set_foo); + * + * Example method declarations: + * int get_foo(void); + * void set_foo(const int &new_foo); + * + * \param key the string to identify this property + * \param get the class method to get the property + * \param set the class method to set the property + */ + template <typename ClassType, typename ValueType> + void register_property( + const std::string &key, + ValueType(ClassType::*get)(void), + void(ClassType::*set)(const ValueType &) + ); + + /*! + * Set the value of a registered property. + * + * This call is synchronous and will not return until + * the block has actually called the registered set operation. + * + * Note: the user must be careful to only use a value + * that is of the exact type associated with this property. + * Otherwise, set_property with throw a type error. + * + * Example with template argument to be type explicit: + * my_block->set_property<size_t>("foo", 42); + * + * \param key the string to identify this property + * \param value the new value to set to this property + */ + template <typename ValueType> + void set_property(const std::string &key, const ValueType &value); + + /*! + * Get the value of a registered property. + * + * Note: the user must specify the correct value type + * that is of the exact type associated with this property. + * Otherwise, get_property with throw a type error. + * + * Example with template argument to be type explicit: + * const size_t foo = my_block->get_property<size_t>("foo"); + * + * \param key the string to identify this property + * \return the value of this property + */ + template <typename ValueType> + ValueType get_property(const std::string &key); + + /******************************************************************* * Work related routines and fail states ******************************************************************/ @@ -392,8 +458,17 @@ struct GRAS_API Block : Element const SBufferConfig &config ); + /******************************************************************* + * private implementation guts for template support + ******************************************************************/ + void _register_property(const std::string &, PropertyRegistrySptr); + void _set_property(const std::string &, const PMCC &); + PMCC _get_property(const std::string &); + }; } //namespace gras +#include <gras/detail/block.hpp> + #endif /*INCLUDED_GRAS_BLOCK_HPP*/ diff --git a/include/gras/detail/block.hpp b/include/gras/detail/block.hpp new file mode 100644 index 0000000..a8bc2b1 --- /dev/null +++ b/include/gras/detail/block.hpp @@ -0,0 +1,35 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#ifndef INCLUDED_GRAS_DETAIL_BLOCK_HPP +#define INCLUDED_GRAS_DETAIL_BLOCK_HPP + +namespace gras +{ + +template <typename ClassType, typename ValueType> +GRAS_FORCE_INLINE void Block::register_property( + const std::string &key, + ValueType(ClassType::*get)(void), + void(ClassType::*set)(const ValueType &) +) +{ + PropertyRegistrySptr pr; + pr.reset(new PropertyRegistryImpl<ClassType, ValueType>(this, get, set)); + this->_register_property(key, pr); +} + +template <typename ValueType> +GRAS_FORCE_INLINE void Block::set_property(const std::string &key, const ValueType &value) +{ + return this->_set_property(key, PMC_M(value)); +} + +template <typename ValueType> +GRAS_FORCE_INLINE ValueType Block::get_property(const std::string &key) +{ + return this->_get_property(key).as<ValueType>(); +} + +} //namespace gras + +#endif /*INCLUDED_GRAS_DETAIL_BLOCK_HPP*/ diff --git a/include/gras/detail/property.hpp b/include/gras/detail/property.hpp new file mode 100644 index 0000000..fd13025 --- /dev/null +++ b/include/gras/detail/property.hpp @@ -0,0 +1,54 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#ifndef INCLUDED_GRAS_DETAIL_PROPERTY_HPP +#define INCLUDED_GRAS_DETAIL_PROPERTY_HPP + +#include <gras/gras.hpp> +#include <PMC/PMC.hpp> +#include <boost/shared_ptr.hpp> + +namespace gras +{ + +struct GRAS_API PropertyRegistry +{ + PropertyRegistry(void); + virtual ~PropertyRegistry(void); + virtual void set(const PMCC &) = 0; + virtual PMCC get(void) = 0; +}; + +typedef boost::shared_ptr<PropertyRegistry> PropertyRegistrySptr; + +template <typename ClassType, typename ValueType> +struct PropertyRegistryImpl : PropertyRegistry +{ + PropertyRegistryImpl( + ClassType *my_class, + ValueType(ClassType::*getter)(void), + void(ClassType::*setter)(const ValueType &) + ): + _my_class(my_class), + _getter(getter), + _setter(setter) + {} + virtual ~PropertyRegistryImpl(void){} + + void set(const PMCC &value) + { + return _setter(_my_class, value.as<ValueType>()); + } + + PMCC get(void) + { + return PMC_M(_getter(_my_class)); + } + + ClassType *_my_class; + ValueType(ClassType::*_getter)(void); + void(ClassType::*_setter)(const ValueType &); +}; + +} //namespace gras + +#endif /*INCLUDED_GRAS_DETAIL_PROPERTY_HPP*/ diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index ade4f82..e667570 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -45,6 +45,7 @@ list(APPEND GRAS_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/buffer_queue_pool.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tags.cpp ${CMAKE_CURRENT_SOURCE_DIR}/block.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/block_props.cpp ${CMAKE_CURRENT_SOURCE_DIR}/block_actor.cpp ${CMAKE_CURRENT_SOURCE_DIR}/block_task.cpp ${CMAKE_CURRENT_SOURCE_DIR}/block_allocator.cpp diff --git a/lib/block_props.cpp b/lib/block_props.cpp new file mode 100644 index 0000000..bba9441 --- /dev/null +++ b/lib/block_props.cpp @@ -0,0 +1,87 @@ +// Copyright (C) by Josh Blum. See LICENSE.txt for licensing information. + +#include "element_impl.hpp" +#include <gras/block.hpp> + +using namespace gras; + +PropertyRegistry::PropertyRegistry(void){} +PropertyRegistry::~PropertyRegistry(void){} + +void BlockActor::handle_prop_access( + const PropAccessMessage &message, + const Theron::Address from +) +{ + ASSERT(this->prio_count.Load() != 0); + this->prio_count.Decrement(); + + PropAccessMessage reply; + reply.set = not message.set; + reply.key = message.key; + + PropertyRegistrySptr pr = prop_registry[message.key]; + if (not pr) reply.error = "no property registered for key: " + message.key; + else try + { + if (message.set) pr->set(message.value); + else reply.value = pr->get(); + } + catch (const std::exception &e) + { + reply.error = e.what(); + } + catch (...) + { + reply.error = "unknown error"; + } + + this->Send(reply, from); //ACK +} + +void Block::_register_property(const std::string &key, PropertyRegistrySptr pr) +{ + (*this)->block->prop_registry[key] = pr; +} + +struct PropAccessReceiver : Theron::Receiver +{ + PropAccessReceiver(void) + { + this->RegisterHandler(this, &PropAccessReceiver::handle_prop_access); + } + + void handle_prop_access(const PropAccessMessage &msg, const Theron::Address) + { + this->message = msg; + } + + PropAccessMessage message; +}; + +PMCC BlockActor::prop_access_dispatcher(const std::string &key, const PMCC &value, const bool set) +{ + PropAccessReceiver receiver; + PropAccessMessage message; + message.set = set; + message.key = key; + message.value = value; + this->Push(message, receiver.GetAddress()); + this->prio_count.Increment(); + receiver.Wait(); + if (not receiver.message.error.empty()) + { + throw std::runtime_error(receiver.message.error); + } + return receiver.message.value; +} + +void Block::_set_property(const std::string &key, const PMCC &value) +{ + (*this)->block->prop_access_dispatcher(key, value, true); +} + +PMCC Block::_get_property(const std::string &key) +{ + return (*this)->block->prop_access_dispatcher(key, PMCC(), false); +} diff --git a/lib/gras_impl/block_actor.hpp b/lib/gras_impl/block_actor.hpp index d088254..8efc388 100644 --- a/lib/gras_impl/block_actor.hpp +++ b/lib/gras_impl/block_actor.hpp @@ -19,6 +19,7 @@ #include <Theron/Detail/Threading/Atomic.h> #include <vector> #include <set> +#include <map> namespace gras { @@ -76,6 +77,7 @@ struct BlockActor : Apology::Worker this->RegisterHandler(this, &BlockActor::handle_output_alloc); this->RegisterHandler(this, &BlockActor::handle_output_update); + this->RegisterHandler(this, &BlockActor::handle_prop_access); this->RegisterHandler(this, &BlockActor::handle_self_kick); this->RegisterHandler(this, &BlockActor::handle_get_stats); } @@ -105,6 +107,7 @@ struct BlockActor : Apology::Worker void handle_output_alloc(const OutputAllocMessage &, const Theron::Address); void handle_output_update(const OutputUpdateMessage &, const Theron::Address); + void handle_prop_access(const PropAccessMessage &, const Theron::Address); void handle_self_kick(const SelfKickMessage &, const Theron::Address); void handle_get_stats(const GetStatsMessage &, const Theron::Address); @@ -193,6 +196,10 @@ struct BlockActor : Apology::Worker std::vector<std::vector<OutputHintMessage> > output_allocation_hints; + //property stuff + PMCC prop_access_dispatcher(const std::string &key, const PMCC &value, const bool set); + std::map<std::string, PropertyRegistrySptr> prop_registry; + BlockStats stats; }; diff --git a/lib/gras_impl/messages.hpp b/lib/gras_impl/messages.hpp index 6cc685b..15a7c2e 100644 --- a/lib/gras_impl/messages.hpp +++ b/lib/gras_impl/messages.hpp @@ -131,6 +131,14 @@ struct OutputUpdateMessage //-- do not ack //---------------------------------------------------------------------- +struct PropAccessMessage +{ + bool set; + std::string key; + PMCC value; + std::string error; +}; + struct SelfKickMessage { //empty @@ -172,6 +180,7 @@ THERON_DECLARE_REGISTERED_MESSAGE(gras::OutputHintMessage); THERON_DECLARE_REGISTERED_MESSAGE(gras::OutputAllocMessage); THERON_DECLARE_REGISTERED_MESSAGE(gras::OutputUpdateMessage); +THERON_DECLARE_REGISTERED_MESSAGE(gras::PropAccessMessage); THERON_DECLARE_REGISTERED_MESSAGE(gras::SelfKickMessage); THERON_DECLARE_REGISTERED_MESSAGE(gras::GetStatsMessage); diff --git a/lib/register_messages.cpp b/lib/register_messages.cpp index e502e5b..058f308 100644 --- a/lib/register_messages.cpp +++ b/lib/register_messages.cpp @@ -26,5 +26,6 @@ THERON_DEFINE_REGISTERED_MESSAGE(gras::OutputHintMessage); THERON_DEFINE_REGISTERED_MESSAGE(gras::OutputAllocMessage); THERON_DEFINE_REGISTERED_MESSAGE(gras::OutputUpdateMessage); +THERON_DEFINE_REGISTERED_MESSAGE(gras::PropAccessMessage); THERON_DEFINE_REGISTERED_MESSAGE(gras::SelfKickMessage); THERON_DEFINE_REGISTERED_MESSAGE(gras::GetStatsMessage); |