summaryrefslogtreecommitdiff
path: root/mblock
diff options
context:
space:
mode:
Diffstat (limited to 'mblock')
-rw-r--r--mblock/src/lib/Makefile.am15
-rw-r--r--mblock/src/lib/mb_common.h8
-rw-r--r--mblock/src/lib/mb_connection.cc6
-rw-r--r--mblock/src/lib/mb_connection.h4
-rw-r--r--mblock/src/lib/mb_endpoint.cc (renamed from mblock/src/lib/mb_port_detail.cc)23
-rw-r--r--mblock/src/lib/mb_endpoint.h6
-rw-r--r--mblock/src/lib/mb_exception.cc5
-rw-r--r--mblock/src/lib/mb_exception.h5
-rw-r--r--mblock/src/lib/mb_mblock.cc24
-rw-r--r--mblock/src/lib/mb_mblock.h15
-rw-r--r--mblock/src/lib/mb_mblock_impl.cc57
-rw-r--r--mblock/src/lib/mb_mblock_impl.h33
-rw-r--r--mblock/src/lib/mb_msg_queue.cc4
-rw-r--r--mblock/src/lib/mb_msg_queue.h4
-rw-r--r--mblock/src/lib/mb_port.cc1
-rw-r--r--mblock/src/lib/mb_port.h2
-rw-r--r--mblock/src/lib/mb_port_detail.h35
-rw-r--r--mblock/src/lib/mb_port_simple.cc80
-rw-r--r--mblock/src/lib/mb_port_simple.h5
-rw-r--r--mblock/src/lib/mb_runtime.cc20
-rw-r--r--mblock/src/lib/mb_runtime.h23
-rw-r--r--mblock/src/lib/mb_runtime_single_threaded.cc (renamed from mblock/src/lib/mb_runtime_impl.cc)36
-rw-r--r--mblock/src/lib/mb_runtime_single_threaded.h (renamed from mblock/src/lib/mb_runtime_impl.h)25
-rw-r--r--mblock/src/lib/mb_util.cc2
-rw-r--r--mblock/src/lib/qa_mblock.cc2
-rw-r--r--mblock/src/lib/qa_mblock_prims.cc37
-rw-r--r--mblock/src/lib/qa_mblock_send.cc450
-rw-r--r--mblock/src/lib/qa_mblock_send.h43
28 files changed, 809 insertions, 161 deletions
diff --git a/mblock/src/lib/Makefile.am b/mblock/src/lib/Makefile.am
index c049bd347..e1922fcd8 100644
--- a/mblock/src/lib/Makefile.am
+++ b/mblock/src/lib/Makefile.am
@@ -21,7 +21,7 @@
include $(top_srcdir)/Makefile.common
-INCLUDES = $(PMT_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES)
+INCLUDES = $(DEFINES) $(OMNITHREAD_INCLUDES) $(PMT_INCLUDES) $(BOOST_CFLAGS) $(CPPUNIT_INCLUDES)
TESTS = test_mblock
@@ -33,6 +33,7 @@ EXTRA_DIST =
# These are the source files that go into the mblock shared library
libmblock_la_SOURCES = \
mb_connection.cc \
+ mb_endpoint.cc \
mb_exception.cc \
mb_mblock.cc \
mb_mblock_impl.cc \
@@ -44,7 +45,7 @@ libmblock_la_SOURCES = \
mb_port_simple.cc \
mb_protocol_class.cc \
mb_runtime.cc \
- mb_runtime_impl.cc \
+ mb_runtime_single_threaded.cc \
mb_util.cc
@@ -53,6 +54,7 @@ libmblock_la_LDFLAGS = $(NO_UNDEFINED) -avoid-version
# link the library against the c++ standard library
libmblock_la_LIBADD = \
+ $(OMNITHREAD_LIBS) \
$(PMT_LIBS) \
-lstdc++
@@ -67,6 +69,7 @@ include_HEADERS = \
mb_port_simple.h \
mb_protocol_class.h \
mb_runtime.h \
+ mb_runtime_single_threaded.h \
mb_util.h
@@ -75,17 +78,17 @@ noinst_HEADERS = \
mb_endpoint.h \
mb_mblock_impl.h \
mb_msg_accepter_smp.h \
- mb_port_detail.h \
- mb_runtime_impl.h \
qa_mblock.h \
- qa_mblock_prims.h
+ qa_mblock_prims.h \
+ qa_mblock_send.h
# Build the qa code into its own library
libmblock_qa_la_SOURCES = \
qa_mblock.cc \
- qa_mblock_prims.cc
+ qa_mblock_prims.cc \
+ qa_mblock_send.cc
# magic flags
diff --git a/mblock/src/lib/mb_common.h b/mblock/src/lib/mb_common.h
index 13837a8c5..3c9ec8e16 100644
--- a/mblock/src/lib/mb_common.h
+++ b/mblock/src/lib/mb_common.h
@@ -67,8 +67,8 @@ mb_pri_clamp(mb_pri_t p)
class mb_runtime;
typedef boost::shared_ptr<mb_runtime> mb_runtime_sptr;
-class mb_runtime_impl;
-typedef boost::shared_ptr<mb_runtime_impl> mb_runtime_impl_sptr;
+//class mb_runtime_impl;
+//typedef boost::shared_ptr<mb_runtime_impl> mb_runtime_impl_sptr;
class mb_mblock;
typedef boost::shared_ptr<mb_mblock> mb_mblock_sptr;
@@ -79,8 +79,8 @@ typedef boost::shared_ptr<mb_mblock_impl> mb_mblock_impl_sptr;
class mb_port;
typedef boost::shared_ptr<mb_port> mb_port_sptr;
-class mb_port_detail;
-typedef boost::shared_ptr<mb_port_detail> mb_port_detail_sptr;
+//class mb_port_detail;
+//typedef boost::shared_ptr<mb_port_detail> mb_port_detail_sptr;
class mb_msg_accepter;
typedef boost::shared_ptr<mb_msg_accepter> mb_msg_accepter_sptr;
diff --git a/mblock/src/lib/mb_connection.cc b/mblock/src/lib/mb_connection.cc
index 526de6506..56338cd8e 100644
--- a/mblock/src/lib/mb_connection.cc
+++ b/mblock/src/lib/mb_connection.cc
@@ -52,17 +52,17 @@ mb_conn_table::lookup_conn_by_name(const std::string &component_name,
}
bool
-mb_conn_table::lookup_conn_by_port(mb_port_sptr port,
+mb_conn_table::lookup_conn_by_port(const mb_port *port,
mb_conn_iter *itp, int *which_ep)
{
mb_conn_iter end = d_connections.end();
for (mb_conn_iter it = d_connections.begin(); it != end; ++it){
- if (it->d_ep[0].port() == port){
+ if (it->d_ep[0].port().get() == port){
*itp = it;
*which_ep = 0;
return true;
}
- if (it->d_ep[1].port() == port){
+ if (it->d_ep[1].port().get() == port){
*itp = it;
*which_ep = 1;
return true;
diff --git a/mblock/src/lib/mb_connection.h b/mblock/src/lib/mb_connection.h
index 859d84677..caac95790 100644
--- a/mblock/src/lib/mb_connection.h
+++ b/mblock/src/lib/mb_connection.h
@@ -53,8 +53,8 @@ public:
mb_conn_iter *it, int *which_ep);
bool
- lookup_conn_by_port(mb_port_sptr port,
- mb_conn_iter *it, int *which_ep);
+ lookup_conn_by_port(const mb_port *port,
+ mb_conn_iter *it, int *which_ep);
void
create_conn(const mb_endpoint &ep0, const mb_endpoint &ep1);
diff --git a/mblock/src/lib/mb_port_detail.cc b/mblock/src/lib/mb_endpoint.cc
index 3a58fa24d..3fe2d08c5 100644
--- a/mblock/src/lib/mb_port_detail.cc
+++ b/mblock/src/lib/mb_endpoint.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2006 Free Software Foundation, Inc.
+ * Copyright 2007 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -22,13 +22,28 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+#include <mb_endpoint.h>
-#include <mb_port_detail.h>
+bool
+mb_endpoint::inside_of_relay_port_p() const
+{
+ return d_port->port_type() == mb_port::RELAY && d_component_name == "self";
+}
-mb_port_detail::mb_port_detail()
+pmt_t
+mb_endpoint::incoming_message_set() const
{
+ if (inside_of_relay_port_p()) // swap incoming and outgoing
+ return port()->outgoing_message_set();
+ else
+ return port()->incoming_message_set();
}
-mb_port_detail::~mb_port_detail()
+pmt_t
+mb_endpoint::outgoing_message_set() const
{
+ if (inside_of_relay_port_p()) // swap incoming and outgoing
+ return port()->incoming_message_set();
+ else
+ return port()->outgoing_message_set();
}
diff --git a/mblock/src/lib/mb_endpoint.h b/mblock/src/lib/mb_endpoint.h
index 90ae6fe67..82b0feb7e 100644
--- a/mblock/src/lib/mb_endpoint.h
+++ b/mblock/src/lib/mb_endpoint.h
@@ -47,6 +47,12 @@ public:
const std::string &component_name() const { return d_component_name; }
const std::string &port_name() const { return d_port_name; }
mb_port_sptr port() const { return d_port; }
+
+ //! Does this endpoint represent the inside of a relay port
+ bool inside_of_relay_port_p() const;
+
+ pmt_t incoming_message_set() const;
+ pmt_t outgoing_message_set() const;
};
#endif /* INCLUDED_MB_ENDPOINT_H */
diff --git a/mblock/src/lib/mb_exception.cc b/mblock/src/lib/mb_exception.cc
index 4282f6dd0..4d4ca70b1 100644
--- a/mblock/src/lib/mb_exception.cc
+++ b/mblock/src/lib/mb_exception.cc
@@ -33,6 +33,11 @@ mbe_base::mbe_base(mb_mblock *mb, const std::string &msg)
{
}
+mbe_not_implemented::mbe_not_implemented(mb_mblock *mb, const std::string &msg)
+ : mbe_base(mb, "Not implemented: " + msg)
+{
+}
+
mbe_no_such_component::mbe_no_such_component(mb_mblock *mb, const std::string &component_name)
: mbe_base(mb, "No such component: " + component_name)
{
diff --git a/mblock/src/lib/mb_exception.h b/mblock/src/lib/mb_exception.h
index 188acf48f..40abd1c96 100644
--- a/mblock/src/lib/mb_exception.h
+++ b/mblock/src/lib/mb_exception.h
@@ -32,6 +32,11 @@ public:
mbe_base(mb_mblock *mb, const std::string &msg);
};
+class mbe_not_implemented : public mbe_base
+{
+public:
+ mbe_not_implemented(mb_mblock *mb, const std::string &msg);
+};
class mbe_no_such_component : public mbe_base
diff --git a/mblock/src/lib/mb_mblock.cc b/mblock/src/lib/mb_mblock.cc
index 9ab1fbbff..bf9f5b0ce 100644
--- a/mblock/src/lib/mb_mblock.cc
+++ b/mblock/src/lib/mb_mblock.cc
@@ -27,6 +27,12 @@
#include <mb_mblock_impl.h>
+mb_visitor::~mb_visitor()
+{
+ // nop base case for virtual destructor.
+}
+
+
mb_mblock::mb_mblock()
: d_impl(mb_mblock_impl_sptr(new mb_mblock_impl(this)))
{
@@ -113,3 +119,21 @@ mb_mblock::walk_tree(mb_visitor *visitor, const std::string &path)
{
return d_impl->walk_tree(visitor, path);
}
+
+std::string
+mb_mblock::fullname() const
+{
+ return d_impl->fullname();
+}
+
+void
+mb_mblock::set_fullname(const std::string name)
+{
+ d_impl->set_fullname(name);
+}
+
+mb_mblock *
+mb_mblock::parent() const
+{
+ return d_impl->mblock_parent();
+}
diff --git a/mblock/src/lib/mb_mblock.h b/mblock/src/lib/mb_mblock.h
index c656f90f2..00e4051c0 100644
--- a/mblock/src/lib/mb_mblock.h
+++ b/mblock/src/lib/mb_mblock.h
@@ -35,8 +35,7 @@ class mb_visitor
{
public:
virtual ~mb_visitor();
- bool operator()(mb_mblock *mblock, const std::string &path) { return visit(mblock, path); }
- virtual bool visit(mb_mblock *mblock, const std::string &path) = 0;
+ virtual bool operator()(mb_mblock *mblock, const std::string &path) = 0;
};
// ----------------------------------------------------------------------
@@ -69,6 +68,7 @@ protected:
*/
mb_mblock();
+public:
/*!
* \brief Called by the runtime system to execute the initial
* transition of the finite state machine.
@@ -77,6 +77,7 @@ protected:
*/
virtual void init_fsm();
+protected:
/*!
* \brief Called by the runtime system when there's a message to handle.
*
@@ -178,13 +179,21 @@ protected:
public:
virtual ~mb_mblock();
+ void set_fullname(const std::string name);
+
+ //! Return full name of this block
+ std::string fullname() const;
+
+ //! Return the parent of this mblock, or 0 if we're the top-level block.
+ mb_mblock *parent() const;
+
/*!
* \brief Perform a pre-order depth-first traversal of the hierarchy.
*
* The traversal stops and returns false if any call to visitor returns false.
*/
bool
- walk_tree(mb_visitor *visitor, const std::string &path="");
+ walk_tree(mb_visitor *visitor, const std::string &path="top");
//! \implementation
diff --git a/mblock/src/lib/mb_mblock_impl.cc b/mblock/src/lib/mb_mblock_impl.cc
index f4fa523ee..a9e81e8de 100644
--- a/mblock/src/lib/mb_mblock_impl.cc
+++ b/mblock/src/lib/mb_mblock_impl.cc
@@ -51,7 +51,7 @@ mb_mblock_impl::comp_is_defined(const std::string &name)
////////////////////////////////////////////////////////////////////////
mb_mblock_impl::mb_mblock_impl(mb_mblock *mb)
- : d_mb(mb), d_mb_parent(0)
+ : d_mb(mb), d_mb_parent(0), d_fullname("<unknown>")
{
}
@@ -67,11 +67,6 @@ mb_mblock_impl::define_port(const std::string &port_name,
bool conjugated,
mb_port::port_type_t port_type)
{
- if (port_type == mb_port::RELAY)
- throw mbe_base(d_mb,
- "mb_block_impl::define_port: RELAY ports are not implemented: "
- + port_name);
-
if (port_is_defined(port_name))
throw mbe_duplicate_port(d_mb, port_name);
@@ -90,7 +85,7 @@ mb_mblock_impl::define_component(const std::string &name,
if (comp_is_defined(name)) // check for duplicate name
throw mbe_duplicate_component(d_mb, name);
- component->d_impl->d_mb_parent = d_mb; // set component's parent link
+ component->d_impl->d_mb_parent = d_mb; // set component's parent link
d_comp_map[name] = component;
}
@@ -103,7 +98,7 @@ mb_mblock_impl::connect(const std::string &comp_name1,
mb_endpoint ep0 = check_and_resolve_endpoint(comp_name1, port_name1);
mb_endpoint ep1 = check_and_resolve_endpoint(comp_name2, port_name2);
- if (!ports_are_compatible(ep0.port(), ep1.port()))
+ if (!endpoints_are_compatible(ep0, ep1))
throw mbe_incompatible_ports(d_mb,
comp_name1, port_name1,
comp_name2, port_name2);
@@ -194,16 +189,14 @@ mb_mblock_impl::resolve_port(const std::string &comp_name,
bool
-mb_mblock_impl::ports_are_compatible(mb_port_sptr p0, mb_port_sptr p1)
+mb_mblock_impl::endpoints_are_compatible(const mb_endpoint &ep0,
+ const mb_endpoint &ep1)
{
- using std::cout;
- using std::endl;
-
- pmt_t p0_outgoing = p0->outgoing_message_set();
- pmt_t p0_incoming = p0->incoming_message_set();
+ pmt_t p0_outgoing = ep0.outgoing_message_set();
+ pmt_t p0_incoming = ep0.incoming_message_set();
- pmt_t p1_outgoing = p1->outgoing_message_set();
- pmt_t p1_incoming = p1->incoming_message_set();
+ pmt_t p1_outgoing = ep1.outgoing_message_set();
+ pmt_t p1_incoming = ep1.incoming_message_set();
return (pmt_subsetp(p0_outgoing, p1_incoming)
&& pmt_subsetp(p1_outgoing, p0_incoming));
@@ -232,3 +225,35 @@ mb_mblock_impl::make_accepter(const std::string port_name)
return mb_msg_accepter_sptr(ma);
}
+
+bool
+mb_mblock_impl::lookup_other_endpoint(const mb_port *port, mb_endpoint *ep)
+{
+ mb_conn_iter it;
+ int which_ep = 0;
+
+ if (!d_conn_table.lookup_conn_by_port(port, &it, &which_ep))
+ return false;
+
+ *ep = it->d_ep[which_ep^1];
+ return true;
+}
+
+mb_mblock_sptr
+mb_mblock_impl::component(const std::string &comp_name)
+{
+ if (comp_name == "self")
+ return d_mb->shared_from_this();
+
+ if (d_comp_map.count(comp_name) == 0)
+ return mb_mblock_sptr(); // null pointer
+
+ return d_comp_map[comp_name];
+}
+
+void
+mb_mblock_impl::set_fullname(const std::string &name)
+{
+ d_fullname = name;
+}
+
diff --git a/mblock/src/lib/mb_mblock_impl.h b/mblock/src/lib/mb_mblock_impl.h
index 1e62dd8d7..38cb5d5f6 100644
--- a/mblock/src/lib/mb_mblock_impl.h
+++ b/mblock/src/lib/mb_mblock_impl.h
@@ -40,6 +40,8 @@ class mb_mblock_impl : boost::noncopyable
mb_mblock *d_mb; // pointer to our associated mblock
mb_mblock *d_mb_parent; // pointer to our parent
+ std::string d_fullname; // hierarchical name
+
mb_port_map_t d_port_map; // our ports
mb_comp_map_t d_comp_map; // our components
mb_conn_table d_conn_table; // our connections
@@ -145,6 +147,34 @@ public:
mb_msg_queue &
msgq() { return d_msgq; }
+ //! Return full name of this block
+ std::string fullname() const { return d_fullname; }
+
+ //! Set the name of this block
+ void set_fullname(const std::string &name);
+
+ /*!
+ * \brief If bound, store endpoint from the other end of the connection.
+ *
+ * \param port [in] port the port that we're searching for.
+ * \param ep [out] the other end point from the matching connection.
+ *
+ * \returns true iff there's a matching connection.
+ */
+ bool
+ lookup_other_endpoint(const mb_port *port, mb_endpoint *ep);
+
+
+ mb_mblock *
+ mblock() const { return d_mb; }
+
+ mb_mblock *
+ mblock_parent() const { return d_mb_parent; }
+
+ mb_mblock_sptr
+ component(const std::string &comp_name);
+
+
/*
* Our implementation methods
*/
@@ -164,7 +194,8 @@ private:
const std::string &port_name);
static bool
- ports_are_compatible(mb_port_sptr p0, mb_port_sptr p1);
+ endpoints_are_compatible(const mb_endpoint &ep0,
+ const mb_endpoint &ep1);
};
diff --git a/mblock/src/lib/mb_msg_queue.cc b/mblock/src/lib/mb_msg_queue.cc
index e62694925..8afdea07e 100644
--- a/mblock/src/lib/mb_msg_queue.cc
+++ b/mblock/src/lib/mb_msg_queue.cc
@@ -38,7 +38,7 @@ mb_msg_queue::~mb_msg_queue()
void
mb_msg_queue::insert(mb_message_sptr msg)
{
- // omni_mutex_lock l(d_mutex); FIXME
+ omni_mutex_lock l(d_mutex);
mb_pri_t q = mb_pri_clamp(msg->priority());
@@ -57,7 +57,7 @@ mb_msg_queue::insert(mb_message_sptr msg)
mb_message_sptr
mb_msg_queue::get_highest_pri_msg()
{
- // omni_mutex_lock l(d_mutex); FIXME
+ omni_mutex_lock l(d_mutex);
// FIXME use bitmap and ffz to find best queue in O(1)
diff --git a/mblock/src/lib/mb_msg_queue.h b/mblock/src/lib/mb_msg_queue.h
index 2749e6a59..57f6dd0b3 100644
--- a/mblock/src/lib/mb_msg_queue.h
+++ b/mblock/src/lib/mb_msg_queue.h
@@ -22,7 +22,7 @@
#define INCLUDED_MB_MSG_QUEUE_H
#include <mb_common.h>
-//#include <omnithread.h> FIXME
+#include <omnithread.h>
/*!
* \brief priority queue for mblock messages
@@ -37,7 +37,7 @@ class mb_msg_queue : boost::noncopyable
bool empty_p() const { return head == 0; }
};
- // omni_mutex d_mutex; FIXME
+ omni_mutex d_mutex;
// FIXME add bitmap to indicate which queues are non-empty.
subq d_queue[MB_NPRI];
diff --git a/mblock/src/lib/mb_port.cc b/mblock/src/lib/mb_port.cc
index 5c9f544c4..b265db2dc 100644
--- a/mblock/src/lib/mb_port.cc
+++ b/mblock/src/lib/mb_port.cc
@@ -24,7 +24,6 @@
#endif
#include <mb_port.h>
-#include <mb_port_detail.h>
#include <mb_protocol_class.h>
mb_port::mb_port(mb_mblock *mblock,
diff --git a/mblock/src/lib/mb_port.h b/mblock/src/lib/mb_port.h
index 59a508c92..3c3e96368 100644
--- a/mblock/src/lib/mb_port.h
+++ b/mblock/src/lib/mb_port.h
@@ -54,6 +54,8 @@ protected:
bool conjugated,
mb_port::port_type_t port_type);
+ mb_mblock *mblock() const { return d_mblock; }
+
public:
std::string port_name() const { return d_port_name; }
pmt_t protocol_class() const { return d_protocol_class; }
diff --git a/mblock/src/lib/mb_port_detail.h b/mblock/src/lib/mb_port_detail.h
deleted file mode 100644
index 3623a1b48..000000000
--- a/mblock/src/lib/mb_port_detail.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * GNU Radio is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#ifndef INCLUDED_MB_PORT_DETAIL_H
-#define INCLUDED_MB_PORT_DETAIL_H
-
-#include <mb_port.h>
-
-class mb_port_detail : boost::noncopyable
-{
-public:
- mb_port_detail();
- ~mb_port_detail();
-};
-
-
-#endif /* INCLUDED_MB_PORT_DETAIL_H */
diff --git a/mblock/src/lib/mb_port_simple.cc b/mblock/src/lib/mb_port_simple.cc
index 4896df3a6..1315b6172 100644
--- a/mblock/src/lib/mb_port_simple.cc
+++ b/mblock/src/lib/mb_port_simple.cc
@@ -25,6 +25,11 @@
#include <mb_port_simple.h>
#include <mb_msg_accepter.h>
+#include <mb_exception.h>
+#include <mb_mblock.h>
+#include <mb_mblock_impl.h>
+#include <assert.h>
+
mb_port_simple::mb_port_simple(mb_mblock *mblock,
const std::string &port_name,
@@ -43,17 +48,84 @@ mb_port_simple::~mb_port_simple()
void
mb_port_simple::send(pmt_t signal, pmt_t data, pmt_t metadata, mb_pri_t priority)
{
- mb_msg_accepter_sptr accepter = find_accepter();
+ if (port_type() == mb_port::RELAY) // Can't send directly to a RELAY port
+ throw mbe_invalid_port_type(mblock(), mblock()->fullname(), port_name());
+
+ mb_msg_accepter_sptr accepter = find_accepter(this);
if (accepter)
(*accepter)(signal, data, metadata, priority);
}
+
mb_msg_accepter_sptr
-mb_port_simple::find_accepter()
+mb_port_simple::find_accepter(mb_port_simple *start)
{
+ mb_port_simple *p = start;
+ mb_port_simple *pp = 0;
+ mb_mblock *context = 0;
+ mb_endpoint peer_ep;
mb_msg_accepter_sptr r;
- // FIXME, actually do the work ;)
+ // Set up initial context.
+
+ switch(p->port_type()){
+ case mb_port::INTERNAL: // binding is in our name space
+ context = p->mblock();
+ break;
+
+ case mb_port::EXTERNAL: // binding is in parent's name space
+ context = p->mblock()->parent();
+ break;
+
+ default:
+ throw std::logic_error("Can't happen: mb_port_simple::find_accepter [1]");
+ }
+
+
+ traverse:
+
+ if (!context->impl()->lookup_other_endpoint(p, &peer_ep))
+ return mb_msg_accepter_sptr(); // not bound
+
+ pp = dynamic_cast<mb_port_simple *>(peer_ep.port().get()); // peer port
+ assert(pp);
- return r;
+ switch (pp->port_type()){
+ case mb_port::INTERNAL: // Terminate here.
+ case mb_port::EXTERNAL:
+ r = pp->make_accepter();
+ // FIXME cache the result
+ return r;
+
+ case mb_port::RELAY: // Traverse to other side of relay port.
+ if (peer_ep.inside_of_relay_port_p()){
+ // We're on inside of relay port, headed out.
+ p = pp;
+ context = p->mblock()->parent();
+
+ // Corner case: we're attempting to traverse a relay port on the border
+ // of the top block...
+ if (!context)
+ return mb_msg_accepter_sptr(); // not bound
+
+ goto traverse;
+ }
+ else {
+ // We're on the outside of relay port, headed in.
+ p = pp;
+ context = p->mblock();
+ goto traverse;
+ }
+ break;
+
+ default:
+ throw std::logic_error("Can't happen: mb_port_simple::find_accepter [2]");
+ }
+}
+
+
+mb_msg_accepter_sptr
+mb_port_simple::make_accepter()
+{
+ return d_mblock->impl()->make_accepter(port_name());
}
diff --git a/mblock/src/lib/mb_port_simple.h b/mblock/src/lib/mb_port_simple.h
index 3ce3e3cb1..5cfbd3dc0 100644
--- a/mblock/src/lib/mb_port_simple.h
+++ b/mblock/src/lib/mb_port_simple.h
@@ -29,8 +29,11 @@
class mb_port_simple : public mb_port
{
protected:
+ static mb_msg_accepter_sptr
+ find_accepter(mb_port_simple *start);
+
mb_msg_accepter_sptr
- find_accepter();
+ make_accepter();
public:
mb_port_simple(mb_mblock *mblock,
diff --git a/mblock/src/lib/mb_runtime.cc b/mblock/src/lib/mb_runtime.cc
index 8c396f190..fa762270b 100644
--- a/mblock/src/lib/mb_runtime.cc
+++ b/mblock/src/lib/mb_runtime.cc
@@ -24,29 +24,15 @@
#endif
#include <mb_runtime.h>
-#include <mb_runtime_impl.h>
+#include <mb_runtime_single_threaded.h>
mb_runtime_sptr
mb_make_runtime()
{
- return mb_runtime_sptr(new mb_runtime());
-}
-
-mb_runtime::mb_runtime()
- : d_impl(mb_runtime_impl_sptr(new mb_runtime_impl()))
-{
- // FIXME
-
+ return mb_runtime_sptr(new mb_runtime_single_threaded());
}
mb_runtime::~mb_runtime()
{
- // FIXME
-}
-
-bool
-mb_runtime::run()
-{
- // FIXME
- return true;
+ // nop
}
diff --git a/mblock/src/lib/mb_runtime.h b/mblock/src/lib/mb_runtime.h
index c4eb206bd..9b47537b2 100644
--- a/mblock/src/lib/mb_runtime.h
+++ b/mblock/src/lib/mb_runtime.h
@@ -24,40 +24,31 @@
#include <mb_common.h>
/*!
- * \brief Public constructor for mb_runtime.
+ * \brief Public constructor (factory) for mb_runtime objects.
*/
mb_runtime_sptr mb_make_runtime();
/*!
- * \brief Runtime support for m-blocks
+ * \brief Abstract runtime support for m-blocks
*
* There should generally be only a single instance of this class.
- *
- * It should be created by the top-level initialization code,
- * and that instance should be passed into the constructor of the
- * top-level mblock.
*/
class mb_runtime : boost::noncopyable
{
-private:
- mb_runtime_impl_sptr d_impl; // implementation details
-
- mb_runtime();
-
- friend mb_runtime_sptr mb_make_runtime();
-
public:
- ~mb_runtime();
+ mb_runtime(){}
+ virtual ~mb_runtime();
/*!
- * \brief Run the mblocks...
+ * \brief Run the mblock hierarchy rooted at \p top
*
* This routine turns into the m-block scheduler, and
* blocks until the system is shutdown.
*
+ * \param top top-level mblock
* \returns true if the system ran successfully.
*/
- bool run();
+ virtual bool run(mb_mblock_sptr top) = 0;
};
#endif /* INCLUDED_MB_RUNTIME_H */
diff --git a/mblock/src/lib/mb_runtime_impl.cc b/mblock/src/lib/mb_runtime_single_threaded.cc
index 5a354ef16..dc8597aeb 100644
--- a/mblock/src/lib/mb_runtime_impl.cc
+++ b/mblock/src/lib/mb_runtime_single_threaded.cc
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2006 Free Software Foundation, Inc.
+ * Copyright 2007 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -22,15 +22,39 @@
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
+#include <mb_runtime_single_threaded.h>
+#include <mb_mblock.h>
-#include <mb_runtime_impl.h>
-mb_runtime_impl::mb_runtime_impl()
+mb_runtime_single_threaded::mb_runtime_single_threaded()
{
- // FIXME
+ // nop for now
}
-mb_runtime_impl::~mb_runtime_impl()
+mb_runtime_single_threaded::~mb_runtime_single_threaded()
{
- // FIXME
+ // nop for now
+}
+
+bool
+mb_runtime_single_threaded::run(mb_mblock_sptr top)
+{
+ class initial_visitor : public mb_visitor
+ {
+ public:
+ bool operator()(mb_mblock *mblock, const std::string &path)
+ {
+ mblock->set_fullname(path);
+ mblock->init_fsm();
+ return true;
+ }
+ };
+
+ initial_visitor visitor;
+
+ d_top = top; // remember top of tree
+
+ d_top->walk_tree(&visitor);
+
+ return true;
}
diff --git a/mblock/src/lib/mb_runtime_impl.h b/mblock/src/lib/mb_runtime_single_threaded.h
index 2325a3518..b56e0a5e1 100644
--- a/mblock/src/lib/mb_runtime_impl.h
+++ b/mblock/src/lib/mb_runtime_single_threaded.h
@@ -1,6 +1,6 @@
/* -*- c++ -*- */
/*
- * Copyright 2006 Free Software Foundation, Inc.
+ * Copyright 2007 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
@@ -18,24 +18,25 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#ifndef INCLUDED_MB_RUNTIME_IMPL_H
-#define INCLUDED_MB_RUNTIME_IMPL_H
+#ifndef INCLUDED_MB_RUNTIME_SINGLE_THREADED_H
+#define INCLUDED_MB_RUNTIME_SINGLE_THREADED_H
-#include <mb_common.h>
+#include <mb_runtime.h>
/*!
- * \brief The private implementation details of the runtime system.
+ * \brief Concrete runtime that uses a single thread for all work.
*/
-class mb_runtime_impl : boost::noncopyable
+class mb_runtime_single_threaded : public mb_runtime
{
-private:
- friend class mb_runtime;
-
- mb_runtime_impl();
+ mb_mblock_sptr d_top; // top mblock
public:
- ~mb_runtime_impl();
+ mb_runtime_single_threaded();
+ ~mb_runtime_single_threaded();
+
+ bool run(mb_mblock_sptr top);
};
-#endif /* INCLUDED_MB_RUNTIME_IMPL_H */
+
+#endif /* INCLUDED_MB_RUNTIME_SINGLE_THREADED_H */
diff --git a/mblock/src/lib/mb_util.cc b/mblock/src/lib/mb_util.cc
index 8a14d4c06..03f0469fb 100644
--- a/mblock/src/lib/mb_util.cc
+++ b/mblock/src/lib/mb_util.cc
@@ -30,5 +30,5 @@ std::string
mb_util::join_names(const std::string &comp_name,
const std::string &port_name)
{
- return comp_name + "/" + port_name;
+ return comp_name + ":" + port_name;
}
diff --git a/mblock/src/lib/qa_mblock.cc b/mblock/src/lib/qa_mblock.cc
index 72dccc053..4be4a23c3 100644
--- a/mblock/src/lib/qa_mblock.cc
+++ b/mblock/src/lib/qa_mblock.cc
@@ -26,6 +26,7 @@
#include <qa_mblock.h>
#include <qa_mblock_prims.h>
+#include <qa_mblock_send.h>
CppUnit::TestSuite *
qa_mblock::suite()
@@ -33,6 +34,7 @@ qa_mblock::suite()
CppUnit::TestSuite *s = new CppUnit::TestSuite("mblock");
s->addTest (qa_mblock_prims::suite());
+ s->addTest (qa_mblock_send::suite());
return s;
}
diff --git a/mblock/src/lib/qa_mblock_prims.cc b/mblock/src/lib/qa_mblock_prims.cc
index fc3452f96..7385a17ef 100644
--- a/mblock/src/lib/qa_mblock_prims.cc
+++ b/mblock/src/lib/qa_mblock_prims.cc
@@ -20,6 +20,10 @@
* Boston, MA 02111-1307, USA.
*/
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
#include <qa_mblock_prims.h>
#include <cppunit/TestAssert.h>
#include <mb_mblock.h>
@@ -103,32 +107,16 @@ qa_mblock_prims::test_define_ports()
// define the protocol class
pmt_t pc = mb_make_protocol_class(pmt_intern("cs-protocol"),
- pmt_cons(pmt_intern("start"),
- pmt_cons(pmt_intern("stop"),
- PMT_NIL)),
+ pmt_list2(pmt_intern("start"),
+ pmt_intern("stop")),
PMT_NIL);
// std::cout << "pc = " << pc << '\n';
mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2());
- // intf = mb2->peer_interface();
- // CPPUNIT_ASSERT_EQUAL(size_t(1), intf.size());
- // CPPUNIT_ASSERT(pmt_eq(s_cs, intf[0]->port_name()));
-
-
// raises pmt_exception because of duplicate port definition of "cs"
CPPUNIT_ASSERT_THROW(mb_mblock_sptr(new dp_3()), mbe_duplicate_port);
-
-#if 0
- try {
- mb_mblock_sptr mb2 = mb_mblock_sptr(new dp_2());
- }
- catch (pmt_exception &e){
- std::cerr << e.msg() << ' ' << e.obj() << '\n';
- }
-#endif
-
}
// ================================================================
@@ -321,13 +309,13 @@ void
qa_mblock_prims::test_connect()
{
// define the protocol class
- mb_make_protocol_class(pmt_intern("data"), // name of class
- pmt_cons(pmt_intern("data"), PMT_NIL), // in
- PMT_NIL); // out
+ mb_make_protocol_class(pmt_intern("data"), // name of class
+ pmt_list1(pmt_intern("data")), // in
+ PMT_NIL); // out
- mb_make_protocol_class(pmt_intern("i/o"), // name of class
- pmt_cons(pmt_intern("in"), PMT_NIL), // in
- pmt_cons(pmt_intern("out"), PMT_NIL)); // out
+ mb_make_protocol_class(pmt_intern("i/o"), // name of class
+ pmt_list1(pmt_intern("in")), // in
+ pmt_list1(pmt_intern("out"))); // out
mb_runtime_sptr rt = mb_make_runtime();
@@ -416,4 +404,3 @@ qa_mblock_prims::test_make_accepter()
CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg()->data()));
CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg()->data()));
}
-
diff --git a/mblock/src/lib/qa_mblock_send.cc b/mblock/src/lib/qa_mblock_send.cc
new file mode 100644
index 000000000..ff86adbf3
--- /dev/null
+++ b/mblock/src/lib/qa_mblock_send.cc
@@ -0,0 +1,450 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006,2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qa_mblock_send.h>
+#include <cppunit/TestAssert.h>
+#include <mb_mblock.h>
+#include <mb_runtime.h>
+#include <mb_protocol_class.h>
+#include <mb_exception.h>
+#include <mb_msg_queue.h>
+#include <mb_message.h>
+#include <mb_mblock_impl.h>
+#include <mb_msg_accepter.h>
+#include <stdio.h>
+
+static pmt_t s_data = pmt_intern("data");
+static pmt_t s_status = pmt_intern("status");
+static pmt_t s_control = pmt_intern("control");
+static pmt_t s_p0 = pmt_intern("p0");
+static pmt_t s_p1 = pmt_intern("p1");
+static pmt_t s_p2 = pmt_intern("p2");
+static pmt_t s_p3 = pmt_intern("p3");
+static pmt_t s_e1 = pmt_intern("e1");
+static pmt_t s_r1 = pmt_intern("r1");
+
+static void
+define_protocol_classes()
+{
+ // Defined from client point-of-view.
+ mb_make_protocol_class(pmt_intern("qa-send-cs"), // name
+ pmt_list1(s_status), // incoming
+ pmt_list1(s_control)); // outgoing
+
+}
+
+// ================================================================
+// test_simple_routing
+// ================================================================
+
+// sub-block for test_simple_routing
+
+class sr1 : public mb_mblock
+{
+ mb_port_sptr d_p1;
+ mb_port_sptr d_p2;
+ mb_port_sptr d_p3;
+
+public:
+ sr1();
+ ~sr1();
+ void init_fsm();
+};
+
+sr1::sr1()
+{
+ d_p1 = define_port("p1", "qa-send-cs", true, mb_port::EXTERNAL);
+ d_p2 = define_port("p2", "qa-send-cs", true, mb_port::EXTERNAL);
+ d_p3 = define_port("p3", "qa-send-cs", false, mb_port::EXTERNAL);
+}
+
+sr1::~sr1(){}
+
+void
+sr1::init_fsm()
+{
+ // std::cout << fullname() << "[sr1]: init_fsm\n";
+
+ // send two messages to each port
+ pmt_t our_name = pmt_intern(fullname());
+ d_p1->send(s_status, pmt_list3(our_name, s_p1, pmt_from_long(0)));
+ d_p1->send(s_status, pmt_list3(our_name, s_p1, pmt_from_long(1)));
+
+ d_p2->send(s_status, pmt_list3(our_name, s_p2, pmt_from_long(0)));
+ d_p2->send(s_status, pmt_list3(our_name, s_p2, pmt_from_long(1)));
+}
+
+// ----------------------------------------------------------------
+
+// top-level container block for test_simple_routing
+class sr0 : public mb_mblock
+{
+ mb_port_sptr d_p0;
+
+public:
+ sr0();
+ ~sr0();
+ void init_fsm();
+};
+
+sr0::sr0()
+{
+ d_p0 = define_port("p0", "qa-send-cs", false, mb_port::INTERNAL);
+
+ define_component("mb1", mb_mblock_sptr(new sr1()));
+ define_component("mb2", mb_mblock_sptr(new sr1()));
+
+ connect("self", "p0", "mb1", "p1");
+ connect("mb1", "p2", "mb2", "p3");
+ connect("mb1", "p3", "mb2", "p2");
+}
+
+sr0::~sr0(){}
+
+void
+sr0::init_fsm()
+{
+ // std::cout << fullname() << "[sr0]: init_fsm\n";
+
+ // send two messages to p0
+ pmt_t our_name = pmt_intern(fullname());
+ d_p0->send(s_control, pmt_list3(our_name, s_p0, pmt_from_long(0)));
+ d_p0->send(s_control, pmt_list3(our_name, s_p0, pmt_from_long(1)));
+}
+
+// ----------------------------------------------------------------
+
+/*
+ * This tests basic message routing using INTERNAL and EXTERNAL ports.
+ * It does not rely on the guts of the runtime being complete,
+ * which is good, because at the time this is being written, it isn't.
+ */
+void
+qa_mblock_send::test_simple_routing()
+{
+ define_protocol_classes();
+
+ mb_message_sptr msg;
+
+ mb_runtime_sptr rt = mb_make_runtime();
+ mb_mblock_sptr mb0 = mb_mblock_sptr(new sr0());
+ rt->run(mb0);
+
+ // Reach into the guts and see if the messages ended up where they should have
+
+ // mb0 should have received two messages sent from mb1 via its p1
+ msg = mb0->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ // std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p0, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/mb1"), s_p1, pmt_from_long(0)),
+ msg->data()));
+
+ msg = mb0->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ // std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p0, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/mb1"), s_p1, pmt_from_long(1)),
+ msg->data()));
+
+ // mb1 should have received
+ // two messages from mb0 via its p0 and
+ // two messages from mb2 via its p3
+
+ mb_mblock_sptr mb1 = mb0->impl()->component("mb1");
+
+ msg = mb1->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ // std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p1, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top"), s_p0, pmt_from_long(0)),
+ msg->data()));
+
+ msg = mb1->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ // std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p1, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top"), s_p0, pmt_from_long(1)),
+ msg->data()));
+
+ msg = mb1->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ // std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p3, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/mb2"), s_p2, pmt_from_long(0)),
+ msg->data()));
+
+ msg = mb1->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ // std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p3, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/mb2"), s_p2, pmt_from_long(1)),
+ msg->data()));
+
+
+ // mb2 should have received
+ // two messages from mb2 via its p2
+
+ mb_mblock_sptr mb2 = mb0->impl()->component("mb2");
+
+ msg = mb2->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ // std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p3, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/mb1"), s_p2, pmt_from_long(0)),
+ msg->data()));
+
+ msg = mb2->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ // std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p3, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/mb1"), s_p2, pmt_from_long(1)),
+ msg->data()));
+}
+
+// ================================================================
+// test_relay_routing_1
+// ================================================================
+
+// internal block for test_relay_routing
+
+class rr2 : public mb_mblock
+{
+ mb_port_sptr d_p1;
+ mb_port_sptr d_p2;
+
+public:
+ rr2();
+ ~rr2();
+ void init_fsm();
+};
+
+rr2::rr2()
+{
+ d_p1 = define_port("p1", "qa-send-cs", true, mb_port::EXTERNAL);
+ d_p2 = define_port("p2", "qa-send-cs", false, mb_port::EXTERNAL);
+}
+
+rr2::~rr2(){}
+
+void
+rr2::init_fsm()
+{
+ // std::cout << fullname() << "[rr2]: init_fsm\n";
+
+ // send two messages via p1
+ pmt_t our_name = pmt_intern(fullname());
+ d_p1->send(s_status, pmt_list3(our_name, s_p1, pmt_from_long(0)));
+ d_p1->send(s_status, pmt_list3(our_name, s_p1, pmt_from_long(1)));
+}
+
+// ----------------------------------------------------------------
+
+// intermediate block for test_relay_routing
+
+class rr1 : public mb_mblock
+{
+ mb_port_sptr d_p1;
+ mb_port_sptr d_p2;
+
+public:
+ rr1();
+ ~rr1();
+};
+
+rr1::rr1()
+{
+ d_p1 = define_port("p1", "qa-send-cs", true, mb_port::RELAY);
+ d_p2 = define_port("p2", "qa-send-cs", false, mb_port::RELAY);
+
+ define_component("c0", mb_mblock_sptr(new rr2()));
+
+ connect("self", "p1", "c0", "p1");
+ connect("self", "p2", "c0", "p2");
+}
+
+rr1::~rr1(){}
+
+// ----------------------------------------------------------------
+
+// top-level container for test_relay_routing
+
+class rr0_a : public mb_mblock
+{
+public:
+ rr0_a();
+ ~rr0_a();
+};
+
+rr0_a::rr0_a()
+{
+ define_component("c0", mb_mblock_sptr(new rr1()));
+ define_component("c1", mb_mblock_sptr(new rr2()));
+
+ connect("c0", "p1", "c1", "p2");
+ connect("c0", "p2", "c1", "p1");
+}
+
+rr0_a::~rr0_a(){}
+
+
+/*
+ * This tests basic message routing using RELAY and EXTERNAL ports.
+ * It does not rely on the guts of the runtime being complete,
+ * which is good, because at the time this is being written, it isn't.
+ */
+void
+qa_mblock_send::test_relay_routing_1()
+{
+ mb_message_sptr msg;
+
+ mb_runtime_sptr rt = mb_make_runtime();
+ mb_mblock_sptr top = mb_mblock_sptr(new rr0_a());
+ rt->run(top);
+
+ // Reach into the guts and see if the messages ended up where they should have
+
+ mb_mblock_sptr c0 = top->impl()->component("c0");
+ mb_mblock_sptr c0c0 = c0->impl()->component("c0");
+
+ mb_mblock_sptr c1 = top->impl()->component("c1");
+
+ // c0c0 should have received
+ // two message from c1 via its p2
+
+ msg = c0c0->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ //std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c1"), s_p1, pmt_from_long(0)),
+ msg->data()));
+
+ msg = c0c0->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ //std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c1"), s_p1, pmt_from_long(1)),
+ msg->data()));
+
+ // c1 should have received
+ // two message from c0c0 via its p2
+
+ msg = c1->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ //std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c0/c0"), s_p1, pmt_from_long(0)),
+ msg->data()));
+
+ msg = c1->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ //std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c0/c0"), s_p1, pmt_from_long(1)),
+ msg->data()));
+}
+
+// ================================================================
+// test_relay_routing_2
+// ================================================================
+
+// top-level container for test_relay_routing_2
+
+class rr0_b : public mb_mblock
+{
+public:
+ rr0_b();
+ ~rr0_b();
+};
+
+rr0_b::rr0_b()
+{
+ define_component("c0", mb_mblock_sptr(new rr1()));
+ define_component("c1", mb_mblock_sptr(new rr1()));
+
+ connect("c0", "p1", "c1", "p2");
+ connect("c0", "p2", "c1", "p1");
+}
+
+rr0_b::~rr0_b(){}
+
+
+/*
+ * This tests basic message routing using RELAY and EXTERNAL ports.
+ * It does not rely on the guts of the runtime being complete,
+ * which is good, because at the time this is being written, it isn't.
+ */
+void
+qa_mblock_send::test_relay_routing_2()
+{
+ mb_message_sptr msg;
+
+ mb_runtime_sptr rt = mb_make_runtime();
+ mb_mblock_sptr top = mb_mblock_sptr(new rr0_b());
+ rt->run(top);
+
+ // Reach into the guts and see if the messages ended up where they should have
+
+ mb_mblock_sptr c0 = top->impl()->component("c0");
+ mb_mblock_sptr c0c0 = c0->impl()->component("c0");
+
+ mb_mblock_sptr c1 = top->impl()->component("c1");
+ mb_mblock_sptr c1c0 = c1->impl()->component("c0");
+
+ // c0c0 should have received
+ // two message from c1c0 via its p2
+
+ msg = c0c0->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ // std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c1/c0"), s_p1, pmt_from_long(0)),
+ msg->data()));
+
+ msg = c0c0->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ // std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c1/c0"), s_p1, pmt_from_long(1)),
+ msg->data()));
+
+ // c1c0 should have received
+ // two message from c0c0 via its p2
+
+ msg = c1c0->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ // std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c0/c0"), s_p1, pmt_from_long(0)),
+ msg->data()));
+
+ msg = c1c0->impl()->msgq().get_highest_pri_msg();
+ CPPUNIT_ASSERT(msg);
+ // std::cerr << msg->data() << std::endl;
+ CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id());
+ CPPUNIT_ASSERT(pmt_equal(pmt_list3(pmt_intern("top/c0/c0"), s_p1, pmt_from_long(1)),
+ msg->data()));
+}
diff --git a/mblock/src/lib/qa_mblock_send.h b/mblock/src/lib/qa_mblock_send.h
new file mode 100644
index 000000000..6aeee7ad8
--- /dev/null
+++ b/mblock/src/lib/qa_mblock_send.h
@@ -0,0 +1,43 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006,2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * GNU Radio is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GNU Radio; see the file COPYING. If not, write to
+ * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef INCLUDED_QA_MBLOCK_SEND_H
+#define INCLUDED_QA_MBLOCK_SEND_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+
+class qa_mblock_send : public CppUnit::TestCase {
+
+ CPPUNIT_TEST_SUITE(qa_mblock_send);
+ CPPUNIT_TEST(test_simple_routing);
+ CPPUNIT_TEST(test_relay_routing_1);
+ CPPUNIT_TEST(test_relay_routing_2);
+ CPPUNIT_TEST_SUITE_END();
+
+ private:
+ void test_simple_routing();
+ void test_relay_routing_1();
+ void test_relay_routing_2();
+};
+
+#endif /* INCLUDED_QA_MBLOCK_SEND_H */
+