diff options
Diffstat (limited to 'gnuradio-core')
24 files changed, 648 insertions, 418 deletions
diff --git a/gnuradio-core/src/lib/runtime/Makefile.am b/gnuradio-core/src/lib/runtime/Makefile.am index 346f23b6a..4b51f7f4d 100644 --- a/gnuradio-core/src/lib/runtime/Makefile.am +++ b/gnuradio-core/src/lib/runtime/Makefile.am @@ -1,5 +1,5 @@ # -# Copyright 2003,2004 Free Software Foundation, Inc. +# Copyright 2003,2004,2007 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -48,12 +48,13 @@ libruntime_la_SOURCES = \ 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 \ @@ -67,6 +68,7 @@ libruntime_qa_la_SOURCES = \ 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 @@ -91,14 +93,15 @@ grinclude_HEADERS = \ 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 \ @@ -114,6 +117,7 @@ noinst_HEADERS = \ 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 @@ -130,12 +134,12 @@ swiginclude_HEADERS = \ 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 diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2.cc b/gnuradio-core/src/lib/runtime/gr_hier_block2.cc index 5b6688412..890638bae 100644 --- a/gnuradio-core/src/lib/runtime/gr_hier_block2.cc +++ b/gnuradio-core/src/lib/runtime/gr_hier_block2.cc @@ -35,7 +35,7 @@ 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)); + return gr_hier_block2_sptr(new gr_hier_block2(name, input_signature, output_signature)); } gr_hier_block2::gr_hier_block2(const std::string &name, @@ -48,39 +48,37 @@ 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); } diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2.h b/gnuradio-core/src/lib/runtime/gr_hier_block2.h index 02ce10106..75223d149 100644 --- a/gnuradio-core/src/lib/runtime/gr_hier_block2.h +++ b/gnuradio-core/src/lib/runtime/gr_hier_block2.h @@ -40,34 +40,32 @@ class gr_hier_block2_detail; 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 */ diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc index 99131afb6..15c898c77 100644 --- a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc +++ b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc @@ -25,7 +25,6 @@ #include <gr_hier_block2_detail.h> #include <gr_io_signature.h> -#include <gr_runtime.h> #include <stdexcept> #include <iostream> @@ -36,8 +35,7 @@ gr_hier_block2_detail::gr_hier_block2_detail(gr_hier_block2 *owner) : 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()) { } @@ -263,8 +261,7 @@ gr_hier_block2_detail::lock() if (d_parent_detail) d_parent_detail->lock(); else - if (d_runtime) - d_runtime->lock(); + d_owner->lock(); } void @@ -276,6 +273,5 @@ gr_hier_block2_detail::unlock() if (d_parent_detail) d_parent_detail->unlock(); else - if (d_runtime) - d_runtime->unlock(); + d_owner->unlock(); } diff --git a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h index b315061be..ace22ea9a 100644 --- a/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h +++ b/gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h @@ -40,7 +40,6 @@ private: 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, @@ -54,7 +53,6 @@ private: 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(); diff --git a/gnuradio-core/src/lib/runtime/gr_runtime.h b/gnuradio-core/src/lib/runtime/gr_runtime.h deleted file mode 100644 index 1168b3eda..000000000 --- a/gnuradio-core/src/lib/runtime/gr_runtime.h +++ /dev/null @@ -1,105 +0,0 @@ -/* -*- 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 */ diff --git a/gnuradio-core/src/lib/runtime/gr_runtime_types.h b/gnuradio-core/src/lib/runtime/gr_runtime_types.h index 8af663cdf..74d2614a8 100644 --- a/gnuradio-core/src/lib/runtime/gr_runtime_types.h +++ b/gnuradio-core/src/lib/runtime/gr_runtime_types.h @@ -38,7 +38,8 @@ class gr_buffer; 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; @@ -47,8 +48,8 @@ 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_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 */ diff --git a/gnuradio-core/src/lib/runtime/gr_scheduler_thread.cc b/gnuradio-core/src/lib/runtime/gr_scheduler_thread.cc new file mode 100644 index 000000000..9cce5eaec --- /dev/null +++ b/gnuradio-core/src/lib/runtime/gr_scheduler_thread.cc @@ -0,0 +1,75 @@ +/* -*- 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(); +} diff --git a/gnuradio-core/src/lib/runtime/gr_runtime_impl.h b/gnuradio-core/src/lib/runtime/gr_scheduler_thread.h index f6230018a..c989f797c 100644 --- a/gnuradio-core/src/lib/runtime/gr_runtime_impl.h +++ b/gnuradio-core/src/lib/runtime/gr_scheduler_thread.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2007 Free Software Foundation, Inc. + * Copyright 2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -20,13 +20,12 @@ * Boston, MA 02110-1301, USA. */ -#ifndef INCLUDED_GR_RUNTIME_IMPL_H -#define INCLUDED_GR_RUNTIME_IMPL_H +#ifndef INCLUDED_GR_SCHEDULER_THREAD_H +#define INCLUDED_GR_SCHEDULER_THREAD_H -#include <gr_runtime_types.h> -#include <gr_block.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; @@ -56,40 +55,4 @@ public: 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 */ +#endif /* INCLUDED_GR_SCHEDULER_THREAD_H */ diff --git a/gnuradio-core/src/lib/runtime/gr_runtime.cc b/gnuradio-core/src/lib/runtime/gr_top_block.cc index 6b1419e20..407df8bba 100644 --- a/gnuradio-core/src/lib/runtime/gr_runtime.cc +++ b/gnuradio-core/src/lib/runtime/gr_top_block.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2007 Free Software Foundation, Inc. + * Copyright 2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,66 +24,64 @@ #include "config.h" #endif -#include <gr_runtime.h> -#include <gr_runtime_impl.h> +#include <gr_top_block.h> +#include <gr_top_block_impl.h> +#include <gr_io_signature.h> #include <iostream> -gr_runtime_sptr -gr_make_runtime(gr_hier_block2_sptr top_block) +gr_top_block_sptr +gr_make_top_block(const std::string &name) { - return gr_runtime_sptr(new gr_runtime(top_block)); + return gr_top_block_sptr(new gr_top_block(name)); } -gr_runtime::gr_runtime(gr_hier_block2_sptr top_block) +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_runtime_impl(top_block, this); + d_impl = new gr_top_block_impl(this); } -gr_runtime::~gr_runtime() +gr_top_block::~gr_top_block() { delete d_impl; } void -gr_runtime::start() +gr_top_block::start() { d_impl->start(); } void -gr_runtime::stop() +gr_top_block::stop() { d_impl->stop(); } void -gr_runtime::wait() +gr_top_block::wait() { d_impl->wait(); } void -gr_runtime::run() +gr_top_block::run() { start(); wait(); } void -gr_runtime::restart() -{ - d_impl->restart(); -} - -void -gr_runtime::lock() +gr_top_block::lock() { d_impl->lock(); } void -gr_runtime::unlock() +gr_top_block::unlock() { d_impl->unlock(); } - diff --git a/gnuradio-core/src/lib/runtime/gr_top_block.h b/gnuradio-core/src/lib/runtime/gr_top_block.h new file mode 100644 index 000000000..16fd97074 --- /dev/null +++ b/gnuradio-core/src/lib/runtime/gr_top_block.h @@ -0,0 +1,95 @@ +/* -*- 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 */ diff --git a/gnuradio-core/src/lib/runtime/gr_runtime.i b/gnuradio-core/src/lib/runtime/gr_top_block.i index d750553a4..d310f2aea 100644 --- a/gnuradio-core/src/lib/runtime/gr_runtime.i +++ b/gnuradio-core/src/lib/runtime/gr_top_block.i @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2006,2007 Free Software Foundation, Inc. + * Copyright 2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -20,23 +20,31 @@ * 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>; +%include <gr_top_block.i> -gr_runtime_sptr gr_make_runtime(gr_hier_block2_sptr top_block); +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>; -class gr_runtime -{ -protected: - gr_runtime(gr_hier_block2_sptr 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: - 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); + ~gr_top_block(); + + void start(); + void stop(); + void wait(); + void run(); + void lock(); + void unlock(); }; %{ @@ -49,34 +57,15 @@ public: %} %inline %{ -void runtime_run_unlocked(gr_runtime_sptr r) throw (std::runtime_error) +void top_block_run_unlocked(gr_top_block_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) +void top_block_wait_unlocked(gr_top_block_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(); -} - %} diff --git a/gnuradio-core/src/lib/runtime/gr_runtime_impl.cc b/gnuradio-core/src/lib/runtime/gr_top_block_impl.cc index 30a39f1d8..f0b67ddde 100644 --- a/gnuradio-core/src/lib/runtime/gr_runtime_impl.cc +++ b/gnuradio-core/src/lib/runtime/gr_top_block_impl.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2007 Free Software Foundation, Inc. + * Copyright 2007 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,23 +24,18 @@ #include "config.h" #endif -#include <gr_runtime.h> -#include <gr_runtime_impl.h> +#include <gr_top_block.h> +#include <gr_top_block_impl.h> #include <gr_flat_flowgraph.h> -#include <gr_hier_block2.h> -#include <gr_hier_block2_detail.h> +#include <gr_scheduler_thread.h> #include <gr_local_sighandler.h> -#ifdef HAVE_SIGNAL_H -#include <signal.h> -#endif - #include <stdexcept> #include <iostream> -#define GR_RUNTIME_IMPL_DEBUG 0 +#define GR_TOP_BLOCK_IMPL_DEBUG 0 -static gr_runtime_impl *s_runtime = 0; +static gr_top_block_impl *s_impl = 0; // Make a vector of gr_block from a vector of gr_basic_block static @@ -55,45 +50,44 @@ make_gr_block_vector(gr_basic_block_vector_t &blocks) return result; } -// FIXME: This prevents using more than one gr_runtime instance -void +// FIXME: This prevents using more than one gr_top_block instance +static void runtime_sigint_handler(int signum) { - if (GR_RUNTIME_IMPL_DEBUG) - std::cout << "SIGINT received, calling stop() on all threads" << std::endl; + if (GR_TOP_BLOCK_IMPL_DEBUG) + std::cout << "SIGINT received, calling stop()" << std::endl; - if (s_runtime) - s_runtime->stop(); + if (s_impl) + s_impl->stop(); } -gr_runtime_impl::gr_runtime_impl(gr_hier_block2_sptr top_block, gr_runtime *owner) +gr_top_block_impl::gr_top_block_impl(gr_top_block *owner) : d_running(false), - d_top_block(top_block), d_ffg(gr_make_flat_flowgraph()), - d_owner(owner) + d_owner(owner), + d_lock_count(0) { - s_runtime = this; - top_block->set_runtime(d_owner); + s_impl = this; } -gr_runtime_impl::~gr_runtime_impl() +gr_top_block_impl::~gr_top_block_impl() { - s_runtime = 0; // don't call delete we don't own these + s_impl = 0; // don't call delete we don't own these d_owner = 0; } void -gr_runtime_impl::start() +gr_top_block_impl::start() { - if (GR_RUNTIME_IMPL_DEBUG) + if (GR_TOP_BLOCK_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 + // Create new flat flow graph by flattening hierarchy d_ffg->clear(); - d_top_block->d_detail->flatten(d_ffg); + d_owner->flatten(d_ffg); // Validate new simple flow graph and wire it up d_ffg->validate(); @@ -104,9 +98,9 @@ gr_runtime_impl::start() } void -gr_runtime_impl::start_threads() +gr_top_block_impl::start_threads() { - if (GR_RUNTIME_IMPL_DEBUG) + if (GR_TOP_BLOCK_IMPL_DEBUG) std::cout << "start_threads: entered" << std::endl; d_graphs = d_ffg->partition(); @@ -114,7 +108,7 @@ gr_runtime_impl::start_threads() 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) + if (GR_TOP_BLOCK_IMPL_DEBUG) std::cout << "start_threads: starting " << thread << std::endl; thread->start(); } @@ -123,13 +117,13 @@ gr_runtime_impl::start_threads() } void -gr_runtime_impl::stop() +gr_top_block_impl::stop() { - if (GR_RUNTIME_IMPL_DEBUG) + 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_RUNTIME_IMPL_DEBUG) + if (GR_TOP_BLOCK_IMPL_DEBUG) std::cout << "stop: stopping thread " << (*p) << std::endl; (*p)->stop(); } @@ -138,57 +132,59 @@ gr_runtime_impl::stop() } void -gr_runtime_impl::wait() +gr_top_block_impl::wait() { - if (GR_RUNTIME_IMPL_DEBUG) + 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_RUNTIME_IMPL_DEBUG) + 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_RUNTIME_IMPL_DEBUG) + 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_runtime_impl::lock() +gr_top_block_impl::lock() { omni_mutex_lock lock(d_reconf); d_lock_count++; - if (GR_RUNTIME_IMPL_DEBUG) + if (GR_TOP_BLOCK_IMPL_DEBUG) std::cout << "runtime: locked, count = " << d_lock_count << std::endl; } void -gr_runtime_impl::unlock() +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_RUNTIME_IMPL_DEBUG) - std::cout << "runtime: unlocked, count = " << d_lock_count << std::endl; + if (GR_TOP_BLOCK_IMPL_DEBUG) + std::cout << "unlock: unlocked, count = " << d_lock_count << std::endl; - if (d_lock_count == 0) + if (d_lock_count == 0) { + if (GR_TOP_BLOCK_IMPL_DEBUG) + std::cout << "unlock: restarting flowgraph" << std::endl; restart(); + } } void -gr_runtime_impl::restart() +gr_top_block_impl::restart() { - if (GR_RUNTIME_IMPL_DEBUG) + if (GR_TOP_BLOCK_IMPL_DEBUG) std::cout << "restart: entered" << std::endl; if (!d_running) @@ -197,57 +193,18 @@ gr_runtime_impl::restart() // Stop scheduler threads and wait for completion stop(); wait(); - if (GR_RUNTIME_IMPL_DEBUG) + 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_top_block->d_detail->flatten(new_ffg); + d_owner->flatten(new_ffg); new_ffg->validate(); new_ffg->merge_connections(d_ffg); - if (GR_RUNTIME_IMPL_DEBUG) + if (GR_TOP_BLOCK_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(); -} diff --git a/gnuradio-core/src/lib/runtime/gr_top_block_impl.h b/gnuradio-core/src/lib/runtime/gr_top_block_impl.h new file mode 100644 index 000000000..8052ce4fa --- /dev/null +++ b/gnuradio-core/src/lib/runtime/gr_top_block_impl.h @@ -0,0 +1,71 @@ +/* -*- 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 */ diff --git a/gnuradio-core/src/lib/runtime/qa_gr_top_block.cc b/gnuradio-core/src/lib/runtime/qa_gr_top_block.cc new file mode 100644 index 000000000..3322b6ac4 --- /dev/null +++ b/gnuradio-core/src/lib/runtime/qa_gr_top_block.cc @@ -0,0 +1,110 @@ +/* -*- 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(); +} diff --git a/gnuradio-core/src/lib/runtime/qa_gr_top_block.h b/gnuradio-core/src/lib/runtime/qa_gr_top_block.h new file mode 100644 index 000000000..9a243452d --- /dev/null +++ b/gnuradio-core/src/lib/runtime/qa_gr_top_block.h @@ -0,0 +1,51 @@ +/* -*- 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 */ diff --git a/gnuradio-core/src/lib/runtime/qa_runtime.cc b/gnuradio-core/src/lib/runtime/qa_runtime.cc index 5c00a4fbe..ba0f14b93 100644 --- a/gnuradio-core/src/lib/runtime/qa_runtime.cc +++ b/gnuradio-core/src/lib/runtime/qa_runtime.cc @@ -34,6 +34,7 @@ #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> @@ -46,6 +47,7 @@ qa_runtime::suite () 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 ()); diff --git a/gnuradio-core/src/lib/runtime/runtime.i b/gnuradio-core/src/lib/runtime/runtime.i index d162cff9b..20cf68a03 100644 --- a/gnuradio-core/src/lib/runtime/runtime.i +++ b/gnuradio-core/src/lib/runtime/runtime.i @@ -27,7 +27,6 @@ #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> @@ -38,6 +37,7 @@ #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> @@ -54,7 +54,7 @@ %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> diff --git a/gnuradio-core/src/python/gnuradio/gr/Makefile.am b/gnuradio-core/src/python/gnuradio/gr/Makefile.am index c9c946c2b..77cc53e3f 100644 --- a/gnuradio-core/src/python/gnuradio/gr/Makefile.am +++ b/gnuradio-core/src/python/gnuradio/gr/Makefile.am @@ -41,7 +41,8 @@ grgrpython_PYTHON = \ hier_block.py \ hier_block2.py \ prefs.py \ - scheduler.py + scheduler.py \ + top_block.py noinst_PYTHON = \ benchmark_filters.py \ diff --git a/gnuradio-core/src/python/gnuradio/gr/__init__.py b/gnuradio-core/src/python/gnuradio/gr/__init__.py index 8da93ec57..69f745fbf 100644 --- a/gnuradio-core/src/python/gnuradio/gr/__init__.py +++ b/gnuradio-core/src/python/gnuradio/gr/__init__.py @@ -30,6 +30,7 @@ from flow_graph import * 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 diff --git a/gnuradio-core/src/python/gnuradio/gr/hier_block2.py b/gnuradio-core/src/python/gnuradio/gr/hier_block2.py index 4699bb6fe..bc6402b87 100644 --- a/gnuradio-core/src/python/gnuradio/gr/hier_block2.py +++ b/gnuradio-core/src/python/gnuradio/gr/hier_block2.py @@ -1,5 +1,5 @@ # -# Copyright 2006 Free Software Foundation, Inc. +# Copyright 2006,2007 Free Software Foundation, Inc. # # This file is part of GNU Radio # @@ -19,9 +19,7 @@ # 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. @@ -77,34 +75,3 @@ class hier_block2(object): 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) diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py b/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py index 9fa002501..d07d4cb38 100755 --- a/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py +++ b/gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py @@ -100,8 +100,7 @@ class test_hier_block2(gr_unittest.TestCase): 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) @@ -185,8 +184,7 @@ class test_hier_block2(gr_unittest.TestCase): 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__": diff --git a/gnuradio-core/src/python/gnuradio/gr/qa_runtime.py b/gnuradio-core/src/python/gnuradio/gr/qa_runtime.py deleted file mode 100755 index ce0bdde21..000000000 --- a/gnuradio-core/src/python/gnuradio/gr/qa_runtime.py +++ /dev/null @@ -1,29 +0,0 @@ -#!/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/top_block.py b/gnuradio-core/src/python/gnuradio/gr/top_block.py new file mode 100644 index 000000000..9b709c01d --- /dev/null +++ b/gnuradio-core/src/python/gnuradio/gr/top_block.py @@ -0,0 +1,91 @@ +# +# 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) + |