From 76ed4c2fea5f59bfe02bbbb17754ef7eda44feca Mon Sep 17 00:00:00 2001
From: jcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5>
Date: Tue, 12 Dec 2006 20:00:39 +0000
Subject: Merge jcorgan/hier developer branch into trunk.  Enables creation of
 true hierarchical blocks, from either C++ or Python, as well as creating pure
 C++ gnuradio applications. EXPERIMENTAL.

git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@4070 221aa14e-8319-0410-a670-987f0aec2ac5
---
 gnuradio-core/src/lib/runtime/Makefile.am          |  20 +
 gnuradio-core/src/lib/runtime/gr_basic_block.cc    |  59 +++
 gnuradio-core/src/lib/runtime/gr_basic_block.h     |  99 +++++
 gnuradio-core/src/lib/runtime/gr_basic_block.i     |  52 +++
 gnuradio-core/src/lib/runtime/gr_block.cc          |  23 +-
 gnuradio-core/src/lib/runtime/gr_block.h           |  66 +--
 gnuradio-core/src/lib/runtime/gr_block.i           |  16 +-
 gnuradio-core/src/lib/runtime/gr_block_detail.cc   |   3 +-
 gnuradio-core/src/lib/runtime/gr_block_detail.h    |  28 +-
 gnuradio-core/src/lib/runtime/gr_hier_block2.cc    |  63 +++
 gnuradio-core/src/lib/runtime/gr_hier_block2.h     |  67 +++
 gnuradio-core/src/lib/runtime/gr_hier_block2.i     |  52 +++
 .../src/lib/runtime/gr_hier_block2_detail.cc       | 227 ++++++++++
 .../src/lib/runtime/gr_hier_block2_detail.h        |  66 +++
 gnuradio-core/src/lib/runtime/gr_runtime.cc        |  70 +++
 gnuradio-core/src/lib/runtime/gr_runtime.h         |  49 +++
 gnuradio-core/src/lib/runtime/gr_runtime.i         |  42 ++
 gnuradio-core/src/lib/runtime/gr_runtime_impl.cc   | 130 ++++++
 gnuradio-core/src/lib/runtime/gr_runtime_impl.h    |  74 ++++
 gnuradio-core/src/lib/runtime/gr_runtime_types.h   |  24 +-
 .../src/lib/runtime/gr_simple_flowgraph.cc         |  67 +++
 .../src/lib/runtime/gr_simple_flowgraph.h          |  52 +++
 .../src/lib/runtime/gr_simple_flowgraph.i          |  45 ++
 .../src/lib/runtime/gr_simple_flowgraph_detail.cc  | 471 +++++++++++++++++++++
 .../src/lib/runtime/gr_simple_flowgraph_detail.h   | 128 ++++++
 gnuradio-core/src/lib/runtime/qa_gr_block.cc       |   1 -
 gnuradio-core/src/lib/runtime/qa_gr_hier_block2.cc |  46 ++
 gnuradio-core/src/lib/runtime/qa_gr_hier_block2.h  |  43 ++
 gnuradio-core/src/lib/runtime/qa_runtime.cc        |   2 +
 gnuradio-core/src/lib/runtime/runtime.i            |   7 +
 gnuradio-core/src/python/gnuradio/gr/Makefile.am   |   2 +
 gnuradio-core/src/python/gnuradio/gr/__init__.py   |   2 +-
 .../src/python/gnuradio/gr/hier_block2.py          |  40 ++
 .../src/python/gnuradio/gr/qa_hier_block2.py       | 238 +++++++++++
 gnuradio-core/src/python/gnuradio/gr/qa_runtime.py |  31 ++
 .../src/python/gnuradio/gr/qa_simple_flowgraph.py  | 142 +++++++
 36 files changed, 2446 insertions(+), 101 deletions(-)
 create mode 100644 gnuradio-core/src/lib/runtime/gr_basic_block.cc
 create mode 100644 gnuradio-core/src/lib/runtime/gr_basic_block.h
 create mode 100644 gnuradio-core/src/lib/runtime/gr_basic_block.i
 create mode 100644 gnuradio-core/src/lib/runtime/gr_hier_block2.cc
 create mode 100644 gnuradio-core/src/lib/runtime/gr_hier_block2.h
 create mode 100644 gnuradio-core/src/lib/runtime/gr_hier_block2.i
 create mode 100644 gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc
 create mode 100644 gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h
 create mode 100644 gnuradio-core/src/lib/runtime/gr_runtime.cc
 create mode 100644 gnuradio-core/src/lib/runtime/gr_runtime.h
 create mode 100644 gnuradio-core/src/lib/runtime/gr_runtime.i
 create mode 100644 gnuradio-core/src/lib/runtime/gr_runtime_impl.cc
 create mode 100644 gnuradio-core/src/lib/runtime/gr_runtime_impl.h
 create mode 100644 gnuradio-core/src/lib/runtime/gr_simple_flowgraph.cc
 create mode 100644 gnuradio-core/src/lib/runtime/gr_simple_flowgraph.h
 create mode 100644 gnuradio-core/src/lib/runtime/gr_simple_flowgraph.i
 create mode 100644 gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.cc
 create mode 100644 gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.h
 create mode 100644 gnuradio-core/src/lib/runtime/qa_gr_hier_block2.cc
 create mode 100644 gnuradio-core/src/lib/runtime/qa_gr_hier_block2.h
 create mode 100644 gnuradio-core/src/python/gnuradio/gr/hier_block2.py
 create mode 100755 gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py
 create mode 100755 gnuradio-core/src/python/gnuradio/gr/qa_runtime.py
 create mode 100755 gnuradio-core/src/python/gnuradio/gr/qa_simple_flowgraph.py

(limited to 'gnuradio-core/src')

diff --git a/gnuradio-core/src/lib/runtime/Makefile.am b/gnuradio-core/src/lib/runtime/Makefile.am
index 2c1ea7eff0..47ae07a6ba 100644
--- a/gnuradio-core/src/lib/runtime/Makefile.am
+++ b/gnuradio-core/src/lib/runtime/Makefile.am
@@ -30,8 +30,13 @@ libruntime_la_LIBADD =		\
 
 
 libruntime_la_SOURCES = 			\
+	gr_basic_block.cc			\
+	gr_simple_flowgraph.cc			\
+	gr_simple_flowgraph_detail.cc		\
 	gr_block.cc				\
 	gr_block_detail.cc			\
+	gr_hier_block2.cc			\
+	gr_hier_block2_detail.cc		\
 	gr_buffer.cc				\
 	gr_dispatcher.cc			\
 	gr_error_handler.cc			\
@@ -43,6 +48,8 @@ libruntime_la_SOURCES = 			\
 	gr_pagesize.cc				\
 	gr_preferences.cc			\
 	gr_realtime.cc				\
+	gr_runtime.cc				\
+	gr_runtime_impl.cc			\
 	gr_single_threaded_scheduler.cc		\
 	gr_tmp_path.cc				\
 	gr_vmcircbuf.cc				\
@@ -54,14 +61,20 @@ libruntime_la_SOURCES = 			\
 
 libruntime_qa_la_SOURCES = 			\
 	qa_gr_block.cc				\
+	qa_gr_hier_block2.cc			\
 	qa_gr_buffer.cc				\
 	qa_gr_io_signature.cc			\
 	qa_gr_vmcircbuf.cc			\
 	qa_runtime.cc				
 
 grinclude_HEADERS = 				\
+	gr_basic_block.h			\
+	gr_simple_flowgraph.h			\
+	gr_simple_flowgraph_detail.h		\
 	gr_block.h				\
 	gr_block_detail.h			\
+	gr_hier_block2.h			\
+	gr_hier_block2_detail.h			\
 	gr_buffer.h				\
 	gr_complex.h				\
 	gr_dispatcher.h				\
@@ -74,6 +87,8 @@ grinclude_HEADERS = 				\
 	gr_pagesize.h				\
 	gr_preferences.h			\
 	gr_realtime.h				\
+	gr_runtime.h				\
+	gr_runtime_impl.h			\
 	gr_runtime_types.h			\
 	gr_select_handler.h			\
 	gr_single_threaded_scheduler.h		\
@@ -88,14 +103,17 @@ noinst_HEADERS = 				\
 	gr_vmcircbuf_sysv_shm.h			\
 	gr_vmcircbuf_createfilemapping.h	\
 	qa_gr_block.h				\
+	qa_gr_hier_block2.h			\
 	qa_gr_buffer.h				\
 	qa_gr_io_signature.h			\
 	qa_gr_vmcircbuf.h			\
 	qa_runtime.h				
 
 swiginclude_HEADERS =			\
+	gr_basic_block.i		\
 	gr_block.i			\
 	gr_block_detail.i		\
+	gr_hier_block2.i		\
 	gr_buffer.i			\
 	gr_dispatcher.i			\
 	gr_error_handler.i		\
@@ -104,6 +122,8 @@ swiginclude_HEADERS =			\
 	gr_msg_handler.i		\
 	gr_msg_queue.i			\
 	gr_realtime.i			\
+	gr_runtime.i			\
+	gr_simple_flowgraph.i		\
 	gr_single_threaded_scheduler.i	\
 	gr_swig_block_magic.i		\
 	runtime.i
diff --git a/gnuradio-core/src/lib/runtime/gr_basic_block.cc b/gnuradio-core/src/lib/runtime/gr_basic_block.cc
new file mode 100644
index 0000000000..a5f1a4f832
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_basic_block.cc
@@ -0,0 +1,59 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_basic_block.h>
+#include <stdexcept>
+
+static long s_next_id = 0;
+static long s_ncurrently_allocated = 0;
+
+long 
+gr_basic_block_ncurrently_allocated()
+{
+    return s_ncurrently_allocated;
+}
+
+gr_basic_block::gr_basic_block(const std::string &name,
+                               gr_io_signature_sptr input_signature,
+                               gr_io_signature_sptr output_signature) 
+  : d_name(name),
+    d_input_signature(input_signature),
+    d_output_signature(output_signature),
+    d_unique_id(s_next_id++)
+{
+    s_ncurrently_allocated++;
+}
+  
+gr_basic_block::~gr_basic_block()
+{
+    s_ncurrently_allocated--;
+}
+
+gr_basic_block_sptr 
+gr_basic_block::basic_block()
+{
+    return shared_from_this();
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_basic_block.h b/gnuradio-core/src/lib/runtime/gr_basic_block.h
new file mode 100644
index 0000000000..583c3241d5
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_basic_block.h
@@ -0,0 +1,99 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GR_BASIC_BLOCK_H
+#define INCLUDED_GR_BASIC_BLOCK_H
+
+#include <gr_runtime_types.h>
+#include <boost/enable_shared_from_this.hpp>
+#include <string>
+
+/*!
+ * \brief The abstract base class for all signal processing blocks.
+ * \ingroup block
+ *
+ * Basic blocks are the bare abstraction of an entity that has a name
+ * and a set of inputs and outputs.  These are never instantiated
+ * directly; rather, this is the abstract parent class of both gr_hier_block,
+ * which is a recursive container, and gr_block, which implements actual
+ * signal processing functions.
+ */
+
+class gr_basic_block : public boost::enable_shared_from_this<gr_basic_block>
+{
+protected:
+    std::string          d_name;
+    gr_io_signature_sptr d_input_signature;
+    gr_io_signature_sptr d_output_signature;
+    long                 d_unique_id;
+
+    //! Protected constructor prevents instantiation by non-derived classes
+    gr_basic_block(const std::string &name,
+                   gr_io_signature_sptr input_signature,
+                   gr_io_signature_sptr output_signature);
+
+    //! may only be called during constructor
+    void set_input_signature(gr_io_signature_sptr iosig) {
+        d_input_signature = iosig;
+    }
+    
+    //! may only be called during constructor
+    void set_output_signature(gr_io_signature_sptr iosig) {
+        d_output_signature = iosig;
+    }
+
+public:
+    virtual ~gr_basic_block();
+    long unique_id() const { return d_unique_id; }
+    std::string name() const { return d_name; }
+    gr_io_signature_sptr input_signature() const  { return d_input_signature; }
+    gr_io_signature_sptr output_signature() const { return d_output_signature; }
+    gr_basic_block_sptr basic_block(); // Needed for Python type coercion
+
+    /*!
+     * \brief Confirm that ninputs and noutputs is an acceptable combination.
+     *
+     * \param ninputs	number of input streams connected
+     * \param noutputs	number of output streams connected
+     *
+     * \returns true if this is a valid configuration for this block.
+     *
+     * This function is called by the runtime system whenever the
+     * topology changes.  Most classes do not need to override this.
+     * This check is in addition to the constraints specified by the input
+     * and output gr_io_signatures.
+     */
+    virtual bool check_topology(int ninputs, int noutputs) { return true; }
+};
+
+typedef std::vector<gr_basic_block_sptr> gr_basic_block_vector_t;
+typedef std::vector<gr_basic_block_sptr>::iterator gr_basic_block_viter_t;
+
+long gr_basic_block_ncurrently_allocated();
+
+inline std::ostream &operator << (std::ostream &os, gr_basic_block_sptr basic_block)
+{
+    os << basic_block->name() << "(" << basic_block->unique_id() << ")";
+    return os;
+}
+
+#endif /* INCLUDED_GR_BASIC_BLOCK_H */
diff --git a/gnuradio-core/src/lib/runtime/gr_basic_block.i b/gnuradio-core/src/lib/runtime/gr_basic_block.i
new file mode 100644
index 0000000000..33b895d438
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_basic_block.i
@@ -0,0 +1,52 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+class gr_basic_block;
+typedef boost::shared_ptr<gr_basic_block> gr_basic_block_sptr;
+%template(gr_basic_block_sptr) boost::shared_ptr<gr_basic_block>;
+
+// support vectors of these...
+namespace std {
+  %template(x_vector_gr_basic_block_sptr) vector<gr_basic_block_sptr>;
+};
+
+class gr_basic_block
+{
+protected:
+    gr_basic_block();
+
+public:
+    virtual ~gr_basic_block();
+    std::string name() const;
+    gr_io_signature_sptr input_signature() const;
+    gr_io_signature_sptr output_signature() const;
+    long unique_id() const;
+    gr_basic_block_sptr basic_block();
+    bool check_topology (int ninputs, int noutputs);
+};
+
+%rename(block_ncurrently_allocated) gr_basic_block_ncurrently_allocated;
+long gr_basic_block_ncurrently_allocated();
+
+%pythoncode %{
+gr_basic_block_sptr.__repr__ = lambda self: "<gr_basic_block %s (%d)>" % (self.name(), self.unique_id ())
+%}
diff --git a/gnuradio-core/src/lib/runtime/gr_block.cc b/gnuradio-core/src/lib/runtime/gr_block.cc
index 65e16045a9..1b1d357560 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.cc
+++ b/gnuradio-core/src/lib/runtime/gr_block.cc
@@ -27,34 +27,21 @@
 #include <gr_block.h>
 #include <gr_block_detail.h>
 #include <stdexcept>
-
-static long s_next_id = 0;
-static long s_ncurrently_allocated = 0;
-
-long
-gr_block_ncurrently_allocated ()
-{
-  return s_ncurrently_allocated;
-}
+#include <iostream>
 
 gr_block::gr_block (const std::string &name,
 		    gr_io_signature_sptr input_signature,
 		    gr_io_signature_sptr output_signature)
-  : d_name (name),
-    d_input_signature (input_signature),
-    d_output_signature (output_signature),
+  : gr_basic_block(name, input_signature, output_signature),
     d_output_multiple (1),
     d_relative_rate (1.0),
-    d_unique_id (s_next_id++),
     d_history(1),
     d_fixed_rate(false)
 {
-  s_ncurrently_allocated++;
 }
   
 gr_block::~gr_block ()
 {
-  s_ncurrently_allocated--;
 }
 
 // stub implementation:  1:1
@@ -69,12 +56,6 @@ gr_block::forecast (int noutput_items, gr_vector_int &ninput_items_required)
 
 // default implementation
 
-bool
-gr_block::check_topology (int ninputs, int noutputs)
-{
-  return true;
-}
-
 bool
 gr_block::start()
 {
diff --git a/gnuradio-core/src/lib/runtime/gr_block.h b/gnuradio-core/src/lib/runtime/gr_block.h
index 9723be1085..247238bb0a 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.h
+++ b/gnuradio-core/src/lib/runtime/gr_block.h
@@ -23,13 +23,17 @@
 #ifndef INCLUDED_GR_BLOCK_H
 #define INCLUDED_GR_BLOCK_H
 
-#include <gr_runtime_types.h>
-#include <string>
+#include <gr_basic_block.h>
 
 /*!
- * \brief The abstract base class for all signal processing blocks.
+ * \brief The abstract base class for all 'terminal' processing blocks.
  * \ingroup block
  *
+ * A signal processing flow is constructed by creating a tree of 
+ * hierarchical blocks, which at any level may also contain terminal nodes
+ * that actually implement signal processing functions. This is the base
+ * class for all such leaf nodes.
+ 
  * Blocks have a set of input streams and output streams.  The
  * input_signature and output_signature define the number of input
  * streams and output streams respectively, and the type of the data
@@ -49,16 +53,11 @@
  * It reads the input items and writes the output items.
  */
 
-class gr_block {
+class gr_block : public gr_basic_block {
 
  public:
   
   virtual ~gr_block ();
-  
-  std::string name () const { return d_name; }
-  gr_io_signature_sptr input_signature () const  { return d_input_signature; }
-  gr_io_signature_sptr output_signature () const { return d_output_signature; }
-  long unique_id () const { return d_unique_id; }
 
   /*!
    * Assume block computes y_i = f(x_i, x_i-1, x_i-2, x_i-3...)
@@ -113,21 +112,6 @@ class gr_block {
 			    gr_vector_const_void_star &input_items,
 			    gr_vector_void_star &output_items) = 0;
 
-  /*!
-   * \brief Confirm that ninputs and noutputs is an acceptable combination.
-   *
-   * \param ninputs	number of input streams connected
-   * \param noutputs	number of output streams connected
-   *
-   * \returns true if this is a valid configuration for this block.
-   *
-   * This function is called by the runtime system whenever the
-   * topology changes.  Most classes do not need to override this.
-   * This check is in addition to the constraints specified by the input
-   * and output gr_io_signatures.
-   */
-  virtual bool check_topology (int ninputs, int noutputs);
-
   /*!
    * \brief Called to enable drivers, etc for i/o devices.
    *
@@ -205,32 +189,17 @@ class gr_block {
 
  private:
 
-  std::string		d_name;
-  gr_io_signature_sptr	d_input_signature;
-  gr_io_signature_sptr	d_output_signature;
-  int			d_output_multiple;
-  double		d_relative_rate;	// approx output_rate / input_rate
-  gr_block_detail_sptr	d_detail;		// implementation details
-  long			d_unique_id;		// convenient for debugging
-  unsigned		d_history;
-  bool			d_fixed_rate;
-
-  
+  int                   d_output_multiple;
+  double                d_relative_rate;	// approx output_rate / input_rate
+  gr_block_detail_sptr	d_detail;		    // implementation details
+  unsigned              d_history;
+  bool                  d_fixed_rate;
+    
  protected:
 
   gr_block (const std::string &name,
-	    gr_io_signature_sptr input_signature,
-	    gr_io_signature_sptr output_signature);
-
-  //! may only be called during constructor
-  void set_input_signature (gr_io_signature_sptr iosig){
-    d_input_signature = iosig;
-  }
-
-  //! may only be called during constructor
-  void set_output_signature (gr_io_signature_sptr iosig){
-    d_output_signature = iosig;
-  }
+            gr_io_signature_sptr input_signature,
+            gr_io_signature_sptr output_signature);
 
   void set_fixed_rate(bool fixed_rate){ d_fixed_rate = fixed_rate; }
 
@@ -242,6 +211,7 @@ class gr_block {
   void set_detail (gr_block_detail_sptr detail) { d_detail = detail; }
 };
 
-long gr_block_ncurrently_allocated ();
+typedef std::vector<gr_block_sptr> gr_block_vector_t;
+typedef std::vector<gr_block_sptr>::iterator gr_block_viter_t;
 
 #endif /* INCLUDED_GR_BLOCK_H */
diff --git a/gnuradio-core/src/lib/runtime/gr_block.i b/gnuradio-core/src/lib/runtime/gr_block.i
index 3bfd243676..5d0f5fb1bb 100644
--- a/gnuradio-core/src/lib/runtime/gr_block.i
+++ b/gnuradio-core/src/lib/runtime/gr_block.i
@@ -20,6 +20,8 @@
  * Boston, MA 02110-1301, USA.
  */
 
+%include <gr_basic_block.i>
+
 class gr_block;
 typedef boost::shared_ptr<gr_block> gr_block_sptr;
 %template(gr_block_sptr) boost::shared_ptr<gr_block>;
@@ -29,26 +31,21 @@ namespace std {
   %template(x_vector_gr_block_sptr)	vector<gr_block_sptr>;
 };
 
-class gr_block {
+class gr_block : public gr_basic_block {
  protected:
   gr_block (const std::string &name,
-	     gr_io_signature_sptr input_signature,
-	     gr_io_signature_sptr output_signature);
+            gr_io_signature_sptr input_signature,
+            gr_io_signature_sptr output_signature);
 
  public:
   
   virtual ~gr_block ();
   
-  std::string name () const;
-  gr_io_signature_sptr input_signature () const;
-  gr_io_signature_sptr output_signature () const;
-  long unique_id () const;
   unsigned history () const;
 
   int  output_multiple () const;
   double relative_rate () const;
 
-  bool check_topology (int ninputs, int noutputs);
   bool start();
   bool stop();
 
@@ -57,9 +54,6 @@ class gr_block {
   void set_detail (gr_block_detail_sptr detail) { d_detail = detail; }
 };
 
-%rename(block_ncurrently_allocated) gr_block_ncurrently_allocated;
-long gr_block_ncurrently_allocated ();
-
 %pythoncode %{
 gr_block_sptr.__repr__ = lambda self: "<gr_block %s (%d)>" % (self.name(), self.unique_id ())
 gr_block_sptr.block = lambda self: self
diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.cc b/gnuradio-core/src/lib/runtime/gr_block_detail.cc
index ed414d472a..5feb180f78 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_detail.cc
+++ b/gnuradio-core/src/lib/runtime/gr_block_detail.cc
@@ -38,7 +38,8 @@ gr_block_detail_ncurrently_allocated ()
 gr_block_detail::gr_block_detail (unsigned int ninputs, unsigned int noutputs)
   : d_ninputs (ninputs), d_noutputs (noutputs),
     d_input (ninputs), d_output (noutputs),
-    d_done (false)
+    d_done (false),
+    d_color (gr_block_detail::WHITE)
 {
   s_ncurrently_allocated++;
 }
diff --git a/gnuradio-core/src/lib/runtime/gr_block_detail.h b/gnuradio-core/src/lib/runtime/gr_block_detail.h
index 8c46159194..d89b7fea18 100644
--- a/gnuradio-core/src/lib/runtime/gr_block_detail.h
+++ b/gnuradio-core/src/lib/runtime/gr_block_detail.h
@@ -1,19 +1,19 @@
 /* -*- c++ -*- */
 /*
  * Copyright 2004 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 detail.
- * 
+ *
  * 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., 51 Franklin Street,
@@ -75,18 +75,26 @@ class gr_block_detail {
 
   void produce_each (int how_many_items);
 
+  /*!
+   * \brief Allow the flowgraph to set for sorting and partitioning
+   */
+  enum vcolor { WHITE, GREY, BLACK };
+  void set_color(vcolor color) { d_color = color; }
+  vcolor color() const { return d_color; }
+
   // ----------------------------------------------------------------------------
 
  private:
-  unsigned int			    d_ninputs;
-  unsigned int			    d_noutputs;
+  unsigned int                       d_ninputs;
+  unsigned int                       d_noutputs;
   std::vector<gr_buffer_reader_sptr> d_input;
-  std::vector<gr_buffer_sptr>	    d_output;
-  bool				    d_done;
-    
+  std::vector<gr_buffer_sptr>	     d_output;
+  bool                               d_done;
+  vcolor                             d_color;
+
   gr_block_detail (unsigned int ninputs, unsigned int noutputs);
 
-  friend gr_block_detail_sptr 
+  friend gr_block_detail_sptr
   gr_make_block_detail (unsigned int ninputs, unsigned int noutputs);
 };
 
diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2.cc b/gnuradio-core/src/lib/runtime/gr_hier_block2.cc
new file mode 100644
index 0000000000..65dea95fbb
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_hier_block2.cc
@@ -0,0 +1,63 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_hier_block2.h>
+#include <gr_io_signature.h>
+#include <gr_hier_block2_detail.h>
+#include <iostream>
+
+gr_hier_block2_sptr gr_make_hier_block2(const std::string &name, 
+                                        gr_io_signature_sptr input_signature,
+                                        gr_io_signature_sptr output_signature)
+{
+    return gr_hier_block2_sptr(new gr_hier_block2(name, input_signature, output_signature));
+}
+
+gr_hier_block2::gr_hier_block2(const std::string &name,
+                               gr_io_signature_sptr input_signature,
+                               gr_io_signature_sptr output_signature)
+  : gr_basic_block(name, input_signature, output_signature),
+    d_detail(new gr_hier_block2_detail(this))
+{
+}
+
+gr_hier_block2::~gr_hier_block2()
+{
+    delete d_detail;
+}
+
+void 
+gr_hier_block2::define_component(const std::string &name, gr_basic_block_sptr block)
+{
+    d_detail->define_component(name, block);
+}
+
+void 
+gr_hier_block2::connect(const std::string &src_name, int src_port, 
+                        const std::string &dst_name, int dst_port)
+{
+    d_detail->connect(src_name, src_port, dst_name, dst_port);
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2.h b/gnuradio-core/src/lib/runtime/gr_hier_block2.h
new file mode 100644
index 0000000000..9d2dd35690
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_hier_block2.h
@@ -0,0 +1,67 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef INCLUDED_GR_HIER_BLOCK2_H
+#define INCLUDED_GR_HIER_BLOCK2_H
+
+#include <gr_basic_block.h>
+
+/*!
+ * \brief public constructor for gr_hier_block2
+ */
+gr_hier_block2_sptr gr_make_hier_block2(const std::string &name,
+                                        gr_io_signature_sptr input_signature,
+                                        gr_io_signature_sptr output_signature);
+
+class gr_hier_block2_detail;
+
+/*!
+ * \brief gr_hier_block2 - Hierarchical container class for gr_block's
+ *
+ */
+class gr_hier_block2 : public gr_basic_block
+{
+private:
+    friend class gr_hier_block2_detail;
+    friend class gr_runtime_impl;
+    friend gr_hier_block2_sptr gr_make_hier_block2(const std::string &name,
+                                                   gr_io_signature_sptr input_signature,
+                                                   gr_io_signature_sptr output_signature);
+
+    /*!
+     * \brief Private implementation details of gr_hier_block2
+     */
+    gr_hier_block2_detail *d_detail;
+    
+protected: 
+    gr_hier_block2(const std::string &name,
+                   gr_io_signature_sptr input_signature,
+                   gr_io_signature_sptr output_signature);
+
+public:
+    virtual ~gr_hier_block2();
+
+    void define_component(const std::string &name, gr_basic_block_sptr basic_block);
+    void connect(const std::string &src_name, int src_port, 
+                 const std::string &dst_name, int dst_port);
+};
+
+#endif /* INCLUDED_GR_HIER_BLOCK2_H */
diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2.i b/gnuradio-core/src/lib/runtime/gr_hier_block2.i
new file mode 100644
index 0000000000..c5a6765349
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_hier_block2.i
@@ -0,0 +1,52 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2005 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+%include <gr_basic_block.i>
+
+class gr_hier_block2;
+typedef boost::shared_ptr<gr_hier_block2> gr_hier_block2_sptr;
+%template(gr_hier_block2_sptr) boost::shared_ptr<gr_hier_block2>;
+
+// Hack to have a Python shim implementation of gr.hier_block2
+// that instantiates one of these and passes through calls
+%rename(hier_block2_swig) gr_make_hier_block2;
+gr_hier_block2_sptr gr_make_hier_block2(const std::string name,
+                                        gr_io_signature_sptr input_signature,
+                                        gr_io_signature_sptr output_signature);
+
+class gr_hier_block2 : public gr_basic_block
+{
+private:
+    gr_hier_block2(const std::string name,
+                   gr_io_signature_sptr input_signature,
+                   gr_io_signature_sptr output_signature);
+
+public:
+    ~gr_hier_block2 ();
+
+    // Add a named block to the container
+    void define_component(const std::string &name, gr_basic_block_sptr basic_block)
+        throw (std::invalid_argument);
+    void connect(const std::string &src_name, int src_port,
+                 const std::string &dst_name, int dst_port)
+        throw (std::invalid_argument);
+};
diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc
new file mode 100644
index 0000000000..545a64bfd4
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc
@@ -0,0 +1,227 @@
+/*
+ * 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_hier_block2_detail.h>
+#include <gr_simple_flowgraph.h>
+#include <gr_io_signature.h>
+#include <stdexcept>
+#include <iostream>
+
+gr_hier_block2_detail::gr_hier_block2_detail(gr_hier_block2 *owner) :
+d_owner(owner)
+{
+}
+
+gr_hier_block2_detail::~gr_hier_block2_detail()
+{
+    d_owner = 0; // Don't use delete, we didn't allocate
+}
+
+gr_basic_block_sptr
+gr_hier_block2_detail::lookup_block(const std::string &name)
+{
+    gr_hier_component_miter_t p = d_components.find(name);
+    if (p != d_components.end())
+        return p->second;
+    else
+        return gr_basic_block_sptr();
+}
+
+void 
+gr_hier_block2_detail::define_component(const std::string &name, gr_basic_block_sptr block)
+{
+    if (!block)
+	throw std::invalid_argument("null block passed");
+
+    if (name == "self")
+        throw std::invalid_argument("name is reserved");
+
+    // TODO: reject names with '.' inside
+    
+    if (!lookup_block(name))
+        d_components[name] = block;
+    else
+        throw std::invalid_argument("name already in use");
+}
+
+void 
+gr_hier_block2_detail::connect(const std::string &src_name, int src_port, 
+                               const std::string &dst_name, int dst_port)
+{
+    gr_io_signature_sptr src_io_signature;
+    gr_io_signature_sptr dst_io_signature;
+    
+    // Check against our *input_signature* if we're wiring from one of our external inputs
+    if (src_name == "self") 
+        src_io_signature = d_owner->input_signature();
+    else {
+        gr_basic_block_sptr src_block = lookup_block(src_name);
+        if (!src_block)
+            throw std::invalid_argument("undefined src name");
+        src_io_signature = src_block->output_signature();
+    }
+    
+    // Check against our *output_signature* if we're wiring to one of our external outputs
+    if (dst_name == "self") 
+    	dst_io_signature = d_owner->output_signature();
+    else {
+        gr_basic_block_sptr dst_block = lookup_block(dst_name);
+        if (!dst_block)
+            throw std::invalid_argument("undefined dst name");
+        dst_io_signature = dst_block->input_signature();
+    }
+    
+    // Check port numbers are valid
+    check_valid_port(src_io_signature, src_port);
+    check_valid_port(dst_io_signature, dst_port);
+
+    // Check destination port not already in use
+    check_dst_not_used(dst_name, dst_port);
+
+    // Check endpoint types match
+    check_type_match(src_io_signature, src_port, dst_io_signature, dst_port);
+
+    d_edges.push_back(gr_make_edge(src_name, src_port, dst_name, dst_port));
+}
+
+void 
+gr_hier_block2_detail::check_valid_port(gr_io_signature_sptr sig, int port)
+{
+    if (port < 0)
+        throw std::invalid_argument("port number must not be negative");
+	
+    if (sig->max_streams() >= 0 && port >= sig->max_streams())
+        throw std::invalid_argument("port number exceeds max streams");
+}
+
+void 
+gr_hier_block2_detail::check_dst_not_used(const std::string name, int port)
+{
+    for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
+        if ((*p)->dst_name() == name && (*p)->dst_port() == port)
+            throw std::invalid_argument("destination port in use");
+}
+
+void 
+gr_hier_block2_detail::check_type_match(gr_io_signature_sptr src_sig, int src_port,
+                                        gr_io_signature_sptr dst_sig, int dst_port)
+{
+    if (src_sig->sizeof_stream_item(src_port) != dst_sig->sizeof_stream_item(dst_port))
+        throw std::invalid_argument("type mismatch");
+}
+
+std::string
+gr_hier_block2_detail::prepend_prefix(const std::string &prefix, const std::string &str)
+{
+    return prefix + ((prefix == "") ? "" : ".") + str;
+}
+
+gr_endpoint
+gr_hier_block2_detail::match_endpoint(const std::string &name, int port, bool is_input)
+{
+    for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
+        if (is_input) {
+            if ((*p)->src_name() == name && (*p)->src_port() == port)
+                return resolve_endpoint((*p)->dst_name(), (*p)->dst_port(), "", !is_input);
+	    }
+        else {
+            if ((*p)->dst_name() == name && (*p)->dst_port() == port)
+                return resolve_endpoint((*p)->src_name(), (*p)->src_port(), "", !is_input);
+        }
+    }
+
+    // Should never get here
+    throw std::runtime_error("unable to match endpoint");
+}
+
+gr_endpoint
+gr_hier_block2_detail::resolve_endpoint(const std::string &name, int port, 
+                                        const std::string &prefix, bool is_input)
+{
+    gr_basic_block_sptr basic_block = lookup_block(name);
+
+    // Check if 'name' points to gr_block (leaf node)
+    gr_block_sptr block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(basic_block));
+    if (block)
+        return gr_endpoint(prepend_prefix(prefix, name), port);
+
+    // Check if 'name' points to hierarchical block
+    gr_hier_block2_sptr hier_block2(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(basic_block));
+    if (hier_block2) {
+        std::string child_prefix = prepend_prefix(prefix, name);
+        gr_endpoint match(hier_block2->d_detail->match_endpoint("self", port, !is_input));
+        return gr_endpoint(prepend_prefix(child_prefix, match.name()), match.port());
+    }
+
+    // Shouldn't ever get here
+    throw std::runtime_error("unable to resolve endpoint");
+}
+
+void
+gr_hier_block2_detail::flatten(gr_simple_flowgraph_sptr sfg, const std::string &prefix)
+{
+    flatten_components(sfg, prefix);
+    flatten_edges(sfg, prefix);
+}
+
+void
+gr_hier_block2_detail::flatten_components(gr_simple_flowgraph_sptr sfg, const std::string &prefix)
+{
+    // Add my non-hierarchical components to the simple flowgraph, then recurse
+    for (gr_hier_component_miter_t p = d_components.begin(); p != d_components.end(); p++) {
+        std::string name = prepend_prefix(prefix, p->first);
+
+        gr_basic_block_sptr basic_block = p->second;
+        gr_block_sptr block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(basic_block));
+        if (block)	
+            sfg->define_component(name, block);
+
+        gr_hier_block2_sptr hier_block2(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(basic_block));
+        if (hier_block2)
+            hier_block2->d_detail->flatten_components(sfg, name);
+    }
+}
+
+void
+gr_hier_block2_detail::flatten_edges(gr_simple_flowgraph_sptr sfg, const std::string &prefix)
+{
+    // Add my edges to the flow graph, resolving references to actual endpoints
+    for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
+    	// Connections to self get resolved/added by parent if actually connected
+        if ((*p)->src_name() == "self" || (*p)->dst_name() == "self")
+            continue;
+
+        gr_endpoint src_endp = resolve_endpoint((*p)->src_name(), (*p)->src_port(), prefix, true);
+        gr_endpoint dst_endp = resolve_endpoint((*p)->dst_name(), (*p)->dst_port(), prefix, false);
+        sfg->connect(src_endp.name(), src_endp.port(), dst_endp.name(), dst_endp.port());
+    }
+
+    // Recurse hierarchical children
+    for (gr_hier_component_miter_t p = d_components.begin(); p != d_components.end(); p++) {
+        gr_hier_block2_sptr hier_block2(boost::dynamic_pointer_cast<gr_hier_block2, gr_basic_block>(p->second));
+        if (hier_block2)
+            hier_block2->d_detail->flatten_edges(sfg, prepend_prefix(prefix, p->first));
+    }
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h
new file mode 100644
index 0000000000..095bd40f56
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h
@@ -0,0 +1,66 @@
+/*
+ * 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+#ifndef INCLUDED_GR_HIER_BLOCK2_DETAIL_H
+#define INCLUDED_GR_HIER_BLOCK2_DETAIL_H
+
+#include <gr_hier_block2.h>
+#include <gr_simple_flowgraph_detail.h>
+#include <boost/utility.hpp>
+
+typedef std::map<std::string, gr_basic_block_sptr> gr_hier_component_map_t;
+typedef std::map<std::string, gr_basic_block_sptr>::iterator gr_hier_component_miter_t;
+
+class gr_hier_block2_detail : boost::noncopyable
+{
+private:
+    friend class gr_hier_block2;
+    friend class gr_runtime_impl;
+    
+    // Constructor--it's private, only friends can instantiate
+    gr_hier_block2_detail(gr_hier_block2 *owner);
+
+    // Private implementation data
+    gr_hier_block2 *d_owner;
+    gr_hier_component_map_t d_components;
+    gr_edge_vector_t d_edges;
+        
+    // Private implementation methods
+    void define_component(const std::string &name, gr_basic_block_sptr block);
+    gr_basic_block_sptr lookup_block(const std::string &name);
+    void connect(const std::string &src_name, int src_port, 
+                 const std::string &dst_name, int dst_port);
+    void check_valid_port(gr_io_signature_sptr sig, int port);
+    void check_dst_not_used(const std::string name, int port);
+    void check_type_match(gr_io_signature_sptr src_sig, int src_port,
+                          gr_io_signature_sptr dst_sig, int dst_port);
+    std::string prepend_prefix(const std::string &prefix, const std::string &str);
+    void flatten(gr_simple_flowgraph_sptr sfg, const std::string &prefix = "");
+    void flatten_components(gr_simple_flowgraph_sptr sfg, const std::string &prefix);
+    void flatten_edges(gr_simple_flowgraph_sptr sfg, const std::string &prefix);
+    gr_endpoint match_endpoint(const std::string &name, int port, bool is_input);
+    gr_endpoint resolve_endpoint(const std::string &name, int port, 
+                                 const std::string &prefix, bool is_input);
+    
+public:
+    ~gr_hier_block2_detail();
+};
+
+#endif /* INCLUDED_GR_HIER_BLOCK2_DETAIL_H */
diff --git a/gnuradio-core/src/lib/runtime/gr_runtime.cc b/gnuradio-core/src/lib/runtime/gr_runtime.cc
new file mode 100644
index 0000000000..926e878575
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_runtime.cc
@@ -0,0 +1,70 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_runtime.h>
+#include <gr_runtime_impl.h>
+#include <iostream>
+
+gr_runtime_sptr 
+gr_make_runtime(gr_hier_block2_sptr top_block)
+{
+    return gr_runtime_sptr(new gr_runtime(top_block));
+}
+
+gr_runtime::gr_runtime(gr_hier_block2_sptr top_block)
+{
+    d_impl = new gr_runtime_impl(top_block);
+}
+  
+gr_runtime::~gr_runtime()
+{
+    delete d_impl;
+}
+
+void 
+gr_runtime::start()
+{
+    d_impl->start();
+}
+
+void 
+gr_runtime::stop()
+{
+    d_impl->stop();
+}
+
+void 
+gr_runtime::wait()
+{
+    d_impl->wait();
+}
+
+void 
+gr_runtime::run()
+{
+    start();
+    wait();
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_runtime.h b/gnuradio-core/src/lib/runtime/gr_runtime.h
new file mode 100644
index 0000000000..fc58da456b
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_runtime.h
@@ -0,0 +1,49 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GR_RUNTIME_H
+#define INCLUDED_GR_RUNTIME_H
+
+#include <gr_runtime_types.h>
+
+class gr_runtime_impl;
+
+gr_runtime_sptr gr_make_runtime(gr_hier_block2_sptr top_block);
+
+class gr_runtime
+{
+private:
+    gr_runtime(gr_hier_block2_sptr top_block);
+    friend gr_runtime_sptr gr_make_runtime(gr_hier_block2_sptr top_block);
+
+    gr_runtime_impl *d_impl;
+    
+public:
+    ~gr_runtime();
+
+    void start();
+    void stop();
+    void wait();
+    void run();
+};
+
+#endif /* INCLUDED_GR_RUNTIME_H */
diff --git a/gnuradio-core/src/lib/runtime/gr_runtime.i b/gnuradio-core/src/lib/runtime/gr_runtime.i
new file mode 100644
index 0000000000..496adff37f
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_runtime.i
@@ -0,0 +1,42 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2004 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., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+class gr_runtime;
+typedef boost::shared_ptr<gr_runtime> gr_runtime_sptr;
+%template(gr_runtime_sptr) boost::shared_ptr<gr_runtime>;
+
+%rename(runtime) gr_make_runtime;
+gr_runtime_sptr gr_make_runtime(gr_hier_block2_sptr top_block);
+
+class gr_runtime
+{
+protected:
+    gr_runtime(gr_hier_block2_sptr top_block);
+
+public:
+    void start()
+        throw (std::runtime_error);
+    void stop();
+    void wait();
+    void run()
+        throw (std::runtime_error);
+};
diff --git a/gnuradio-core/src/lib/runtime/gr_runtime_impl.cc b/gnuradio-core/src/lib/runtime/gr_runtime_impl.cc
new file mode 100644
index 0000000000..2b104cd99e
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_runtime_impl.cc
@@ -0,0 +1,130 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#define GR_RUNTIME_IMPL_DEBUG 0
+
+#include <gr_runtime_impl.h>
+#include <gr_simple_flowgraph.h>
+#include <gr_hier_block2.h>
+#include <gr_hier_block2_detail.h>
+#include <stdexcept>
+#include <iostream>
+
+gr_runtime_impl::gr_runtime_impl(gr_hier_block2_sptr top_block) :
+d_running(false),
+d_top_block(top_block),
+d_sfg(gr_make_simple_flowgraph()),
+d_graphs()
+{
+}
+
+gr_runtime_impl::~gr_runtime_impl()
+{
+}
+
+void
+gr_runtime_impl::start()
+{
+    if (d_running)
+        throw std::runtime_error("already running");
+    else
+        d_running = true;
+
+    d_sfg->d_detail->reset();
+    d_top_block->d_detail->flatten(d_sfg);
+    d_sfg->d_detail->validate();
+    d_sfg->d_detail->setup_connections();
+
+    d_graphs = d_sfg->d_detail->partition();
+    if (GR_RUNTIME_IMPL_DEBUG)
+        std::cout << "Flow graph has " << d_graphs.size()
+                  << " sub-graphs." << std::endl;
+
+    d_threads.clear();
+    for (std::vector<gr_block_vector_t>::iterator p = d_graphs.begin();
+         p != d_graphs.end(); p++) {
+        gr_scheduler_thread_sptr thread = gr_make_scheduler_thread(*p);
+        thread->start();
+        d_threads.push_back(thread);
+    }
+}
+
+void
+gr_runtime_impl::stop()
+{
+    if (!d_running)
+        return;
+
+    for (gr_scheduler_thread_viter_t p = d_threads.begin(); 
+         p != d_threads.end(); p++)
+        (*p)->stop();
+
+    d_running = false;
+}
+
+void
+gr_runtime_impl::wait()
+{
+    for (gr_scheduler_thread_viter_t p = d_threads.begin(); 
+         p != d_threads.end(); p++) {
+        while(1) {
+            (*p)->join(NULL);
+            if (!(*p)->state() == omni_thread::STATE_TERMINATED)
+                break;
+        }
+    }
+}
+
+gr_scheduler_thread_sptr gr_make_scheduler_thread(gr_block_vector_t graph)
+{
+    return gr_scheduler_thread_sptr(new gr_scheduler_thread(graph));
+}
+
+gr_scheduler_thread::gr_scheduler_thread(gr_block_vector_t graph) :
+    omni_thread(NULL, PRIORITY_NORMAL),
+    d_sts(gr_make_single_threaded_scheduler(graph))
+{
+}
+
+gr_scheduler_thread::~gr_scheduler_thread()
+{
+}
+
+void gr_scheduler_thread::start()
+{
+    start_undetached();
+}
+
+void *gr_scheduler_thread::run_undetached(void *arg)
+{
+    d_sts->run();
+    return 0;
+}
+
+void gr_scheduler_thread::stop()
+{
+    d_sts->stop();
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_runtime_impl.h b/gnuradio-core/src/lib/runtime/gr_runtime_impl.h
new file mode 100644
index 0000000000..54977ef974
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_runtime_impl.h
@@ -0,0 +1,74 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GR_RUNTIME_IMPL_H
+#define INCLUDED_GR_RUNTIME_IMPL_H
+
+#include <gr_runtime_types.h>
+#include <gr_block.h>
+#include <omnithread.h>
+#include <gr_single_threaded_scheduler.h>
+
+class gr_scheduler_thread;
+typedef boost::shared_ptr<gr_scheduler_thread> gr_scheduler_thread_sptr;
+typedef std::vector<gr_scheduler_thread_sptr> gr_scheduler_thread_vector_t;
+typedef std::vector<gr_scheduler_thread_sptr>::iterator gr_scheduler_thread_viter_t;
+
+gr_scheduler_thread_sptr gr_make_scheduler_thread(gr_block_vector_t graph);
+
+class gr_scheduler_thread : public omni_thread
+{
+private:
+    gr_scheduler_thread(gr_block_vector_t graph);
+    friend gr_scheduler_thread_sptr gr_make_scheduler_thread(gr_block_vector_t graph);
+
+    gr_single_threaded_scheduler_sptr d_sts;    
+
+public:
+    ~gr_scheduler_thread();
+    virtual void *run_undetached(void *arg);
+    void start();
+    void stop();
+};
+
+class gr_runtime_impl
+{
+private:
+    gr_runtime_impl(gr_hier_block2_sptr top_block);
+    friend class gr_runtime;
+    
+    bool                           d_running;
+    gr_hier_block2_sptr            d_top_block;
+    gr_simple_flowgraph_sptr       d_sfg;
+    std::vector<gr_block_vector_t> d_graphs;
+    gr_scheduler_thread_vector_t   d_threads;
+            
+    void start();
+    void stop();
+    void wait();
+    
+public:
+    ~gr_runtime_impl();
+
+};
+
+#endif /* INCLUDED_GR_RUNTIME_IMPL_H */
diff --git a/gnuradio-core/src/lib/runtime/gr_runtime_types.h b/gnuradio-core/src/lib/runtime/gr_runtime_types.h
index 55cbabe182..dfa0ce94f8 100644
--- a/gnuradio-core/src/lib/runtime/gr_runtime_types.h
+++ b/gnuradio-core/src/lib/runtime/gr_runtime_types.h
@@ -20,8 +20,8 @@
  * Boston, MA 02110-1301, USA.
  */
 
-#ifndef INCLUDED_GR_RUNTIME_H
-#define INCLUDED_GR_RUNTIME_H
+#ifndef INCLUDED_GR_RUNTIME_TYPES_H
+#define INCLUDED_GR_RUNTIME_TYPES_H
 
 #include <gr_types.h>
 
@@ -29,16 +29,24 @@
  * typedefs for smart pointers we use throughout the runtime system
  */
 
+class gr_basic_block;
 class gr_block;
 class gr_block_detail;
+class gr_hier_block2;
 class gr_io_signature;
 class gr_buffer;
 class gr_buffer_reader;
+class gr_simple_flowgraph;
+class gr_runtime;
 
-typedef boost::shared_ptr<gr_block>		gr_block_sptr;
-typedef boost::shared_ptr<gr_block_detail>	gr_block_detail_sptr;
-typedef boost::shared_ptr<gr_io_signature>  	gr_io_signature_sptr;
-typedef boost::shared_ptr<gr_buffer>		gr_buffer_sptr;
-typedef boost::shared_ptr<gr_buffer_reader>	gr_buffer_reader_sptr;
+typedef boost::shared_ptr<gr_basic_block>       gr_basic_block_sptr;
+typedef boost::shared_ptr<gr_block>             gr_block_sptr;
+typedef boost::shared_ptr<gr_block_detail>	    gr_block_detail_sptr;
+typedef boost::shared_ptr<gr_hier_block2>	    gr_hier_block2_sptr;
+typedef boost::shared_ptr<gr_io_signature>      gr_io_signature_sptr;
+typedef boost::shared_ptr<gr_buffer>		    gr_buffer_sptr;
+typedef boost::shared_ptr<gr_buffer_reader>	    gr_buffer_reader_sptr;
+typedef boost::shared_ptr<gr_runtime>		    gr_runtime_sptr;
+typedef boost::shared_ptr<gr_simple_flowgraph>  gr_simple_flowgraph_sptr;
 
-#endif /* INCLUDED_GR_RUNTIME_H */
+#endif /* INCLUDED_GR_RUNTIME_TYPES_H */
diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.cc b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.cc
new file mode 100644
index 0000000000..21aeb587c3
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.cc
@@ -0,0 +1,67 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_simple_flowgraph.h>
+#include <gr_simple_flowgraph_detail.h>
+#include <iostream>
+
+#define GR_SIMPLE_FLOWGRAPH_DEBUG 0
+
+gr_simple_flowgraph_sptr gr_make_simple_flowgraph()
+{
+    return gr_simple_flowgraph_sptr(new gr_simple_flowgraph());
+}
+
+gr_simple_flowgraph::gr_simple_flowgraph() :
+d_detail(new gr_simple_flowgraph_detail())
+{
+}
+  
+gr_simple_flowgraph::~gr_simple_flowgraph()
+{
+    delete d_detail;
+}
+
+void
+gr_simple_flowgraph::define_component(const std::string &name, gr_block_sptr block)
+{
+    if (GR_SIMPLE_FLOWGRAPH_DEBUG)
+        std::cout << "Defining block " << block << " as " << name << std::endl;
+    d_detail->define_component(name, block);
+}
+
+void
+gr_simple_flowgraph::connect(const std::string &src_name, int src_port,
+                             const std::string &dst_name, int dst_port)
+{
+    d_detail->connect(src_name, src_port, dst_name, dst_port);
+}
+
+void
+gr_simple_flowgraph::validate()
+{
+    d_detail->validate();
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.h b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.h
new file mode 100644
index 0000000000..ca2c505e5a
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.h
@@ -0,0 +1,52 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GR_SIMPLE_FLOWGRAPH_H
+#define INCLUDED_GR_SIMPLE_FLOWGRAPH_H
+
+#include <gr_block.h>
+#include <boost/shared_ptr.hpp>
+#include <string>
+
+gr_simple_flowgraph_sptr gr_make_simple_flowgraph();
+
+class gr_simple_flowgraph_detail;
+
+class gr_simple_flowgraph
+{
+private:
+    friend class gr_runtime_impl;
+    friend gr_simple_flowgraph_sptr gr_make_simple_flowgraph();
+    gr_simple_flowgraph();
+
+    gr_simple_flowgraph_detail *d_detail;
+            
+public:
+    ~gr_simple_flowgraph();
+
+    void define_component(const std::string &name, gr_block_sptr block);    
+    void connect(const std::string &src, int src_port, 
+                 const std::string &dst, int dst_port);
+    void validate();
+};
+
+#endif /* INCLUDED_GR_SIMPLE_FLOWGRAPH_H */
diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.i b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.i
new file mode 100644
index 0000000000..c3654fe50b
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.i
@@ -0,0 +1,45 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+class gr_simple_flowgraph;
+typedef boost::shared_ptr<gr_simple_flowgraph> gr_simple_flowgraph_sptr;
+%template(gr_simple_flowgraph_sptr) boost::shared_ptr<gr_simple_flowgraph>;
+%rename(simple_flowgraph) gr_make_simple_flowgraph;
+%ignore gr_simple_flowgraph;
+
+gr_simple_flowgraph_sptr gr_make_simple_flowgraph();
+
+class gr_simple_flowgraph 
+{
+private:
+    gr_simple_flowgraph();
+
+public:
+    ~gr_simple_flowgraph();
+    void define_component(const std::string name, gr_block_sptr block)
+        throw (std::invalid_argument);
+    void connect(const std::string &src, int src_port,
+                 const std::string &dst, int dst_port)
+        throw (std::invalid_argument);
+    void validate()
+        throw (std::runtime_error);
+};
diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.cc b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.cc
new file mode 100644
index 0000000000..2698bc6d83
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.cc
@@ -0,0 +1,471 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <gr_simple_flowgraph.h>
+#include <gr_simple_flowgraph_detail.h>
+#include <gr_io_signature.h>
+#include <gr_block_detail.h>
+#include <gr_buffer.h>
+#include <iostream>
+#include <stdexcept>
+
+#define GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG 0
+
+gr_edge_sptr
+gr_make_edge(const std::string &src_name, int src_port,
+	     const std::string &dst_name, int dst_port)
+{
+    return gr_edge_sptr(new gr_edge(src_name, src_port, dst_name, dst_port));
+}
+
+gr_edge::gr_edge(const std::string &src_name, int src_port, const std::string &dst_name, int dst_port)
+  : d_src(src_name, src_port),
+    d_dst(dst_name, dst_port)
+{
+}
+
+gr_edge::~gr_edge()
+{
+}
+
+gr_simple_flowgraph_detail::gr_simple_flowgraph_detail() :
+d_components(),
+d_edges()
+{
+}
+
+gr_simple_flowgraph_detail::~gr_simple_flowgraph_detail()
+{
+}
+
+void
+gr_simple_flowgraph_detail::reset()
+{
+    // Boost shared pointers will deallocate as needed
+    d_edges.clear();
+    d_components.clear();
+}
+
+gr_block_sptr
+gr_simple_flowgraph_detail::lookup_block(const std::string &name)
+{
+    gr_component_miter_t p = d_components.find(name);
+    if (p != d_components.end())
+        return p->second;
+    else
+        return gr_block_sptr();
+}
+
+void
+gr_simple_flowgraph_detail::define_component(const std::string &name, gr_block_sptr block)
+{
+    if (!block)
+        throw std::invalid_argument("null block passed");
+
+    if (!lookup_block(name))
+        d_components[name] = block;
+    else
+        throw std::invalid_argument("name already in use");
+}
+
+void
+gr_simple_flowgraph_detail::connect(const std::string &src_name, int src_port,
+                                    const std::string &dst_name, int dst_port)
+{
+    gr_block_sptr src_block = lookup_block(src_name);
+    gr_block_sptr dst_block = lookup_block(dst_name);
+
+    if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+	std::cout << "Connecting " << src_name << ":" << src_port << "->"
+              << dst_name << ":" << dst_port << std::endl;
+
+    if (!src_block)
+        throw std::invalid_argument("unknown src name");
+    if (!dst_block)
+        throw std::invalid_argument("unknown dst name");
+
+    check_valid_port(src_block->output_signature(), src_port);
+    check_valid_port(dst_block->input_signature(), dst_port);
+    check_dst_not_used(dst_name, dst_port);
+    check_type_match(src_block, src_port, dst_block, dst_port);
+
+    d_edges.push_back(gr_make_edge(src_name, src_port, dst_name, dst_port));
+}
+
+void
+gr_simple_flowgraph_detail::check_valid_port(gr_io_signature_sptr sig, int port)
+{
+    if (port < 0)
+        throw std::invalid_argument("negative port number");
+    if (sig->max_streams() >= 0 && port >= sig->max_streams())
+        throw std::invalid_argument("port number exceeds max");
+}
+
+void
+gr_simple_flowgraph_detail::check_dst_not_used(const std::string &name, int port)
+{
+    for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
+	if ((*p)->dst_name() == name && (*p)->dst_port() == port)
+	    throw std::invalid_argument("dst already in use");
+}
+
+void
+gr_simple_flowgraph_detail::check_type_match(gr_block_sptr src_block, int src_port,
+                                             gr_block_sptr dst_block, int dst_port)
+{
+    int src_size = src_block->output_signature()->sizeof_stream_item(src_port);
+    int dst_size = dst_block->input_signature()->sizeof_stream_item(dst_port);
+
+    if (src_size != dst_size)
+        throw std::invalid_argument("type size mismatch");
+}
+
+void
+gr_simple_flowgraph_detail::validate()
+{
+    for (gr_component_miter_t p = d_components.begin(); p != d_components.end(); p++) {
+    	std::vector<int> used_ports;
+    	int ninputs, noutputs;
+
+        used_ports = calc_used_ports(p->first, true); // inputs
+    	ninputs = used_ports.size();
+    	check_contiguity(p->second, used_ports, true); // inputs
+
+    	used_ports = calc_used_ports(p->first, false); // outputs
+    	noutputs = used_ports.size();
+    	check_contiguity(p->second, used_ports, false); // outputs
+
+    	if (!(p->second->check_topology(ninputs, noutputs)))
+    	    throw std::runtime_error("check topology failed");
+    }
+}
+
+std::vector<int>
+gr_simple_flowgraph_detail::calc_used_ports(const std::string &name, bool check_inputs)
+{
+    if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+        std::cout << "Calculating used " << (check_inputs ? "input " : "output ")
+                  << "ports...";
+
+    std::vector<int> tmp, result;
+    std::insert_iterator<std::vector<int> > inserter(result, result.begin());
+
+    gr_edge_vector_t edges = calc_connections(name, check_inputs);
+
+    for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) {
+        if (check_inputs == true)
+            tmp.push_back((*p)->dst_port());
+        else
+            tmp.push_back((*p)->src_port());
+    }
+
+    // remove duplicates
+    std::sort(tmp.begin(), tmp.end());
+    std::unique_copy(tmp.begin(), tmp.end(), inserter);
+
+    if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+        std::cout << result.size() << std::endl;
+
+    return result;
+}
+
+gr_edge_vector_t
+gr_simple_flowgraph_detail::calc_connections(const std::string &name, bool check_inputs)
+{
+    gr_edge_vector_t result;
+
+    for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
+        if (check_inputs) {
+            if ((*p)->dst_name() == name)
+                result.push_back(*p);
+        }
+        else {
+            if ((*p)->src_name() == name)
+                result.push_back(*p);
+        }
+    }
+
+    return result;    // assumes no duplicates
+}
+
+void
+gr_simple_flowgraph_detail::check_contiguity(gr_block_sptr block,
+                                             const std::vector<int> &used_ports,
+                                             bool check_inputs)
+{
+    if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+        std::cout << "Checking " << (check_inputs ? "input " : "output ")
+                  << "contiguity...";
+
+    gr_io_signature_sptr sig =
+        check_inputs ? block->input_signature() : block->output_signature();
+
+    int nports = used_ports.size();
+    int min_ports = sig->min_streams();
+
+    if (nports == 0) {
+        if (min_ports == 0) {
+            if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+                std::cout << "ok." << std::endl;
+            return;
+        }
+        else {
+            if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+                std::cout << "needs " << min_ports << ", only has "
+                          << nports << std::endl;
+
+            throw std::runtime_error("insufficient ports");
+        }
+    }
+
+    if (used_ports[nports-1]+1 != nports) {
+        for (int i = 0; i < nports; i++) {
+            if (used_ports[i] != i) {
+                if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+	                std::cout << "missing " << (check_inputs ? "input ":"output ")
+                              << i << std::endl;
+
+                throw std::runtime_error("missing input assignment");
+	        }
+	    }
+    }
+
+    if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+        std::cout << "ok." << std::endl;
+}
+
+void
+gr_simple_flowgraph_detail::setup_connections()
+{
+    // Assign block details to component blocks
+    for (gr_component_miter_t p = d_components.begin(); p != d_components.end(); p++) {
+        if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+            std::cout << "Allocating output buffers for " << p->first << "..." << std::endl;
+
+        int ninputs = calc_used_ports(p->first, true).size();
+        int noutputs = calc_used_ports(p->first, false).size();
+        gr_block_detail_sptr detail = gr_make_block_detail(ninputs, noutputs);
+        for (int i = 0; i < noutputs; i++)
+            detail->set_output(i, allocate_buffer(p->first, i));
+        p->second->set_detail(detail);
+    }
+
+    // Connect inputs to outputs for each block
+    for(gr_component_miter_t p = d_components.begin(); p != d_components.end(); p++) {
+        // Get its detail and edges that feed into it
+        gr_block_detail_sptr detail = p->second->detail();
+        gr_edge_vector_t in_edges = calc_upstream_edges(p->first);
+
+        if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+	    if (in_edges.size() > 0)
+        	std::cout << "Connecting inputs to " << p->first << "..." << std::endl;
+
+        // For each edge that feeds into it
+        for (gr_edge_viter_t e = in_edges.begin(); e != in_edges.end(); e++) {
+            // Set the input buffer on the destination port to the output
+            // buffer on the source port
+            int dst_port = (*e)->dst_port();
+            int src_port = (*e)->src_port();
+            gr_block_sptr src_block = lookup_block((*e)->src_name());
+            gr_buffer_sptr src_buffer = src_block->detail()->output(src_port);
+
+            if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+                std::cout << "Setting input on " << (*e)->dst_name()
+                          << ":" << dst_port << std::endl;
+
+            detail->set_input(dst_port, gr_buffer_add_reader(src_buffer, p->second->history()-1));
+        }
+    }
+}
+
+gr_buffer_sptr
+gr_simple_flowgraph_detail::allocate_buffer(const std::string &name, int port)
+{
+    gr_block_sptr block = lookup_block(name);
+    int item_size = block->output_signature()->sizeof_stream_item(port);
+    int nitems = s_fixed_buffer_size/item_size;
+
+    // Make sure there are at least twice the output_multiple no. of items
+    if (nitems < 2*block->output_multiple())	// Note: this means output_multiple()
+        nitems = 2*block->output_multiple();	// can't be changed by block dynamically
+
+    // If any downstream blocks are decimators and/or have a large output_multiple,
+    // ensure we have a buffer at least twice their decimation factor*output_multiple
+    gr_block_vector_t blocks = calc_downstream_blocks(name, port);
+    for (gr_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
+        int decimation = (int)(1.0/(*p)->relative_rate());
+        int multiple   = (*p)->output_multiple();
+        int history    = (*p)->history();
+        nitems = std::max(nitems, 2*(decimation*multiple+history));
+    }
+
+    if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+        std::cout << "Allocating buffer for port " << port << " with "
+                  << nitems << " items of size " << item_size << std::endl;
+
+    return gr_make_buffer(nitems, item_size);
+}
+
+gr_block_vector_t
+gr_simple_flowgraph_detail::calc_downstream_blocks(const std::string &name, int port)
+{
+    gr_block_vector_t tmp, result;
+    std::insert_iterator<gr_block_vector_t> inserter(result, result.begin());
+
+    for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
+        if ((*p)->src_name() == name && (*p)->src_port() == port)
+            tmp.push_back(lookup_block((*p)->dst_name()));
+
+    // Remove duplicates
+    sort(tmp.begin(), tmp.end());
+    unique_copy(tmp.begin(), tmp.end(), inserter);
+    return result;
+}
+
+gr_edge_vector_t
+gr_simple_flowgraph_detail::calc_upstream_edges(const std::string &name)
+{
+    gr_edge_vector_t result;
+
+    for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
+        if ((*p)->dst_name() == name)
+            result.push_back(*p);
+
+    return result; // Assume no duplicates
+}
+
+gr_block_vector_t
+gr_simple_flowgraph_detail::calc_used_blocks()
+{
+    std::vector<std::string> tmp, tmp_unique;
+    std::insert_iterator<std::vector<std::string> > inserter(tmp_unique, tmp_unique.begin());
+    gr_block_vector_t result;
+
+    for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
+        tmp.push_back((*p)->src_name());
+        tmp.push_back((*p)->dst_name());
+    }
+
+    sort(tmp.begin(), tmp.end());
+    unique_copy(tmp.begin(), tmp.end(), inserter);
+
+    for (std::vector<std::string>::iterator p = tmp_unique.begin();
+         p != tmp_unique.end(); p++)
+        result.push_back(lookup_block(*p));
+
+    if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
+        std::cout << "Flowgraph uses " << result.size()
+                  << " distinct blocks." << std::endl;
+
+    return result;
+}
+
+std::vector<gr_block_vector_t>
+gr_simple_flowgraph_detail::partition()
+{
+    std::vector<gr_block_vector_t> result;
+    gr_block_vector_t blocks = calc_used_blocks();
+    gr_block_vector_t graph;
+
+    while (blocks.size() > 0) {
+        graph = calc_reachable_blocks(blocks[0], blocks);
+        assert(graph.size());
+        result.push_back(topological_sort(graph));
+
+        for (gr_block_viter_t p = graph.begin(); p != graph.end(); p++)
+            blocks.erase(find(blocks.begin(), blocks.end(), *p));
+    }
+
+    return result;
+}
+
+gr_block_vector_t
+gr_simple_flowgraph_detail::calc_reachable_blocks(gr_block_sptr block, gr_block_vector_t &blocks)
+{
+    gr_block_vector_t result;
+
+    // Mark all blocks as unvisited
+    for (gr_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
+        (*p)->detail()->set_color(gr_block_detail::WHITE);
+
+    // Recursively mark all reachable blocks
+    reachable_dfs_visit(block, blocks);
+
+    // Collect all the blocks that have been visited
+    for (gr_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
+        if ((*p)->detail()->color() == gr_block_detail::BLACK)
+            result.push_back(*p);
+
+    return result;
+}
+
+// Recursively mark all reachable blocks from given block and block list
+void 
+gr_simple_flowgraph_detail::reachable_dfs_visit(gr_block_sptr block, gr_block_vector_t &blocks)
+{
+    // Mark the current one as visited
+    block->detail()->set_color(gr_block_detail::BLACK);
+
+    // Recurse into adjacent vertices
+    gr_block_vector_t adjacent = calc_adjacent_blocks(block, blocks);
+
+    for (gr_block_viter_t p = adjacent.begin(); p != adjacent.end(); p++)
+        if ((*p)->detail()->color() == gr_block_detail::WHITE)
+	        reachable_dfs_visit(*p, blocks);
+}
+
+// Return a list of block adjacent to a given block along any edge
+gr_block_vector_t 
+gr_simple_flowgraph_detail::calc_adjacent_blocks(gr_block_sptr block, gr_block_vector_t &blocks)
+{
+    gr_block_vector_t tmp, result;
+    std::insert_iterator<gr_block_vector_t> inserter(result, result.begin());
+    
+    // Find any blocks that are inputs or outputs
+    for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
+        if (lookup_block((*p)->src_name()) == block)
+            tmp.push_back(lookup_block((*p)->dst_name()));
+        if (lookup_block((*p)->dst_name()) == block)
+            tmp.push_back(lookup_block((*p)->src_name()));
+    }    
+
+    // Remove duplicates
+    sort(tmp.begin(), tmp.end());
+    unique_copy(tmp.begin(), tmp.end(), inserter);
+    return result;
+}
+
+gr_block_vector_t
+gr_simple_flowgraph_detail::topological_sort(gr_block_vector_t &blocks)
+{
+    gr_block_vector_t result;
+
+    // NOP for now
+    result = blocks;
+
+    return result;
+}
+
diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.h b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.h
new file mode 100644
index 0000000000..368a0619ff
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.h
@@ -0,0 +1,128 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_GR_SIMPLE_FLOWGRAPH_DETAIL_H
+#define INCLUDED_GR_SIMPLE_FLOWGRAPH_DETAIL_H
+
+#include <gr_block.h>
+#include <map>
+
+#define GR_FIXED_BUFFER_SIZE (32*(1L<<10))
+
+typedef std::map<std::string, gr_block_sptr> gr_component_map_t;
+typedef std::map<std::string, gr_block_sptr>::iterator gr_component_miter_t;
+
+class gr_endpoint
+{
+private:
+    std::string d_name;
+    int d_port;
+
+public:
+    gr_endpoint(const std::string &name, int port) { d_name = name; d_port = port; }
+    const std::string &name() const { return d_name; }
+    int port() const { return d_port; }
+};    
+
+class gr_edge;
+typedef boost::shared_ptr<gr_edge> gr_edge_sptr;
+gr_edge_sptr gr_make_edge(const std::string &src_name, int src_port, 
+                          const std::string &dst_name, int dst_port);
+
+class gr_edge
+{
+private:
+    friend gr_edge_sptr gr_make_edge(const std::string &src_name, int src_port,
+                                     const std::string &dst_name, int dst_port);
+    gr_edge(const std::string &name, int src_port,
+            const std::string &name, int dst_port);
+
+    gr_endpoint d_src;
+    gr_endpoint d_dst;
+
+public:
+    ~gr_edge();
+    const std::string src_name() const { return d_src.name(); }
+    const std::string dst_name() const { return d_dst.name(); }
+    int src_port() const { return d_src.port(); }
+    int dst_port() const { return d_dst.port(); }
+};
+
+typedef std::vector<gr_edge_sptr> gr_edge_vector_t;
+typedef std::vector<gr_edge_sptr>::iterator gr_edge_viter_t;
+
+class gr_simple_flowgraph_detail
+{
+private:
+    friend class gr_simple_flowgraph;
+    friend class gr_runtime_impl;
+    
+    gr_simple_flowgraph_detail();
+
+    gr_component_map_t d_components;
+    gr_edge_vector_t   d_edges;
+    static const unsigned int s_fixed_buffer_size = GR_FIXED_BUFFER_SIZE;
+    
+    void reset();
+    void define_component(const std::string &name, gr_block_sptr block);    
+    void connect(const std::string &src, int src_port, 
+                 const std::string &dst, int dst_port);
+    gr_block_sptr lookup_block(const std::string &name);
+    void check_valid_port(gr_io_signature_sptr sig, int port);
+    void check_dst_not_used(const std::string &name, int port);
+    void check_type_match(gr_block_sptr src_block, int src_port,
+                          gr_block_sptr dst_block, int dst_port);
+    void validate();
+    gr_edge_vector_t calc_connections(const std::string &name, bool check_inputs); // false=use outputs
+    std::vector<int> calc_used_ports(const std::string &name, bool check_inputs); 
+    void check_contiguity(gr_block_sptr block, const std::vector<int> &used_ports, 
+                          bool check_inputs);
+    void setup_connections();
+    gr_buffer_sptr allocate_buffer(const std::string &name, int port);
+    gr_block_vector_t calc_downstream_blocks(const std::string &name, int port);
+    gr_edge_vector_t calc_upstream_edges(const std::string &name);
+    gr_block_vector_t calc_used_blocks();
+    std::vector<gr_block_vector_t> partition();
+    gr_block_vector_t calc_reachable_blocks(gr_block_sptr block, gr_block_vector_t &blocks);
+    gr_block_vector_t topological_sort(gr_block_vector_t &blocks);
+    void reachable_dfs_visit(gr_block_sptr block, gr_block_vector_t &blocks);
+    gr_block_vector_t calc_adjacent_blocks(gr_block_sptr block, gr_block_vector_t &blocks);
+        
+public:
+    ~gr_simple_flowgraph_detail();
+};
+
+inline std::ostream&
+operator <<(std::ostream& os, const gr_block_sptr p)
+{
+    os << "<gr_block " << p->name() << " (" << p->unique_id() << ")>";
+    return os;
+}
+
+inline std::ostream&
+operator <<(std::ostream &os, const gr_endpoint endp)
+{
+    os << endp.name() << ":" << endp.port();
+    return os;
+}
+
+#endif /* INCLUDED_GR_SIMPLE_FLOWGRAPH_H */
diff --git a/gnuradio-core/src/lib/runtime/qa_gr_block.cc b/gnuradio-core/src/lib/runtime/qa_gr_block.cc
index 4773a6eaa6..630d727493 100644
--- a/gnuradio-core/src/lib/runtime/qa_gr_block.cc
+++ b/gnuradio-core/src/lib/runtime/qa_gr_block.cc
@@ -25,7 +25,6 @@
 #endif
 #include <qa_gr_block.h>
 #include <gr_block.h>
-#include <gr_runtime_types.h>
 #include <gr_io_signature.h>
 #include <gr_null_sink.h>
 #include <gr_null_source.h>
diff --git a/gnuradio-core/src/lib/runtime/qa_gr_hier_block2.cc b/gnuradio-core/src/lib/runtime/qa_gr_hier_block2.cc
new file mode 100644
index 0000000000..766ea2f6b1
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/qa_gr_hier_block2.cc
@@ -0,0 +1,46 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <qa_gr_hier_block2.h>
+#include <gr_hier_block2.h>
+#include <gr_io_signature.h>
+#include <gr_null_source.h>
+#include <gr_null_sink.h>
+
+void qa_gr_hier_block2::test_make()
+{
+    gr_hier_block2_sptr src1(gr_make_hier_block2("test",
+						 gr_make_io_signature(1, 1, sizeof(int)),
+						 gr_make_io_signature(1, 1, sizeof(int))));
+
+    CPPUNIT_ASSERT(src1);
+    CPPUNIT_ASSERT_EQUAL(std::string("test"), src1->name());
+    CPPUNIT_ASSERT_EQUAL(1, src1->input_signature()->max_streams());
+    CPPUNIT_ASSERT_EQUAL(1, src1->output_signature()->min_streams());
+    CPPUNIT_ASSERT_EQUAL(1, src1->output_signature()->max_streams());
+    CPPUNIT_ASSERT_EQUAL(sizeof(int), 
+			 src1->output_signature()->sizeof_stream_item(0));
+}
diff --git a/gnuradio-core/src/lib/runtime/qa_gr_hier_block2.h b/gnuradio-core/src/lib/runtime/qa_gr_hier_block2.h
new file mode 100644
index 0000000000..a6bd8d97bb
--- /dev/null
+++ b/gnuradio-core/src/lib/runtime/qa_gr_hier_block2.h
@@ -0,0 +1,43 @@
+/* -*- 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 GNU Radio; see the file COPYING.  If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef INCLUDED_QA_GR_HIER_BLOCK2_H
+#define INCLUDED_QA_GR_HIER_BLOCK2_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+#include <stdexcept>
+
+class qa_gr_hier_block2 : public CppUnit::TestCase 
+{
+    CPPUNIT_TEST_SUITE(qa_gr_hier_block2);
+
+    CPPUNIT_TEST(test_make);
+    
+    CPPUNIT_TEST_SUITE_END();
+
+private:
+    void test_make();
+    void test_derived();
+};
+
+#endif /* INCLUDED_QA_GR_HIER_BLOCK2_H */
diff --git a/gnuradio-core/src/lib/runtime/qa_runtime.cc b/gnuradio-core/src/lib/runtime/qa_runtime.cc
index 165a34703f..ca0c71d3ce 100644
--- a/gnuradio-core/src/lib/runtime/qa_runtime.cc
+++ b/gnuradio-core/src/lib/runtime/qa_runtime.cc
@@ -33,6 +33,7 @@
 #include <qa_gr_vmcircbuf.h>
 #include <qa_gr_io_signature.h>
 #include <qa_gr_block.h>
+#include <qa_gr_hier_block2.h>
 #include <qa_gr_buffer.h>
 
 CppUnit::TestSuite *
@@ -43,6 +44,7 @@ qa_runtime::suite ()
   s->addTest (qa_gr_vmcircbuf::suite ());
   s->addTest (qa_gr_io_signature::suite ());
   s->addTest (qa_gr_block::suite ());
+  s->addTest (qa_gr_hier_block2::suite ());
   s->addTest (qa_gr_buffer::suite ());
   
   return s;
diff --git a/gnuradio-core/src/lib/runtime/runtime.i b/gnuradio-core/src/lib/runtime/runtime.i
index f2fd364378..8e6c01f9a1 100644
--- a/gnuradio-core/src/lib/runtime/runtime.i
+++ b/gnuradio-core/src/lib/runtime/runtime.i
@@ -26,6 +26,9 @@
 #include <gr_buffer.h>
 #include <gr_block.h>
 #include <gr_block_detail.h>
+#include <gr_hier_block2.h>
+#include <gr_runtime.h>
+#include <gr_simple_flowgraph.h>
 #include <gr_single_threaded_scheduler.h>
 #include <gr_message.h>
 #include <gr_msg_handler.h>
@@ -37,9 +40,12 @@
 
 %include <gr_io_signature.i>
 %include <gr_buffer.i>
+%include <gr_basic_block.i>
 %include <gr_block.i>
 %include <gr_block_detail.i>
+%include <gr_hier_block2.i>
 %include <gr_swig_block_magic.i>
+%include <gr_simple_flowgraph.i>
 %include <gr_single_threaded_scheduler.i>
 %include <gr_message.i>
 %include <gr_msg_handler.i>
@@ -47,3 +53,4 @@
 %include <gr_dispatcher.i>
 %include <gr_error_handler.i>
 %include <gr_realtime.i>
+%include <gr_runtime.i>
diff --git a/gnuradio-core/src/python/gnuradio/gr/Makefile.am b/gnuradio-core/src/python/gnuradio/gr/Makefile.am
index fcf0261468..6400b842f5 100644
--- a/gnuradio-core/src/python/gnuradio/gr/Makefile.am
+++ b/gnuradio-core/src/python/gnuradio/gr/Makefile.am
@@ -39,6 +39,7 @@ grgrpython_PYTHON = 		\
 	gr_threading_23.py	\
 	gr_threading_24.py	\
 	hier_block.py		\
+	hier_block2.py		\
 	prefs.py		\
 	scheduler.py		
 
@@ -63,6 +64,7 @@ noinst_PYTHON = 			\
 	qa_fsk_stuff.py			\
 	qa_goertzel.py			\
 	qa_head.py			\
+	qa_hier_block2.py		\
 	qa_hilbert.py			\
 	qa_iir.py			\
 	qa_interleave.py		\
diff --git a/gnuradio-core/src/python/gnuradio/gr/__init__.py b/gnuradio-core/src/python/gnuradio/gr/__init__.py
index 8adf7e3086..d38804870d 100644
--- a/gnuradio-core/src/python/gnuradio/gr/__init__.py
+++ b/gnuradio-core/src/python/gnuradio/gr/__init__.py
@@ -29,7 +29,7 @@ from basic_flow_graph import *
 from flow_graph import *
 from exceptions import *
 from hier_block import *
-
+from hier_block2 import *
 
 # create a couple of aliases
 serial_to_parallel = stream_to_vector
diff --git a/gnuradio-core/src/python/gnuradio/gr/hier_block2.py b/gnuradio-core/src/python/gnuradio/gr/hier_block2.py
new file mode 100644
index 0000000000..c44e6f0718
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gr/hier_block2.py
@@ -0,0 +1,40 @@
+#
+# 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 GNU Radio; see the file COPYING.  If not, write to
+# the Free Software Foundation, Inc., 51 Franklin Street,
+# Boston, MA 02110-1301, USA.
+# 
+
+from gnuradio_swig_python import hier_block2_swig
+
+#
+# This hack forces a 'has-a' relationship to look like an 'is-a' one.
+#
+# It allows Python classes to subclass this one, while passing through
+# method calls to the C++ class shared pointer from SWIG.
+#
+# It also allows us to intercept method calls if needed
+#
+class hier_block2(object):
+    def __init__(self, name, input_signature, output_signature):
+	self._hb = hier_block2_swig(name, input_signature, output_signature)
+
+    def __getattr__(self, name):
+	return getattr(self._hb, name)
+
+    def define_component(self, name, comp):
+	return self._hb.define_component(name, comp.basic_block())
diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py b/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py
new file mode 100755
index 0000000000..9253b892af
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py
@@ -0,0 +1,238 @@
+#!/usr/bin/env python
+
+from gnuradio import gr, gr_unittest
+
+class test_hier_block2(gr_unittest.TestCase):
+
+    def setUp(self):
+	pass
+	
+    def tearDown(self):
+    	pass
+	
+    def test_001_make(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	self.assertEqual("test_block", hblock.name())
+	self.assertEqual(1, hblock.input_signature().max_streams())
+	self.assertEqual(1, hblock.output_signature().min_streams())
+	self.assertEqual(1, hblock.output_signature().max_streams())
+	self.assertEqual(gr.sizeof_int, hblock.output_signature().sizeof_stream_item(0))
+
+    def test_002_define_component(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	hblock.define_component("src", gr.null_source(gr.sizeof_int))
+	hblock.define_component("dst", gr.null_sink(gr.sizeof_int))
+
+    def test_003_define_component_reserved_input(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: hblock.define_component("self", gr.nop(gr.sizeof_int)))
+
+    def test_004_define_component_name_in_use(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	hblock.define_component("src", gr.null_source(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: hblock.define_component("src", gr.null_sink(gr.sizeof_int)))
+
+    def test_006_connect_internal(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_int))
+	hblock.define_component("nop2", gr.nop(gr.sizeof_int))
+	hblock.connect("nop1", 0, "nop2", 0)
+
+    def test_007_connect_input(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_int))
+	hblock.connect("self", 0, "nop1", 0)
+
+    def test_008_connect_output(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_int))
+	hblock.connect("nop1", 0, "self", 0)
+
+    def test_009_connect_unknown_src(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	nop1 = gr.nop(gr.sizeof_int)
+	hblock.define_component("nop1", nop1)
+	self.assertRaises(ValueError, 
+	    lambda: hblock.connect("nop2", 0, "self", 0))
+    
+    def test_010_connect_unknown_dst(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: hblock.connect("self", 0, "nop2", 0))
+
+    def test_011_connect_invalid_src_port_neg(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: hblock.connect("self", -1, "nop1", 0))
+
+    def test_012_connect_invalid_src_port_exceeds(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: hblock.connect("self", 1, "nop1", 0))
+    
+    def test_013_connect_invalid_dst_port_neg(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: hblock.connect("self", -1, "nop1", 0))
+
+    def test_014_connect_invalid_dst_port_exceeds(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: hblock.connect("self", 1, "nop1", 0))
+
+    def test_015_connect_dst_port_in_use(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	nop1 = gr.nop(gr.sizeof_int)
+	hblock.define_component("nop1", nop1)
+	hblock.connect("nop1", 0, "self", 0);
+	self.assertRaises(ValueError, 
+	    lambda: hblock.connect("nop1", 0, "self", 0))
+    
+    def test_016_connect_one_src_two_dst(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	hblock.define_component("src", gr.null_source(gr.sizeof_int))
+	hblock.define_component("dst1", gr.null_sink(gr.sizeof_int))
+	hblock.define_component("dst2", gr.null_sink(gr.sizeof_int))
+	hblock.connect("src", 0, "dst1", 0)
+	hblock.connect("src", 0, "dst2", 0)
+
+    def test_017_connect_type_mismatch(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(1,1,gr.sizeof_int), 
+				gr.io_signature(1,1,gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_char))
+	self.assertRaises(ValueError, 
+	    lambda: hblock.connect("nop1", 0, "self", 0))
+
+    def test_018_check_topology(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(0,0,gr.sizeof_int), 
+				gr.io_signature(0,0,gr.sizeof_int))
+	hblock.check_topology(0, 0);
+    """
+    def test_019_validate(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(0,0,gr.sizeof_int), 
+				gr.io_signature(0,0,gr.sizeof_int))
+	runtime = gr.runtime(hblock)
+	runtime.validate()
+    
+    def test_020_validate_1(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(0,0,gr.sizeof_int), 
+				gr.io_signature(0,0,gr.sizeof_int))
+	hblock.define_component("src", gr.null_source(gr.sizeof_int))
+	hblock.define_component("dst1", gr.null_sink(gr.sizeof_int))
+	hblock.define_component("dst2", gr.null_sink(gr.sizeof_int))
+	hblock.connect("src", 0, "dst1", 0)
+	hblock.connect("src", 0, "dst2", 0)			
+	runtime = gr.runtime(hblock)
+	runtime.validate()
+
+    def test_021_validate_2(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(0,0,gr.sizeof_int), 
+				gr.io_signature(0,0,gr.sizeof_int))
+	hblock.define_component("src1", gr.null_source(gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_int))
+	hblock.define_component("dst1", gr.null_sink(gr.sizeof_int))
+	hblock.define_component("dst2", gr.null_sink(gr.sizeof_int))
+	hblock.connect("src1", 0, "nop1", 0)
+	hblock.connect("src1", 0, "nop1", 1)
+	hblock.connect("nop1", 0, "dst1", 0)
+	hblock.connect("nop1", 1, "dst2", 0)
+	runtime = gr.runtime(hblock)
+	runtime.validate()
+        
+    def test_022_validate_3(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(0,0,gr.sizeof_int), 
+				gr.io_signature(0,0,gr.sizeof_int))
+	hblock.define_component("src1", gr.null_source(gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_int))
+	hblock.define_component("dst1", gr.null_sink(gr.sizeof_int))
+	hblock.define_component("dst2", gr.null_sink(gr.sizeof_int))
+	hblock.connect("src1", 0, "nop1", 0)
+	hblock.connect("src1", 0, "nop1", 2)
+	hblock.connect("nop1", 0, "dst1", 0)
+	hblock.connect("nop1", 1, "dst2", 0)
+	runtime = gr.runtime(hblock)
+	self.assertRaises(RuntimeError,
+	    lambda: runtime.validate())
+        
+    def test_023_validate_4(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(0,0,gr.sizeof_int), 
+				gr.io_signature(0,0,gr.sizeof_int))
+	hblock.define_component("src1", gr.null_source(gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_int))
+	hblock.define_component("dst1", gr.null_sink(gr.sizeof_int))
+	hblock.define_component("dst2", gr.null_sink(gr.sizeof_int))
+	hblock.connect("src1", 0, "nop1", 0)
+	hblock.connect("src1", 0, "nop1", 1)
+	hblock.connect("nop1", 0, "dst1", 0)
+	hblock.connect("nop1", 2, "dst2", 0)
+	runtime = gr.runtime(hblock)
+	self.assertRaises(RuntimeError,
+	    lambda: runtime.validate())
+        
+    def test_024_validate_5(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(0,0,gr.sizeof_int), 
+				gr.io_signature(0,0,gr.sizeof_int))
+	hblock.define_component("src1", gr.null_source(gr.sizeof_int))
+	hblock.define_component("nop1", gr.nop(gr.sizeof_int))
+	hblock.define_component("dst1", gr.null_sink(gr.sizeof_int))
+	hblock.define_component("dst2", gr.null_sink(gr.sizeof_int))
+	hblock.connect("src1", 0, "nop1", 0)
+	hblock.connect("src1", 0, "nop1", 1)
+	hblock.connect("nop1", 0, "dst1", 0)
+	hblock.connect("nop1", 1, "dst2", 0)
+	runtime = gr.runtime(hblock)
+	runtime.validate()
+	# Pending implementation of disconnect
+	# hblock.disconnect("src1", 0, "nop1", 1)
+	# runtime.validate()	
+	# self.assertRaises(ValueError,
+	#     lambda: hblock.disconnect("src1", 0, "nop1", 1))
+	"""
+	        
+if __name__ == "__main__":
+    gr_unittest.main()
diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_runtime.py b/gnuradio-core/src/python/gnuradio/gr/qa_runtime.py
new file mode 100755
index 0000000000..3e7f4e5f9f
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gr/qa_runtime.py
@@ -0,0 +1,31 @@
+#!/usr/bin/env python
+
+from gnuradio import gr, gr_unittest
+
+class test_runtime(gr_unittest.TestCase):
+
+    def setUp(self):
+	pass
+	
+    def tearDown(self):
+    	pass
+
+    """
+    def test_001_run(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(0,0,0), 
+				gr.io_signature(0,0,0))
+	runtime = gr.runtime(hblock)
+	runtime.run()
+
+    def test_002_run_twice(self):
+	hblock = gr.hier_block2("test_block", 
+				gr.io_signature(0,0,0), 
+				gr.io_signature(0,0,0))
+	runtime = gr.runtime(hblock)
+	runtime.run()
+	self.assertRaises(RuntimeError, lambda: runtime.run())
+    """
+        
+if __name__ == "__main__":
+    gr_unittest.main()
diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_simple_flowgraph.py b/gnuradio-core/src/python/gnuradio/gr/qa_simple_flowgraph.py
new file mode 100755
index 0000000000..939f5855fc
--- /dev/null
+++ b/gnuradio-core/src/python/gnuradio/gr/qa_simple_flowgraph.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python
+
+from gnuradio import gr, gr_unittest
+
+class test_simple_flowgraph(gr_unittest.TestCase):
+
+    def setUp(self):
+	pass
+	
+    def tearDown(self):
+	pass
+			
+    def test_001_define_component(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src", gr.null_source(gr.sizeof_int))
+	sfg.define_component("dst", gr.null_sink(gr.sizeof_int))
+
+    def test_002_define_component_name_in_use(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src", gr.null_source(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: sfg.define_component("src", gr.null_sink(gr.sizeof_int)))
+    
+    def test_003_connect(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src", gr.null_source(gr.sizeof_int))
+	sfg.define_component("dst", gr.null_sink(gr.sizeof_int))
+	sfg.connect("src", 0, "dst", 0)
+
+    def test_004connect_unknown_src(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("dst", gr.null_sink(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: sfg.connect("src", 0, "dst", 0))
+    
+    def test_005_connect_unknown_dst(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src", gr.null_source(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: sfg.connect("src", 0, "dst", 0))
+
+    def test_006_connect_invalid_src_port_neg(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src", gr.null_source(gr.sizeof_int))
+	sfg.define_component("dst", gr.null_sink(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: sfg.connect("src", -1, "dst", 0))
+
+    def test_007_connect_invalid_src_port_exceeds(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src", gr.null_source(gr.sizeof_int))
+	sfg.define_component("dst", gr.null_sink(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: sfg.connect("src", 1, "dst", 0))
+
+    def test_008_connect_invalid_dst_port_neg(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src", gr.null_source(gr.sizeof_int))
+	sfg.define_component("dst", gr.null_sink(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: sfg.connect("src", 0, "dst", -1))
+
+    def test_009_connect_invalid_dst_port_exceeds(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src", gr.null_source(gr.sizeof_int))
+	sfg.define_component("dst", gr.null_sink(gr.sizeof_int))
+	self.assertRaises(ValueError, 
+	    lambda: sfg.connect("src", 0, "dst", 1))
+
+    def test_010_connect_invalid_dst_port_in_use(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src1", gr.null_source(gr.sizeof_int))
+	sfg.define_component("src2", gr.null_source(gr.sizeof_int))
+	sfg.define_component("dst", gr.null_sink(gr.sizeof_int))
+	sfg.connect("src1", 0, "dst", 0)
+	self.assertRaises(ValueError, 
+	    lambda: sfg.connect("src2", 0, "dst", 0))
+    
+    def test_011_connect_one_src_two_dst(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src", gr.null_source(gr.sizeof_int))
+	sfg.define_component("dst1", gr.null_sink(gr.sizeof_int))
+	sfg.define_component("dst2", gr.null_sink(gr.sizeof_int))
+	sfg.connect("src", 0, "dst1", 0)
+	sfg.connect("src", 0, "dst2", 0)
+
+    def test_012_connect_type_mismatch(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src", gr.null_source(gr.sizeof_int))
+	sfg.define_component("dst", gr.null_sink(gr.sizeof_char))
+	self.assertRaises(ValueError,
+	    lambda: sfg.connect("src", 0, "dst", 0))
+
+    def test_013_validate(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src", gr.null_source(gr.sizeof_int))
+	sfg.define_component("dst1", gr.null_sink(gr.sizeof_int))
+	sfg.define_component("dst2", gr.null_sink(gr.sizeof_int))
+	sfg.connect("src", 0, "dst1", 0)
+	sfg.connect("src", 0, "dst2", 0)
+	sfg.validate()
+	
+    def test_014_validate(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src1", gr.null_source (gr.sizeof_int))
+	sfg.define_component("nop1", gr.nop (gr.sizeof_int))
+	sfg.define_component("dst1", gr.null_sink (gr.sizeof_int))
+	sfg.define_component("dst2", gr.null_sink (gr.sizeof_int))
+	sfg.connect("src1", 0, "nop1", 0)
+	sfg.connect("src1", 0, "nop1", 1)
+	sfg.connect("nop1", 0, "dst1", 0)
+	sfg.connect("nop1", 1, "dst2", 0)
+	sfg.validate ()
+										       
+    def test_015_validate(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src1", gr.null_source (gr.sizeof_int))
+	sfg.define_component("nop1", gr.nop (gr.sizeof_int))
+	sfg.define_component("dst1", gr.null_sink (gr.sizeof_int))
+	sfg.define_component("dst2", gr.null_sink (gr.sizeof_int))
+	sfg.connect("src1", 0, "nop1", 0)
+	sfg.connect("src1", 0, "nop1", 2)
+	sfg.connect("nop1", 0, "dst1", 0)
+	sfg.connect("nop1", 1, "dst2", 0)
+	self.assertRaises(RuntimeError,
+	    lambda: sfg.validate ())
+    									       
+    def test_016_validate(self):
+	sfg = gr.simple_flowgraph()
+	sfg.define_component("src1", gr.null_source (gr.sizeof_int))
+	sfg.define_component("nop1", gr.nop (gr.sizeof_int))
+	sfg.define_component("dst1", gr.null_sink (gr.sizeof_int))
+	sfg.define_component("dst2", gr.null_sink (gr.sizeof_int))
+	sfg.connect("src1", 0, "nop1", 0)
+	sfg.connect("src1", 0, "nop1", 1)
+	sfg.connect("nop1", 0, "dst1", 0)
+	sfg.connect("nop1", 2, "dst2", 0)
+	self.assertRaises(RuntimeError,
+	    lambda: sfg.validate ())
+										       
+if __name__ == "__main__":
+    gr_unittest.main()
-- 
cgit v1.2.3