AC_CONFIG_FILES([ \
gnuradio-examples/Makefile \
+ gnuradio-examples/c++/Makefile \
gnuradio-examples/python/Makefile \
gnuradio-examples/python/apps/hf_explorer/Makefile \
gnuradio-examples/python/apps/hf_radio/Makefile \
#
-# Copyright 2003,2004 Free Software Foundation, Inc.
+# Copyright 2003,2004,2007 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
gr_pagesize.cc \
gr_preferences.cc \
gr_realtime.cc \
- gr_runtime.cc \
- gr_runtime_impl.cc \
+ gr_scheduler_thread.cc \
gr_single_threaded_scheduler.cc \
gr_sync_block.cc \
gr_sync_decimator.cc \
gr_sync_interpolator.cc \
+ gr_top_block.cc \
+ gr_top_block_impl.cc \
gr_tmp_path.cc \
gr_vmcircbuf.cc \
gr_vmcircbuf_mmap_shm_open.cc \
qa_gr_hier_block2.cc \
qa_gr_buffer.cc \
qa_gr_flowgraph.cc \
+ qa_gr_top_block.cc \
qa_gr_io_signature.cc \
qa_gr_vmcircbuf.cc \
qa_runtime.cc
gr_pagesize.h \
gr_preferences.h \
gr_realtime.h \
- gr_runtime.h \
- gr_runtime_impl.h \
gr_runtime_types.h \
+ gr_scheduler_thread.h \
gr_select_handler.h \
gr_single_threaded_scheduler.h \
gr_sync_block.h \
gr_sync_decimator.h \
gr_sync_interpolator.h \
+ gr_top_block.h \
+ gr_top_block_impl.h \
gr_timer.h \
gr_tmp_path.h \
gr_types.h \
qa_gr_hier_block2.h \
qa_gr_buffer.h \
qa_gr_io_signature.h \
+ qa_gr_top_block.h \
qa_gr_vmcircbuf.h \
qa_runtime.h
gr_msg_handler.i \
gr_msg_queue.i \
gr_realtime.i \
- gr_runtime.i \
gr_single_threaded_scheduler.i \
gr_sync_block.i \
gr_sync_decimator.i \
gr_sync_interpolator.i \
gr_swig_block_magic.i \
+ gr_top_block.i \
runtime.i
MOSTLYCLEANFILES = *~ *.loT
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));
+ 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_hier_block2::~gr_hier_block2()
{
- delete d_detail;
+ delete d_detail;
}
void
gr_hier_block2::connect(gr_basic_block_sptr src, int src_port,
gr_basic_block_sptr dst, int dst_port)
{
- d_detail->connect(src, src_port, dst, dst_port);
+ d_detail->connect(src, src_port, dst, dst_port);
}
void
gr_hier_block2::disconnect(gr_basic_block_sptr src, int src_port,
gr_basic_block_sptr dst, int dst_port)
{
- d_detail->disconnect(src, src_port, dst, dst_port);
+ d_detail->disconnect(src, src_port, dst, dst_port);
}
void
-gr_hier_block2::set_runtime(gr_runtime *runtime)
+gr_hier_block2::lock()
{
- if (GR_HIER_BLOCK2_DEBUG)
- std::cout << "Setting runtime on " << this << " to " << runtime << std::endl;
- d_detail->set_runtime(runtime);
+ d_detail->lock();
}
void
-gr_hier_block2::lock()
+gr_hier_block2::unlock()
{
- d_detail->lock();
+ d_detail->unlock();
}
void
-gr_hier_block2::unlock()
+gr_hier_block2::flatten(gr_flat_flowgraph_sptr ffg)
{
- d_detail->unlock();
+ d_detail->flatten(ffg);
}
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;
-
- /* Internal use only */
- void set_runtime(gr_runtime *runtime);
-
+ friend class gr_hier_block2_detail;
+ 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);
-
+ gr_hier_block2(const std::string &name,
+ gr_io_signature_sptr input_signature,
+ gr_io_signature_sptr output_signature);
+
public:
- virtual ~gr_hier_block2();
+ virtual ~gr_hier_block2();
+
+ void connect(gr_basic_block_sptr src, int src_port,
+ gr_basic_block_sptr dst, int dst_port);
+ void disconnect(gr_basic_block_sptr src, int src_port,
+ gr_basic_block_sptr dst, int dst_port);
+ virtual void lock();
+ virtual void unlock();
- void connect(gr_basic_block_sptr src, int src_port,
- gr_basic_block_sptr dst, int dst_port);
- void disconnect(gr_basic_block_sptr src, int src_port,
- gr_basic_block_sptr dst, int dst_port);
- void lock();
- void unlock();
+ void flatten(gr_flat_flowgraph_sptr ffg);
};
#endif /* INCLUDED_GR_HIER_BLOCK2_H */
#include <gr_hier_block2_detail.h>
#include <gr_io_signature.h>
-#include <gr_runtime.h>
#include <stdexcept>
#include <iostream>
d_parent_detail(0),
d_fg(gr_make_flowgraph()),
d_inputs(owner->input_signature()->max_streams()),
- d_outputs(owner->output_signature()->max_streams()),
- d_runtime()
+ d_outputs(owner->output_signature()->max_streams())
{
}
if (d_parent_detail)
d_parent_detail->lock();
else
- if (d_runtime)
- d_runtime->lock();
+ d_owner->lock();
}
void
if (d_parent_detail)
d_parent_detail->unlock();
else
- if (d_runtime)
- d_runtime->unlock();
+ d_owner->unlock();
}
gr_flowgraph_sptr d_fg;
gr_endpoint_vector_t d_inputs;
gr_endpoint_vector_t d_outputs;
- gr_runtime *d_runtime;
// Private implementation methods
void connect(gr_basic_block_sptr src, int src_port,
void flatten(gr_flat_flowgraph_sptr sfg);
gr_endpoint resolve_port(int port, bool is_input);
gr_endpoint resolve_endpoint(const gr_endpoint &endp, bool is_input);
- void set_runtime(gr_runtime *runtime) { d_runtime = runtime; }
void lock();
void unlock();
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2006,2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, 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, this);
-}
-
-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();
-}
-
-void
-gr_runtime::restart()
-{
- d_impl->restart();
-}
-
-void
-gr_runtime::lock()
-{
- d_impl->lock();
-}
-
-void
-gr_runtime::unlock()
-{
- d_impl->unlock();
-}
-
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2006,2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, 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);
-
-/*!
- *\brief Runtime object that controls simple flow graph operation
- *
- * This class is instantiated with a top-level gr_hier_block2. The
- * runtime then flattens the hierarchical block into a gr_simple_flowgraph,
- * and allows control through start(), stop(), wait(), and run().
- *
- */
-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();
-
- /*!
- * Start the flow graph. Creates an undetached scheduler thread for
- * each flow graph partition. Returns to caller once created.
- */
- void start();
-
- /*!
- * Stop a running flow graph. Tells each created scheduler thread
- * to exit, then returns to caller.
- */
- void stop();
-
- /*!
- * Wait for a stopped flow graph to complete. Joins each completed
- * thread.
- */
- void wait();
-
- /*!
- * Calls start(), then wait(). Used to run a flow graph that will stop
- * on its own, or to run a flow graph indefinitely until SIGTERM is
- * received().
- */
- void run();
-
- /*!
- * Restart a running flow graph, after topology changes have
- * been made to its top_block (or children). Causes each created
- * scheduler thread to end, recalculates the flow graph, and
- * recreates new threads (possibly a different number from before.)
- */
- void restart();
-
- /*!
- * Lock a flow graph in preparation for reconfiguration. When an equal
- * number of calls to lock() and unlock() have occurred, the flow graph
- * will be restarted automatically.
- *
- * N.B. lock() and unlock() cannot be called from a flow graph thread or
- * deadlock will occur when reconfiguration happens.
- */
- void lock();
-
- /*!
- * Lock a flow graph in preparation for reconfiguration. When an equal
- * number of calls to lock() and unlock() have occurred, the flow graph
- * will be restarted automatically.
- *
- * N.B. lock() and unlock() cannot be called from a flow graph thread or
- * deadlock will occur when reconfiguration happens.
- */
- void unlock();
-};
-
-#endif /* INCLUDED_GR_RUNTIME_H */
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2004,2006,2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, 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>;
-
-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 run() throw (std::runtime_error);
- void start() throw (std::runtime_error);
- void stop() throw (std::runtime_error);
- void wait() throw (std::runtime_error);
- void restart() throw (std::runtime_error);
-};
-
-%{
-class ensure_py_gil_state2 {
- PyGILState_STATE d_gstate;
-public:
- ensure_py_gil_state2() { d_gstate = PyGILState_Ensure(); }
- ~ensure_py_gil_state2() { PyGILState_Release(d_gstate); }
-};
-%}
-
-%inline %{
-void runtime_run_unlocked(gr_runtime_sptr r) throw (std::runtime_error)
-{
- ensure_py_gil_state2 _lock;
- r->run();
-}
-
-void runtime_start_unlocked(gr_runtime_sptr r) throw (std::runtime_error)
-{
- ensure_py_gil_state2 _lock;
- r->start();
-}
-
-void runtime_stop_unlocked(gr_runtime_sptr r) throw (std::runtime_error)
-{
- ensure_py_gil_state2 _lock;
- r->stop();
-}
-
-void runtime_wait_unlocked(gr_runtime_sptr r) throw (std::runtime_error)
-{
- ensure_py_gil_state2 _lock;
- r->wait();
-}
-
-void runtime_restart_unlocked(gr_runtime_sptr r) throw (std::runtime_error)
-{
- ensure_py_gil_state2 _lock;
- r->restart();
-}
-
-%}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2006,2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, 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 <gr_flat_flowgraph.h>
-#include <gr_hier_block2.h>
-#include <gr_hier_block2_detail.h>
-#include <gr_local_sighandler.h>
-
-#ifdef HAVE_SIGNAL_H
-#include <signal.h>
-#endif
-
-#include <stdexcept>
-#include <iostream>
-
-#define GR_RUNTIME_IMPL_DEBUG 0
-
-static gr_runtime_impl *s_runtime = 0;
-
-// Make a vector of gr_block from a vector of gr_basic_block
-static
-gr_block_vector_t
-make_gr_block_vector(gr_basic_block_vector_t &blocks)
-{
- gr_block_vector_t result;
- for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
- result.push_back(make_gr_block_sptr(*p));
- }
-
- return result;
-}
-
-// FIXME: This prevents using more than one gr_runtime instance
-void
-runtime_sigint_handler(int signum)
-{
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "SIGINT received, calling stop() on all threads" << std::endl;
-
- if (s_runtime)
- s_runtime->stop();
-}
-
-gr_runtime_impl::gr_runtime_impl(gr_hier_block2_sptr top_block, gr_runtime *owner)
- : d_running(false),
- d_top_block(top_block),
- d_ffg(gr_make_flat_flowgraph()),
- d_owner(owner)
-{
- s_runtime = this;
- top_block->set_runtime(d_owner);
-}
-
-gr_runtime_impl::~gr_runtime_impl()
-{
- s_runtime = 0; // don't call delete we don't own these
- d_owner = 0;
-}
-
-void
-gr_runtime_impl::start()
-{
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "start: entered" << std::endl;
-
- if (d_running)
- throw std::runtime_error("already running");
-
- // Create new simple flow graph by flattening hierarchical block
- d_ffg->clear();
- d_top_block->d_detail->flatten(d_ffg);
-
- // Validate new simple flow graph and wire it up
- d_ffg->validate();
- d_ffg->setup_connections();
-
- // Execute scheduler threads
- start_threads();
-}
-
-void
-gr_runtime_impl::start_threads()
-{
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "start_threads: entered" << std::endl;
-
- d_graphs = d_ffg->partition();
- for (std::vector<gr_basic_block_vector_t>::iterator p = d_graphs.begin();
- p != d_graphs.end(); p++) {
- gr_scheduler_thread *thread = new gr_scheduler_thread(make_gr_block_vector(*p));
- d_threads.push_back(thread);
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "start_threads: starting " << thread << std::endl;
- thread->start();
- }
-
- d_running = true;
-}
-
-void
-gr_runtime_impl::stop()
-{
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "stop: entered" << std::endl;
-
- for (gr_scheduler_thread_viter_t p = d_threads.begin(); p != d_threads.end(); p++) {
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "stop: stopping thread " << (*p) << std::endl;
- (*p)->stop();
- }
-
- d_running = false;
-}
-
-void
-gr_runtime_impl::wait()
-{
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "wait: entered" << std::endl;
-
- void *dummy_status; // don't ever dereference this
- gr_local_sighandler sigint(SIGINT, runtime_sigint_handler);
-
- for (gr_scheduler_thread_viter_t p = d_threads.begin(); p != d_threads.end(); p++) {
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "wait: joining thread " << (*p) << std::endl;
- (*p)->join(&dummy_status); // pthreads will self-delete, so pointer is now dead
- (*p) = 0; // FIXME: switch to stl::list and actually remove from container
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "wait: join returned" << std::endl;
- }
-
- d_threads.clear();
-}
-
-
-// N.B. lock() and unlock() cannot be called from a flow graph thread or
-// deadlock will occur when reconfiguration happens
-void
-gr_runtime_impl::lock()
-{
- omni_mutex_lock lock(d_reconf);
- d_lock_count++;
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "runtime: locked, count = " << d_lock_count << std::endl;
-}
-
-void
-gr_runtime_impl::unlock()
-{
- omni_mutex_lock lock(d_reconf);
- if (d_lock_count == 0)
- throw std::runtime_error("unpaired unlock() call");
-
- d_lock_count--;
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "runtime: unlocked, count = " << d_lock_count << std::endl;
-
- if (d_lock_count == 0)
- restart();
-}
-
-void
-gr_runtime_impl::restart()
-{
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "restart: entered" << std::endl;
-
- if (!d_running)
- throw std::runtime_error("not running");
-
- // Stop scheduler threads and wait for completion
- stop();
- wait();
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "restart: threads stopped" << std::endl;
-
- // Create new simple flow graph
- gr_flat_flowgraph_sptr new_ffg = gr_make_flat_flowgraph();
- d_top_block->d_detail->flatten(new_ffg);
- new_ffg->validate();
- new_ffg->merge_connections(d_ffg);
-
- if (GR_RUNTIME_IMPL_DEBUG)
- std::cout << "restart: replacing old flow graph with new" << std::endl;
- d_ffg = new_ffg;
-
- start_threads();
-}
-
-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)
-{
- // First code to run in new thread context
-
- // Mask off SIGINT in this thread to gaurantee mainline thread gets signal
-#ifdef HAVE_SIGPROCMASK
- sigset_t old_set;
- sigset_t new_set;
- sigemptyset(&new_set);
- sigaddset(&new_set, SIGINT);
- sigprocmask(SIG_BLOCK, &new_set, &old_set);
-#endif
- // Run the single-threaded scheduler
- d_sts->run();
- return 0;
-}
-
-void
-gr_scheduler_thread::stop()
-{
- d_sts->stop();
-}
+++ /dev/null
-/* -*- c++ -*- */
-/*
- * Copyright 2006,2007 Free Software Foundation, Inc.
- *
- * This file is part of GNU Radio
- *
- * GNU Radio is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 3, 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>
-
-// omnithread calls delete on itself after thread exits, so can't use shared ptr
-class gr_scheduler_thread;
-typedef std::vector<gr_scheduler_thread *> gr_scheduler_thread_vector_t;
-typedef gr_scheduler_thread_vector_t::iterator gr_scheduler_thread_viter_t;
-
-/*!
- *\brief A single thread of execution for the scheduler
- *
- * This class implements a single thread that runs undetached, and
- * invokes the single-threaded block scheduler. The runtime makes
- * one of these for each distinct partition of a flowgraph and runs
- * them in parallel.
- *
- */
-class gr_scheduler_thread : public omni_thread
-{
-private:
- gr_single_threaded_scheduler_sptr d_sts;
-
-public:
- gr_scheduler_thread(gr_block_vector_t graph);
- ~gr_scheduler_thread();
-
- virtual void *run_undetached(void *arg);
- void start();
- void stop();
-};
-
-/*!
- *\brief Implementation details of gr_runtime
- *
- * The actual implementation of gr_runtime. Separate class allows
- * decoupling of changes from dependent classes.
- *
- */
-class gr_runtime_impl
-{
-private:
- gr_runtime_impl(gr_hier_block2_sptr top_block, gr_runtime *owner);
- friend void runtime_sigint_handler(int signum);
- friend class gr_runtime;
-
- bool d_running;
- gr_hier_block2_sptr d_top_block;
- gr_flat_flowgraph_sptr d_ffg;
- std::vector<gr_basic_block_vector_t> d_graphs;
- gr_scheduler_thread_vector_t d_threads;
- gr_runtime *d_owner;
- int d_lock_count;
- omni_mutex d_reconf;
-
- void start();
- void start_threads();
- void stop();
- void wait();
- void restart();
- void lock();
- void unlock();
-
-public:
- ~gr_runtime_impl();
-
-};
-
-#endif /* INCLUDED_GR_RUNTIME_IMPL_H */
class gr_buffer_reader;
class gr_flowgraph;
class gr_flat_flowgraph;
-class gr_runtime;
+class gr_top_block;
+class gr_top_block_detail;
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_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_flowgraph> gr_flowgraph_sptr;
typedef boost::shared_ptr<gr_flat_flowgraph> gr_flat_flowgraph_sptr;
+typedef boost::shared_ptr<gr_top_block> gr_top_block_sptr;
#endif /* INCLUDED_GR_RUNTIME_TYPES_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, 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_scheduler_thread.h>
+#include <iostream>
+
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#define GR_SCHEDULER_THREAD_DEBUG 0
+
+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)
+{
+ // First code to run in new thread context
+
+ // Mask off SIGINT in this thread to gaurantee mainline thread gets signal
+#ifdef HAVE_SIGPROCMASK
+ sigset_t old_set;
+ sigset_t new_set;
+ sigemptyset(&new_set);
+ sigaddset(&new_set, SIGINT);
+ sigprocmask(SIG_BLOCK, &new_set, &old_set);
+#endif
+ // Run the single-threaded scheduler
+ d_sts->run();
+ return 0;
+}
+
+void
+gr_scheduler_thread::stop()
+{
+ if (GR_SCHEDULER_THREAD_DEBUG)
+ std::cout << "gr_scheduler_thread::stop()" << std::endl;
+ d_sts->stop();
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, 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_SCHEDULER_THREAD_H
+#define INCLUDED_GR_SCHEDULER_THREAD_H
+
+#include <omnithread.h>
+#include <gr_single_threaded_scheduler.h>
+#include <gr_block.h>
+
+// omnithread calls delete on itself after thread exits, so can't use shared ptr
+class gr_scheduler_thread;
+typedef std::vector<gr_scheduler_thread *> gr_scheduler_thread_vector_t;
+typedef gr_scheduler_thread_vector_t::iterator gr_scheduler_thread_viter_t;
+
+/*!
+ *\brief A single thread of execution for the scheduler
+ *
+ * This class implements a single thread that runs undetached, and
+ * invokes the single-threaded block scheduler. The runtime makes
+ * one of these for each distinct partition of a flowgraph and runs
+ * them in parallel.
+ *
+ */
+class gr_scheduler_thread : public omni_thread
+{
+private:
+ gr_single_threaded_scheduler_sptr d_sts;
+
+public:
+ gr_scheduler_thread(gr_block_vector_t graph);
+ ~gr_scheduler_thread();
+
+ virtual void *run_undetached(void *arg);
+ void start();
+ void stop();
+};
+
+#endif /* INCLUDED_GR_SCHEDULER_THREAD_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, 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_top_block.h>
+#include <gr_top_block_impl.h>
+#include <gr_io_signature.h>
+#include <iostream>
+
+gr_top_block_sptr
+gr_make_top_block(const std::string &name)
+{
+ return gr_top_block_sptr(new gr_top_block(name));
+}
+
+gr_top_block::gr_top_block(const std::string &name)
+ : gr_hier_block2(name,
+ gr_make_io_signature(0,0,0),
+ gr_make_io_signature(0,0,0))
+
+{
+ d_impl = new gr_top_block_impl(this);
+}
+
+gr_top_block::~gr_top_block()
+{
+ delete d_impl;
+}
+
+void
+gr_top_block::start()
+{
+ d_impl->start();
+}
+
+void
+gr_top_block::stop()
+{
+ d_impl->stop();
+}
+
+void
+gr_top_block::wait()
+{
+ d_impl->wait();
+}
+
+void
+gr_top_block::run()
+{
+ start();
+ wait();
+}
+
+void
+gr_top_block::lock()
+{
+ d_impl->lock();
+}
+
+void
+gr_top_block::unlock()
+{
+ d_impl->unlock();
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, 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_TOP_BLOCK_H
+#define INCLUDED_GR_TOP_BLOCK_H
+
+#include <gr_hier_block2.h>
+
+class gr_top_block_impl;
+
+gr_top_block_sptr gr_make_top_block(const std::string &name);
+
+/*!
+ *\brief Top-level hierarchical block representing a flowgraph
+ *
+ */
+class gr_top_block : public gr_hier_block2
+{
+private:
+ friend gr_top_block_sptr gr_make_top_block(const std::string &name);
+
+ gr_top_block_impl *d_impl;
+
+protected:
+ gr_top_block(const std::string &name);
+
+public:
+ ~gr_top_block();
+
+ /*!
+ * Start the enclosed flowgraph. Creates an undetached scheduler thread for
+ * each flow graph partition. Returns to caller once created.
+ */
+ void start();
+
+ /*!
+ * Stop the running flowgraph. Tells each created scheduler thread
+ * to exit, then returns to caller.
+ */
+ void stop();
+
+ /*!
+ * Wait for a stopped flowgraph to complete. Joins each completed
+ * thread.
+ */
+ void wait();
+
+ /*!
+ * Calls start(), then wait(). Used to run a flowgraph that will stop
+ * on its own, or to run a flowgraph indefinitely until SIGKILL is
+ * received().
+ */
+ void run();
+
+ /*!
+ * Lock a flowgraph in preparation for reconfiguration. When an equal
+ * number of calls to lock() and unlock() have occurred, the flowgraph
+ * will be restarted automatically.
+ *
+ * N.B. lock() and unlock() cannot be called from a flowgraph thread or
+ * deadlock will occur when reconfiguration happens.
+ */
+ virtual void lock();
+
+ /*!
+ * Lock a flowgraph in preparation for reconfiguration. When an equal
+ * number of calls to lock() and unlock() have occurred, the flowgraph
+ * will be restarted automatically.
+ *
+ * N.B. lock() and unlock() cannot be called from a flowgraph thread or
+ * deadlock will occur when reconfiguration happens.
+ */
+ virtual void unlock();
+};
+
+#endif /* INCLUDED_GR_TOP_BLOCK_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, 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_top_block.i>
+
+class gr_top_block;
+typedef boost::shared_ptr<gr_top_block> gr_top_block_sptr;
+%template(gr_top_block_sptr) boost::shared_ptr<gr_top_block>;
+
+// Hack to have a Python shim implementation of gr.top_block
+// that instantiates one of these and passes through calls
+%rename(top_block_swig) gr_make_top_block;
+gr_top_block_sptr gr_make_top_block(const std::string name);
+
+class gr_top_block : public gr_hier_block2
+{
+private:
+ gr_top_block(const std::string &name);
+
+public:
+ ~gr_top_block();
+
+ void start();
+ void stop();
+ void wait();
+ void run();
+ void lock();
+ void unlock();
+};
+
+%{
+class ensure_py_gil_state2 {
+ PyGILState_STATE d_gstate;
+public:
+ ensure_py_gil_state2() { d_gstate = PyGILState_Ensure(); }
+ ~ensure_py_gil_state2() { PyGILState_Release(d_gstate); }
+};
+%}
+
+%inline %{
+void top_block_run_unlocked(gr_top_block_sptr r) throw (std::runtime_error)
+{
+ ensure_py_gil_state2 _lock;
+ r->run();
+}
+
+void top_block_wait_unlocked(gr_top_block_sptr r) throw (std::runtime_error)
+{
+ ensure_py_gil_state2 _lock;
+ r->wait();
+}
+%}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, 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_top_block.h>
+#include <gr_top_block_impl.h>
+#include <gr_flat_flowgraph.h>
+#include <gr_scheduler_thread.h>
+#include <gr_local_sighandler.h>
+
+#include <stdexcept>
+#include <iostream>
+
+#define GR_TOP_BLOCK_IMPL_DEBUG 0
+
+static gr_top_block_impl *s_impl = 0;
+
+// Make a vector of gr_block from a vector of gr_basic_block
+static
+gr_block_vector_t
+make_gr_block_vector(gr_basic_block_vector_t &blocks)
+{
+ gr_block_vector_t result;
+ for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
+ result.push_back(make_gr_block_sptr(*p));
+ }
+
+ return result;
+}
+
+// FIXME: This prevents using more than one gr_top_block instance
+static void
+runtime_sigint_handler(int signum)
+{
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "SIGINT received, calling stop()" << std::endl;
+
+ if (s_impl)
+ s_impl->stop();
+}
+
+gr_top_block_impl::gr_top_block_impl(gr_top_block *owner)
+ : d_running(false),
+ d_ffg(gr_make_flat_flowgraph()),
+ d_owner(owner),
+ d_lock_count(0)
+{
+ s_impl = this;
+}
+
+gr_top_block_impl::~gr_top_block_impl()
+{
+ s_impl = 0; // don't call delete we don't own these
+ d_owner = 0;
+}
+
+void
+gr_top_block_impl::start()
+{
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "start: entered" << std::endl;
+
+ if (d_running)
+ throw std::runtime_error("already running");
+
+ // Create new flat flow graph by flattening hierarchy
+ d_ffg->clear();
+ d_owner->flatten(d_ffg);
+
+ // Validate new simple flow graph and wire it up
+ d_ffg->validate();
+ d_ffg->setup_connections();
+
+ // Execute scheduler threads
+ start_threads();
+}
+
+void
+gr_top_block_impl::start_threads()
+{
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "start_threads: entered" << std::endl;
+
+ d_graphs = d_ffg->partition();
+ for (std::vector<gr_basic_block_vector_t>::iterator p = d_graphs.begin();
+ p != d_graphs.end(); p++) {
+ gr_scheduler_thread *thread = new gr_scheduler_thread(make_gr_block_vector(*p));
+ d_threads.push_back(thread);
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "start_threads: starting " << thread << std::endl;
+ thread->start();
+ }
+
+ d_running = true;
+}
+
+void
+gr_top_block_impl::stop()
+{
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "stop: entered" << std::endl;
+
+ for (gr_scheduler_thread_viter_t p = d_threads.begin(); p != d_threads.end(); p++) {
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "stop: stopping thread " << (*p) << std::endl;
+ (*p)->stop();
+ }
+
+ d_running = false;
+}
+
+void
+gr_top_block_impl::wait()
+{
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "wait: entered" << std::endl;
+
+ void *dummy_status; // don't ever dereference this
+ gr_local_sighandler sigint(SIGINT, runtime_sigint_handler);
+
+ for (gr_scheduler_thread_viter_t p = d_threads.begin(); p != d_threads.end(); p++) {
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "wait: joining thread " << (*p) << std::endl;
+ (*p)->join(&dummy_status); // pthreads will self-delete, so pointer is now dead
+ (*p) = 0; // FIXME: switch to stl::list and actually remove from container
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "wait: join returned" << std::endl;
+ }
+
+ d_threads.clear();
+}
+
+// N.B. lock() and unlock() cannot be called from a flow graph thread or
+// deadlock will occur when reconfiguration happens
+void
+gr_top_block_impl::lock()
+{
+ omni_mutex_lock lock(d_reconf);
+ d_lock_count++;
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "runtime: locked, count = " << d_lock_count << std::endl;
+}
+
+void
+gr_top_block_impl::unlock()
+{
+ omni_mutex_lock lock(d_reconf);
+ if (d_lock_count == 0)
+ throw std::runtime_error("unpaired unlock() call");
+
+ d_lock_count--;
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "unlock: unlocked, count = " << d_lock_count << std::endl;
+
+ if (d_lock_count == 0) {
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "unlock: restarting flowgraph" << std::endl;
+ restart();
+ }
+}
+
+void
+gr_top_block_impl::restart()
+{
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "restart: entered" << std::endl;
+
+ if (!d_running)
+ throw std::runtime_error("not running");
+
+ // Stop scheduler threads and wait for completion
+ stop();
+ wait();
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "restart: threads stopped" << std::endl;
+
+ // Create new simple flow graph
+ gr_flat_flowgraph_sptr new_ffg = gr_make_flat_flowgraph();
+ d_owner->flatten(new_ffg);
+ new_ffg->validate();
+ new_ffg->merge_connections(d_ffg);
+
+ if (GR_TOP_BLOCK_IMPL_DEBUG)
+ std::cout << "restart: replacing old flow graph with new" << std::endl;
+ d_ffg = new_ffg;
+
+ start_threads();
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, 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_TOP_BLOCK_IMPL_H
+#define INCLUDED_GR_TOP_BLOCK_IMPL_H
+
+#include <gr_scheduler_thread.h>
+
+/*!
+ *\brief Implementation details of gr_top_block
+ *
+ * The actual implementation of gr_top_block. Separate class allows
+ * decoupling of changes from dependent classes.
+ *
+ */
+class gr_top_block_impl
+{
+public:
+ gr_top_block_impl(gr_top_block *owner);
+ ~gr_top_block_impl();
+
+ // Create and start scheduler threads
+ void start();
+
+ // Signal scheduler threads to stop
+ void stop();
+
+ // Wait for scheduler threads to exit
+ void wait();
+
+ // Lock the top block to allow reconfiguration
+ void lock();
+
+ // Unlock the top block at end of reconfiguration
+ void unlock();
+
+private:
+
+ bool d_running;
+ gr_flat_flowgraph_sptr d_ffg;
+ gr_scheduler_thread_vector_t d_threads;
+ gr_top_block *d_owner;
+ int d_lock_count;
+ omni_mutex d_reconf;
+
+ std::vector<gr_basic_block_vector_t> d_graphs;
+
+ void start_threads();
+ void restart();
+};
+
+#endif /* INCLUDED_GR_TOP_BLOCK_IMPL_H */
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, 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_top_block.h>
+#include <gr_top_block.h>
+#include <gr_head.h>
+#include <gr_null_source.h>
+#include <gr_null_sink.h>
+
+void qa_gr_top_block::t0()
+{
+ gr_top_block_sptr tb = gr_make_top_block("top");
+
+ CPPUNIT_ASSERT(tb);
+}
+
+void qa_gr_top_block::t1_run()
+{
+ gr_top_block_sptr tb = gr_make_top_block("top");
+
+ gr_block_sptr src = gr_make_null_source(sizeof(int));
+ gr_block_sptr head = gr_make_head(sizeof(int), 1);
+ gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, dst, 0);
+ tb->run();
+}
+
+void qa_gr_top_block::t2_start_stop_wait()
+{
+ gr_top_block_sptr tb = gr_make_top_block("top");
+
+ gr_block_sptr src = gr_make_null_source(sizeof(int));
+ gr_block_sptr head = gr_make_head(sizeof(int), 1000000);
+ gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, dst, 0);
+
+ tb->start();
+ tb->stop();
+ tb->wait();
+}
+
+void qa_gr_top_block::t3_lock_unlock()
+{
+ gr_top_block_sptr tb = gr_make_top_block("top");
+
+ gr_block_sptr src = gr_make_null_source(sizeof(int));
+ gr_block_sptr head = gr_make_head(sizeof(int), 1000000);
+ gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, dst, 0);
+
+ tb->start();
+
+ tb->lock();
+ tb->unlock();
+
+ tb->stop();
+ tb->wait();
+}
+
+void qa_gr_top_block::t4_reconfigure()
+{
+ gr_top_block_sptr tb = gr_make_top_block("top");
+
+ gr_block_sptr src = gr_make_null_source(sizeof(int));
+ gr_block_sptr head = gr_make_head(sizeof(int), 1);
+ gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+ // Start infinite flowgraph
+ tb->connect(src, 0, dst, 0);
+ tb->start();
+
+ // Reconfigure with gr_head in the middle
+ tb->lock();
+ tb->disconnect(src, 0, dst, 0);
+ tb->connect(src, 0, head, 0);
+ tb->connect(head, 0, dst, 0);
+ tb->unlock();
+
+ // Wait for flowgraph to end on its own
+ tb->wait();
+}
--- /dev/null
+/* -*- c++ -*- */
+/*
+ * Copyright 2007 Free Software Foundation, Inc.
+ *
+ * This file is part of GNU Radio
+ *
+ * GNU Radio is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3, 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_TOP_BLOCK_H
+#define INCLUDED_QA_GR_TOP_BLOCK_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+#include <stdexcept>
+
+class qa_gr_top_block : public CppUnit::TestCase
+{
+ CPPUNIT_TEST_SUITE(qa_gr_top_block);
+
+ CPPUNIT_TEST(t0);
+ CPPUNIT_TEST(t1_run);
+ CPPUNIT_TEST(t2_start_stop_wait);
+ CPPUNIT_TEST(t3_lock_unlock);
+ // CPPUNIT_TEST(t4_reconfigure); triggers 'join never returns' bug
+
+ CPPUNIT_TEST_SUITE_END();
+
+private:
+
+ void t0();
+ void t1_run();
+ void t2_start_stop_wait();
+ void t3_lock_unlock();
+ void t4_reconfigure();
+};
+
+#endif /* INCLUDED_QA_GR_TOP_BLOCK_H */
#include <qa_gr_io_signature.h>
#include <qa_gr_block.h>
#include <qa_gr_flowgraph.h>
+#include <qa_gr_top_block.h>
#include <qa_gr_hier_block2.h>
#include <qa_gr_buffer.h>
s->addTest (qa_gr_io_signature::suite ());
s->addTest (qa_gr_block::suite ());
s->addTest (qa_gr_flowgraph::suite ());
+ s->addTest (qa_gr_top_block::suite ());
s->addTest (qa_gr_hier_block2::suite ());
s->addTest (qa_gr_buffer::suite ());
#include <gr_block.h>
#include <gr_block_detail.h>
#include <gr_hier_block2.h>
-#include <gr_runtime.h>
#include <gr_single_threaded_scheduler.h>
#include <gr_message.h>
#include <gr_msg_handler.h>
#include <gr_sync_block.h>
#include <gr_sync_decimator.h>
#include <gr_sync_interpolator.h>
+#include <gr_top_block.h>
%}
%include <gr_io_signature.i>
%include <gr_dispatcher.i>
%include <gr_error_handler.i>
%include <gr_realtime.i>
-%include <gr_runtime.i>
%include <gr_sync_block.i>
%include <gr_sync_decimator.i>
%include <gr_sync_interpolator.i>
+%include <gr_top_block.i>
hier_block.py \
hier_block2.py \
prefs.py \
- scheduler.py
+ scheduler.py \
+ top_block.py
noinst_PYTHON = \
benchmark_filters.py \
from exceptions import *
from hier_block import *
from hier_block2 import *
+from top_block import *
# create a couple of aliases
serial_to_parallel = stream_to_vector
#
-# Copyright 2006 Free Software Foundation, Inc.
+# Copyright 2006,2007 Free Software Foundation, Inc.
#
# This file is part of GNU Radio
#
# Boston, MA 02110-1301, USA.
#
-from gnuradio_swig_python import hier_block2_swig, gr_make_runtime, \
- runtime_run_unlocked, runtime_start_unlocked, runtime_stop_unlocked, \
- runtime_wait_unlocked, runtime_restart_unlocked, io_signature
+from gnuradio_swig_python import hier_block2_swig
#
# This hack forces a 'has-a' relationship to look like an 'is-a' one.
self._hb.disconnect(src_block.basic_block(), src_port,
dst_block.basic_block(), dst_port)
-# Convenience class to create a no input, no output block for runtime top block
-class top_block(hier_block2):
- def __init__(self, name):
- hier_block2.__init__(self, name, io_signature(0,0,0), io_signature(0,0,0))
-
-# This allows the 'run_locked' methods, which are defined in gr_runtime.i,
-# to release the Python global interpreter lock before calling the actual
-# method in gr.runtime
-#
-# This probably should be elsewhere but it works here
-class runtime(object):
- def __init__(self, top_block):
- if (isinstance(top_block, hier_block2)):
- self._r = gr_make_runtime(top_block._hb)
- else:
- self._r = gr_make_runtime(top_block)
-
- def run(self):
- runtime_run_unlocked(self._r)
-
- def start(self):
- runtime_start_unlocked(self._r)
-
- def stop(self):
- runtime_stop_unlocked(self._r)
-
- def wait(self):
- runtime_wait_unlocked(self._r)
-
- def restart(self):
- runtime_restart_unlocked(self._r)
sink2 = gr.vector_sink_f()
hblock.connect(src, sink1)
hblock.connect(src, sink2)
- runtime = gr.runtime(hblock)
- runtime.run()
+ hblock.run()
actual1 = sink1.data()
actual2 = sink2.data()
self.assertEquals(expected, actual1)
src = gr.vector_source_f(data, False)
dst = gr.vector_sink_f()
hblock.connect(src, dst)
- r = gr.runtime(hblock)
- r.run()
+ hblock.run()
self.assertEquals(data, dst.data())
if __name__ == "__main__":
+++ /dev/null
-#!/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()
--- /dev/null
+#
+# Copyright 2007 Free Software Foundation, Inc.
+#
+# This file is part of GNU Radio
+#
+# GNU Radio is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, 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 top_block_swig, \
+ top_block_wait_unlocked, top_block_run_unlocked
+
+#
+# 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.
+#
+# This allows the 'run_locked' methods, which are defined in gr_top_block.i,
+# to release the Python global interpreter lock before calling the actual
+# method in gr_top_block
+#
+class top_block(object):
+ def __init__(self, name="top_block"):
+ self._tb = top_block_swig(name)
+
+ def __getattr__(self, name):
+ return getattr(self._tb, name)
+
+ def run(self):
+ top_block_run_unlocked(self._tb)
+
+ def wait(self):
+ top_block_wait_unlocked(self._tb)
+
+ # FIXME: these are duplicated from hier_block2.py; they should really be implemented
+ # in the original C++ class (gr_hier_block2), then they would all be inherited here
+
+ def connect(self, *points):
+ '''connect requires two or more arguments that can be coerced to endpoints.
+ If more than two arguments are provided, they are connected together successively.
+ '''
+ if len (points) < 2:
+ raise ValueError, ("connect requires at least two endpoints; %d provided." % (len (points),))
+ for i in range (1, len (points)):
+ self._connect(points[i-1], points[i])
+
+ def _connect(self, src, dst):
+ (src_block, src_port) = self._coerce_endpoint(src)
+ (dst_block, dst_port) = self._coerce_endpoint(dst)
+ self._tb.connect(src_block.basic_block(), src_port,
+ dst_block.basic_block(), dst_port)
+
+ def _coerce_endpoint(self, endp):
+ if hasattr(endp, 'basic_block'):
+ return (endp, 0)
+ else:
+ if hasattr(endp, "__getitem__") and len(endp) == 2:
+ return endp # Assume user put (block, port)
+ else:
+ raise ValueError("unable to coerce endpoint")
+
+ def disconnect(self, *points):
+ '''connect requires two or more arguments that can be coerced to endpoints.
+ If more than two arguments are provided, they are disconnected successively.
+ '''
+ if len (points) < 2:
+ raise ValueError, ("disconnect requires at least two endpoints; %d provided." % (len (points),))
+ for i in range (1, len (points)):
+ self._disconnect(points[i-1], points[i])
+
+ def _disconnect(self, src, dst):
+ (src_block, src_port) = self._coerce_endpoint(src)
+ (dst_block, dst_port) = self._coerce_endpoint(dst)
+ self._tb.disconnect(src_block.basic_block(), src_port,
+ dst_block.basic_block(), dst_port)
+
include $(top_srcdir)/Makefile.common
-SUBDIRS = python
+SUBDIRS = python c++
#
include $(top_srcdir)/Makefile.common
-
-# FIXME: do not build automatically; need to detect required pre-requisites
-
# SUBDIRS = dial_tone
This example requires that gr-audio-alsa be built in the main tree in order
to compile successfully. It is not built automatically.
+
+To build this example, you must make two modifications to the build system:
+
+1) Add the following line inside config/grc_gnuradio_examples.m4:
+
+ gnuradio-examples/c++/dial_tone/Makefile
+
+ ...to the list of Makefiles already in there.
+
+2) In gnuradio-examples/c++/Makefile.am, uncomment the SUBDIRS line
+
+# SUBDIRS = dial_tone
+
+Then, from the top-level directory, re-run ./bootstrap and ./configure.
\ No newline at end of file
// Hierarchical block constructor, with no inputs or outputs
dial_tone::dial_tone() :
-gr_hier_block2("dial_tone",
- gr_make_io_signature(0,0,0),
- gr_make_io_signature(0,0,0))
+ gr_top_block("dial_tone")
{
gr_sig_source_f_sptr src0 = gr_make_sig_source_f(48000, GR_SIN_WAVE, 350, 0.1);
gr_sig_source_f_sptr src1 = gr_make_sig_source_f(48000, GR_SIN_WAVE, 440, 0.1);
* Boston, MA 02110-1301, USA.
*/
-#include <gr_hier_block2.h>
+#include <gr_top_block.h>
class dial_tone;
typedef boost::shared_ptr<dial_tone> dial_tone_sptr;
dial_tone_sptr make_dial_tone();
-class dial_tone : public gr_hier_block2
+class dial_tone : public gr_top_block
{
private:
dial_tone();
// Tell the runtime to go...
#include <dial_tone.h>
-#include <gr_runtime.h>
int main()
{
dial_tone_sptr top_block = make_dial_tone();
- gr_runtime_sptr runtime = gr_make_runtime(top_block);
-
- runtime->run();
+ top_block->run();
return 0;
}
options.audio_output,
options.amplitude)
- # Create an instance of a runtime, passing it the top block
- # to process
- runtime = gr.runtime(top)
-
try:
# Run forever
- runtime.run()
+ top.run()
except KeyboardInterrupt:
# Ctrl-C exits
pass
# Create an instance of a hierarchical block
top_block = dect_receiver(options)
- # Create an instance of a runtime, passing it the top block
- # to process
- runtime = gr.runtime(top_block)
-
try:
# Run forever
- runtime.run()
+ top_block.run()
except KeyboardInterrupt:
# Ctrl-C exits
pass
# Create an instance of a hierarchical block
top_block = my_graph(mods[options.modulation], demods[options.modulation], rx_callback, options)
-
- # Create an instance of a runtime, passing it the top block
- runtime = gr.runtime(top_block)
- runtime.start()
+ top_block.start()
# generate and send packets
nbytes = int(1e6 * options.megabytes)
send_pkt(eof=True)
- runtime.wait()
+ top_block.wait()
if __name__ == '__main__':
try:
# Create an instance of a hierarchical block
top_block = receive_path(demods[options.modulation], rx_callback, options)
-
- # Create an instance of a runtime, passing it the top block
- runtime = gr.runtime(top_block)
- runtime.start()
-
- runtime.wait() # wait for it to finish
+ top_block.run()
if __name__ == '__main__':
try:
# Create an instance of a hierarchical block
top_block = transmit_path(mods[options.modulation], options)
-
- # Create an instance of a runtime, passing it the top block
- runtime = gr.runtime(top_block)
- runtime.start()
+ top_block.start()
# generate and send packets
nbytes = int(1e6 * options.megabytes)
pktno += 1
send_pkt(eof=True)
- runtime.wait()
+ top_block.wait()
if __name__ == '__main__':
try:
top_block = audio_sink(options.src_name, options.src_port,
options.packet_size, options.sample_rate)
- # Create an instance of a runtime, passing it the top block
- runtime = gr.runtime(top_block)
-
try:
# Run forever
- runtime.run()
+ top_block.run()
except KeyboardInterrupt:
# Ctrl-C exits
pass
top_block = audio_source(options.src_name, options.dst_name, options.dst_port,
options.packet_size, options.sample_rate)
- # Create an instance of a runtime, passing it the top block
- runtime = gr.runtime(top_block)
-
try:
# Run forever
- runtime.run()
+ top_block.run()
except KeyboardInterrupt:
# Ctrl-C exits
pass
top_block = dial_tone_sink(options.src_name, options.src_port,
options.packet_size, options.sample_rate)
- # Create an instance of a runtime, passing it the top block
- runtime = gr.runtime(top_block)
-
try:
# Run forever
- runtime.run()
+ top_block.run()
except KeyboardInterrupt:
# Ctrl-C exits
pass
top_block = dial_tone_source(options.src_name, options.dst_name, options.dst_port,
options.packet_size, options.sample_rate)
- # Create an instance of a runtime, passing it the top block
- runtime = gr.runtime(top_block)
-
try:
# Run forever
- runtime.run()
+ top_block.run()
except KeyboardInterrupt:
# Ctrl-C exits
pass
# Create an instance of a hierarchical block
top_block = vector_sink(options.src_name, options.src_port, options.packet_size)
- # Create an instance of a runtime, passing it the top block
- runtime = gr.runtime(top_block)
-
try:
# Run forever
- runtime.run()
+ top_block.run()
except KeyboardInterrupt:
# Ctrl-C exits
pass
top_block = vector_source(options.src_name, options.dst_name,
options.dst_port, options.packet_size)
- # Create an instance of a runtime, passing it the top block
- runtime = gr.runtime(top_block)
-
try:
# Run forever
- runtime.run()
+ top_block.run()
except KeyboardInterrupt:
# Ctrl-C exits
pass
sys.exit(1)
top_block = usrp_sounder_rx(options)
- runtime = gr.runtime(top_block)
try:
- runtime.run()
+ top_block.run()
except KeyboardInterrupt:
pass
options.verbose, options.degree, options.chip_rate,
options.amplitude)
- # Create an instance of a runtime, passing it the top block
- # to process
- runtime = gr.runtime(top_block)
-
try:
# Run forever
- runtime.run()
+ top_block.run()
except KeyboardInterrupt:
# Ctrl-C exits
pass
top_block = my_graph(options.type, options.amplitude, options.waveform_freq, options.offset,
options.tx_subdev_spec, options.interp, options.rf_freq)
- runtime = gr.runtime(top_block)
-
try:
# Run forever
- runtime.run()
+ top_block.run()
except KeyboardInterrupt:
# Ctrl-C exits
pass
# Flow graph emits pages into message queue
queue = gr.msg_queue()
tb = app_top_block(options, queue)
- r = gr.runtime(tb)
try:
- r.start()
+ tb.start()
while 1:
if not queue.empty_p():
msg = queue.delete_head() # Blocking read
time.sleep(1)
except KeyboardInterrupt:
- r.stop()
+ tb.stop()
if __name__ == "__main__":
main()
queue = gr.msg_queue()
tb = app_top_block(options, queue)
- r = gr.runtime(tb)
try:
- r.start()
+ tb.start()
while 1:
if not queue.empty_p():
msg = queue.delete_head() # Blocking read
time.sleep(1)
except KeyboardInterrupt:
- r.stop()
+ tb.stop()
if __name__ == "__main__":
main()
queue = gr.msg_queue()
tb = app_top_block(options, queue)
- r = gr.runtime(tb)
try:
- r.start()
+ tb.start()
while 1:
if not queue.empty_p():
msg = queue.delete_head() # Blocking read
time.sleep(1)
except KeyboardInterrupt:
- r.stop()
+ tb.stop()
if __name__ == "__main__":
main()
vbox.Fit(self)
def OnCloseWindow (self, event):
- self.runtime().stop()
+ self.top_block().stop()
self.Destroy ()
- def runtime (self):
- return self.panel.runtime
+ def top_block (self):
+ return self.panel.top_block
class stdpanel (wx.Panel):
def __init__ (self, parent, frame, top_block_maker):
self.SetAutoLayout (True)
vbox.Fit (self)
- self.runtime = gr.runtime(self.top_block)
- self.runtime.start ()
+ self.top_block.start ()
class std_top_block (gr.top_block):
def __init__ (self, parent, panel, vbox, argv):