summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/gras/CMakeLists.txt2
-rw-r--r--include/gras/block.hpp75
-rw-r--r--include/gras/detail/block.hpp35
-rw-r--r--include/gras/detail/property.hpp54
-rw-r--r--lib/CMakeLists.txt1
-rw-r--r--lib/block_props.cpp87
-rw-r--r--lib/gras_impl/block_actor.hpp7
-rw-r--r--lib/gras_impl/messages.hpp9
-rw-r--r--lib/register_messages.cpp1
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);