From 7833f98efff394454973a0a3441ddac608066737 Mon Sep 17 00:00:00 2001 From: eb Date: Wed, 28 Mar 2007 18:58:21 +0000 Subject: [PATCH 1/1] Merged mblock work-in-progress eb/mb -r4798:4808 into trunk. git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@4809 221aa14e-8319-0410-a670-987f0aec2ac5 --- configure.ac | 2 +- mblock/src/lib/Makefile.am | 12 +++- mblock/src/lib/README.locking | 4 ++ mblock/src/lib/mb_common.h | 2 +- mblock/src/lib/mb_mblock.cc | 20 ++++-- mblock/src/lib/mb_mblock.h | 15 +++-- mblock/src/lib/mb_mblock_impl.cc | 32 +++++++-- mblock/src/lib/mb_mblock_impl.h | 37 +++++++---- mblock/src/lib/mb_msg_accepter_smp.cc | 2 - mblock/src/lib/mb_msg_queue.cc | 39 +++++++++-- mblock/src/lib/mb_msg_queue.h | 13 +++- mblock/src/lib/mb_port_simple.cc | 5 +- mblock/src/lib/mb_runtime.cc | 4 +- mblock/src/lib/mb_runtime.h | 24 ++++++- ...e_single_threaded.cc => mb_runtime_nop.cc} | 20 +++--- mblock/src/lib/mb_runtime_nop.h | 44 +++++++++++++ mblock/src/lib/mb_runtime_placeholder.cc | 57 ++++++++++++++++ mblock/src/lib/mb_runtime_placeholder.h | 50 ++++++++++++++ .../src/lib/mb_runtime_thread_per_mblock.cc | 65 +++++++++++++++++++ ...eaded.h => mb_runtime_thread_per_mblock.h} | 14 ++-- mblock/src/lib/mbi_runtime_lock.h | 61 +++++++++++++++++ mblock/src/lib/qa_mblock_prims.cc | 42 ++++++------ mblock/src/lib/qa_mblock_send.cc | 51 ++++++++------- 23 files changed, 509 insertions(+), 106 deletions(-) create mode 100644 mblock/src/lib/README.locking rename mblock/src/lib/{mb_runtime_single_threaded.cc => mb_runtime_nop.cc} (79%) create mode 100644 mblock/src/lib/mb_runtime_nop.h create mode 100644 mblock/src/lib/mb_runtime_placeholder.cc create mode 100644 mblock/src/lib/mb_runtime_placeholder.h create mode 100644 mblock/src/lib/mb_runtime_thread_per_mblock.cc rename mblock/src/lib/{mb_runtime_single_threaded.h => mb_runtime_thread_per_mblock.h} (78%) create mode 100644 mblock/src/lib/mbi_runtime_lock.h diff --git a/configure.ac b/configure.ac index 74259352..28f4ec93 100644 --- a/configure.ac +++ b/configure.ac @@ -213,7 +213,7 @@ GRC_GR_PAGER GRC_GR_RADIO_ASTRONOMY GRC_GR_TRELLIS GRC_GR_VIDEO_SDL -#GRC_GR_QTGUI dnl disabled until grc_gr_qtgui.m4 is final +GRC_GR_QTGUI dnl disabled until grc_gr_qtgui.m4 is final GRC_GR_WXGUI GRC_PMT GRC_MBLOCK dnl this must come after GRC_PMT diff --git a/mblock/src/lib/Makefile.am b/mblock/src/lib/Makefile.am index 478793e9..6273e16d 100644 --- a/mblock/src/lib/Makefile.am +++ b/mblock/src/lib/Makefile.am @@ -27,7 +27,8 @@ TESTS = test_mblock lib_LTLIBRARIES = libmblock.la libmblock-qa.la -EXTRA_DIST = +EXTRA_DIST = \ + README.locking # These are the source files that go into the mblock shared library @@ -45,7 +46,9 @@ libmblock_la_SOURCES = \ mb_port_simple.cc \ mb_protocol_class.cc \ mb_runtime.cc \ - mb_runtime_single_threaded.cc \ + mb_runtime_nop.cc \ + mb_runtime_placeholder.cc \ + mb_runtime_thread_per_mblock.cc \ mb_util.cc @@ -69,7 +72,9 @@ include_HEADERS = \ mb_port_simple.h \ mb_protocol_class.h \ mb_runtime.h \ - mb_runtime_single_threaded.h \ + mb_runtime_nop.h \ + mb_runtime_placeholder.h \ + mb_runtime_thread_per_mblock.h \ mb_util.h @@ -78,6 +83,7 @@ noinst_HEADERS = \ mb_endpoint.h \ mb_mblock_impl.h \ mb_msg_accepter_smp.h \ + mbi_runtime_lock.h \ qa_mblock.h \ qa_mblock_prims.h \ qa_mblock_send.h diff --git a/mblock/src/lib/README.locking b/mblock/src/lib/README.locking new file mode 100644 index 00000000..12d4735e --- /dev/null +++ b/mblock/src/lib/README.locking @@ -0,0 +1,4 @@ +The Big Runtime Lock must be held when: + +Manipulating or traversing any mblock's d_port_map, d_comp_map or d_conn_table. + diff --git a/mblock/src/lib/mb_common.h b/mblock/src/lib/mb_common.h index 3c9ec8e1..34c72049 100644 --- a/mblock/src/lib/mb_common.h +++ b/mblock/src/lib/mb_common.h @@ -26,7 +26,7 @@ #include #include #include - +#include /* * The priority type and valid range diff --git a/mblock/src/lib/mb_mblock.cc b/mblock/src/lib/mb_mblock.cc index bf9f5b0c..9b8658f2 100644 --- a/mblock/src/lib/mb_mblock.cc +++ b/mblock/src/lib/mb_mblock.cc @@ -121,15 +121,27 @@ mb_mblock::walk_tree(mb_visitor *visitor, const std::string &path) } std::string -mb_mblock::fullname() const +mb_mblock::instance_name() const { - return d_impl->fullname(); + return d_impl->instance_name(); } void -mb_mblock::set_fullname(const std::string name) +mb_mblock::set_instance_name(const std::string name) { - d_impl->set_fullname(name); + d_impl->set_instance_name(name); +} + +std::string +mb_mblock::class_name() const +{ + return d_impl->class_name(); +} + +void +mb_mblock::set_class_name(const std::string name) +{ + d_impl->set_class_name(name); } mb_mblock * diff --git a/mblock/src/lib/mb_mblock.h b/mblock/src/lib/mb_mblock.h index 00e4051c..594920f9 100644 --- a/mblock/src/lib/mb_mblock.h +++ b/mblock/src/lib/mb_mblock.h @@ -24,7 +24,6 @@ #include #include #include -#include /*! @@ -175,15 +174,21 @@ protected: int nconnections() const; + //! Set the class name + void set_class_name(const std::string name); public: virtual ~mb_mblock(); - void set_fullname(const std::string name); - - //! Return full name of this block - std::string fullname() const; + //! Return instance name of this block + std::string instance_name() const; + + //! Return the class name of this block + std::string class_name() const; + //! Set the instance name of this block. + void set_instance_name(const std::string name); + //! Return the parent of this mblock, or 0 if we're the top-level block. mb_mblock *parent() const; diff --git a/mblock/src/lib/mb_mblock_impl.cc b/mblock/src/lib/mb_mblock_impl.cc index a9e81e8d..1a9e5014 100644 --- a/mblock/src/lib/mb_mblock_impl.cc +++ b/mblock/src/lib/mb_mblock_impl.cc @@ -30,6 +30,8 @@ #include #include #include +#include +#include static pmt_t s_self = pmt_intern("self"); @@ -51,7 +53,8 @@ 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_fullname("") + : d_mb(mb), d_mb_parent(0), d_runtime(mb_runtime_placeholder::singleton()), + d_instance_name(""), d_class_name("mblock") { } @@ -67,6 +70,8 @@ mb_mblock_impl::define_port(const std::string &port_name, bool conjugated, mb_port::port_type_t port_type) { + mbi_runtime_lock l(this); + if (port_is_defined(port_name)) throw mbe_duplicate_port(d_mb, port_name); @@ -82,6 +87,8 @@ void mb_mblock_impl::define_component(const std::string &name, mb_mblock_sptr component) { + mbi_runtime_lock l(this); + if (comp_is_defined(name)) // check for duplicate name throw mbe_duplicate_component(d_mb, name); @@ -95,6 +102,8 @@ mb_mblock_impl::connect(const std::string &comp_name1, const std::string &comp_name2, const std::string &port_name2) { + mbi_runtime_lock l(this); + mb_endpoint ep0 = check_and_resolve_endpoint(comp_name1, port_name1); mb_endpoint ep1 = check_and_resolve_endpoint(comp_name2, port_name2); @@ -113,24 +122,32 @@ mb_mblock_impl::disconnect(const std::string &comp_name1, const std::string &comp_name2, const std::string &port_name2) { + mbi_runtime_lock l(this); + d_conn_table.disconnect(comp_name1, port_name1, comp_name2, port_name2); } void mb_mblock_impl::disconnect_component(const std::string component_name) { + mbi_runtime_lock l(this); + d_conn_table.disconnect_component(component_name); } void mb_mblock_impl::disconnect_all() { + mbi_runtime_lock l(this); + d_conn_table.disconnect_all(); } int -mb_mblock_impl::nconnections() const +mb_mblock_impl::nconnections() { + mbi_runtime_lock l(this); + return d_conn_table.nconnections(); } @@ -219,6 +236,7 @@ mb_mblock_impl::walk_tree(mb_visitor *visitor, const std::string &path) mb_msg_accepter_sptr mb_mblock_impl::make_accepter(const std::string port_name) { + // FIXME this should probably use some kind of configurable factory mb_msg_accepter *ma = new mb_msg_accepter_smp(d_mb->shared_from_this(), pmt_intern(port_name)); @@ -252,8 +270,14 @@ mb_mblock_impl::component(const std::string &comp_name) } void -mb_mblock_impl::set_fullname(const std::string &name) +mb_mblock_impl::set_instance_name(const std::string &name) +{ + d_instance_name = name; +} + +void +mb_mblock_impl::set_class_name(const std::string &name) { - d_fullname = name; + d_class_name = name; } diff --git a/mblock/src/lib/mb_mblock_impl.h b/mblock/src/lib/mb_mblock_impl.h index 38cb5d5f..fc0fa694 100644 --- a/mblock/src/lib/mb_mblock_impl.h +++ b/mblock/src/lib/mb_mblock_impl.h @@ -39,8 +39,10 @@ class mb_mblock_impl : boost::noncopyable { mb_mblock *d_mb; // pointer to our associated mblock mb_mblock *d_mb_parent; // pointer to our parent + mb_runtime *d_runtime; // pointer to runtime - std::string d_fullname; // hierarchical name + std::string d_instance_name; // hierarchical name + std::string d_class_name; // name of this (derived) class mb_port_map_t d_port_map; // our ports mb_comp_map_t d_comp_map; // our components @@ -136,7 +138,7 @@ public: * \brief Return number of connections (QA mostly) */ int - nconnections() const; + nconnections(); bool walk_tree(mb_visitor *visitor, const std::string &path=""); @@ -147,11 +149,17 @@ public: mb_msg_queue & msgq() { return d_msgq; } - //! Return full name of this block - std::string fullname() const { return d_fullname; } + //! Return instance name of this block + std::string instance_name() const { return d_instance_name; } - //! Set the name of this block - void set_fullname(const std::string &name); + //! Set the instance name of this block + void set_instance_name(const std::string &name); + + //! Return the class name of this block + std::string class_name() const { return d_class_name; } + + //! Set the class name + void set_class_name(const std::string &name); /*! * \brief If bound, store endpoint from the other end of the connection. @@ -165,15 +173,20 @@ public: lookup_other_endpoint(const mb_port *port, mb_endpoint *ep); - mb_mblock * - mblock() const { return d_mb; } + //! Return point to associated mblock + mb_mblock *mblock() const { return d_mb; } + + //! Return pointer to the parent of our mblock + mb_mblock *mblock_parent() const { return d_mb_parent; } - mb_mblock * - mblock_parent() const { return d_mb_parent; } + //! Lookup a component by name + mb_mblock_sptr component(const std::string &comp_name); - mb_mblock_sptr - component(const std::string &comp_name); + //! Return the runtime instance + mb_runtime *runtime() { return d_runtime; } + //! Set the runtime instance + void set_runtime(mb_runtime *runtime) { d_runtime = runtime; } /* * Our implementation methods diff --git a/mblock/src/lib/mb_msg_accepter_smp.cc b/mblock/src/lib/mb_msg_accepter_smp.cc index 9e543979..3123b329 100644 --- a/mblock/src/lib/mb_msg_accepter_smp.cc +++ b/mblock/src/lib/mb_msg_accepter_smp.cc @@ -45,6 +45,4 @@ mb_msg_accepter_smp::operator()(pmt_t signal, pmt_t data, mb_message_sptr msg = mb_make_message(signal, data, metadata, priority); msg->set_port_id(d_port_name); d_mb->impl()->msgq().insert(msg); - - // FIXME tell runtime that we're ready to run } diff --git a/mblock/src/lib/mb_msg_queue.cc b/mblock/src/lib/mb_msg_queue.cc index 8afdea07..79e245ad 100644 --- a/mblock/src/lib/mb_msg_queue.cc +++ b/mblock/src/lib/mb_msg_queue.cc @@ -25,9 +25,9 @@ #include #include -// FIXME turn this into a template so we can use it for the runq of mblocks too mb_msg_queue::mb_msg_queue() + : d_not_empty(&d_mutex) { } @@ -51,14 +51,21 @@ mb_msg_queue::insert(mb_message_sptr msg) d_queue[q].tail = msg; msg->d_next.reset(); // msg->d_next = 0; } + // FIXME set bit in bitmap + + d_not_empty.signal(); } +/* + * Delete highest pri message from the queue and return it. + * Returns equivalent of zero pointer if queue is empty. + * + * Caller must be holding d_mutex + */ mb_message_sptr -mb_msg_queue::get_highest_pri_msg() +mb_msg_queue::get_highest_pri_msg_helper() { - omni_mutex_lock l(d_mutex); - // FIXME use bitmap and ffz to find best queue in O(1) for (mb_pri_t q = 0; q <= MB_PRI_WORST; q++){ @@ -78,3 +85,27 @@ mb_msg_queue::get_highest_pri_msg() return mb_message_sptr(); // equivalent of a zero pointer } + + +mb_message_sptr +mb_msg_queue::get_highest_pri_msg_nowait() +{ + omni_mutex_lock l(d_mutex); + + return get_highest_pri_msg_helper(); +} + +mb_message_sptr +mb_msg_queue::get_highest_pri_msg() +{ + omni_mutex_lock l(d_mutex); + + while (1){ + mb_message_sptr msg = get_highest_pri_msg_helper(); + if (msg) // Got one; return it + return msg; + + d_not_empty.wait(); // Wait for something + } +} + diff --git a/mblock/src/lib/mb_msg_queue.h b/mblock/src/lib/mb_msg_queue.h index 57f6dd0b..7977b7d8 100644 --- a/mblock/src/lib/mb_msg_queue.h +++ b/mblock/src/lib/mb_msg_queue.h @@ -37,10 +37,13 @@ class mb_msg_queue : boost::noncopyable bool empty_p() const { return head == 0; } }; - omni_mutex d_mutex; + omni_mutex d_mutex; + omni_condition d_not_empty; // reader waits on this // FIXME add bitmap to indicate which queues are non-empty. - subq d_queue[MB_NPRI]; + subq d_queue[MB_NPRI]; + + mb_message_sptr get_highest_pri_msg_helper(); public: mb_msg_queue(); @@ -53,6 +56,12 @@ public: * \brief Delete highest pri message from the queue and return it. * Returns equivalent of zero pointer if queue is empty. */ + mb_message_sptr get_highest_pri_msg_nowait(); + + /* + * \brief Delete highest pri message from the queue and return it. + * If the queue is empty, this call blocks until it can return a message. + */ mb_message_sptr get_highest_pri_msg(); }; diff --git a/mblock/src/lib/mb_port_simple.cc b/mblock/src/lib/mb_port_simple.cc index 1315b617..80cb65ef 100644 --- a/mblock/src/lib/mb_port_simple.cc +++ b/mblock/src/lib/mb_port_simple.cc @@ -29,6 +29,7 @@ #include #include #include +#include mb_port_simple::mb_port_simple(mb_mblock *mblock, @@ -49,7 +50,7 @@ void mb_port_simple::send(pmt_t signal, pmt_t data, pmt_t metadata, mb_pri_t priority) { if (port_type() == mb_port::RELAY) // Can't send directly to a RELAY port - throw mbe_invalid_port_type(mblock(), mblock()->fullname(), port_name()); + throw mbe_invalid_port_type(mblock(), mblock()->instance_name(), port_name()); mb_msg_accepter_sptr accepter = find_accepter(this); if (accepter) @@ -66,6 +67,8 @@ mb_port_simple::find_accepter(mb_port_simple *start) mb_endpoint peer_ep; mb_msg_accepter_sptr r; + mbi_runtime_lock l(p->mblock()); + // Set up initial context. switch(p->port_type()){ diff --git a/mblock/src/lib/mb_runtime.cc b/mblock/src/lib/mb_runtime.cc index fa762270..34a0af35 100644 --- a/mblock/src/lib/mb_runtime.cc +++ b/mblock/src/lib/mb_runtime.cc @@ -24,12 +24,12 @@ #endif #include -#include +#include mb_runtime_sptr mb_make_runtime() { - return mb_runtime_sptr(new mb_runtime_single_threaded()); + return mb_runtime_sptr(new mb_runtime_thread_per_mblock()); } mb_runtime::~mb_runtime() diff --git a/mblock/src/lib/mb_runtime.h b/mblock/src/lib/mb_runtime.h index 9b47537b..0929e30d 100644 --- a/mblock/src/lib/mb_runtime.h +++ b/mblock/src/lib/mb_runtime.h @@ -22,6 +22,7 @@ #define INCLUDED_MB_RUNTIME_H #include +#include /*! * \brief Public constructor (factory) for mb_runtime objects. @@ -33,8 +34,11 @@ mb_runtime_sptr mb_make_runtime(); * * There should generally be only a single instance of this class. */ -class mb_runtime : boost::noncopyable +class mb_runtime : boost::noncopyable, + public boost::enable_shared_from_this { + omni_mutex d_brl; // big runtime lock (avoid using this if possible...) + public: mb_runtime(){} virtual ~mb_runtime(); @@ -49,6 +53,24 @@ public: * \returns true if the system ran successfully. */ virtual bool run(mb_mblock_sptr top) = 0; + + + // ---------------------------------------------------------------- + // Stuff from here down is really private to the implementation... + // ---------------------------------------------------------------- + + /*! + * \brief lock the big runtime lock + * \implementation + */ + inline void lock() { d_brl.lock(); } + + /*! + * \brief unlock the big runtime lock + * \implementation + */ + inline void unlock() { d_brl.unlock(); } + }; #endif /* INCLUDED_MB_RUNTIME_H */ diff --git a/mblock/src/lib/mb_runtime_single_threaded.cc b/mblock/src/lib/mb_runtime_nop.cc similarity index 79% rename from mblock/src/lib/mb_runtime_single_threaded.cc rename to mblock/src/lib/mb_runtime_nop.cc index dc8597ae..a19f0793 100644 --- a/mblock/src/lib/mb_runtime_single_threaded.cc +++ b/mblock/src/lib/mb_runtime_nop.cc @@ -22,29 +22,35 @@ #ifdef HAVE_CONFIG_H #include #endif -#include +#include #include +mb_runtime_sptr +mb_make_runtime_nop() +{ + return mb_runtime_sptr(new mb_runtime_nop()); +} -mb_runtime_single_threaded::mb_runtime_single_threaded() + +mb_runtime_nop::mb_runtime_nop() { // nop for now } -mb_runtime_single_threaded::~mb_runtime_single_threaded() +mb_runtime_nop::~mb_runtime_nop() { // nop for now } bool -mb_runtime_single_threaded::run(mb_mblock_sptr top) +mb_runtime_nop::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->set_instance_name(path); mblock->init_fsm(); return true; } @@ -52,9 +58,7 @@ mb_runtime_single_threaded::run(mb_mblock_sptr top) initial_visitor visitor; - d_top = top; // remember top of tree - - d_top->walk_tree(&visitor); + top->walk_tree(&visitor); return true; } diff --git a/mblock/src/lib/mb_runtime_nop.h b/mblock/src/lib/mb_runtime_nop.h new file mode 100644 index 00000000..dc788799 --- /dev/null +++ b/mblock/src/lib/mb_runtime_nop.h @@ -0,0 +1,44 @@ +/* -*- c++ -*- */ +/* + * Copyright 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 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_NOP_H +#define INCLUDED_MB_RUNTIME_NOP_H + +#include + +/*! + * \brief Public constructor (factory) for mb_runtime_nop objects. + */ +mb_runtime_sptr mb_make_runtime_nop(); + +/*! + * \brief Concrete runtime that does nothing. Used only during early QA tests. + */ +class mb_runtime_nop : public mb_runtime +{ + +public: + mb_runtime_nop(); + ~mb_runtime_nop(); + + bool run(mb_mblock_sptr top); +}; + +#endif /* INCLUDED_MB_RUNTIME_NOP_H */ diff --git a/mblock/src/lib/mb_runtime_placeholder.cc b/mblock/src/lib/mb_runtime_placeholder.cc new file mode 100644 index 00000000..5ce7cc2a --- /dev/null +++ b/mblock/src/lib/mb_runtime_placeholder.cc @@ -0,0 +1,57 @@ +/* -*- c++ -*- */ +/* + * Copyright 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include + + +static mb_runtime *s_singleton = 0; + + +mb_runtime_placeholder::mb_runtime_placeholder() +{ + // nop +} + +mb_runtime_placeholder::~mb_runtime_placeholder() +{ + // nop +} + +bool +mb_runtime_placeholder::run(mb_mblock_sptr top) +{ + throw mbe_not_implemented(top.get(), "mb_runtime_placeholder::run"); +} + +mb_runtime * +mb_runtime_placeholder::singleton() +{ + if (s_singleton) + return s_singleton; + + s_singleton = new mb_runtime_placeholder(); + return s_singleton; +} diff --git a/mblock/src/lib/mb_runtime_placeholder.h b/mblock/src/lib/mb_runtime_placeholder.h new file mode 100644 index 00000000..b55d39f9 --- /dev/null +++ b/mblock/src/lib/mb_runtime_placeholder.h @@ -0,0 +1,50 @@ +/* -*- c++ -*- */ +/* + * Copyright 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 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_PLACEHOLDER_H +#define INCLUDED_MB_RUNTIME_PLACEHOLDER_H + +#include + +/*! + * \brief Concrete runtime that serves as a placeholder until the real + * runtime is known. + * + * The singleton instance of this class is installed in the d_runtime + * instance variable of each mb_mblock_impl at construction time. + * Having a valid instance of runtime removes the "pre runtime::run" + * corner case, and allows us to lock and unlock the big runtime lock + * even though there's no "real runtime" yet. + */ +class mb_runtime_placeholder : public mb_runtime +{ + +public: + mb_runtime_placeholder(); + ~mb_runtime_placeholder(); + + //! throws mbe_not_implemented + bool run(mb_mblock_sptr top); + + //! Return the placeholder singleton + static mb_runtime *singleton(); +}; + +#endif /* INCLUDED_MB_RUNTIME_PLACEHOLDER_H */ diff --git a/mblock/src/lib/mb_runtime_thread_per_mblock.cc b/mblock/src/lib/mb_runtime_thread_per_mblock.cc new file mode 100644 index 00000000..925dcdc4 --- /dev/null +++ b/mblock/src/lib/mb_runtime_thread_per_mblock.cc @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif +#include +#include +#include + + +mb_runtime_thread_per_mblock::mb_runtime_thread_per_mblock() +{ + // nop for now +} + +mb_runtime_thread_per_mblock::~mb_runtime_thread_per_mblock() +{ + // nop for now +} + +bool +mb_runtime_thread_per_mblock::run(mb_mblock_sptr top) +{ + class initial_visitor : public mb_visitor + { + mb_runtime *d_rt; + + public: + initial_visitor(mb_runtime *rt) : d_rt(rt) {} + bool operator()(mb_mblock *mblock, const std::string &path) + { + mblock->impl()->set_runtime(d_rt); + mblock->set_instance_name(path); + mblock->init_fsm(); + return true; + } + }; + + initial_visitor visitor(this); + + d_top = top; // remember top of tree + + d_top->walk_tree(&visitor); + + return true; +} diff --git a/mblock/src/lib/mb_runtime_single_threaded.h b/mblock/src/lib/mb_runtime_thread_per_mblock.h similarity index 78% rename from mblock/src/lib/mb_runtime_single_threaded.h rename to mblock/src/lib/mb_runtime_thread_per_mblock.h index b56e0a5e..cef756ec 100644 --- a/mblock/src/lib/mb_runtime_single_threaded.h +++ b/mblock/src/lib/mb_runtime_thread_per_mblock.h @@ -18,25 +18,23 @@ * 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_SINGLE_THREADED_H -#define INCLUDED_MB_RUNTIME_SINGLE_THREADED_H +#ifndef INCLUDED_MB_RUNTIME_THREAD_PER_MBLOCK_H +#define INCLUDED_MB_RUNTIME_THREAD_PER_MBLOCK_H #include /*! * \brief Concrete runtime that uses a single thread for all work. */ -class mb_runtime_single_threaded : public mb_runtime +class mb_runtime_thread_per_mblock : public mb_runtime { mb_mblock_sptr d_top; // top mblock public: - mb_runtime_single_threaded(); - ~mb_runtime_single_threaded(); + mb_runtime_thread_per_mblock(); + ~mb_runtime_thread_per_mblock(); bool run(mb_mblock_sptr top); }; - - -#endif /* INCLUDED_MB_RUNTIME_SINGLE_THREADED_H */ +#endif /* INCLUDED_MB_RUNTIME_THREAD_PER_MBLOCK_H */ diff --git a/mblock/src/lib/mbi_runtime_lock.h b/mblock/src/lib/mbi_runtime_lock.h new file mode 100644 index 00000000..3138a7e1 --- /dev/null +++ b/mblock/src/lib/mbi_runtime_lock.h @@ -0,0 +1,61 @@ +/* -*- c++ -*- */ +/* + * Copyright 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_MBI_RUNTIME_LOCK_H +#define INCLUDED_MBI_RUNTIME_LOCK_H + +#include +#include +#include + +/*! + * \brief acquire and release big runtime lock + * + * As an alternative to: + * { + * rt->lock(); + * ..... + * rt->unlock(); + * } + * + * you can use a single instance of the mbi_runtime_lock class: + * + * { + * mbi_runtime_lock l(rt); + * .... + * } + * + * This has the advantage that rt->unlock() will be called automatically + * when an exception is thrown. + */ + +class mbi_runtime_lock : boost::noncopyable { + mb_runtime *d_rt; +public: + mbi_runtime_lock(mb_runtime *rt) : d_rt(rt) { d_rt->lock(); } + mbi_runtime_lock(mb_mblock_impl *mi) : d_rt(mi->runtime()) { d_rt->lock(); } + mbi_runtime_lock(mb_mblock *mb) : d_rt(mb->impl()->runtime()) { d_rt->lock(); } + ~mbi_runtime_lock(void) { d_rt->unlock(); } + +}; + +#endif /* INCLUDED_MBI_RUNTIME_LOCK_H */ + diff --git a/mblock/src/lib/qa_mblock_prims.cc b/mblock/src/lib/qa_mblock_prims.cc index 7385a17e..79ed5a21 100644 --- a/mblock/src/lib/qa_mblock_prims.cc +++ b/mblock/src/lib/qa_mblock_prims.cc @@ -95,7 +95,6 @@ dp_3::~dp_3(){} void qa_mblock_prims::test_define_ports() { - mb_runtime_sptr rt = mb_make_runtime(); // std::vector intf; mb_mblock_sptr mb1 = mb_mblock_sptr(new dp_1()); @@ -175,7 +174,6 @@ dc_not_ok::~dc_not_ok(){} void qa_mblock_prims::test_define_components() { - mb_runtime_sptr rt = mb_make_runtime(); mb_mblock_sptr mb1 = mb_mblock_sptr(new dc_ok()); // OK // raises pmt_exception because of duplicate component definition of "c0" @@ -317,8 +315,6 @@ qa_mblock_prims::test_connect() pmt_list1(pmt_intern("in")), // in pmt_list1(pmt_intern("out"))); // out - - mb_runtime_sptr rt = mb_make_runtime(); mb_mblock_sptr mb0 = mb_mblock_sptr(new tc_0()); } @@ -330,7 +326,7 @@ qa_mblock_prims::test_msg_queue() mb_msg_queue q; // check initial state - CPPUNIT_ASSERT(q.get_highest_pri_msg() == 0); + CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0); CPPUNIT_ASSERT(MB_NPRI >= 5); // sanity check for this test @@ -340,11 +336,11 @@ qa_mblock_prims::test_msg_queue() q.insert(mb_make_message(PMT_NIL, pmt_from_long(1), PMT_NIL, MB_PRI_BEST + 2)); q.insert(mb_make_message(PMT_NIL, pmt_from_long(2), PMT_NIL, MB_PRI_BEST + 2)); - CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(q.get_highest_pri_msg()->data())); - CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(q.get_highest_pri_msg()->data())); - CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(q.get_highest_pri_msg()->data())); + CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(q.get_highest_pri_msg_nowait()->data())); + CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(q.get_highest_pri_msg_nowait()->data())); + CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(q.get_highest_pri_msg_nowait()->data())); - CPPUNIT_ASSERT(q.get_highest_pri_msg() == 0); + CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0); // insert messages of different priorities in pseudo-random order @@ -361,19 +357,19 @@ qa_mblock_prims::test_msg_queue() q.insert(mb_make_message(PMT_NIL, PMT_NIL, PMT_NIL, MB_PRI_BEST + 1)); // confirm that they come out in order - CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg()->priority()); - CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg()->priority()); - CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg()->priority()); - CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg()->priority()); - CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg()->priority()); - CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg()->priority()); - CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg()->priority()); - CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg()->priority()); - CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg()->priority()); - CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg()->priority()); + CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority()); + CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 0, q.get_highest_pri_msg_nowait()->priority()); + CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority()); + CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 1, q.get_highest_pri_msg_nowait()->priority()); + CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority()); + CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 2, q.get_highest_pri_msg_nowait()->priority()); + CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority()); + CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 3, q.get_highest_pri_msg_nowait()->priority()); + CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority()); + CPPUNIT_ASSERT_EQUAL(MB_PRI_BEST + 4, q.get_highest_pri_msg_nowait()->priority()); // check final state - CPPUNIT_ASSERT(q.get_highest_pri_msg() == 0); + CPPUNIT_ASSERT(q.get_highest_pri_msg_nowait() == 0); } //////////////////////////////////////////////////////////////// @@ -397,10 +393,10 @@ qa_mblock_prims::test_make_accepter() pmt_t cs = pmt_intern("cs"); - mb_message_sptr msg = mb->impl()->msgq().get_highest_pri_msg(); + mb_message_sptr msg = mb->impl()->msgq().get_highest_pri_msg_nowait(); CPPUNIT_ASSERT(pmt_eq(cs, msg->port_id())); // confirm that port_id is set CPPUNIT_ASSERT_EQUAL(0L, pmt_to_long(msg->data())); // and that data is correct - 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())); + CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data())); + CPPUNIT_ASSERT_EQUAL(2L, pmt_to_long(mb->impl()->msgq().get_highest_pri_msg_nowait()->data())); } diff --git a/mblock/src/lib/qa_mblock_send.cc b/mblock/src/lib/qa_mblock_send.cc index ff86adbf..46d6b644 100644 --- a/mblock/src/lib/qa_mblock_send.cc +++ b/mblock/src/lib/qa_mblock_send.cc @@ -28,6 +28,7 @@ #include #include #include +#include // QA only #include #include #include @@ -86,10 +87,10 @@ sr1::~sr1(){} void sr1::init_fsm() { - // std::cout << fullname() << "[sr1]: init_fsm\n"; + // std::cout << instance_name() << "[sr1]: init_fsm\n"; // send two messages to each port - pmt_t our_name = pmt_intern(fullname()); + pmt_t our_name = pmt_intern(instance_name()); 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))); @@ -127,10 +128,10 @@ sr0::~sr0(){} void sr0::init_fsm() { - // std::cout << fullname() << "[sr0]: init_fsm\n"; + // std::cout << instance_name() << "[sr0]: init_fsm\n"; // send two messages to p0 - pmt_t our_name = pmt_intern(fullname()); + pmt_t our_name = pmt_intern(instance_name()); 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))); } @@ -149,21 +150,21 @@ qa_mblock_send::test_simple_routing() mb_message_sptr msg; - mb_runtime_sptr rt = mb_make_runtime(); + mb_runtime_sptr rt = mb_make_runtime_nop(); 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(); + msg = mb0->impl()->msgq().get_highest_pri_msg_nowait(); 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(); + msg = mb0->impl()->msgq().get_highest_pri_msg_nowait(); CPPUNIT_ASSERT(msg); // std::cerr << msg->data() << std::endl; CPPUNIT_ASSERT_EQUAL(s_p0, msg->port_id()); @@ -176,28 +177,28 @@ qa_mblock_send::test_simple_routing() mb_mblock_sptr mb1 = mb0->impl()->component("mb1"); - msg = mb1->impl()->msgq().get_highest_pri_msg(); + msg = mb1->impl()->msgq().get_highest_pri_msg_nowait(); 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(); + msg = mb1->impl()->msgq().get_highest_pri_msg_nowait(); 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(); + msg = mb1->impl()->msgq().get_highest_pri_msg_nowait(); 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(); + msg = mb1->impl()->msgq().get_highest_pri_msg_nowait(); CPPUNIT_ASSERT(msg); // std::cerr << msg->data() << std::endl; CPPUNIT_ASSERT_EQUAL(s_p3, msg->port_id()); @@ -210,14 +211,14 @@ qa_mblock_send::test_simple_routing() mb_mblock_sptr mb2 = mb0->impl()->component("mb2"); - msg = mb2->impl()->msgq().get_highest_pri_msg(); + msg = mb2->impl()->msgq().get_highest_pri_msg_nowait(); 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(); + msg = mb2->impl()->msgq().get_highest_pri_msg_nowait(); CPPUNIT_ASSERT(msg); // std::cerr << msg->data() << std::endl; CPPUNIT_ASSERT_EQUAL(s_p3, msg->port_id()); @@ -253,10 +254,10 @@ rr2::~rr2(){} void rr2::init_fsm() { - // std::cout << fullname() << "[rr2]: init_fsm\n"; + // std::cout << instance_name() << "[rr2]: init_fsm\n"; // send two messages via p1 - pmt_t our_name = pmt_intern(fullname()); + pmt_t our_name = pmt_intern(instance_name()); 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))); } @@ -321,7 +322,7 @@ qa_mblock_send::test_relay_routing_1() { mb_message_sptr msg; - mb_runtime_sptr rt = mb_make_runtime(); + mb_runtime_sptr rt = mb_make_runtime_nop(); mb_mblock_sptr top = mb_mblock_sptr(new rr0_a()); rt->run(top); @@ -335,14 +336,14 @@ qa_mblock_send::test_relay_routing_1() // c0c0 should have received // two message from c1 via its p2 - msg = c0c0->impl()->msgq().get_highest_pri_msg(); + msg = c0c0->impl()->msgq().get_highest_pri_msg_nowait(); 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(); + msg = c0c0->impl()->msgq().get_highest_pri_msg_nowait(); CPPUNIT_ASSERT(msg); //std::cerr << msg->data() << std::endl; CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id()); @@ -352,14 +353,14 @@ qa_mblock_send::test_relay_routing_1() // c1 should have received // two message from c0c0 via its p2 - msg = c1->impl()->msgq().get_highest_pri_msg(); + msg = c1->impl()->msgq().get_highest_pri_msg_nowait(); 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(); + msg = c1->impl()->msgq().get_highest_pri_msg_nowait(); CPPUNIT_ASSERT(msg); //std::cerr << msg->data() << std::endl; CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id()); @@ -402,7 +403,7 @@ qa_mblock_send::test_relay_routing_2() { mb_message_sptr msg; - mb_runtime_sptr rt = mb_make_runtime(); + mb_runtime_sptr rt = mb_make_runtime_nop(); mb_mblock_sptr top = mb_mblock_sptr(new rr0_b()); rt->run(top); @@ -417,14 +418,14 @@ qa_mblock_send::test_relay_routing_2() // c0c0 should have received // two message from c1c0 via its p2 - msg = c0c0->impl()->msgq().get_highest_pri_msg(); + msg = c0c0->impl()->msgq().get_highest_pri_msg_nowait(); 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(); + msg = c0c0->impl()->msgq().get_highest_pri_msg_nowait(); CPPUNIT_ASSERT(msg); // std::cerr << msg->data() << std::endl; CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id()); @@ -434,14 +435,14 @@ qa_mblock_send::test_relay_routing_2() // c1c0 should have received // two message from c0c0 via its p2 - msg = c1c0->impl()->msgq().get_highest_pri_msg(); + msg = c1c0->impl()->msgq().get_highest_pri_msg_nowait(); 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(); + msg = c1c0->impl()->msgq().get_highest_pri_msg_nowait(); CPPUNIT_ASSERT(msg); // std::cerr << msg->data() << std::endl; CPPUNIT_ASSERT_EQUAL(s_p2, msg->port_id()); -- 2.30.2