From 7c9883d7500fcea8232e2dc860ceb2baaeb18823 Mon Sep 17 00:00:00 2001 From: eb Date: Mon, 26 Feb 2007 00:40:37 +0000 Subject: [PATCH] Merged mblock work-in-progress from eb/mb -r4341:4633 into trunk. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@4634 221aa14e-8319-0410-a670-987f0aec2ac5 --- mblock/src/lib/Makefile.am | 15 +- mblock/src/lib/mb_common.h | 8 +- mblock/src/lib/mb_connection.cc | 6 +- mblock/src/lib/mb_connection.h | 4 +- .../lib/{mb_port_detail.cc => mb_endpoint.cc} | 23 +- mblock/src/lib/mb_endpoint.h | 6 + mblock/src/lib/mb_exception.cc | 5 + mblock/src/lib/mb_exception.h | 5 + mblock/src/lib/mb_mblock.cc | 24 + mblock/src/lib/mb_mblock.h | 15 +- mblock/src/lib/mb_mblock_impl.cc | 57 ++- mblock/src/lib/mb_mblock_impl.h | 33 +- mblock/src/lib/mb_msg_queue.cc | 4 +- mblock/src/lib/mb_msg_queue.h | 4 +- mblock/src/lib/mb_port.cc | 1 - mblock/src/lib/mb_port.h | 2 + mblock/src/lib/mb_port_detail.h | 35 -- mblock/src/lib/mb_port_simple.cc | 80 +++- mblock/src/lib/mb_port_simple.h | 5 +- mblock/src/lib/mb_runtime.cc | 20 +- mblock/src/lib/mb_runtime.h | 23 +- ..._impl.cc => mb_runtime_single_threaded.cc} | 36 +- ...me_impl.h => mb_runtime_single_threaded.h} | 25 +- mblock/src/lib/mb_util.cc | 2 +- mblock/src/lib/qa_mblock.cc | 2 + mblock/src/lib/qa_mblock_prims.cc | 37 +- mblock/src/lib/qa_mblock_send.cc | 450 ++++++++++++++++++ mblock/src/lib/qa_mblock_send.h | 43 ++ pmt/src/lib/pmt.cc | 24 + pmt/src/lib/pmt.h | 20 + 30 files changed, 853 insertions(+), 161 deletions(-) rename mblock/src/lib/{mb_port_detail.cc => mb_endpoint.cc} (57%) delete mode 100644 mblock/src/lib/mb_port_detail.h rename mblock/src/lib/{mb_runtime_impl.cc => mb_runtime_single_threaded.cc} (55%) rename mblock/src/lib/{mb_runtime_impl.h => mb_runtime_single_threaded.h} (62%) create mode 100644 mblock/src/lib/qa_mblock_send.cc create mode 100644 mblock/src/lib/qa_mblock_send.h diff --git a/mblock/src/lib/Makefile.am b/mblock/src/lib/Makefile.am index c049bd34..e1922fcd 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 13837a8c..3c9ec8e1 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_sptr; -class mb_runtime_impl; -typedef boost::shared_ptr mb_runtime_impl_sptr; +//class mb_runtime_impl; +//typedef boost::shared_ptr mb_runtime_impl_sptr; class mb_mblock; typedef boost::shared_ptr mb_mblock_sptr; @@ -79,8 +79,8 @@ typedef boost::shared_ptr mb_mblock_impl_sptr; class mb_port; typedef boost::shared_ptr mb_port_sptr; -class mb_port_detail; -typedef boost::shared_ptr mb_port_detail_sptr; +//class mb_port_detail; +//typedef boost::shared_ptr mb_port_detail_sptr; class mb_msg_accepter; typedef boost::shared_ptr mb_msg_accepter_sptr; diff --git a/mblock/src/lib/mb_connection.cc b/mblock/src/lib/mb_connection.cc index 526de650..56338cd8 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 859d8467..caac9579 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 similarity index 57% rename from mblock/src/lib/mb_port_detail.cc rename to mblock/src/lib/mb_endpoint.cc index 3a58fa24..3fe2d08c 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 #endif +#include -#include +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 90ae6fe6..82b0feb7 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 4282f6dd..4d4ca70b 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 188acf48..40abd1c9 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 9ab1fbbf..bf9f5b0c 100644 --- a/mblock/src/lib/mb_mblock.cc +++ b/mblock/src/lib/mb_mblock.cc @@ -27,6 +27,12 @@ #include +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 c656f90f..00e4051c 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 f4fa523e..a9e81e8d 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("") { } @@ -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 1e62dd8d..38cb5d5f 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 e6269492..8afdea07 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 2749e6a5..57f6dd0b 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 -//#include FIXME +#include /*! * \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 5c9f544c..b265db2d 100644 --- a/mblock/src/lib/mb_port.cc +++ b/mblock/src/lib/mb_port.cc @@ -24,7 +24,6 @@ #endif #include -#include #include mb_port::mb_port(mb_mblock *mblock, diff --git a/mblock/src/lib/mb_port.h b/mblock/src/lib/mb_port.h index 59a508c9..3c3e9636 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 3623a1b4..00000000 --- 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 - -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 4896df3a..1315b617 100644 --- a/mblock/src/lib/mb_port_simple.cc +++ b/mblock/src/lib/mb_port_simple.cc @@ -25,6 +25,11 @@ #include #include +#include +#include +#include +#include + 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(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 3ce3e3cb..5cfbd3dc 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 8c396f19..fa762270 100644 --- a/mblock/src/lib/mb_runtime.cc +++ b/mblock/src/lib/mb_runtime.cc @@ -24,29 +24,15 @@ #endif #include -#include +#include 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 c4eb206b..9b47537b 100644 --- a/mblock/src/lib/mb_runtime.h +++ b/mblock/src/lib/mb_runtime.h @@ -24,40 +24,31 @@ #include /*! - * \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 similarity index 55% rename from mblock/src/lib/mb_runtime_impl.cc rename to mblock/src/lib/mb_runtime_single_threaded.cc index 5a354ef1..dc8597ae 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 #endif +#include +#include -#include -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 similarity index 62% rename from mblock/src/lib/mb_runtime_impl.h rename to mblock/src/lib/mb_runtime_single_threaded.h index 2325a351..b56e0a5e 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 +#include /*! - * \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 8a14d4c0..03f0469f 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 72dccc05..4be4a23c 100644 --- a/mblock/src/lib/qa_mblock.cc +++ b/mblock/src/lib/qa_mblock.cc @@ -26,6 +26,7 @@ #include #include +#include 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 fc3452f9..7385a17e 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 +#endif + #include #include #include @@ -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 00000000..ff86adbf --- /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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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 00000000..6aeee7ad --- /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 +#include + +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 */ + diff --git a/pmt/src/lib/pmt.cc b/pmt/src/lib/pmt.cc index 036a5f8b..cf6547b5 100644 --- a/pmt/src/lib/pmt.cc +++ b/pmt/src/lib/pmt.cc @@ -841,3 +841,27 @@ pmt_subsetp(pmt_t list1, pmt_t list2) } return true; } + +pmt_t +pmt_list1(pmt_t x1) +{ + return pmt_cons(x1, PMT_NIL); +} + +pmt_t +pmt_list2(pmt_t x1, pmt_t x2) +{ + return pmt_cons(x1, pmt_cons(x2, PMT_NIL)); +} + +pmt_t +pmt_list3(pmt_t x1, pmt_t x2, pmt_t x3) +{ + return pmt_cons(x1, pmt_cons(x2, pmt_cons(x3, PMT_NIL))); +} + +pmt_t +pmt_list4(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4) +{ + return pmt_cons(x1, pmt_cons(x2, pmt_cons(x3, pmt_cons(x4, PMT_NIL)))); +} diff --git a/pmt/src/lib/pmt.h b/pmt/src/lib/pmt.h index 2cb032e5..030637c4 100644 --- a/pmt/src/lib/pmt.h +++ b/pmt/src/lib/pmt.h @@ -548,6 +548,26 @@ pmt_t pmt_member(pmt_t obj, pmt_t list); */ bool pmt_subsetp(pmt_t list1, pmt_t list2); +/*! + * \brief Return a list of length 1 containing \p x1 + */ +pmt_t pmt_list1(pmt_t x1); + +/*! + * \brief Return a list of length 2 containing \p x1, \p x2 + */ +pmt_t pmt_list2(pmt_t x1, pmt_t x2); + +/*! + * \brief Return a list of length 3 containing \p x1, \p x2, \p x3 + */ +pmt_t pmt_list3(pmt_t x1, pmt_t x2, pmt_t x3); + +/*! + * \brief Return a list of length 4 containing \p x1, \p x2, \p x3, \p x4 + */ +pmt_t pmt_list4(pmt_t x1, pmt_t x2, pmt_t x3, pmt_t x4); + /* * ------------------------------------------------------------------------ * read / write -- 2.30.2