diff options
author | Tom Rondeau <trondeau@vt.edu> | 2013-04-17 13:43:52 -0400 |
---|---|---|
committer | Tom Rondeau <trondeau@vt.edu> | 2013-04-29 14:52:56 -0400 |
commit | f3e2e07201c50033bf6c9d0c6a6f068557b4f17f (patch) | |
tree | 140b3c2d20a951ffd4abd564c3378ee2e2f9fc7c /gnuradio-runtime/lib | |
parent | 35303ae975a5b1bdecc2492bc96e2b8e89b62a3d (diff) |
runtime: converting runtime core to gr namespace, gnuradio include dir.
Diffstat (limited to 'gnuradio-runtime/lib')
195 files changed, 12548 insertions, 12311 deletions
diff --git a/gnuradio-runtime/lib/CMakeLists.txt b/gnuradio-runtime/lib/CMakeLists.txt index 98db673f5d..5193b98f57 100644 --- a/gnuradio-runtime/lib/CMakeLists.txt +++ b/gnuradio-runtime/lib/CMakeLists.txt @@ -27,8 +27,8 @@ execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "import time;print time.strftime('%a, %d %b %Y %H:%M:%S', time.gmtime())" OUTPUT_VARIABLE BUILD_DATE OUTPUT_STRIP_TRAILING_WHITESPACE ) -message(STATUS "Loading build date ${BUILD_DATE} into gr_constants...") -message(STATUS "Loading version ${VERSION} into gr_constants...") +message(STATUS "Loading build date ${BUILD_DATE} into constants...") +message(STATUS "Loading version ${VERSION} into constants...") #double escape for windows backslash path separators string(REPLACE "\\" "\\\\" prefix ${prefix}) @@ -36,11 +36,11 @@ string(REPLACE "\\" "\\\\" SYSCONFDIR ${SYSCONFDIR}) string(REPLACE "\\" "\\\\" GR_PREFSDIR ${GR_PREFSDIR}) configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/gr_constants.cc.in - ${CMAKE_CURRENT_BINARY_DIR}/gr_constants.cc + ${CMAKE_CURRENT_SOURCE_DIR}/constants.cc.in + ${CMAKE_CURRENT_BINARY_DIR}/constants.cc @ONLY) -list(APPEND gnuradio_runtime_sources ${CMAKE_CURRENT_BINARY_DIR}/gr_constants.cc) +list(APPEND gnuradio_runtime_sources ${CMAKE_CURRENT_BINARY_DIR}/constants.cc) ######################################################################## # Include subdirs rather to populate to the sources lists. @@ -63,67 +63,62 @@ include_directories(${GNURADIO_RUNTIME_INCLUDE_DIRS} GR_INCLUDE_SUBDIRECTORY(pmt) GR_INCLUDE_SUBDIRECTORY(messages) GR_INCLUDE_SUBDIRECTORY(thread) +GR_INCLUDE_SUBDIRECTORY(math) ######################################################################## # Setup library ######################################################################## list(APPEND gnuradio_runtime_sources complex_vec_test.cc - gr_basic_block.cc - gr_block.cc - gr_block_detail.cc - gr_block_executor.cc - gr_block_registry.cc - gr_buffer.cc - gr_circular_file.cc - gr_dispatcher.cc - gr_error_handler.cc - gr_fast_atan2f.cc - gr_feval.cc - gr_flat_flowgraph.cc - gr_flowgraph.cc - gr_fxpt.cc - gr_hier_block2.cc - gr_hier_block2_detail.cc - gri_debugger_hook.cc - gr_io_signature.cc - gr_local_sighandler.cc - gr_logger.cc - gr_message.cc - gr_misc.cc - gr_msg_accepter.cc - gr_msg_handler.cc - gr_msg_queue.cc - gr_pagesize.cc - gr_preferences.cc - gr_prefs.cc - gr_random.cc - gr_realtime.cc - gr_reverse.cc - gr_scheduler.cc - gr_scheduler_sts.cc - gr_scheduler_tpb.cc - gr_select_handler.cc - gr_sincos.c - gr_single_threaded_scheduler.cc - gr_sptr_magic.cc - gr_sync_block.cc - gr_sync_decimator.cc - gr_sync_interpolator.cc - gr_sys_paths.cc - gr_tagged_stream_block.cc - gr_test.cc - gr_top_block.cc - gr_top_block_impl.cc - gr_tpb_detail.cc - gr_tpb_thread_body.cc - gr_vmcircbuf.cc - gr_vmcircbuf_createfilemapping.cc - gr_vmcircbuf_mmap_shm_open.cc - gr_vmcircbuf_mmap_tmpfile.cc - gr_vmcircbuf_sysv_shm.cc malloc16.c - runtime_block_gateway.cc + basic_block.cc + block.cc + block_detail.cc + block_executor.cc + block_gateway_impl.cc + block_registry.cc + buffer.cc + circular_file.cc + dispatcher.cc + error_handler.cc + feval.cc + flat_flowgraph.cc + flowgraph.cc + hier_block2.cc + hier_block2_detail.cc + io_signature.cc + local_sighandler.cc + logger.cc + message.cc + misc.cc + msg_accepter.cc + msg_handler.cc + msg_queue.cc + pagesize.cc + prefs.cc + tagged_stream_block.cc + test.cc + top_block.cc + top_block_impl.cc + realtime.cc + scheduler.cc + scheduler_sts.cc + scheduler_tpb.cc + select_handler.cc + single_threaded_scheduler.cc + sptr_magic.cc + sync_block.cc + sync_decimator.cc + sync_interpolator.cc + sys_paths.cc + tpb_detail.cc + tpb_thread_body.cc + vmcircbuf.cc + vmcircbuf_createfilemapping.cc + vmcircbuf_mmap_shm_open.cc + vmcircbuf_mmap_tmpfile.cc + vmcircbuf_prefs.cc + vmcircbuf_sysv_shm.cc ) # PowerPC workaround for posix_memalign @@ -154,50 +149,7 @@ if(LINUX) list(APPEND gnuradio_runtime_libs rt) endif() -if(ENABLE_GR_CTRLPORT) - -include_directories(${ICE_INCLUDE_DIR}) - -# Add definition so we can compile in ControlPort to the blocks. -ADD_DEFINITIONS(-DGR_CTRLPORT) - -######################################################################## -# Run ICE To compile Slice files -######################################################################## -EXECUTE_PROCESS( - COMMAND "${ICE_SLICE2CPP}" "-I${CMAKE_CURRENT_SOURCE_DIR}" - "--output-dir=${CMAKE_CURRENT_BINARY_DIR}" - "${CMAKE_CURRENT_SOURCE_DIR}/gnuradio.ice" - ) - -list(APPEND gnuradio_runtime_sources - ice_application_base.cc - rpcmanager.cc - rpcpmtconverters_ice.cc - rpcserver_aggregator.cc - rpcserver_booter_aggregator.cc - rpcserver_booter_ice.cc - rpcserver_ice.cc - rpcserver_selector.cc - rpcpmtconverters_ice.cc -) - -# Append generated file in build directory -list(APPEND gnuradio_runtime_sources - ${CMAKE_CURRENT_BINARY_DIR}/gnuradio.cpp -) - -######################################################################## -# Add controlport stuff to gnuradio-runtime -######################################################################## - -include_directories(${CMAKE_CURRENT_BINARY_DIR}) - -list(APPEND gnuradio_runtime_libs - ${ICE_LIBRARIES} -) - -endif(ENABLE_GR_CTRLPORT) +GR_INCLUDE_SUBDIRECTORY(controlport) ######################################################################## # Add DLL resource file when using MSVC @@ -257,23 +209,23 @@ include(GrTest) # Append gnuradio-runtime test sources ######################################################################## list(APPEND test_gnuradio_runtime_sources - qa_gr_buffer.cc - qa_gr_circular_file.cc - qa_gr_fxpt.cc - qa_gr_fxpt_nco.cc - qa_gr_fxpt_vco.cc - qa_gr_io_signature.cc - qa_gr_logger.cc - qa_gr_math.cc - qa_gr_vmcircbuf.cc - qa_runtime.cc - qa_sincos.cc + math/qa_fxpt.cc + math/qa_fxpt_nco.cc + math/qa_fxpt_vco.cc + math/qa_math.cc + math/qa_sincos.cc pmt/qa_pmt.cc pmt/qa_pmt_prims.cc + qa_buffer.cc + qa_io_signature.cc + qa_circular_file.cc + qa_logger.cc + qa_vmcircbuf.cc + qa_runtime.cc ${CMAKE_CURRENT_BINARY_DIR}/pmt/qa_pmt_unv.cc ) -include_directories(${CPPUNIT_INCLUDE_DIRS}) +include_directories(${CPPUNIT_INCLUDE_DIRS} ${CMAKE_CURRENT_SOURCE_DIR}/math) link_directories(${CPPUNIT_LIBRARY_DIRS}) add_library(test-gnuradio-runtime SHARED ${test_gnuradio_runtime_sources}) diff --git a/gnuradio-runtime/lib/basic_block.cc b/gnuradio-runtime/lib/basic_block.cc new file mode 100644 index 0000000000..8060c5355c --- /dev/null +++ b/gnuradio-runtime/lib/basic_block.cc @@ -0,0 +1,233 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2012-2013 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 <gnuradio/basic_block.h> +#include <gnuradio/block_registry.h> +#include <stdexcept> +#include <sstream> +#include <iostream> + +namespace gr { + + static long s_next_id = 0; + static long s_ncurrently_allocated = 0; + + long + basic_block_ncurrently_allocated() + { + return s_ncurrently_allocated; + } + + basic_block::basic_block(const std::string &name, + io_signature::sptr input_signature, + io_signature::sptr output_signature) + : d_name(name), + d_input_signature(input_signature), + d_output_signature(output_signature), + d_unique_id(s_next_id++), + d_symbolic_id(global_block_registry.block_register(this)), + d_symbol_name(global_block_registry.register_symbolic_name(this)), + d_color(WHITE), + d_rpc_set(false), + message_subscribers(pmt::make_dict()) + { + s_ncurrently_allocated++; + } + + basic_block::~basic_block() + { + s_ncurrently_allocated--; + global_block_registry.block_unregister(this); + } + + basic_block_sptr + basic_block::to_basic_block() + { + return shared_from_this(); + } + + void + basic_block::set_block_alias(std::string name) + { + global_block_registry.register_symbolic_name(this, name); + } + + // ** Message passing interface ** + + // - register a new input message port + void + basic_block::message_port_register_in(pmt::pmt_t port_id) + { + if(!pmt::is_symbol(port_id)) { + throw std::runtime_error("message_port_register_in: bad port id"); + } + msg_queue[port_id] = msg_queue_t(); + msg_queue_ready[port_id] = boost::shared_ptr<boost::condition_variable>(new boost::condition_variable()); + } + + pmt::pmt_t + basic_block::message_ports_in() + { + pmt::pmt_t port_names = pmt::make_vector(msg_queue.size(), pmt::PMT_NIL); + msg_queue_map_itr itr = msg_queue.begin(); + for(size_t i = 0; i < msg_queue.size(); i++) { + pmt::vector_set(port_names, i, (*itr).first); + itr++; + } + return port_names; + } + + // - register a new output message port + void + basic_block::message_port_register_out(pmt::pmt_t port_id) + { + if(!pmt::is_symbol(port_id)) { + throw std::runtime_error("message_port_register_out: bad port id"); + } + if(pmt::dict_has_key(message_subscribers, port_id)) { + throw std::runtime_error("message_port_register_out: port already in use"); + } + message_subscribers = pmt::dict_add(message_subscribers, port_id, pmt::PMT_NIL); + } + + pmt::pmt_t + basic_block::message_ports_out() + { + size_t len = pmt::length(message_subscribers); + pmt::pmt_t port_names = pmt::make_vector(len, pmt::PMT_NIL); + pmt::pmt_t keys = pmt::dict_keys(message_subscribers); + for(size_t i = 0; i < len; i++) { + pmt::vector_set(port_names, i, pmt::nth(i, keys)); + } + return port_names; + } + + // - publish a message on a message port + void basic_block::message_port_pub(pmt::pmt_t port_id, pmt::pmt_t msg) + { + if(!pmt::dict_has_key(message_subscribers, port_id)) { + throw std::runtime_error("port does not exist"); + } + + pmt::pmt_t currlist = pmt::dict_ref(message_subscribers, port_id, pmt::PMT_NIL); + // iterate through subscribers on port + while(pmt::is_pair(currlist)) { + pmt::pmt_t target = pmt::car(currlist); + + pmt::pmt_t block = pmt::car(target); + pmt::pmt_t port = pmt::cdr(target); + + currlist = pmt::cdr(currlist); + basic_block_sptr blk = global_block_registry.block_lookup(block); + //blk->post(msg); + blk->post(port, msg); + } + } + + // - subscribe to a message port + void + basic_block::message_port_sub(pmt::pmt_t port_id, pmt::pmt_t target){ + if(!pmt::dict_has_key(message_subscribers, port_id)){ + std::stringstream ss; + ss << "Port does not exist: \"" << pmt::write_string(port_id) << "\" on block: " + << pmt::write_string(target) << std::endl; + throw std::runtime_error(ss.str()); + } + pmt::pmt_t currlist = pmt::dict_ref(message_subscribers,port_id,pmt::PMT_NIL); + + // ignore re-adds of the same target + if(!pmt::list_has(currlist, target)) + message_subscribers = pmt::dict_add(message_subscribers,port_id,pmt::list_add(currlist,target)); + } + + void + basic_block::message_port_unsub(pmt::pmt_t port_id, pmt::pmt_t target) + { + if(!pmt::dict_has_key(message_subscribers, port_id)) { + std::stringstream ss; + ss << "Port does not exist: \"" << pmt::write_string(port_id) << "\" on block: " + << pmt::write_string(target) << std::endl; + throw std::runtime_error(ss.str()); + } + + // ignore unsubs of unknown targets + pmt::pmt_t currlist = pmt::dict_ref(message_subscribers,port_id,pmt::PMT_NIL); + message_subscribers = pmt::dict_add(message_subscribers,port_id,pmt::list_rm(currlist,target)); + } + + void + basic_block::_post(pmt::pmt_t which_port, pmt::pmt_t msg) + { + insert_tail(which_port, msg); + } + + void + basic_block::insert_tail(pmt::pmt_t which_port, pmt::pmt_t msg) + { + gr::thread::scoped_lock guard(mutex); + + if((msg_queue.find(which_port) == msg_queue.end()) || (msg_queue_ready.find(which_port) == msg_queue_ready.end())) { + std::cout << "target port = " << pmt::symbol_to_string(which_port) << std::endl; + throw std::runtime_error("attempted to insert_tail on invalid queue!"); + } + + msg_queue[which_port].push_back(msg); + msg_queue_ready[which_port]->notify_one(); + + // wake up thread if BLKD_IN or BLKD_OUT + global_block_registry.notify_blk(alias()); + } + + pmt::pmt_t + basic_block::delete_head_nowait(pmt::pmt_t which_port) + { + gr::thread::scoped_lock guard(mutex); + + if(empty_p(which_port)) { + return pmt::pmt_t(); + } + + pmt::pmt_t m(msg_queue[which_port].front()); + msg_queue[which_port].pop_front(); + + return m; + } + + pmt::pmt_t + basic_block::delete_head_blocking(pmt::pmt_t which_port) + { + gr::thread::scoped_lock guard(mutex); + + while(empty_p(which_port)) { + msg_queue_ready[which_port]->wait(guard); + } + + pmt::pmt_t m(msg_queue[which_port].front()); + msg_queue[which_port].pop_front(); + return m; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/block.cc b/gnuradio-runtime/lib/block.cc new file mode 100644 index 0000000000..b38377e856 --- /dev/null +++ b/gnuradio-runtime/lib/block.cc @@ -0,0 +1,689 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2009,2010,2013 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 <gnuradio/block.h> +#include <gnuradio/block_registry.h> +#include <gnuradio/block_detail.h> +#include <gnuradio/prefs.h> +#include <stdexcept> +#include <iostream> + +namespace gr { + + block::block(const std::string &name, + io_signature::sptr input_signature, + io_signature::sptr output_signature) + : basic_block(name, input_signature, output_signature), + d_output_multiple (1), + d_output_multiple_set(false), + d_unaligned(0), + d_is_unaligned(false), + d_relative_rate (1.0), + d_history(1), + d_fixed_rate(false), + d_max_noutput_items_set(false), + d_max_noutput_items(0), + d_min_noutput_items(0), + d_tag_propagation_policy(TPP_ALL_TO_ALL), + d_pc_rpc_set(false), + d_max_output_buffer(std::max(output_signature->max_streams(),1), -1), + d_min_output_buffer(std::max(output_signature->max_streams(),1), -1) + { + global_block_registry.register_primitive(alias(), this); + +#ifdef ENABLE_GR_LOG +#ifdef HAVE_LOG4CPP + prefs *p = prefs::singleton(); + std::string config_file = p->get_string("LOG", "log_config", ""); + std::string log_level = p->get_string("LOG", "log_level", "off"); + std::string log_file = p->get_string("LOG", "log_file", ""); + std::string debug_level = p->get_string("LOG", "debug_level", "off"); + std::string debug_file = p->get_string("LOG", "debug_file", ""); + + GR_CONFIG_LOGGER(config_file); + + GR_LOG_GETLOGGER(LOG, "gr_log." + alias()); + GR_LOG_SET_LEVEL(LOG, log_level); + if(log_file.size() > 0) { + if(log_file == "stdout") { + GR_LOG_ADD_CONSOLE_APPENDER(LOG, "cout","gr::log :%p: %c{1} - %m%n"); + } + else if(log_file == "stderr") { + GR_LOG_ADD_CONSOLE_APPENDER(LOG, "cerr","gr::log :%p: %c{1} - %m%n"); + } + else { + GR_LOG_ADD_FILE_APPENDER(LOG, log_file , true,"%r :%p: %c{1} - %m%n"); + } + } + d_logger = LOG; + + GR_LOG_GETLOGGER(DLOG, "gr_log_debug." + alias()); + GR_LOG_SET_LEVEL(DLOG, debug_level); + if(debug_file.size() > 0) { + if(debug_file == "stdout") { + GR_LOG_ADD_CONSOLE_APPENDER(DLOG, "cout","gr::debug :%p: %c{1} - %m%n"); + } + else if(debug_file == "stderr") { + GR_LOG_ADD_CONSOLE_APPENDER(DLOG, "cerr", "gr::debug :%p: %c{1} - %m%n"); + } + else { + GR_LOG_ADD_FILE_APPENDER(DLOG, debug_file, true, "%r :%p: %c{1} - %m%n"); + } + } + d_debug_logger = DLOG; +#endif /* HAVE_LOG4CPP */ +#else /* ENABLE_GR_LOG */ + d_logger = NULL; + d_debug_logger = NULL; +#endif /* ENABLE_GR_LOG */ + } + + block::~block() + { + global_block_registry.unregister_primitive(alias()); + } + + // stub implementation: 1:1 + + void + block::forecast(int noutput_items, gr_vector_int &ninput_items_required) + { + unsigned ninputs = ninput_items_required.size (); + for(unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = noutput_items + history() - 1; + } + + // default implementation + + bool + block::start() + { + return true; + } + + bool + block::stop() + { + return true; + } + + void + block::set_output_multiple(int multiple) + { + if(multiple < 1) + throw std::invalid_argument("block::set_output_multiple"); + + d_output_multiple_set = true; + d_output_multiple = multiple; + } + + void + block::set_alignment(int multiple) + { + if(multiple < 1) + throw std::invalid_argument("block::set_alignment_multiple"); + + d_output_multiple = multiple; + } + + void + block::set_unaligned(int na) + { + // unaligned value must be less than 0 and it doesn't make sense + // that it's larger than the alignment value. + if((na < 0) || (na > d_output_multiple)) + throw std::invalid_argument("block::set_unaligned"); + + d_unaligned = na; + } + + void + block::set_is_unaligned(bool u) + { + d_is_unaligned = u; + } + + void + block::set_relative_rate(double relative_rate) + { + if(relative_rate < 0.0) + throw std::invalid_argument("block::set_relative_rate"); + + d_relative_rate = relative_rate; + } + + void + block::consume(int which_input, int how_many_items) + { + d_detail->consume(which_input, how_many_items); + } + + void + block::consume_each(int how_many_items) + { + d_detail->consume_each(how_many_items); + } + + void + block::produce(int which_output, int how_many_items) + { + d_detail->produce(which_output, how_many_items); + } + + int + block::fixed_rate_ninput_to_noutput(int ninput) + { + throw std::runtime_error("Unimplemented"); + } + + int + block::fixed_rate_noutput_to_ninput(int noutput) + { + throw std::runtime_error("Unimplemented"); + } + + uint64_t + block::nitems_read(unsigned int which_input) + { + if(d_detail) { + return d_detail->nitems_read(which_input); + } + else { + //throw std::runtime_error("No block_detail associated with block yet"); + return 0; + } + } + + uint64_t + block::nitems_written(unsigned int which_output) + { + if(d_detail) { + return d_detail->nitems_written(which_output); + } + else { + //throw std::runtime_error("No block_detail associated with block yet"); + return 0; + } + } + + void + block::add_item_tag(unsigned int which_output, + const tag_t &tag) + { + d_detail->add_item_tag(which_output, tag); + } + + void + block::remove_item_tag(unsigned int which_input, + const tag_t &tag) + { + d_detail->remove_item_tag(which_input, tag); + } + + void + block::get_tags_in_range(std::vector<tag_t> &v, + unsigned int which_output, + uint64_t start, uint64_t end) + { + d_detail->get_tags_in_range(v, which_output, start, end); + } + + void + block::get_tags_in_range(std::vector<tag_t> &v, + unsigned int which_output, + uint64_t start, uint64_t end, + const pmt::pmt_t &key) + { + d_detail->get_tags_in_range(v, which_output, start, end, key); + } + + block::tag_propagation_policy_t + block::tag_propagation_policy() + { + return d_tag_propagation_policy; + } + + void + block::set_tag_propagation_policy(tag_propagation_policy_t p) + { + d_tag_propagation_policy = p; + } + + int + block::max_noutput_items() + { + return d_max_noutput_items; + } + + void + block::set_max_noutput_items(int m) + { + if(m <= 0) + throw std::runtime_error("block::set_max_noutput_items: value for max_noutput_items must be greater than 0.\n"); + + d_max_noutput_items = m; + d_max_noutput_items_set = true; + } + + void + block::unset_max_noutput_items() + { + d_max_noutput_items_set = false; + } + + bool + block::is_set_max_noutput_items() + { + return d_max_noutput_items_set; + } + + void + block::set_processor_affinity(const std::vector<int> &mask) + { + d_affinity = mask; + if(d_detail) { + d_detail->set_processor_affinity(d_affinity); + } + } + + void + block::unset_processor_affinity() + { + d_affinity.clear(); + if(d_detail) { + d_detail->unset_processor_affinity(); + } + } + + float + block::pc_noutput_items() + { + if(d_detail) { + return d_detail->pc_noutput_items(); + } + else { + return 0; + } + } + + float + block::pc_noutput_items_avg() + { + if(d_detail) { + return d_detail->pc_noutput_items_avg(); + } + else { + return 0; + } + } + + float + block::pc_noutput_items_var() + { + if(d_detail) { + return d_detail->pc_noutput_items_var(); + } + else { + return 0; + } + } + + float + block::pc_nproduced() + { + if(d_detail) { + return d_detail->pc_nproduced(); + } + else { + return 0; + } + } + + float + block::pc_nproduced_avg() + { + if(d_detail) { + return d_detail->pc_nproduced_avg(); + } + else { + return 0; + } + } + + float + block::pc_nproduced_var() + { + if(d_detail) { + return d_detail->pc_nproduced_var(); + } + else { + return 0; + } + } + + float + block::pc_input_buffers_full(int which) + { + if(d_detail) { + return d_detail->pc_input_buffers_full(static_cast<size_t>(which)); + } + else { + return 0; + } + } + + float + block::pc_input_buffers_full_avg(int which) + { + if(d_detail) { + return d_detail->pc_input_buffers_full_avg(static_cast<size_t>(which)); + } + else { + return 0; + } + } + + float + block::pc_input_buffers_full_var(int which) + { + if(d_detail) { + return d_detail->pc_input_buffers_full_var(static_cast<size_t>(which)); + } + else { + return 0; + } + } + + std::vector<float> + block::pc_input_buffers_full() + { + if(d_detail) { + return d_detail->pc_input_buffers_full(); + } + else { + return std::vector<float>(1,0); + } + } + + std::vector<float> + block::pc_input_buffers_full_avg() + { + if(d_detail) { + return d_detail->pc_input_buffers_full_avg(); + } + else { + return std::vector<float>(1,0); + } + } + + std::vector<float> + block::pc_input_buffers_full_var() + { + if(d_detail) { + return d_detail->pc_input_buffers_full_var(); + } + else { + return std::vector<float>(1,0); + } + } + + float + block::pc_output_buffers_full(int which) + { + if(d_detail) { + return d_detail->pc_output_buffers_full(static_cast<size_t>(which)); + } + else { + return 0; + } + } + + float + block::pc_output_buffers_full_avg(int which) + { + if(d_detail) { + return d_detail->pc_output_buffers_full_avg(static_cast<size_t>(which)); + } + else { + return 0; + } + } + + float + block::pc_output_buffers_full_var(int which) + { + if(d_detail) { + return d_detail->pc_output_buffers_full_var(static_cast<size_t>(which)); + } + else { + return 0; + } + } + + std::vector<float> + block::pc_output_buffers_full() + { + if(d_detail) { + return d_detail->pc_output_buffers_full(); + } + else { + return std::vector<float>(1,0); + } + } + + std::vector<float> + block::pc_output_buffers_full_avg() + { + if(d_detail) { + return d_detail->pc_output_buffers_full_avg(); + } + else { + return std::vector<float>(1,0); + } + } + + std::vector<float> + block::pc_output_buffers_full_var() + { + if(d_detail) { + return d_detail->pc_output_buffers_full_var(); + } + else { + return std::vector<float>(1,0); + } + } + + float + block::pc_work_time() + { + if(d_detail) { + return d_detail->pc_work_time(); + } + else { + return 0; + } + } + + float + block::pc_work_time_avg() + { + if(d_detail) { + return d_detail->pc_work_time_avg(); + } + else { + return 0; + } + } + + float + block::pc_work_time_var() + { + if(d_detail) { + return d_detail->pc_work_time_var(); + } + else { + return 0; + } + } + + void + block::reset_perf_counters() + { + if(d_detail) { + d_detail->reset_perf_counters(); + } + } + + void + block::setup_pc_rpc() + { + d_pc_rpc_set = true; +#ifdef GR_CTRLPORT + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, float>( + alias(), "noutput_items", &block::pc_noutput_items, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "noutput items", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, float>( + alias(), "avg noutput_items", &block::pc_noutput_items_avg, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "Average noutput items", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, float>( + alias(), "var noutput_items", &block::pc_noutput_items_var, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "Var. noutput items", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, float>( + alias(), "nproduced", &block::pc_nproduced, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "items produced", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, float>( + alias(), "avg nproduced", &block::pc_nproduced_avg, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "Average items produced", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, float>( + alias(), "var nproduced", &block::pc_nproduced_var, + pmt::mp(0), pmt::mp(32768), pmt::mp(0), + "", "Var. items produced", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, float>( + alias(), "work time", &block::pc_work_time, + pmt::mp(0), pmt::mp(1e9), pmt::mp(0), + "", "clock cycles in call to work", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, float>( + alias(), "avg work time", &block::pc_work_time_avg, + pmt::mp(0), pmt::mp(1e9), pmt::mp(0), + "", "Average clock cycles in call to work", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, float>( + alias(), "var work time", &block::pc_work_time_var, + pmt::mp(0), pmt::mp(1e9), pmt::mp(0), + "", "Var. clock cycles in call to work", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, std::vector<float> >( + alias(), "input \% full", &block::pc_input_buffers_full, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "how full input buffers are", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, std::vector<float> >( + alias(), "avg input \% full", &block::pc_input_buffers_full_avg, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "Average of how full input buffers are", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, std::vector<float> >( + alias(), "var input \% full", &block::pc_input_buffers_full_var, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "Var. of how full input buffers are", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, std::vector<float> >( + alias(), "output \% full", &block::pc_output_buffers_full, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "how full output buffers are", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, std::vector<float> >( + alias(), "avg output \% full", &block::pc_output_buffers_full_avg, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "Average of how full output buffers are", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); + + d_rpc_vars.push_back( + rpcbasic_sptr(new rpcbasic_register_get<block, std::vector<float> >( + alias(), "var output \% full", &block::pc_output_buffers_full_var, + pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), + "", "Var. of how full output buffers are", RPC_PRIVLVL_MIN, + DISPTIME | DISPOPTSTRIP))); +#endif /* GR_CTRLPORT */ + } + + std::ostream& + operator << (std::ostream& os, const block *m) + { + os << "<block " << m->name() << " (" << m->unique_id() << ")>"; + return os; + } + + int + block::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + throw std::runtime_error("block::general_work() not implemented"); + return 0; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/block_detail.cc b/gnuradio-runtime/lib/block_detail.cc new file mode 100644 index 0000000000..a3ab4b3f7b --- /dev/null +++ b/gnuradio-runtime/lib/block_detail.cc @@ -0,0 +1,474 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2009,2010,2013 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 <gnuradio/block_detail.h> +#include <gnuradio/buffer.h> +#include <iostream> + +namespace gr { + + static long s_ncurrently_allocated = 0; + + long + block_detail_ncurrently_allocated() + { + return s_ncurrently_allocated; + } + + block_detail::block_detail(unsigned int ninputs, unsigned int noutputs) + : d_produce_or(0), + d_ninputs(ninputs), d_noutputs(noutputs), + d_input(ninputs), d_output(noutputs), + d_done(false), + d_ins_noutput_items(0), + d_avg_noutput_items(0), + d_var_noutput_items(0), + d_ins_nproduced(0), + d_avg_nproduced(0), + d_var_nproduced(0), + d_ins_input_buffers_full(ninputs, 0), + d_avg_input_buffers_full(ninputs, 0), + d_var_input_buffers_full(ninputs, 0), + d_ins_output_buffers_full(noutputs, 0), + d_avg_output_buffers_full(noutputs, 0), + d_var_output_buffers_full(noutputs, 0), + d_ins_work_time(0), + d_avg_work_time(0), + d_var_work_time(0), + d_pc_counter(0) + { + s_ncurrently_allocated++; + } + + block_detail::~block_detail() + { + // should take care of itself + s_ncurrently_allocated--; + } + + void + block_detail::set_input(unsigned int which, buffer_reader_sptr reader) + { + if(which >= d_ninputs) + throw std::invalid_argument("block_detail::set_input"); + + d_input[which] = reader; + } + + void + block_detail::set_output(unsigned int which, buffer_sptr buffer) + { + if(which >= d_noutputs) + throw std::invalid_argument("block_detail::set_output"); + + d_output[which] = buffer; + } + + block_detail_sptr + make_block_detail(unsigned int ninputs, unsigned int noutputs) + { + return block_detail_sptr (new block_detail(ninputs, noutputs)); + } + + void + block_detail::set_done(bool done) + { + d_done = done; + for(unsigned int i = 0; i < d_noutputs; i++) + d_output[i]->set_done(done); + + for(unsigned int i = 0; i < d_ninputs; i++) + d_input[i]->set_done(done); + } + + void + block_detail::consume(int which_input, int how_many_items) + { + if(how_many_items > 0) { + input(which_input)->update_read_pointer(how_many_items); + } + } + + void + block_detail::consume_each(int how_many_items) + { + if(how_many_items > 0) { + for(int i = 0; i < ninputs (); i++) { + d_input[i]->update_read_pointer(how_many_items); + } + } + } + + void + block_detail::produce(int which_output, int how_many_items) + { + if(how_many_items > 0) { + d_output[which_output]->update_write_pointer(how_many_items); + d_produce_or |= how_many_items; + } + } + + void + block_detail::produce_each(int how_many_items) + { + if(how_many_items > 0) { + for(int i = 0; i < noutputs (); i++) { + d_output[i]->update_write_pointer (how_many_items); + } + d_produce_or |= how_many_items; + } + } + + uint64_t + block_detail::nitems_read(unsigned int which_input) + { + if(which_input >= d_ninputs) + throw std::invalid_argument ("block_detail::n_input_items"); + return d_input[which_input]->nitems_read(); + } + + uint64_t + block_detail::nitems_written(unsigned int which_output) + { + if(which_output >= d_noutputs) + throw std::invalid_argument ("block_detail::n_output_items"); + return d_output[which_output]->nitems_written(); + } + + void + block_detail::add_item_tag(unsigned int which_output, const tag_t &tag) + { + if(!pmt::is_symbol(tag.key)) { + throw pmt::wrong_type("block_detail::add_item_tag key", tag.key); + } + else { + // Add tag to gr_buffer's deque tags + d_output[which_output]->add_item_tag(tag); + } + } + + void + block_detail::remove_item_tag(unsigned int which_input, const tag_t &tag) + { + if(!pmt::is_symbol(tag.key)) { + throw pmt::wrong_type("block_detail::add_item_tag key", tag.key); + } + else { + // Add tag to gr_buffer's deque tags + d_input[which_input]->buffer()->remove_item_tag(tag); + } + } + + void + block_detail::get_tags_in_range(std::vector<tag_t> &v, + unsigned int which_input, + uint64_t abs_start, + uint64_t abs_end) + { + // get from gr_buffer_reader's deque of tags + d_input[which_input]->get_tags_in_range(v, abs_start, abs_end); + } + + void + block_detail::get_tags_in_range(std::vector<tag_t> &v, + unsigned int which_input, + uint64_t abs_start, + uint64_t abs_end, + const pmt::pmt_t &key) + { + std::vector<tag_t> found_items; + + v.resize(0); + + // get from gr_buffer_reader's deque of tags + d_input[which_input]->get_tags_in_range(found_items, abs_start, abs_end); + + // Filter further by key name + pmt::pmt_t itemkey; + std::vector<tag_t>::iterator itr; + for(itr = found_items.begin(); itr != found_items.end(); itr++) { + itemkey = (*itr).key; + if(pmt::eqv(key, itemkey)) { + v.push_back(*itr); + } + } + } + + void + block_detail::set_processor_affinity(const std::vector<int> &mask) + { + if(threaded) { + try { + gr::thread::thread_bind_to_processor(thread, mask); + } + catch (std::runtime_error e) { + std::cerr << "set_processor_affinity: invalid mask." << std::endl;; + } + } + } + + void + block_detail::unset_processor_affinity() + { + if(threaded) { + gr::thread::thread_unbind(thread); + } + } + + void + block_detail::start_perf_counters() + { + d_start_of_work = gr::high_res_timer_now(); + } + + void + block_detail::stop_perf_counters(int noutput_items, int nproduced) + { + d_end_of_work = gr::high_res_timer_now(); + gr::high_res_timer_type diff = d_end_of_work - d_start_of_work; + + if(d_pc_counter == 0) { + d_ins_work_time = diff; + d_avg_work_time = diff; + d_var_work_time = 0; + d_ins_nproduced = nproduced; + d_avg_nproduced = nproduced; + d_var_nproduced = 0; + d_ins_noutput_items = noutput_items; + d_avg_noutput_items = noutput_items; + d_var_noutput_items = 0; + for(size_t i=0; i < d_input.size(); i++) { + float pfull = static_cast<float>(d_input[i]->items_available()) / + static_cast<float>(d_input[i]->max_possible_items_available()); + d_ins_input_buffers_full[i] = pfull; + d_avg_input_buffers_full[i] = pfull; + d_var_input_buffers_full[i] = 0; + } + for(size_t i=0; i < d_output.size(); i++) { + float pfull = 1.0f - static_cast<float>(d_output[i]->space_available()) / + static_cast<float>(d_output[i]->bufsize()); + d_ins_output_buffers_full[i] = pfull; + d_avg_output_buffers_full[i] = pfull; + d_var_output_buffers_full[i] = 0; + } + } + else { + float d = diff - d_avg_work_time; + d_ins_work_time = diff; + d_avg_work_time = d_avg_work_time + d/d_pc_counter; + d_var_work_time = d_var_work_time + d*d; + + d = nproduced - d_avg_nproduced; + d_ins_nproduced = nproduced; + d_avg_nproduced = d_avg_nproduced + d/d_pc_counter; + d_var_nproduced = d_var_nproduced + d*d; + + d = noutput_items - d_avg_noutput_items; + d_ins_noutput_items = noutput_items; + d_avg_noutput_items = d_avg_noutput_items + d/d_pc_counter; + d_var_noutput_items = d_var_noutput_items + d*d; + + for(size_t i=0; i < d_input.size(); i++) { + float pfull = static_cast<float>(d_input[i]->items_available()) / + static_cast<float>(d_input[i]->max_possible_items_available()); + + d = pfull - d_avg_input_buffers_full[i]; + d_ins_input_buffers_full[i] = pfull; + d_avg_input_buffers_full[i] = d_avg_input_buffers_full[i] + d/d_pc_counter; + d_var_input_buffers_full[i] = d_var_input_buffers_full[i] + d*d; + } + + for(size_t i=0; i < d_output.size(); i++) { + float pfull = 1.0f - static_cast<float>(d_output[i]->space_available()) / + static_cast<float>(d_output[i]->bufsize()); + + d = pfull - d_avg_output_buffers_full[i]; + d_ins_output_buffers_full[i] = pfull; + d_avg_output_buffers_full[i] = d_avg_output_buffers_full[i] + d/d_pc_counter; + d_var_output_buffers_full[i] = d_var_output_buffers_full[i] + d*d; + } + } + + d_pc_counter++; + } + + void + block_detail::reset_perf_counters() + { + d_pc_counter = 0; + } + + float + block_detail::pc_noutput_items() + { + return d_ins_noutput_items; + } + + float + block_detail::pc_nproduced() + { + return d_ins_nproduced; + } + + float + block_detail::pc_input_buffers_full(size_t which) + { + if(which < d_ins_input_buffers_full.size()) + return d_ins_input_buffers_full[which]; + else + return 0; + } + + std::vector<float> + block_detail::pc_input_buffers_full() + { + return d_ins_input_buffers_full; + } + + float + block_detail::pc_output_buffers_full(size_t which) + { + if(which < d_ins_output_buffers_full.size()) + return d_ins_output_buffers_full[which]; + else + return 0; + } + + std::vector<float> + block_detail::pc_output_buffers_full() + { + return d_ins_output_buffers_full; + } + + float + block_detail::pc_work_time() + { + return d_ins_work_time; + } + + float + block_detail::pc_noutput_items_avg() + { + return d_avg_noutput_items; + } + + float + block_detail::pc_nproduced_avg() + { + return d_avg_nproduced; + } + + float + block_detail::pc_input_buffers_full_avg(size_t which) + { + if(which < d_avg_input_buffers_full.size()) + return d_avg_input_buffers_full[which]; + else + return 0; + } + + std::vector<float> + block_detail::pc_input_buffers_full_avg() + { + return d_avg_input_buffers_full; + } + + float + block_detail::pc_output_buffers_full_avg(size_t which) + { + if(which < d_avg_output_buffers_full.size()) + return d_avg_output_buffers_full[which]; + else + return 0; + } + + std::vector<float> + block_detail::pc_output_buffers_full_avg() + { + return d_avg_output_buffers_full; + } + + float + block_detail::pc_work_time_avg() + { + return d_avg_work_time; + } + + float + block_detail::pc_noutput_items_var() + { + return d_var_noutput_items/(d_pc_counter-1); + } + + float + block_detail::pc_nproduced_var() + { + return d_var_nproduced/(d_pc_counter-1); + } + + float + block_detail::pc_input_buffers_full_var(size_t which) + { + if(which < d_avg_input_buffers_full.size()) + return d_var_input_buffers_full[which]/(d_pc_counter-1); + else + return 0; + } + + std::vector<float> + block_detail::pc_input_buffers_full_var() + { + std::vector<float> var(d_avg_input_buffers_full.size(), 0); + for(size_t i = 0; i < d_avg_input_buffers_full.size(); i++) + var[i] = d_avg_input_buffers_full[i]/(d_pc_counter-1); + return var; + } + + float + block_detail::pc_output_buffers_full_var(size_t which) + { + if(which < d_avg_output_buffers_full.size()) + return d_var_output_buffers_full[which]/(d_pc_counter-1); + else + return 0; + } + + std::vector<float> + block_detail::pc_output_buffers_full_var() + { + std::vector<float> var(d_avg_output_buffers_full.size(), 0); + for(size_t i = 0; i < d_avg_output_buffers_full.size(); i++) + var[i] = d_avg_output_buffers_full[i]/(d_pc_counter-1); + return var; + } + + float + block_detail::pc_work_time_var() + { + return d_var_work_time/(d_pc_counter-1); + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/block_executor.cc b/gnuradio-runtime/lib/block_executor.cc new file mode 100644 index 0000000000..8059ea2d5a --- /dev/null +++ b/gnuradio-runtime/lib/block_executor.cc @@ -0,0 +1,489 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2008-2010,2013 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 <block_executor.h> +#include <gnuradio/block.h> +#include <gnuradio/block_detail.h> +#include <gnuradio/buffer.h> +#include <gnuradio/prefs.h> +#include <boost/thread.hpp> +#include <boost/format.hpp> +#include <iostream> +#include <limits> +#include <assert.h> +#include <stdio.h> + +namespace gr { + +// must be defined to either 0 or 1 +#define ENABLE_LOGGING 0 + +#if (ENABLE_LOGGING) +#define LOG(x) do { x; } while(0) +#else +#define LOG(x) do {;} while(0) +#endif + + static int which_scheduler = 0; + + inline static unsigned int + round_up(unsigned int n, unsigned int multiple) + { + return ((n + multiple - 1) / multiple) * multiple; + } + + inline static unsigned int + round_down(unsigned int n, unsigned int multiple) + { + return (n / multiple) * multiple; + } + + // + // Return minimum available write space in all our downstream + // buffers or -1 if we're output blocked and the output we're + // blocked on is done. + // + static int + min_available_space(block_detail *d, int output_multiple, int min_noutput_items) + { + int min_space = std::numeric_limits<int>::max(); + if(min_noutput_items == 0) + min_noutput_items = 1; + for(int i = 0; i < d->noutputs (); i++) { + gr::thread::scoped_lock guard(*d->output(i)->mutex()); + int avail_n = round_down(d->output(i)->space_available(), output_multiple); + int best_n = round_down(d->output(i)->bufsize()/2, output_multiple); + if(best_n < min_noutput_items) + throw std::runtime_error("Buffer too small for min_noutput_items"); + int n = std::min(avail_n, best_n); + if(n < min_noutput_items){ // We're blocked on output. + if(d->output(i)->done()){ // Downstream is done, therefore we're done. + return -1; + } + return 0; + } + min_space = std::min(min_space, n); + } + return min_space; + } + + static bool + propagate_tags(block::tag_propagation_policy_t policy, block_detail *d, + const std::vector<uint64_t> &start_nitems_read, double rrate, + std::vector<tag_t> &rtags) + { + // Move tags downstream + // if a sink, we don't need to move downstream + if(d->sink_p()) { + return true; + } + + switch(policy) { + case block::TPP_DONT: + return true; + break; + case block::TPP_ALL_TO_ALL: + // every tag on every input propogates to everyone downstream + for(int i = 0; i < d->ninputs(); i++) { + d->get_tags_in_range(rtags, i, start_nitems_read[i], + d->nitems_read(i)); + + std::vector<tag_t>::iterator t; + if(rrate == 1.0) { + for(t = rtags.begin(); t != rtags.end(); t++) { + for(int o = 0; o < d->noutputs(); o++) + d->output(o)->add_item_tag(*t); + } + } + else { + for(t = rtags.begin(); t != rtags.end(); t++) { + tag_t new_tag = *t; + new_tag.offset *= rrate; + for(int o = 0; o < d->noutputs(); o++) + d->output(o)->add_item_tag(new_tag); + } + } + } + break; + case block::TPP_ONE_TO_ONE: + // tags from input i only go to output i + // this requires d->ninputs() == d->noutputs; this is checked when this + // type of tag-propagation system is selected in block_detail + if(d->ninputs() == d->noutputs()) { + for(int i = 0; i < d->ninputs(); i++) { + d->get_tags_in_range(rtags, i, start_nitems_read[i], + d->nitems_read(i)); + + std::vector<tag_t>::iterator t; + for(t = rtags.begin(); t != rtags.end(); t++) { + tag_t new_tag = *t; + new_tag.offset *= rrate; + d->output(i)->add_item_tag(new_tag); + } + } + } + else { + std::cerr << "Error: block_executor: propagation_policy 'ONE-TO-ONE' requires ninputs == noutputs" << std::endl; + return false; + } + + break; + default: + return true; + } + return true; + } + + block_executor::block_executor(block_sptr block, int max_noutput_items) + : d_block(block), d_log(0), d_max_noutput_items(max_noutput_items) + { + if(ENABLE_LOGGING) { + std::string name = str(boost::format("sst-%03d.log") % which_scheduler++); + d_log = new std::ofstream(name.c_str()); + std::unitbuf(*d_log); // make it unbuffered... + *d_log << "block_executor: " + << d_block << std::endl; + } + +#ifdef GR_PERFORMANCE_COUNTERS + prefs *prefs = prefs::singleton(); + d_use_pc = prefs->get_bool("PerfCounters", "on", false); +#endif /* GR_PERFORMANCE_COUNTERS */ + + d_block->start(); // enable any drivers, etc. + } + + block_executor::~block_executor() + { + if(ENABLE_LOGGING) + delete d_log; + + d_block->stop(); // stop any drivers, etc. + } + + block_executor::state + block_executor::run_one_iteration() + { + int noutput_items; + int max_items_avail; + int max_noutput_items = d_max_noutput_items; + int new_alignment = 0; + int alignment_state = -1; + + block *m = d_block.get(); + block_detail *d = m->detail().get(); + + LOG(*d_log << std::endl << m); + + if(d->done()){ + assert(0); + return DONE; + } + + if(d->source_p ()) { + d_ninput_items_required.resize(0); + d_ninput_items.resize(0); + d_input_items.resize(0); + d_input_done.resize(0); + d_output_items.resize(d->noutputs()); + d_start_nitems_read.resize(0); + + // determine the minimum available output space + noutput_items = min_available_space(d, m->output_multiple (), m->min_noutput_items ()); + noutput_items = std::min(noutput_items, max_noutput_items); + LOG(*d_log << " source\n noutput_items = " << noutput_items << std::endl); + if(noutput_items == -1) // we're done + goto were_done; + + if(noutput_items == 0){ // we're output blocked + LOG(*d_log << " BLKD_OUT\n"); + return BLKD_OUT; + } + + goto setup_call_to_work; // jump to common code + } + + else if(d->sink_p ()) { + d_ninput_items_required.resize(d->ninputs ()); + d_ninput_items.resize(d->ninputs ()); + d_input_items.resize(d->ninputs ()); + d_input_done.resize(d->ninputs()); + d_output_items.resize (0); + d_start_nitems_read.resize(d->ninputs()); + LOG(*d_log << " sink\n"); + + max_items_avail = 0; + for(int i = 0; i < d->ninputs (); i++) { + { + /* + * Acquire the mutex and grab local copies of items_available and done. + */ + gr::thread::scoped_lock guard(*d->input(i)->mutex()); + d_ninput_items[i] = d->input(i)->items_available(); + d_input_done[i] = d->input(i)->done(); + } + + LOG(*d_log << " d_ninput_items[" << i << "] = " << d_ninput_items[i] << std::endl); + LOG(*d_log << " d_input_done[" << i << "] = " << d_input_done[i] << std::endl); + + if (d_ninput_items[i] < m->output_multiple() && d_input_done[i]) + goto were_done; + + max_items_avail = std::max (max_items_avail, d_ninput_items[i]); + } + + // take a swag at how much output we can sink + noutput_items = (int)(max_items_avail * m->relative_rate ()); + noutput_items = round_down(noutput_items, m->output_multiple ()); + noutput_items = std::min(noutput_items, max_noutput_items); + LOG(*d_log << " max_items_avail = " << max_items_avail << std::endl); + LOG(*d_log << " noutput_items = " << noutput_items << std::endl); + + if(noutput_items == 0) { // we're blocked on input + LOG(*d_log << " BLKD_IN\n"); + return BLKD_IN; + } + + goto try_again; // Jump to code shared with regular case. + } + + else { + // do the regular thing + d_ninput_items_required.resize (d->ninputs ()); + d_ninput_items.resize (d->ninputs ()); + d_input_items.resize (d->ninputs ()); + d_input_done.resize(d->ninputs()); + d_output_items.resize (d->noutputs ()); + d_start_nitems_read.resize(d->ninputs()); + + max_items_avail = 0; + for(int i = 0; i < d->ninputs (); i++) { + { + /* + * Acquire the mutex and grab local copies of items_available and done. + */ + gr::thread::scoped_lock guard(*d->input(i)->mutex()); + d_ninput_items[i] = d->input(i)->items_available (); + d_input_done[i] = d->input(i)->done(); + } + max_items_avail = std::max(max_items_avail, d_ninput_items[i]); + } + + // determine the minimum available output space + noutput_items = min_available_space(d, m->output_multiple(), m->min_noutput_items()); + if(ENABLE_LOGGING) { + *d_log << " regular "; + if(m->relative_rate() >= 1.0) + *d_log << "1:" << m->relative_rate() << std::endl; + else + *d_log << 1.0/m->relative_rate() << ":1\n"; + *d_log << " max_items_avail = " << max_items_avail << std::endl; + *d_log << " noutput_items = " << noutput_items << std::endl; + } + if(noutput_items == -1) // we're done + goto were_done; + + if(noutput_items == 0) { // we're output blocked + LOG(*d_log << " BLKD_OUT\n"); + return BLKD_OUT; + } + + try_again: + if(m->fixed_rate()) { + // try to work it forward starting with max_items_avail. + // We want to try to consume all the input we've got. + int reqd_noutput_items = m->fixed_rate_ninput_to_noutput(max_items_avail); + + // only test this if we specifically set the output_multiple + if(m->output_multiple_set()) + reqd_noutput_items = round_down(reqd_noutput_items, m->output_multiple()); + + if(reqd_noutput_items > 0 && reqd_noutput_items <= noutput_items) + noutput_items = reqd_noutput_items; + + // if we need this many outputs, overrule the max_noutput_items setting + max_noutput_items = std::max(m->output_multiple(), max_noutput_items); + } + noutput_items = std::min(noutput_items, max_noutput_items); + + // Check if we're still unaligned; use up items until we're + // aligned again. Otherwise, make sure we set the alignment + // requirement. + if(!m->output_multiple_set()) { + if(m->is_unaligned()) { + // When unaligned, don't just set noutput_items to the remaining + // samples to meet alignment; this causes too much overhead in + // requiring a premature call back here. Set the maximum amount + // of samples to handle unalignment and get us back aligned. + if(noutput_items >= m->unaligned()) { + noutput_items = round_up(noutput_items, m->alignment()) \ + - (m->alignment() - m->unaligned()); + new_alignment = 0; + } + else { + new_alignment = m->unaligned() - noutput_items; + } + alignment_state = 0; + } + else if(noutput_items < m->alignment()) { + // if we don't have enough for an aligned call, keep track of + // misalignment, set unaligned flag, and proceed. + new_alignment = m->alignment() - noutput_items; + m->set_unaligned(new_alignment); + m->set_is_unaligned(true); + alignment_state = 1; + } + else { + // enough to round down to the nearest alignment and process. + noutput_items = round_down(noutput_items, m->alignment()); + m->set_is_unaligned(false); + alignment_state = 2; + } + } + + // ask the block how much input they need to produce noutput_items + m->forecast (noutput_items, d_ninput_items_required); + + // See if we've got sufficient input available + int i; + for(i = 0; i < d->ninputs (); i++) + if(d_ninput_items_required[i] > d_ninput_items[i]) // not enough + break; + + if(i < d->ninputs()) { // not enough input on input[i] + // if we can, try reducing the size of our output request + if(noutput_items > m->output_multiple()) { + noutput_items /= 2; + noutput_items = round_up(noutput_items, m->output_multiple()); + goto try_again; + } + + // We're blocked on input + LOG(*d_log << " BLKD_IN\n"); + if(d_input_done[i]) // If the upstream block is done, we're done + goto were_done; + + // Is it possible to ever fulfill this request? + if(d_ninput_items_required[i] > d->input(i)->max_possible_items_available()) { + // Nope, never going to happen... + std::cerr << "\nsched: <block " << m->name() + << " (" << m->unique_id() << ")>" + << " is requesting more input data\n" + << " than we can provide.\n" + << " ninput_items_required = " + << d_ninput_items_required[i] << "\n" + << " max_possible_items_available = " + << d->input(i)->max_possible_items_available() << "\n" + << " If this is a filter, consider reducing the number of taps.\n"; + goto were_done; + } + + // If we were made unaligned in this round but return here without + // processing; reset the unalignment claim before next entry. + if(alignment_state == 1) { + m->set_unaligned(0); + m->set_is_unaligned(false); + } + return BLKD_IN; + } + + // We've got enough data on each input to produce noutput_items. + // Finish setting up the call to work. + for(int i = 0; i < d->ninputs (); i++) + d_input_items[i] = d->input(i)->read_pointer(); + + setup_call_to_work: + + d->d_produce_or = 0; + for(int i = 0; i < d->noutputs (); i++) + d_output_items[i] = d->output(i)->write_pointer(); + + // determine where to start looking for new tags + for(int i = 0; i < d->ninputs(); i++) + d_start_nitems_read[i] = d->nitems_read(i); + +#ifdef GR_PERFORMANCE_COUNTERS + if(d_use_pc) + d->start_perf_counters(); +#endif /* GR_PERFORMANCE_COUNTERS */ + + // Do the actual work of the block + int n = m->general_work(noutput_items, d_ninput_items, + d_input_items, d_output_items); + +#ifdef GR_PERFORMANCE_COUNTERS + if(d_use_pc) + d->stop_perf_counters(noutput_items, n); +#endif /* GR_PERFORMANCE_COUNTERS */ + + LOG(*d_log << " general_work: noutput_items = " << noutput_items + << " result = " << n << std::endl); + + // Adjust number of unaligned items left to process + if(m->is_unaligned()) { + m->set_unaligned(new_alignment); + m->set_is_unaligned(m->unaligned() != 0); + } + + if(!propagate_tags(m->tag_propagation_policy(), d, + d_start_nitems_read, m->relative_rate(), + d_returned_tags)) + goto were_done; + + if(n == block::WORK_DONE) + goto were_done; + + if(n != block::WORK_CALLED_PRODUCE) + d->produce_each (n); // advance write pointers + + if(d->d_produce_or > 0) // block produced something + return READY; + + // We didn't produce any output even though we called general_work. + // We have (most likely) consumed some input. + + /* + // If this is a source, it's broken. + if(d->source_p()) { + std::cerr << "block_executor: source " << m + << " produced no output. We're marking it DONE.\n"; + // FIXME maybe we ought to raise an exception... + goto were_done; + } + */ + + // Have the caller try again... + return READY_NO_OUTPUT; + } + assert(0); + + were_done: + LOG(*d_log << " were_done\n"); + d->set_done (true); + return DONE; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/block_executor.h b/gnuradio-runtime/lib/block_executor.h new file mode 100644 index 0000000000..4e1d2f1602 --- /dev/null +++ b/gnuradio-runtime/lib/block_executor.h @@ -0,0 +1,78 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2008,2013 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_BLOCK_EXECUTOR_H +#define INCLUDED_GR_RUNTIME_BLOCK_EXECUTOR_H + +#include <gnuradio/api.h> +#include <gnuradio/runtime_types.h> +#include <gnuradio/tags.h> +#include <fstream> + +namespace gr { + + /*! + * \brief Manage the execution of a single block. + * \ingroup internal + */ + class GR_RUNTIME_API block_executor + { + protected: + block_sptr d_block; // The block we're trying to run + std::ofstream *d_log; + + // These are allocated here so we don't have to on each iteration + + gr_vector_int d_ninput_items_required; + gr_vector_int d_ninput_items; + gr_vector_const_void_star d_input_items; + std::vector<bool> d_input_done; + gr_vector_void_star d_output_items; + std::vector<uint64_t> d_start_nitems_read; //stores where tag counts are before work + std::vector<tag_t> d_returned_tags; + int d_max_noutput_items; + +#ifdef GR_PERFORMANCE_COUNTERS + bool d_use_pc; +#endif /* GR_PERFORMANCE_COUNTERS */ + + public: + block_executor(block_sptr block, int max_noutput_items=100000); + ~block_executor(); + + enum state { + READY, // We made progress; everything's cool. + READY_NO_OUTPUT, // We consumed some input, but produced no output. + BLKD_IN, // no progress; we're blocked waiting for input data. + BLKD_OUT, // no progress; we're blocked waiting for output buffer space. + DONE, // we're done; don't call me again. + }; + + /* + * \brief Run one iteration. + */ + state run_one_iteration(); + }; + +} /* namespace gr */ + +#endif /* INCLUDED_GR_RUNTIME_BLOCK_EXECUTOR_H */ diff --git a/gnuradio-runtime/lib/block_gateway_impl.cc b/gnuradio-runtime/lib/block_gateway_impl.cc new file mode 100644 index 0000000000..13f4326d7e --- /dev/null +++ b/gnuradio-runtime/lib/block_gateway_impl.cc @@ -0,0 +1,186 @@ +/* + * Copyright 2011-2013 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 "block_gateway_impl.h" +#include <gnuradio/io_signature.h> +#include <iostream> +#include <boost/bind.hpp> + +namespace gr { + + /*********************************************************************** + * Helper routines + **********************************************************************/ + template <typename OutType, typename InType> + void + copy_pointers(OutType &out, const InType &in) + { + out.resize(in.size()); + for(size_t i = 0; i < in.size(); i++) { + out[i] = (void *)(in[i]); + } + } + + + block_gateway::sptr + block_gateway::make(feval_ll *handler, + const std::string &name, + gr::io_signature::sptr in_sig, + gr::io_signature::sptr out_sig, + const block_gw_work_type work_type, + const unsigned factor) + { + return block_gateway::sptr + (new block_gateway_impl(handler, name, in_sig, out_sig, + work_type, factor)); + } + + block_gateway_impl::block_gateway_impl(feval_ll *handler, + const std::string &name, + gr::io_signature::sptr in_sig, + gr::io_signature::sptr out_sig, + const block_gw_work_type work_type, + const unsigned factor) + : block(name, in_sig, out_sig), + _handler(handler), + _work_type(work_type) + { + switch(_work_type) { + case GR_BLOCK_GW_WORK_GENERAL: + _decim = 1; //not relevant, but set anyway + _interp = 1; //not relevant, but set anyway + break; + + case GR_BLOCK_GW_WORK_SYNC: + _decim = 1; + _interp = 1; + this->set_fixed_rate(true); + break; + + case GR_BLOCK_GW_WORK_DECIM: + _decim = factor; + _interp = 1; + break; + + case GR_BLOCK_GW_WORK_INTERP: + _decim = 1; + _interp = factor; + this->set_output_multiple(_interp); + break; + } + } + + void + block_gateway_impl::forecast(int noutput_items, + gr_vector_int &ninput_items_required) + { + switch(_work_type) { + case GR_BLOCK_GW_WORK_GENERAL: + _message.action = block_gw_message_type::ACTION_FORECAST; + _message.forecast_args_noutput_items = noutput_items; + _message.forecast_args_ninput_items_required = ninput_items_required; + _handler->calleval(0); + ninput_items_required = _message.forecast_args_ninput_items_required; + return; + + default: + unsigned ninputs = ninput_items_required.size(); + for(unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = fixed_rate_noutput_to_ninput(noutput_items); + return; + } + } + + int + block_gateway_impl::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + switch(_work_type) { + case GR_BLOCK_GW_WORK_GENERAL: + _message.action = block_gw_message_type::ACTION_GENERAL_WORK; + _message.general_work_args_noutput_items = noutput_items; + _message.general_work_args_ninput_items = ninput_items; + copy_pointers(_message.general_work_args_input_items, input_items); + _message.general_work_args_output_items = output_items; + _handler->calleval(0); + return _message.general_work_args_return_value; + + default: + int r = work (noutput_items, input_items, output_items); + if(r > 0) + consume_each(r*_decim/_interp); + return r; + } + } + + int + block_gateway_impl::work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + _message.action = block_gw_message_type::ACTION_WORK; + _message.work_args_ninput_items = fixed_rate_noutput_to_ninput(noutput_items); + if(_message.work_args_ninput_items == 0) + return -1; + _message.work_args_noutput_items = noutput_items; + copy_pointers(_message.work_args_input_items, input_items); + _message.work_args_output_items = output_items; + _handler->calleval(0); + return _message.work_args_return_value; + } + + int + block_gateway_impl::fixed_rate_noutput_to_ninput(int noutput_items) + { + return (noutput_items*_decim/_interp) + history() - 1; + } + + int + block_gateway_impl::fixed_rate_ninput_to_noutput(int ninput_items) + { + return std::max(0, ninput_items - (int)history() + 1)*_interp/_decim; + } + + bool + block_gateway_impl::start(void) + { + _message.action = block_gw_message_type::ACTION_START; + _handler->calleval(0); + return _message.start_args_return_value; + } + + bool + block_gateway_impl::stop(void) + { + _message.action = block_gw_message_type::ACTION_STOP; + _handler->calleval(0); + return _message.stop_args_return_value; + } + + block_gw_message_type& + block_gateway_impl::block_message(void) + { + return _message; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/block_gateway_impl.h b/gnuradio-runtime/lib/block_gateway_impl.h new file mode 100644 index 0000000000..1707ecf1c8 --- /dev/null +++ b/gnuradio-runtime/lib/block_gateway_impl.h @@ -0,0 +1,75 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 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_RUNTIME_BLOCK_GATEWAY_IMPL_H +#define INCLUDED_RUNTIME_BLOCK_GATEWAY_IMPL_H + +#include <gnuradio/block_gateway.h> + +namespace gr { + + /*********************************************************************** + * The gr::block gateway implementation class + **********************************************************************/ + class block_gateway_impl : public block_gateway + { + public: + block_gateway_impl(feval_ll *handler, + const std::string &name, + gr::io_signature::sptr in_sig, + gr::io_signature::sptr out_sig, + const block_gw_work_type work_type, + const unsigned factor); + + /******************************************************************* + * Overloads for various scheduler-called functions + ******************************************************************/ + void forecast(int noutput_items, + gr_vector_int &ninput_items_required); + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + int work(int noutput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + int fixed_rate_noutput_to_ninput(int noutput_items); + int fixed_rate_ninput_to_noutput(int ninput_items); + + bool start(void); + bool stop(void); + + block_gw_message_type& block_message(void); + + private: + feval_ll *_handler; + block_gw_message_type _message; + const block_gw_work_type _work_type; + unsigned _decim, _interp; + }; + +} /* namespace gr */ + +#endif /* INCLUDED_RUNTIME_BLOCK_GATEWAY_H */ diff --git a/gnuradio-runtime/lib/block_registry.cc b/gnuradio-runtime/lib/block_registry.cc new file mode 100644 index 0000000000..f17e3e4af9 --- /dev/null +++ b/gnuradio-runtime/lib/block_registry.cc @@ -0,0 +1,120 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012-2013 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 <gnuradio/basic_block.h> +#include <gnuradio/block.h> +#include <gnuradio/block_detail.h> +#include <gnuradio/block_registry.h> +#include <gnuradio/tpb_detail.h> +#include <stdio.h> + +gr::block_registry global_block_registry; + +namespace gr { + + block_registry::block_registry() + { + d_ref_map = pmt::make_dict(); + } + + long + block_registry::block_register(basic_block* block) + { + if(d_map.find(block->name()) == d_map.end()) { + d_map[block->name()] = blocksubmap_t(); + d_map[block->name()][0] = block; + return 0; + } + else { + for(size_t i=0; i<=d_map[block->name()].size(); i++){ + if(d_map[block->name()].find(i) == d_map[block->name()].end()){ + d_map[block->name()][i] = block; + return i; + } + } + } + throw std::runtime_error("should not reach this"); + } + + void + block_registry::block_unregister(basic_block* block) + { + d_map[block->name()].erase( d_map[block->name()].find(block->symbolic_id())); + d_ref_map = pmt::dict_delete(d_ref_map, pmt::intern(block->symbol_name())); + if(block->alias_set()) { + d_ref_map = pmt::dict_delete(d_ref_map, pmt::intern(block->alias())); + } + } + + std::string + block_registry::register_symbolic_name(basic_block* block) + { + std::stringstream ss; + ss << block->name() << block->symbolic_id(); + //std::cout << "register_symbolic_name: " << ss.str() << std::endl; + register_symbolic_name(block, ss.str()); + return ss.str(); + } + + void + block_registry::register_symbolic_name(basic_block* block, std::string name) + { + if(pmt::dict_has_key(d_ref_map, pmt::intern(name))) { + throw std::runtime_error("symbol already exists, can not re-use!"); + } + d_ref_map = pmt::dict_add(d_ref_map, pmt::intern(name), pmt::make_any(block)); + } + + basic_block_sptr + block_registry::block_lookup(pmt::pmt_t symbol) + { + pmt::pmt_t ref = pmt::dict_ref(d_ref_map, symbol, pmt::PMT_NIL); + if(pmt::eq(ref, pmt::PMT_NIL)) { + throw std::runtime_error("block lookup failed! block not found!"); + } + basic_block* blk = boost::any_cast<basic_block*>(pmt::any_ref(ref)); + return blk->shared_from_this(); + } + + void + block_registry::register_primitive(std::string blk, block* ref) + { + primitive_map[blk] = ref; + } + + void + block_registry::unregister_primitive(std::string blk) + { + primitive_map.erase(primitive_map.find(blk)); + } + + void + block_registry::notify_blk(std::string blk) + { + if(primitive_map.find(blk) == primitive_map.end()) { + return; + } + if(primitive_map[blk]->detail().get()) + primitive_map[blk]->detail()->d_tpb.notify_msg(); + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/buffer.cc b/gnuradio-runtime/lib/buffer.cc new file mode 100644 index 0000000000..1bcfc2a6e4 --- /dev/null +++ b/gnuradio-runtime/lib/buffer.cc @@ -0,0 +1,343 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2009,2010,2013 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 <gnuradio/buffer.h> +#include <gnuradio/math.h> +#include "vmcircbuf.h" +#include <stdexcept> +#include <iostream> +#include <assert.h> +#include <algorithm> +#include <boost/math/common_factor_rt.hpp> + +namespace gr { + + static long s_buffer_count = 0; // counts for debugging storage mgmt + static long s_buffer_reader_count = 0; + + /* ---------------------------------------------------------------------------- + Notes on storage management + + Pretty much all the fundamental classes are now using the + shared_ptr stuff for automatic reference counting. To ensure that + no mistakes are made, we make the constructors for classes private, + and then provide a free factory function that returns a smart + pointer to the desired class. + + gr::buffer and gr::buffer_reader are no exceptions. However, they + both want pointers to each other, and unless we do something, we'll + never delete any of them because of the circular structure. + They'll always have a reference count of at least one. We could + use boost::weak_ptr's from gr::buffer to gr::buffer_reader but that + introduces it's own problems. (gr::buffer_reader's destructor needs + to call gr::buffer::drop_reader, but has no easy way to get a + shared_ptr to itself.) + + Instead, we solve this problem by having gr::buffer hold a raw + pointer to gr::buffer_reader in its d_reader vector. + gr::buffer_reader's destructor calls gr::buffer::drop_reader, so + we're never left with an dangling pointer. gr::buffer_reader still + has a shared_ptr to the buffer ensuring that the buffer doesn't go + away under it. However, when the reference count of a + gr::buffer_reader goes to zero, we can successfully reclaim it. + ---------------------------------------------------------------------------- */ + + /* + * Compute the minimum number of buffer items that work (i.e., + * address space wrap-around works). To work is to satisfy this + * contraint for integer buffer_size and k: + * + * type_size * nitems == k * page_size + */ + static long + minimum_buffer_items(long type_size, long page_size) + { + return page_size / boost::math::gcd (type_size, page_size); + } + + + buffer::buffer(int nitems, size_t sizeof_item, block_sptr link) + : d_base(0), d_bufsize(0), d_vmcircbuf(0), + d_sizeof_item(sizeof_item), d_link(link), + d_write_index(0), d_abs_write_offset(0), d_done(false), + d_last_min_items_read(0) + { + if(!allocate_buffer (nitems, sizeof_item)) + throw std::bad_alloc (); + + s_buffer_count++; + } + + buffer_sptr + make_buffer(int nitems, size_t sizeof_item, block_sptr link) + { + return buffer_sptr(new buffer(nitems, sizeof_item, link)); + } + + buffer::~buffer() + { + delete d_vmcircbuf; + assert(d_readers.size() == 0); + s_buffer_count--; + } + + /*! + * sets d_vmcircbuf, d_base, d_bufsize. + * returns true iff successful. + */ + bool + buffer::allocate_buffer(int nitems, size_t sizeof_item) + { + int orig_nitems = nitems; + + // Any buffersize we come up with must be a multiple of min_nitems. + int granularity = gr::vmcircbuf_sysconfig::granularity(); + int min_nitems = minimum_buffer_items(sizeof_item, granularity); + + // Round-up nitems to a multiple of min_nitems. + if(nitems % min_nitems != 0) + nitems = ((nitems / min_nitems) + 1) * min_nitems; + + // If we rounded-up a whole bunch, give the user a heads up. + // This only happens if sizeof_item is not a power of two. + + if(nitems > 2 * orig_nitems && nitems * (int) sizeof_item > granularity){ + std::cerr << "gr::buffer::allocate_buffer: warning: tried to allocate\n" + << " " << orig_nitems << " items of size " + << sizeof_item << ". Due to alignment requirements\n" + << " " << nitems << " were allocated. If this isn't OK, consider padding\n" + << " your structure to a power-of-two bytes.\n" + << " On this platform, our allocation granularity is " << granularity << " bytes.\n"; + } + + d_bufsize = nitems; + d_vmcircbuf = gr::vmcircbuf_sysconfig::make(d_bufsize * d_sizeof_item); + if(d_vmcircbuf == 0){ + std::cerr << "gr::buffer::allocate_buffer: failed to allocate buffer of size " + << d_bufsize * d_sizeof_item / 1024 << " KB\n"; + return false; + } + + d_base = (char*)d_vmcircbuf->pointer_to_first_copy(); + return true; + } + + int + buffer::space_available() + { + if(d_readers.empty()) + return d_bufsize - 1; // See comment below + + else { + // Find out the maximum amount of data available to our readers + + int most_data = d_readers[0]->items_available(); + uint64_t min_items_read = d_readers[0]->nitems_read(); + for(size_t i = 1; i < d_readers.size (); i++) { + most_data = std::max(most_data, d_readers[i]->items_available()); + min_items_read = std::min(min_items_read, d_readers[i]->nitems_read()); + } + + if(min_items_read != d_last_min_items_read) { + prune_tags(d_last_min_items_read); + d_last_min_items_read = min_items_read; + } + + // The -1 ensures that the case d_write_index == d_read_index is + // unambiguous. It indicates that there is no data for the reader + return d_bufsize - most_data - 1; + } + } + + void * + buffer::write_pointer() + { + return &d_base[d_write_index * d_sizeof_item]; + } + + void + buffer::update_write_pointer(int nitems) + { + gr::thread::scoped_lock guard(*mutex()); + d_write_index = index_add(d_write_index, nitems); + d_abs_write_offset += nitems; + } + + void + buffer::set_done(bool done) + { + gr::thread::scoped_lock guard(*mutex()); + d_done = done; + } + + buffer_reader_sptr + buffer_add_reader(buffer_sptr buf, int nzero_preload, block_sptr link) + { + if(nzero_preload < 0) + throw std::invalid_argument("buffer_add_reader: nzero_preload must be >= 0"); + + buffer_reader_sptr r(new buffer_reader(buf, + buf->index_sub(buf->d_write_index, + nzero_preload), + link)); + buf->d_readers.push_back(r.get ()); + + return r; + } + + void + buffer::drop_reader(buffer_reader *reader) + { + std::vector<buffer_reader *>::iterator result = + std::find(d_readers.begin(), d_readers.end(), reader); + + if(result == d_readers.end()) + throw std::invalid_argument("buffer::drop_reader"); // we didn't find it... + + d_readers.erase(result); + } + + void + buffer::add_item_tag(const tag_t &tag) + { + gr::thread::scoped_lock guard(*mutex()); + d_item_tags.push_back(tag); + } + + void + buffer::remove_item_tag(const tag_t &tag) + { + gr::thread::scoped_lock guard(*mutex()); + for(std::deque<tag_t>::iterator it = d_item_tags.begin(); it != d_item_tags.end(); ++it) { + if(*it == tag) { + d_item_tags.erase(it); + break; + } + } + } + + void + buffer::prune_tags(uint64_t max_time) + { + /* NOTE: this function _should_ lock the mutex before editing + d_item_tags. In practice, this function is only called at + runtime by min_available_space in block_executor.cc, which + locks the mutex itself. + + If this function is used elsewhere, remember to lock the + buffer's mutex al la the scoped_lock line below. + */ + //gr::thread::scoped_lock guard(*mutex()); + std::deque<tag_t>::iterator itr = d_item_tags.begin(); + + uint64_t item_time; + + // Since tags are not guarenteed to be in any particular order, we + // need to erase here instead of pop_front. An erase in the middle + // invalidates all iterators; so this resets the iterator to find + // more. Mostly, we wil be erasing from the front and + // therefore lose little time this way. + while(itr != d_item_tags.end()) { + item_time = (*itr).offset; + if(item_time < max_time) { + d_item_tags.erase(itr); + itr = d_item_tags.begin(); + } + else + itr++; + } + } + + long + buffer_ncurrently_allocated() + { + return s_buffer_count; + } + + // ---------------------------------------------------------------------------- + + buffer_reader::buffer_reader(buffer_sptr buffer, unsigned int read_index, + block_sptr link) + : d_buffer(buffer), d_read_index(read_index), d_abs_read_offset(0), d_link(link) + { + s_buffer_reader_count++; + } + + buffer_reader::~buffer_reader() + { + d_buffer->drop_reader(this); + s_buffer_reader_count--; + } + + int + buffer_reader::items_available() const + { + return d_buffer->index_sub(d_buffer->d_write_index, d_read_index); + } + + const void * + buffer_reader::read_pointer() + { + return &d_buffer->d_base[d_read_index * d_buffer->d_sizeof_item]; + } + + void + buffer_reader::update_read_pointer(int nitems) + { + gr::thread::scoped_lock guard(*mutex()); + d_read_index = d_buffer->index_add (d_read_index, nitems); + d_abs_read_offset += nitems; + } + + void + buffer_reader::get_tags_in_range(std::vector<tag_t> &v, + uint64_t abs_start, + uint64_t abs_end) + { + gr::thread::scoped_lock guard(*mutex()); + + v.resize(0); + std::deque<tag_t>::iterator itr = d_buffer->get_tags_begin(); + + uint64_t item_time; + while(itr != d_buffer->get_tags_end()) { + item_time = (*itr).offset; + + if((item_time >= abs_start) && (item_time < abs_end)) { + v.push_back(*itr); + } + + itr++; + } + } + + long + buffer_reader_ncurrently_allocated() + { + return s_buffer_reader_count; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/circular_file.cc b/gnuradio-runtime/lib/circular_file.cc new file mode 100644 index 0000000000..4d7d06082a --- /dev/null +++ b/gnuradio-runtime/lib/circular_file.cc @@ -0,0 +1,208 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2010,2013 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 "circular_file.h" + +#include <unistd.h> +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <assert.h> +#include <stdlib.h> + +#include <algorithm> +#include <stdio.h> +#include <string.h> + +#ifdef HAVE_IO_H +#include <io.h> +#endif + +namespace gr { + + static const int HEADER_SIZE = 4096; + static const int HEADER_MAGIC = 0xEB021026; + + static const int HD_MAGIC = 0; + static const int HD_HEADER_SIZE = 1; // integer offsets into header + static const int HD_BUFFER_SIZE = 2; + static const int HD_BUFFER_BASE = 3; + static const int HD_BUFFER_CURRENT = 4; + + circular_file::circular_file(const char *filename, + bool writable, int size) + : d_fd(-1), d_header(0), d_buffer(0), d_mapped_size(0), d_bytes_read(0) + { + int mm_prot; + if(writable) { +#ifdef HAVE_MMAP + mm_prot = PROT_READ | PROT_WRITE; +#endif + d_fd = open(filename, O_CREAT | O_RDWR | O_TRUNC, 0664); + if(d_fd < 0) { + perror(filename); + exit(1); + } +#ifdef HAVE_MMAP /* FIXME */ + if(ftruncate(d_fd, size + HEADER_SIZE) != 0) { + perror(filename); + exit(1); + } +#endif + } + else { +#ifdef HAVE_MMAP + mm_prot = PROT_READ; +#endif + d_fd = open (filename, O_RDONLY); + if(d_fd < 0) { + perror(filename); + exit(1); + } + } + + struct stat statbuf; + if(fstat (d_fd, &statbuf) < 0) { + perror(filename); + exit(1); + } + + if(statbuf.st_size < HEADER_SIZE) { + fprintf(stderr, "%s: file too small to be circular buffer\n", filename); + exit(1); + } + + d_mapped_size = statbuf.st_size; +#ifdef HAVE_MMAP + void *p = mmap (0, d_mapped_size, mm_prot, MAP_SHARED, d_fd, 0); + if(p == MAP_FAILED) { + perror("gr::circular_file: mmap failed"); + exit(1); + } + + d_header = (int*)p; +#else + perror("gr::circular_file: mmap unsupported by this system"); + exit(1); +#endif + + if(writable) { // init header + + if(size < 0) { + fprintf(stderr, "gr::circular_buffer: size must be > 0 when writable\n"); + exit(1); + } + + d_header[HD_MAGIC] = HEADER_MAGIC; + d_header[HD_HEADER_SIZE] = HEADER_SIZE; + d_header[HD_BUFFER_SIZE] = size; + d_header[HD_BUFFER_BASE] = HEADER_SIZE; // right after header + d_header[HD_BUFFER_CURRENT] = 0; + } + + // sanity check (the asserts are a bit unforgiving...) + + assert(d_header[HD_MAGIC] == HEADER_MAGIC); + assert(d_header[HD_HEADER_SIZE] == HEADER_SIZE); + assert(d_header[HD_BUFFER_SIZE] > 0); + assert(d_header[HD_BUFFER_BASE] >= d_header[HD_HEADER_SIZE]); + assert(d_header[HD_BUFFER_BASE] + d_header[HD_BUFFER_SIZE] <= d_mapped_size); + assert(d_header[HD_BUFFER_CURRENT] >= 0 && + d_header[HD_BUFFER_CURRENT] < d_header[HD_BUFFER_SIZE]); + + d_bytes_read = 0; + d_buffer = (unsigned char*)d_header + d_header[HD_BUFFER_BASE]; + } + + circular_file::~circular_file() + { +#ifdef HAVE_MMAP + if(munmap ((char *) d_header, d_mapped_size) < 0) { + perror("gr::circular_file: munmap"); + exit(1); + } +#endif + close(d_fd); + } + + bool + circular_file::write(void *vdata, int nbytes) + { + unsigned char *data = (unsigned char*)vdata; + int buffer_size = d_header[HD_BUFFER_SIZE]; + int buffer_current = d_header[HD_BUFFER_CURRENT]; + + while(nbytes > 0) { + int n = std::min(nbytes, buffer_size - buffer_current); + memcpy(d_buffer + buffer_current, data, n); + + buffer_current += n; + if(buffer_current >= buffer_size) + buffer_current = 0; + + data += n; + nbytes -= n; + } + + d_header[HD_BUFFER_CURRENT] = buffer_current; + return true; + } + + int + circular_file::read(void *vdata, int nbytes) + { + unsigned char *data = (unsigned char *) vdata; + int buffer_current = d_header[HD_BUFFER_CURRENT]; + int buffer_size = d_header[HD_BUFFER_SIZE]; + int total = 0; + + nbytes = std::min(nbytes, buffer_size - d_bytes_read); + + while(nbytes > 0) { + int offset = (buffer_current + d_bytes_read) % buffer_size; + int n = std::min (nbytes, buffer_size - offset); + memcpy(data, d_buffer + offset, n); + data += n; + d_bytes_read += n; + total += n; + nbytes -= n; + } + return total; + } + + void + circular_file::reset_read_pointer() + { + d_bytes_read = 0; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/circular_file.h b/gnuradio-runtime/lib/circular_file.h new file mode 100644 index 0000000000..1dc431d69a --- /dev/null +++ b/gnuradio-runtime/lib/circular_file.h @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002,2013 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 GR_CIRCULAR_FILE_H +#define GR_CIRCULAR_FILE_H + +#include <gnuradio/api.h> + +namespace gr { + + /* + * writes input data into a circular buffer on disk. + * + * the file contains a fixed header: + * 0x0000: int32 magic (0xEB021026) + * 0x0004: int32 size in bytes of header (constant 4096) + * 0x0008: int32 size in bytes of circular buffer (not including header) + * 0x000C: int32 file offset to beginning of circular buffer + * 0x0010: int32 byte offset from beginning of circular buffer to + * current start of data + */ + class GR_RUNTIME_API circular_file + { + private: + int d_fd; + int *d_header; + unsigned char *d_buffer; + int d_mapped_size; + int d_bytes_read; + + public: + circular_file(const char *filename, bool writable = false, int size = 0); + ~circular_file(); + + bool write(void *data, int nbytes); + + // returns # of bytes actually read or 0 if end of buffer, or -1 on error. + int read(void *data, int nbytes); + + // reset read pointer to beginning of buffer. + void reset_read_pointer(); + }; + +} /* namespace gr */ + +#endif /* GR_CIRCULAR_FILE_H */ diff --git a/gnuradio-runtime/lib/complex_vec_test.h b/gnuradio-runtime/lib/complex_vec_test.h index bcfa732f41..d69d523374 100644 --- a/gnuradio-runtime/lib/complex_vec_test.h +++ b/gnuradio-runtime/lib/complex_vec_test.h @@ -1,4 +1,26 @@ -#include <gr_runtime_api.h> +/* -*- c++ -*- */ +/* + * Copyright 2013 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 <gnuradio/api.h> #include <vector> #include <complex> diff --git a/gnuradio-runtime/lib/gr_constants.cc.in b/gnuradio-runtime/lib/constants.cc.in index b94f254d66..828c4397f7 100644 --- a/gnuradio-runtime/lib/gr_constants.cc.in +++ b/gnuradio-runtime/lib/constants.cc.in @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006,2009 Free Software Foundation, Inc. + * Copyright 2006,2009,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,34 +24,38 @@ #include <config.h> #endif -#include <gr_constants.h> - -const std::string -gr_prefix() -{ - return "@prefix@"; -} - -const std::string -gr_sysconfdir() -{ - return "@SYSCONFDIR@"; -} - -const std::string -gr_prefsdir() -{ - return "@GR_PREFSDIR@"; -} - -const std::string -gr_build_date() -{ - return "@BUILD_DATE@"; -} - -const std::string -gr_version() -{ - return "@VERSION@"; -} +#include <gnuradio/constants.h> + +namespace gr { + + const std::string + prefix() + { + return "@prefix@"; + } + + const std::string + sysconfdir() + { + return "@SYSCONFDIR@"; + } + + const std::string + prefsdir() + { + return "@GR_PREFSDIR@"; + } + + const std::string + build_date() + { + return "@BUILD_DATE@"; + } + + const std::string + version() + { + return "@VERSION@"; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/controlport/CMakeLists.txt b/gnuradio-runtime/lib/controlport/CMakeLists.txt new file mode 100644 index 0000000000..c05a82bf4f --- /dev/null +++ b/gnuradio-runtime/lib/controlport/CMakeLists.txt @@ -0,0 +1,62 @@ +# Copyright 2013 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. + +if(ENABLE_GR_CTRLPORT) + +include_directories(${ICE_INCLUDE_DIR}) + +# Add definition so we can compile in ControlPort to the blocks. +ADD_DEFINITIONS(-DGR_CTRLPORT) + +######################################################################## +# Run ICE To compile Slice files +######################################################################## +EXECUTE_PROCESS( + COMMAND "${ICE_SLICE2CPP}" "-I${CMAKE_CURRENT_SOURCE_DIR}" + "--output-dir=${CMAKE_CURRENT_BINARY_DIR}/" + "${CMAKE_CURRENT_SOURCE_DIR}/gnuradio.ice" + ) + +list(APPEND gnuradio_runtime_sources + ${CMAKE_CURRENT_SOURCE_DIR}/ice_application_base.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rpcmanager.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rpcpmtconverters_ice.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rpcserver_aggregator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rpcserver_booter_aggregator.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rpcserver_booter_ice.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rpcserver_ice.cc + ${CMAKE_CURRENT_SOURCE_DIR}/rpcserver_selector.cc +) + +# Append generated file in build directory +list(APPEND gnuradio_runtime_sources + ${CMAKE_CURRENT_BINARY_DIR}/gnuradio.cpp +) + +######################################################################## +# Add controlport stuff to gnuradio-runtime +######################################################################## + +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +list(APPEND gnuradio_runtime_libs + ${ICE_LIBRARIES} +) + +endif(ENABLE_GR_CTRLPORT) diff --git a/gnuradio-runtime/lib/ICE_LICENSE b/gnuradio-runtime/lib/controlport/ICE_LICENSE index 43ea7572d9..43ea7572d9 100644 --- a/gnuradio-runtime/lib/ICE_LICENSE +++ b/gnuradio-runtime/lib/controlport/ICE_LICENSE diff --git a/gnuradio-runtime/lib/frontend.ice b/gnuradio-runtime/lib/controlport/frontend.ice index b7474f37bf..b7474f37bf 100644 --- a/gnuradio-runtime/lib/frontend.ice +++ b/gnuradio-runtime/lib/controlport/frontend.ice diff --git a/gnuradio-runtime/lib/gnuradio.ice b/gnuradio-runtime/lib/controlport/gnuradio.ice index 731cbea956..731cbea956 100644 --- a/gnuradio-runtime/lib/gnuradio.ice +++ b/gnuradio-runtime/lib/controlport/gnuradio.ice diff --git a/gnuradio-runtime/lib/ice_application_base.cc b/gnuradio-runtime/lib/controlport/ice_application_base.cc index 88db6056c1..b390c77c84 100644 --- a/gnuradio-runtime/lib/ice_application_base.cc +++ b/gnuradio-runtime/lib/controlport/ice_application_base.cc @@ -20,7 +20,7 @@ * Boston, MA 02110-1301, USA. */ -#include <ice_application_base.h> +#include <gnuradio/ice_application_base.h> int ice_application_common::d_reacquire_attributes(0); bool ice_application_common::d_main_called(false); diff --git a/gnuradio-runtime/lib/rpcmanager.cc b/gnuradio-runtime/lib/controlport/rpcmanager.cc index 4d164b63f3..59ec518960 100644 --- a/gnuradio-runtime/lib/rpcmanager.cc +++ b/gnuradio-runtime/lib/controlport/rpcmanager.cc @@ -20,7 +20,7 @@ * Boston, MA 02110-1301, USA. */ -#include <rpcmanager.h> +#include <gnuradio/rpcmanager.h> #include <iostream> #include <stdexcept> diff --git a/gnuradio-runtime/lib/rpcpmtconverters_ice.cc b/gnuradio-runtime/lib/controlport/rpcpmtconverters_ice.cc index 7c8b6041e9..18b73faeba 100644 --- a/gnuradio-runtime/lib/rpcpmtconverters_ice.cc +++ b/gnuradio-runtime/lib/controlport/rpcpmtconverters_ice.cc @@ -20,7 +20,7 @@ * Boston, MA 02110-1301, USA. */ -#include <rpcpmtconverters_ice.h> +#include <gnuradio/rpcpmtconverters_ice.h> #include <Ice/Ice.h> #include <gnuradio.h> diff --git a/gnuradio-runtime/lib/rpcserver_aggregator.cc b/gnuradio-runtime/lib/controlport/rpcserver_aggregator.cc index d750d64905..3ff553af69 100644 --- a/gnuradio-runtime/lib/rpcserver_aggregator.cc +++ b/gnuradio-runtime/lib/controlport/rpcserver_aggregator.cc @@ -20,8 +20,8 @@ * Boston, MA 02110-1301, USA. */ -#include <rpcserver_aggregator.h> -#include <rpcserver_booter_base.h> +#include <gnuradio/rpcserver_aggregator.h> +#include <gnuradio/rpcserver_booter_base.h> #include <iostream> #include <sstream> #include <stdexcept> diff --git a/gnuradio-runtime/lib/rpcserver_booter_aggregator.cc b/gnuradio-runtime/lib/controlport/rpcserver_booter_aggregator.cc index c4c1b03c15..e86306910d 100644 --- a/gnuradio-runtime/lib/rpcserver_booter_aggregator.cc +++ b/gnuradio-runtime/lib/controlport/rpcserver_booter_aggregator.cc @@ -20,7 +20,7 @@ * Boston, MA 02110-1301, USA. */ -#include <rpcserver_booter_aggregator.h> +#include <gnuradio/rpcserver_booter_aggregator.h> rpcserver_booter_aggregator::rpcserver_booter_aggregator() : d_type(std::string("aggregator")), server(new rpcserver_aggregator()) diff --git a/gnuradio-runtime/lib/rpcserver_booter_ice.cc b/gnuradio-runtime/lib/controlport/rpcserver_booter_ice.cc index 7cc8cc8938..cffa268a6d 100644 --- a/gnuradio-runtime/lib/rpcserver_booter_ice.cc +++ b/gnuradio-runtime/lib/controlport/rpcserver_booter_ice.cc @@ -20,8 +20,8 @@ * Boston, MA 02110-1301, USA. */ -#include <rpcserver_ice.h> -#include <rpcserver_booter_ice.h> +#include <gnuradio/rpcserver_ice.h> +#include <gnuradio/rpcserver_booter_ice.h> namespace { static const char* const CONTROL_PORT_CLASS("ice"); diff --git a/gnuradio-runtime/lib/rpcserver_ice.cc b/gnuradio-runtime/lib/controlport/rpcserver_ice.cc index 2454bf2580..045d7ba4f1 100644 --- a/gnuradio-runtime/lib/rpcserver_ice.cc +++ b/gnuradio-runtime/lib/controlport/rpcserver_ice.cc @@ -20,7 +20,7 @@ * Boston, MA 02110-1301, USA. */ -#include <rpcserver_ice.h> +#include <gnuradio/rpcserver_ice.h> #include <IceUtil/IceUtil.h> #include <Ice/Ice.h> #include <iostream> diff --git a/gnuradio-runtime/lib/rpcserver_selector.cc b/gnuradio-runtime/lib/controlport/rpcserver_selector.cc index 362d5f060a..697ec497b1 100644 --- a/gnuradio-runtime/lib/rpcserver_selector.cc +++ b/gnuradio-runtime/lib/controlport/rpcserver_selector.cc @@ -20,14 +20,14 @@ * Boston, MA 02110-1301, USA. */ -#include <rpcserver_booter_aggregator.h> -#include <rpcmanager.h> -#include <rpcserver_selector.h> +#include <gnuradio/rpcserver_booter_aggregator.h> +#include <gnuradio/rpcmanager.h> +#include <gnuradio/rpcserver_selector.h> bool rpcmanager::make_aggregator(false); #ifdef RPCSERVER_ICE - #include <rpcserver_booter_ice.h> + #include <gnuradio/rpcserver_booter_ice.h> rpcmanager::rpcserver_booter_register_helper<rpcserver_booter_ice> boot_ice; #endif diff --git a/gnuradio-runtime/lib/dispatcher.cc b/gnuradio-runtime/lib/dispatcher.cc new file mode 100644 index 0000000000..7c9e13c5a6 --- /dev/null +++ b/gnuradio-runtime/lib/dispatcher.cc @@ -0,0 +1,195 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2013 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 <gnuradio/dispatcher.h> +#include <math.h> +#include <errno.h> +#include <stdio.h> + +#ifdef HAVE_SELECT +# ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +# else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# endif +# ifdef HAVE_SYS_TYPES_H +# include <sys/types.h> +# endif +# ifdef HAVE_UNISTD_H +# include <unistd.h> +# endif +# endif +#endif + +namespace gr { + + static dispatcher_sptr s_singleton; + + dispatcher_sptr + make_dispatcher() + { + return dispatcher_sptr(new dispatcher()); + } + + dispatcher_sptr + dispatcher_singleton() + { + if(s_singleton) + return s_singleton; + + s_singleton = make_dispatcher(); + return s_singleton; + } + +#if !defined(HAVE_SELECT) // Stub it out + + dispatcher::dispatcher() + { + } + + dispatcher::~dispatcher() + { + } + + bool + dispatcher::add_handler(select_handler_sptr handler) + { + return true; + } + + bool + dispatcher::del_handler(select_handler_sptr handler) + { + return true; + } + + bool + dispatcher::del_handler(select_handler *handler) + { + return true; + } + + void + dispatcher::loop(double timeout) + { + } + +#else // defined(HAVE_SELECT) + + dispatcher::dispatcher() + : d_handler(FD_SETSIZE), d_max_index(-1) + { + } + + dispatcher::~dispatcher() + { + } + + bool + dispatcher::add_handler(select_handler_sptr handler) + { + int fd = handler->fd(); + if(fd < 0 || fd >= FD_SETSIZE) + return false; + + d_max_index = std::max(d_max_index, fd); + d_handler[fd] = handler; + return true; + } + + bool + dispatcher::del_handler(select_handler_sptr handler) + { + return del_handler(handler.get()); + } + + bool + dispatcher::del_handler(select_handler *handler) + { + int fd = handler->fd(); + if(fd < 0 || fd >= FD_SETSIZE) + return false; + + d_handler[fd].reset(); + + if(fd == d_max_index) { + int i; + for(i = fd - 1; i >= 0 && !d_handler[i]; i--) + ; + d_max_index = i; + } + return true; + } + + void + dispatcher::loop(double timeout) + { + struct timeval master; + struct timeval tmp; + fd_set rd_set; + fd_set wr_set; + + double secs = floor (timeout); + master.tv_sec = (long) secs; + master.tv_usec = (long) ((timeout - secs) * 1e6); + + while(d_max_index >= 0) { + FD_ZERO(&rd_set); + FD_ZERO(&wr_set); + + for(int i = 0; i <= d_max_index; i++) { + if(d_handler[i] && d_handler[i]->readable()) + FD_SET(i, &rd_set); + if(d_handler[i] && d_handler[i]->writable()) + FD_SET(i, &wr_set); + } + + tmp = master; + int retval = select(d_max_index+1, &rd_set, &wr_set, 0, &tmp); + if(retval == 0) // timed out with nothing ready + continue; + if(retval < 0) { + if(errno == EINTR) + continue; + perror("gr_dispatcher/select"); + return; + } + + for(int i = 0; i <= d_max_index; i++) { + if(FD_ISSET(i, &rd_set)) + if(d_handler[i]) + d_handler[i]->handle_read(); + if(FD_ISSET(i, &wr_set)) + if(d_handler[i]) + d_handler[i]->handle_write(); + } + } + } + +} /* namespace gr */ + +#endif /* HAVE_SELECT */ diff --git a/gnuradio-runtime/lib/error_handler.cc b/gnuradio-runtime/lib/error_handler.cc new file mode 100644 index 0000000000..50db15d049 --- /dev/null +++ b/gnuradio-runtime/lib/error_handler.cc @@ -0,0 +1,249 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2013 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. + */ +/* + * This code is based on error.cc from the "Click Modular Router". + * Original copyright follows: + */ +/* + * error.{cc,hh} -- flexible classes for error reporting + * Eddie Kohler + * + * Copyright (c) 1999-2000 Massachusetts Institute of Technology + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, subject to the conditions + * listed in the Click LICENSE file. These conditions include: you must + * preserve this copyright notice, and you cannot mention the copyright + * holders in advertising related to the Software without their permission. + * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This + * notice is a summary of the Click LICENSE file; the license in that file is + * legally binding. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/error_handler.h> +#include <assert.h> +#include <stdexcept> +#include <unistd.h> + +#ifdef HAVE_IO_H +#include <io.h> +#endif + +namespace gr { + + static error_handler *s_default_handler = 0; + static error_handler *s_silent_handler = 0; + + bool + error_handler::has_default_handler() + { + return s_default_handler != 0; + } + + void + error_handler::set_default_handler(error_handler *errh) + { + s_default_handler = errh; + } + + error_handler * + error_handler::default_handler() + { + assert(s_default_handler != 0); + return s_default_handler; + } + + error_handler * + error_handler::silent_handler() + { + assert(s_silent_handler != 0); + return s_silent_handler; + } + + // ---------------------------------------------------------------- + + error_handler::~error_handler() + { + // nop + } + + void + error_handler::debug(const char *format, ...) + { + va_list val; + va_start(val, format); + verror(ERR_DEBUG, format, val); + va_end(val); + } + + void + error_handler::message(const char *format, ...) + { + va_list val; + va_start(val, format); + verror(ERR_MESSAGE, format, val); + va_end(val); + } + + void + error_handler::warning(const char *format, ...) + { + va_list val; + va_start(val, format); + verror(ERR_WARNING, format, val); + va_end(val); + } + + void + error_handler::error(const char *format, ...) + { + va_list val; + va_start(val, format); + verror(ERR_ERROR, format, val); + va_end(val); + } + + void + error_handler::fatal(const char *format, ...) + { + va_list val; + va_start(val, format); + verror(ERR_FATAL, format, val); + va_end(val); + } + + void + error_handler::verror(seriousness s, const char *format, va_list val) + { + std::string text = make_text(s, format, val); + handle_text(s, text); + count_error(s); + } + + void + error_handler::verror_text(seriousness s, const std::string &text) + { + // text is already made + handle_text(s, text); + count_error(s); + } + + std::string + error_handler::make_text(seriousness s, const char *format, va_list val) + { + char text_buf[4096]; + vsnprintf(text_buf, sizeof(text_buf), format, val); + text_buf[sizeof(text_buf)-1] = 0; + return text_buf; + } + + // ---------------------------------------------------------------- + + void + base_error_handler::count_error(seriousness s) + { + if(s < ERR_WARNING) + /* do nothing */; + else if(s < ERR_ERROR) + d_nwarnings++; + else + d_nerrors++; + } + + // ---------------------------------------------------------------- + + file_error_handler::file_error_handler(FILE *file) + : d_file(file), d_fd(-1) + { + } + + file_error_handler::file_error_handler(int file_descriptor) + { + d_fd = dup(file_descriptor); // so we can fclose it + if(d_fd == -1){ + perror("gr::file_error_handler:dup"); + throw std::invalid_argument("gr::file_error_handler:dup"); + } + d_file = fdopen(d_fd, "w"); + if(d_file == 0){ + perror("gr::file_error_handler:fdopen"); + throw std::invalid_argument("gr::file_error_handler:fdopen"); + } + } + + file_error_handler::~file_error_handler() + { + if(d_fd != -1){ + fclose(d_file); + } + } + + void + file_error_handler::handle_text(seriousness s, const std::string &text) + { + if(text.length() <= 0) + return; + + fwrite(text.data(), 1, text.length(), d_file); + if(text[text.length()-1] != '\n') + fwrite("\n", 1, 1, d_file); + + if(d_fd != -1) + fflush(d_file); // keep synced with any other users of fd + } + + + // ---------------------------------------------------------------- + // static error handlers + // + + class silent_error_handler : public base_error_handler + { + public: + silent_error_handler() {} + void handle_text(seriousness s, const std::string &str); + }; + + void + silent_error_handler::handle_text(seriousness s, const std::string &str) + { + // nop + } + + class force_init + { + public: + force_init() + { + s_default_handler = new file_error_handler(stdout); + s_silent_handler = new silent_error_handler(); + } + }; + + static force_init kludge; + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/feval.cc b/gnuradio-runtime/lib/feval.cc new file mode 100644 index 0000000000..93976c8ac7 --- /dev/null +++ b/gnuradio-runtime/lib/feval.cc @@ -0,0 +1,136 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2013 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 <gnuradio/feval.h> + +namespace gr { + + feval_dd::~feval_dd(){} + + double + feval_dd::eval(double x) + { + return 0; + } + + double + feval_dd::calleval(double x) + { + return eval(x); + } + + // ---------------------------------------------------------------- + + feval_cc::~feval_cc(){} + + gr_complex + feval_cc::eval(gr_complex x) + { + return 0; + } + + gr_complex + feval_cc::calleval(gr_complex x) + { + return eval(x); + } + + // ---------------------------------------------------------------- + + feval_ll::~feval_ll(){} + + long + feval_ll::eval(long x) + { + return 0; + } + + long + feval_ll::calleval(long x) + { + return eval(x); + } + + // ---------------------------------------------------------------- + + feval::~feval(){} + + void + feval::eval(void) + { + // nop + } + + void + feval::calleval(void) + { + eval(); + } + + // ---------------------------------------------------------------- + + feval_p::~feval_p(){} + + void + feval_p::eval(pmt::pmt_t x) + { + // nop + } + + void + feval_p::calleval(pmt::pmt_t x) + { + eval(x); + } + + /* + * Trivial examples showing C++ (transparently) calling Python + */ + double + feval_dd_example(feval_dd *f, double x) + { + return f->calleval(x); + } + + gr_complex + feval_cc_example(feval_cc *f, gr_complex x) + { + return f->calleval(x); + } + + long + feval_ll_example(feval_ll *f, long x) + { + return f->calleval(x); + } + + void + feval_example(feval *f) + { + f->calleval(); + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/flat_flowgraph.cc b/gnuradio-runtime/lib/flat_flowgraph.cc new file mode 100644 index 0000000000..8b188799a5 --- /dev/null +++ b/gnuradio-runtime/lib/flat_flowgraph.cc @@ -0,0 +1,436 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2013 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 "flat_flowgraph.h" +#include <gnuradio/block_detail.h> +#include <gnuradio/buffer.h> +#include <gnuradio/prefs.h> +#include <volk/volk.h> +#include <iostream> +#include <map> +#include <boost/format.hpp> + +namespace gr { + +#define FLAT_FLOWGRAPH_DEBUG 0 + +// 32Kbyte buffer size between blocks +#define GR_FIXED_BUFFER_SIZE (32*(1L<<10)) + + static const unsigned int s_fixed_buffer_size = GR_FIXED_BUFFER_SIZE; + + flat_flowgraph_sptr + make_flat_flowgraph() + { + return flat_flowgraph_sptr(new flat_flowgraph()); + } + + flat_flowgraph::flat_flowgraph() + { + } + + flat_flowgraph::~flat_flowgraph() + { + } + + void + flat_flowgraph::setup_connections() + { + basic_block_vector_t blocks = calc_used_blocks(); + + // Assign block details to blocks + for(basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) + cast_to_block_sptr(*p)->set_detail(allocate_block_detail(*p)); + + // Connect inputs to outputs for each block + for(basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + connect_block_inputs(*p); + + block_sptr block = cast_to_block_sptr(*p); + block->set_unaligned(0); + block->set_is_unaligned(false); + } + + // Connect message ports connetions + for(msg_edge_viter_t i = d_msg_edges.begin(); i != d_msg_edges.end(); i++) { + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << boost::format("flat_fg connecting msg primitives: (%s, %s)->(%s, %s)\n") % + i->src().block() % i->src().port() % + i->dst().block() % i->dst().port(); + i->src().block()->message_port_sub(i->src().port(), pmt::cons(i->dst().block()->alias_pmt(), i->dst().port())); + } + } + + block_detail_sptr + flat_flowgraph::allocate_block_detail(basic_block_sptr block) + { + int ninputs = calc_used_ports(block, true).size(); + int noutputs = calc_used_ports(block, false).size(); + block_detail_sptr detail = make_block_detail(ninputs, noutputs); + + block_sptr grblock = cast_to_block_sptr(block); + if(!grblock) + throw std::runtime_error("allocate_block_detail found non-gr::block"); + + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "Creating block detail for " << block << std::endl; + + for(int i = 0; i < noutputs; i++) { + grblock->expand_minmax_buffer(i); + + buffer_sptr buffer = allocate_buffer(block, i); + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "Allocated buffer for output " << block << ":" << i << std::endl; + detail->set_output(i, buffer); + + // Update the block's max_output_buffer based on what was actually allocated. + grblock->set_max_output_buffer(i, buffer->bufsize()); + } + + return detail; + } + + buffer_sptr + flat_flowgraph::allocate_buffer(basic_block_sptr block, int port) + { + block_sptr grblock = cast_to_block_sptr(block); + if(!grblock) + throw std::runtime_error("allocate_buffer found non-gr::block"); + int item_size = block->output_signature()->sizeof_stream_item(port); + + // *2 because we're now only filling them 1/2 way in order to + // increase the available parallelism when using the TPB scheduler. + // (We're double buffering, where we used to single buffer) + int nitems = s_fixed_buffer_size * 2 / item_size; + + // Make sure there are at least twice the output_multiple no. of items + if(nitems < 2*grblock->output_multiple()) // Note: this means output_multiple() + nitems = 2*grblock->output_multiple(); // can't be changed by block dynamically + + // If any downstream blocks are decimators and/or have a large output_multiple, + // ensure we have a buffer at least twice their decimation factor*output_multiple + basic_block_vector_t blocks = calc_downstream_blocks(block, port); + + // limit buffer size if indicated + if(grblock->max_output_buffer(port) > 0) { + //std::cout << "constraining output items to " << block->max_output_buffer(port) << "\n"; + nitems = std::min((long)nitems, (long)grblock->max_output_buffer(port)); + nitems -= nitems%grblock->output_multiple(); + if(nitems < 1) + throw std::runtime_error("problems allocating a buffer with the given max output buffer constraint!"); + } + else if(grblock->min_output_buffer(port) > 0) { + nitems = std::max((long)nitems, (long)grblock->min_output_buffer(port)); + nitems -= nitems%grblock->output_multiple(); + if(nitems < 1) + throw std::runtime_error("problems allocating a buffer with the given min output buffer constraint!"); + } + + for(basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + block_sptr dgrblock = cast_to_block_sptr(*p); + if(!dgrblock) + throw std::runtime_error("allocate_buffer found non-gr::block"); + + double decimation = (1.0/dgrblock->relative_rate()); + int multiple = dgrblock->output_multiple(); + int history = dgrblock->history(); + nitems = std::max(nitems, static_cast<int>(2*(decimation*multiple+history))); + } + + // std::cout << "make_buffer(" << nitems << ", " << item_size << ", " << grblock << "\n"; + return make_buffer(nitems, item_size, grblock); + } + + void + flat_flowgraph::connect_block_inputs(basic_block_sptr block) + { + block_sptr grblock = cast_to_block_sptr(block); + if (!grblock) + throw std::runtime_error("connect_block_inputs found non-gr::block"); + + // Get its detail and edges that feed into it + block_detail_sptr detail = grblock->detail(); + edge_vector_t in_edges = calc_upstream_edges(block); + + // For each edge that feeds into it + for(edge_viter_t e = in_edges.begin(); e != in_edges.end(); e++) { + // Set the buffer reader on the destination port to the output + // buffer on the source port + int dst_port = e->dst().port(); + int src_port = e->src().port(); + basic_block_sptr src_block = e->src().block(); + block_sptr src_grblock = cast_to_block_sptr(src_block); + if(!src_grblock) + throw std::runtime_error("connect_block_inputs found non-gr::block"); + buffer_sptr src_buffer = src_grblock->detail()->output(src_port); + + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "Setting input " << dst_port << " from edge " << (*e) << std::endl; + + detail->set_input(dst_port, buffer_add_reader(src_buffer, grblock->history()-1, grblock)); + } + } + + void + flat_flowgraph::merge_connections(flat_flowgraph_sptr old_ffg) + { + // Allocate block details if needed. Only new blocks that aren't pruned out + // by flattening will need one; existing blocks still in the new flowgraph will + // already have one. + for(basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + block_sptr block = cast_to_block_sptr(*p); + + if(!block->detail()) { + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "merge: allocating new detail for block " << (*p) << std::endl; + block->set_detail(allocate_block_detail(block)); + } + else + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "merge: reusing original detail for block " << (*p) << std::endl; + } + + // Calculate the old edges that will be going away, and clear the + // buffer readers on the RHS. + for(edge_viter_t old_edge = old_ffg->d_edges.begin(); old_edge != old_ffg->d_edges.end(); old_edge++) { + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "merge: testing old edge " << (*old_edge) << "..."; + + edge_viter_t new_edge; + for(new_edge = d_edges.begin(); new_edge != d_edges.end(); new_edge++) + if(new_edge->src() == old_edge->src() && + new_edge->dst() == old_edge->dst()) + break; + + if(new_edge == d_edges.end()) { // not found in new edge list + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "not in new edge list" << std::endl; + // zero the buffer reader on RHS of old edge + block_sptr block(cast_to_block_sptr(old_edge->dst().block())); + int port = old_edge->dst().port(); + block->detail()->set_input(port, buffer_reader_sptr()); + } + else { + if (FLAT_FLOWGRAPH_DEBUG) + std::cout << "found in new edge list" << std::endl; + } + } + + // Now connect inputs to outputs, reusing old buffer readers if they exist + for(basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + block_sptr block = cast_to_block_sptr(*p); + + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "merge: merging " << (*p) << "..."; + + if(old_ffg->has_block_p(*p)) { + // Block exists in old flow graph + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "used in old flow graph" << std::endl; + block_detail_sptr detail = block->detail(); + + // Iterate through the inputs and see what needs to be done + int ninputs = calc_used_ports(block, true).size(); // Might be different now + for(int i = 0; i < ninputs; i++) { + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "Checking input " << block << ":" << i << "..."; + edge edge = calc_upstream_edge(*p, i); + + // Fish out old buffer reader and see if it matches correct buffer from edge list + block_sptr src_block = cast_to_block_sptr(edge.src().block()); + block_detail_sptr src_detail = src_block->detail(); + buffer_sptr src_buffer = src_detail->output(edge.src().port()); + buffer_reader_sptr old_reader; + if(i < detail->ninputs()) // Don't exceed what the original detail has + old_reader = detail->input(i); + + // If there's a match, use it + if(old_reader && (src_buffer == old_reader->buffer())) { + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "matched, reusing" << std::endl; + } + else { + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "needs a new reader" << std::endl; + + // Create new buffer reader and assign + detail->set_input(i, buffer_add_reader(src_buffer, block->history()-1, block)); + } + } + } + else { + // Block is new, it just needs buffer readers at this point + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << "new block" << std::endl; + connect_block_inputs(block); + + // Make sure all buffers are aligned + setup_buffer_alignment(block); + } + + // Now deal with the fact that the block details might have + // changed numbers of inputs and outputs vs. in the old + // flowgraph. + } + } + + void + flat_flowgraph::setup_buffer_alignment(block_sptr block) + { + const int alignment = volk_get_alignment(); + for(int i = 0; i < block->detail()->ninputs(); i++) { + void *r = (void*)block->detail()->input(i)->read_pointer(); + unsigned long int ri = (unsigned long int)r % alignment; + //std::cerr << "reader: " << r << " alignment: " << ri << std::endl; + if(ri != 0) { + size_t itemsize = block->detail()->input(i)->get_sizeof_item(); + block->detail()->input(i)->update_read_pointer(alignment-ri/itemsize); + } + block->set_unaligned(0); + block->set_is_unaligned(false); + } + + for(int i = 0; i < block->detail()->noutputs(); i++) { + void *w = (void*)block->detail()->output(i)->write_pointer(); + unsigned long int wi = (unsigned long int)w % alignment; + //std::cerr << "writer: " << w << " alignment: " << wi << std::endl; + if(wi != 0) { + size_t itemsize = block->detail()->output(i)->get_sizeof_item(); + block->detail()->output(i)->update_write_pointer(alignment-wi/itemsize); + } + block->set_unaligned(0); + block->set_is_unaligned(false); + } + } + + std::string + flat_flowgraph::edge_list() + { + std::stringstream s; + for(edge_viter_t e = d_edges.begin(); e != d_edges.end(); e++) + s << (*e) << std::endl; + return s.str(); + } + + void flat_flowgraph::dump() + { + for(edge_viter_t e = d_edges.begin(); e != d_edges.end(); e++) + std::cout << " edge: " << (*e) << std::endl; + + for(basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + std::cout << " block: " << (*p) << std::endl; + block_detail_sptr detail = cast_to_block_sptr(*p)->detail(); + std::cout << " detail @" << detail << ":" << std::endl; + + int ni = detail->ninputs(); + int no = detail->noutputs(); + for(int i = 0; i < no; i++) { + buffer_sptr buffer = detail->output(i); + std::cout << " output " << i << ": " << buffer << std::endl; + } + + for(int i = 0; i < ni; i++) { + buffer_reader_sptr reader = detail->input(i); + std::cout << " reader " << i << ": " << reader + << " reading from buffer=" << reader->buffer() << std::endl; + } + } + } + + block_vector_t + flat_flowgraph::make_block_vector(basic_block_vector_t &blocks) + { + block_vector_t result; + for(basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + result.push_back(cast_to_block_sptr(*p)); + } + + return result; + } + + void + flat_flowgraph::clear_endpoint(const msg_endpoint &e, bool is_src) + { + for(size_t i=0; i<d_msg_edges.size(); i++) { + if(is_src) { + if(d_msg_edges[i].src() == e) { + d_msg_edges.erase(d_msg_edges.begin() + i); + i--; + } + } + else { + if(d_msg_edges[i].dst() == e) { + d_msg_edges.erase(d_msg_edges.begin() + i); + i--; + } + } + } + } + + void + flat_flowgraph::replace_endpoint(const msg_endpoint &e, const msg_endpoint &r, bool is_src) + { + size_t n_replr(0); + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << boost::format("flat_flowgraph::replace_endpoint( %s, %s, %d )\n") % e.block()% r.block()% is_src; + for(size_t i=0; i<d_msg_edges.size(); i++) { + if(is_src) { + if(d_msg_edges[i].src() == e) { + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << boost::format("flat_flowgraph::replace_endpoint() flattening to ( %s, %s )\n") \ + % r.block()% d_msg_edges[i].dst().block(); + d_msg_edges.push_back( msg_edge(r, d_msg_edges[i].dst() ) ); + n_replr++; + } + } + else { + if(d_msg_edges[i].dst() == e) { + if(FLAT_FLOWGRAPH_DEBUG) + std::cout << boost::format("flat_flowgraph::replace_endpoint() flattening to ( %s, %s )\n") \ + % r.block()% d_msg_edges[i].dst().block(); + d_msg_edges.push_back( msg_edge(d_msg_edges[i].src(), r ) ); + n_replr++; + } + } + } + } + + void + flat_flowgraph::enable_pc_rpc() + { +#ifdef GR_PERFORMANCE_COUNTERS + if(prefs::singleton()->get_bool("PerfCounters", "on", false)) { + basic_block_viter_t p; + for(p = d_blocks.begin(); p != d_blocks.end(); p++) { + block_sptr block = cast_to_block_sptr(*p); + if(!block->is_pc_rpc_set()) + block->setup_pc_rpc(); + } + } +#endif /* GR_PERFORMANCE_COUNTERS */ + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/flat_flowgraph.h b/gnuradio-runtime/lib/flat_flowgraph.h new file mode 100644 index 0000000000..fe43969b6f --- /dev/null +++ b/gnuradio-runtime/lib/flat_flowgraph.h @@ -0,0 +1,93 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2007,2013 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_FLAT_FLOWGRAPH_H +#define INCLUDED_GR_RUNTIME_FLAT_FLOWGRAPH_H + +#include <gnuradio/api.h> +#include <gnuradio/flowgraph.h> +#include <gnuradio/block.h> + +namespace gr { + + // Create a shared pointer to a heap allocated gr::flat_flowgraph + // (types defined in gr_runtime_types.h) + GR_RUNTIME_API flat_flowgraph_sptr make_flat_flowgraph(); + + /*! + *\brief Class specializing gr_flat_flowgraph that has all nodes + * as blocks, with no hierarchy + * \ingroup internal + */ + class GR_RUNTIME_API flat_flowgraph : public flowgraph + { + public: + friend GR_RUNTIME_API flat_flowgraph_sptr make_flat_flowgraph(); + + // Destruct an arbitrary gr::flat_flowgraph + ~flat_flowgraph(); + + // Wire list of gr::block together in new flat_flowgraph + void setup_connections(); + + // Merge applicable connections from existing flat flowgraph + void merge_connections(flat_flowgraph_sptr sfg); + + // Return a string list of edges + std::string edge_list(); + + void dump(); + + /*! + * Make a vector of gr::block from a vector of gr::basic_block + */ + static block_vector_t make_block_vector(basic_block_vector_t &blocks); + + void replace_endpoint(const msg_endpoint &e, const msg_endpoint &r, bool is_src); + void clear_endpoint(const msg_endpoint &e, bool is_src); + + /*! + * Enables export of perf. counters to ControlPort on all blocks in + * the flowgraph. + */ + void enable_pc_rpc(); + + private: + flat_flowgraph(); + + block_detail_sptr allocate_block_detail(basic_block_sptr block); + buffer_sptr allocate_buffer(basic_block_sptr block, int port); + void connect_block_inputs(basic_block_sptr block); + + /* When reusing a flowgraph's blocks, this call makes sure all of + * the buffer's are aligned at the machine's alignment boundary + * and tells the blocks that they are aligned. + * + * Called from both setup_connections and merge_connections for + * start and restarts. + */ + void setup_buffer_alignment(block_sptr block); + }; + +} /* namespace gr */ + +#endif /* INCLUDED_GR_RUNTIME_FLAT_FLOWGRAPH_H */ diff --git a/gnuradio-runtime/lib/flowgraph.cc b/gnuradio-runtime/lib/flowgraph.cc new file mode 100644 index 0000000000..0b0285088b --- /dev/null +++ b/gnuradio-runtime/lib/flowgraph.cc @@ -0,0 +1,519 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2011,2013 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 <gnuradio/flowgraph.h> +#include <stdexcept> +#include <sstream> +#include <iterator> + +namespace gr { + +#define FLOWGRAPH_DEBUG 0 + + edge::~edge() + { + } + + flowgraph_sptr make_flowgraph() + { + return flowgraph_sptr(new flowgraph()); + } + + flowgraph::flowgraph() + { + } + + flowgraph::~flowgraph() + { + } + + template<class T> + static + std::vector<T> + unique_vector(std::vector<T> v) + { + std::vector<T> result; + std::insert_iterator<std::vector<T> > inserter(result, result.begin()); + + sort(v.begin(), v.end()); + unique_copy(v.begin(), v.end(), inserter); + return result; + } + + void + flowgraph::connect(const endpoint &src, const endpoint &dst) + { + check_valid_port(src.block()->output_signature(), src.port()); + check_valid_port(dst.block()->input_signature(), dst.port()); + check_dst_not_used(dst); + check_type_match(src, dst); + + // All ist klar, Herr Kommisar + d_edges.push_back(edge(src,dst)); + } + + void + flowgraph::disconnect(const endpoint &src, const endpoint &dst) + { + for(edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + if(src == p->src() && dst == p->dst()) { + d_edges.erase(p); + return; + } + } + + std::stringstream msg; + msg << "cannot disconnect edge " << edge(src, dst) << ", not found"; + throw std::invalid_argument(msg.str()); + } + + void + flowgraph::validate() + { + d_blocks = calc_used_blocks(); + + for(basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + std::vector<int> used_ports; + int ninputs, noutputs; + + if(FLOWGRAPH_DEBUG) + std::cout << "Validating block: " << (*p) << std::endl; + + used_ports = calc_used_ports(*p, true); // inputs + ninputs = used_ports.size(); + check_contiguity(*p, used_ports, true); // inputs + + used_ports = calc_used_ports(*p, false); // outputs + noutputs = used_ports.size(); + check_contiguity(*p, used_ports, false); // outputs + + if(!((*p)->check_topology(ninputs, noutputs))) { + std::stringstream msg; + msg << "check topology failed on " << (*p) + << " using ninputs=" << ninputs + << ", noutputs=" << noutputs; + throw std::runtime_error(msg.str()); + } + } + } + + void + flowgraph::clear() + { + // Boost shared pointers will deallocate as needed + d_blocks.clear(); + d_edges.clear(); + } + + void + flowgraph::check_valid_port(gr::io_signature::sptr sig, int port) + { + std::stringstream msg; + + if(port < 0) { + msg << "negative port number " << port << " is invalid"; + throw std::invalid_argument(msg.str()); + } + + int max = sig->max_streams(); + if(max != io_signature::IO_INFINITE && port >= max) { + msg << "port number " << port << " exceeds max of "; + if(max == 0) + msg << "(none)"; + else + msg << max-1; + throw std::invalid_argument(msg.str()); + } + } + + void + flowgraph::check_valid_port(const msg_endpoint &e) + { + if(FLOWGRAPH_DEBUG) + std::cout << "check_valid_port( " << e.block() << ", " << e.port() << ")\n"; + + if(!e.block()->has_msg_port(e.port())) + throw std::invalid_argument("invalid msg port in connect() or disconnect()"); + } + + void + flowgraph::check_dst_not_used(const endpoint &dst) + { + // A destination is in use if it is already on the edge list + for(edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) + if(p->dst() == dst) { + std::stringstream msg; + msg << "destination already in use by edge " << (*p); + throw std::invalid_argument(msg.str()); + } + } + + void + flowgraph::check_type_match(const endpoint &src, const endpoint &dst) + { + int src_size = src.block()->output_signature()->sizeof_stream_item(src.port()); + int dst_size = dst.block()->input_signature()->sizeof_stream_item(dst.port()); + + if(src_size != dst_size) { + std::stringstream msg; + msg << "itemsize mismatch: " << src << " using " << src_size + << ", " << dst << " using " << dst_size; + throw std::invalid_argument(msg.str()); + } + } + + basic_block_vector_t + flowgraph::calc_used_blocks() + { + basic_block_vector_t tmp; + + // make sure free standing message blocks are included + for(msg_edge_viter_t p = d_msg_edges.begin(); p != d_msg_edges.end(); p++) { + //for now only blocks receiving messages get a thread context - uncomment to allow senders to also obtain one + // tmp.push_back(p->src().block()); + tmp.push_back(p->dst().block()); + } + + // Collect all blocks in the edge list + for(edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + tmp.push_back(p->src().block()); + tmp.push_back(p->dst().block()); + } + + return unique_vector<basic_block_sptr>(tmp); + } + + std::vector<int> + flowgraph::calc_used_ports(basic_block_sptr block, bool check_inputs) + { + std::vector<int> tmp; + + // Collect all seen ports + edge_vector_t edges = calc_connections(block, check_inputs); + for(edge_viter_t p = edges.begin(); p != edges.end(); p++) { + if(check_inputs == true) + tmp.push_back(p->dst().port()); + else + tmp.push_back(p->src().port()); + } + + return unique_vector<int>(tmp); + } + + edge_vector_t + flowgraph::calc_connections(basic_block_sptr block, bool check_inputs) + { + edge_vector_t result; + + for(edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + if(check_inputs) { + if(p->dst().block() == block) + result.push_back(*p); + } + else { + if(p->src().block() == block) + result.push_back(*p); + } + } + + return result; // assumes no duplicates + } + + void + flowgraph::check_contiguity(basic_block_sptr block, + const std::vector<int> &used_ports, + bool check_inputs) + { + std::stringstream msg; + + gr::io_signature::sptr sig = + check_inputs ? block->input_signature() : block->output_signature(); + + int nports = used_ports.size(); + int min_ports = sig->min_streams(); + int max_ports = sig->max_streams(); + + if(nports == 0 && min_ports == 0) + return; + + if(nports < min_ports) { + msg << block << ": insufficient connected " + << (check_inputs ? "input ports " : "output ports ") + << "(" << min_ports << " needed, " << nports << " connected)"; + throw std::runtime_error(msg.str()); + } + + if(nports > max_ports && max_ports != io_signature::IO_INFINITE) { + msg << block << ": too many connected " + << (check_inputs ? "input ports " : "output ports ") + << "(" << max_ports << " allowed, " << nports << " connected)"; + throw std::runtime_error(msg.str()); + } + + if(used_ports[nports-1]+1 != nports) { + for(int i = 0; i < nports; i++) { + if(used_ports[i] != i) { + msg << block << ": missing connection " + << (check_inputs ? "to input port " : "from output port ") + << i; + throw std::runtime_error(msg.str()); + } + } + } + } + + basic_block_vector_t + flowgraph::calc_downstream_blocks(basic_block_sptr block, int port) + { + basic_block_vector_t tmp; + + for(edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) + if(p->src() == endpoint(block, port)) + tmp.push_back(p->dst().block()); + + return unique_vector<basic_block_sptr>(tmp); + } + + basic_block_vector_t + flowgraph::calc_downstream_blocks(basic_block_sptr block) + { + basic_block_vector_t tmp; + + for(edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) + if(p->src().block() == block) + tmp.push_back(p->dst().block()); + + return unique_vector<basic_block_sptr>(tmp); + } + + edge_vector_t + flowgraph::calc_upstream_edges(basic_block_sptr block) + { + edge_vector_t result; + + for(edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) + if(p->dst().block() == block) + result.push_back(*p); + + return result; // Assume no duplicates + } + + bool + flowgraph::has_block_p(basic_block_sptr block) + { + basic_block_viter_t result; + result = std::find(d_blocks.begin(), d_blocks.end(), block); + return (result != d_blocks.end()); + } + + edge + flowgraph::calc_upstream_edge(basic_block_sptr block, int port) + { + edge result; + + for(edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + if(p->dst() == endpoint(block, port)) { + result = (*p); + break; + } + } + + return result; + } + + std::vector<basic_block_vector_t> + flowgraph::partition() + { + std::vector<basic_block_vector_t> result; + basic_block_vector_t blocks = calc_used_blocks(); + basic_block_vector_t graph; + + while(blocks.size() > 0) { + graph = calc_reachable_blocks(blocks[0], blocks); + assert(graph.size()); + result.push_back(topological_sort(graph)); + + for(basic_block_viter_t p = graph.begin(); p != graph.end(); p++) + blocks.erase(find(blocks.begin(), blocks.end(), *p)); + } + + return result; + } + + basic_block_vector_t + flowgraph::calc_reachable_blocks(basic_block_sptr block, basic_block_vector_t &blocks) + { + basic_block_vector_t result; + + // Mark all blocks as unvisited + for(basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) + (*p)->set_color(basic_block::WHITE); + + // Recursively mark all reachable blocks + reachable_dfs_visit(block, blocks); + + // Collect all the blocks that have been visited + for(basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) + if((*p)->color() == basic_block::BLACK) + result.push_back(*p); + + return result; + } + + // Recursively mark all reachable blocks from given block and block list + void + flowgraph::reachable_dfs_visit(basic_block_sptr block, basic_block_vector_t &blocks) + { + // Mark the current one as visited + block->set_color(basic_block::BLACK); + + // Recurse into adjacent vertices + basic_block_vector_t adjacent = calc_adjacent_blocks(block, blocks); + + for(basic_block_viter_t p = adjacent.begin(); p != adjacent.end(); p++) + if((*p)->color() == basic_block::WHITE) + reachable_dfs_visit(*p, blocks); + } + + // Return a list of block adjacent to a given block along any edge + basic_block_vector_t + flowgraph::calc_adjacent_blocks(basic_block_sptr block, basic_block_vector_t &blocks) + { + basic_block_vector_t tmp; + + // Find any blocks that are inputs or outputs + for(edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { + if(p->src().block() == block) + tmp.push_back(p->dst().block()); + if(p->dst().block() == block) + tmp.push_back(p->src().block()); + } + + return unique_vector<basic_block_sptr>(tmp); + } + + basic_block_vector_t + flowgraph::topological_sort(basic_block_vector_t &blocks) + { + basic_block_vector_t tmp; + basic_block_vector_t result; + tmp = sort_sources_first(blocks); + + // Start 'em all white + for(basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) + (*p)->set_color(basic_block::WHITE); + + for(basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) { + if((*p)->color() == basic_block::WHITE) + topological_dfs_visit(*p, result); + } + + reverse(result.begin(), result.end()); + return result; + } + + basic_block_vector_t + flowgraph::sort_sources_first(basic_block_vector_t &blocks) + { + basic_block_vector_t sources, nonsources, result; + + for(basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + if(source_p(*p)) + sources.push_back(*p); + else + nonsources.push_back(*p); + } + + for(basic_block_viter_t p = sources.begin(); p != sources.end(); p++) + result.push_back(*p); + + for(basic_block_viter_t p = nonsources.begin(); p != nonsources.end(); p++) + result.push_back(*p); + + return result; + } + + bool + flowgraph::source_p(basic_block_sptr block) + { + return (calc_upstream_edges(block).size() == 0); + } + + void + flowgraph::topological_dfs_visit(basic_block_sptr block, basic_block_vector_t &output) + { + block->set_color(basic_block::GREY); + basic_block_vector_t blocks(calc_downstream_blocks(block)); + + for(basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + switch((*p)->color()) { + case basic_block::WHITE: + topological_dfs_visit(*p, output); + break; + + case basic_block::GREY: + throw std::runtime_error("flow graph has loops!"); + + case basic_block::BLACK: + continue; + + default: + throw std::runtime_error("invalid color on block!"); + } + } + + block->set_color(basic_block::BLACK); + output.push_back(block); + } + + void + flowgraph::connect(const msg_endpoint &src, const msg_endpoint &dst) + { + check_valid_port(src); + check_valid_port(dst); + for(msg_edge_viter_t p = d_msg_edges.begin(); p != d_msg_edges.end(); p++) { + if(p->src() == src && p->dst() == dst){ + throw std::runtime_error("connect called on already connected edge!"); + } + } + d_msg_edges.push_back(msg_edge(src,dst)); + } + + void + flowgraph::disconnect(const msg_endpoint &src, const msg_endpoint &dst) + { + check_valid_port(src); + check_valid_port(dst); + for(msg_edge_viter_t p = d_msg_edges.begin(); p != d_msg_edges.end(); p++) { + if(p->src() == src && p->dst() == dst){ + d_msg_edges.erase(p); + return; + } + } + throw std::runtime_error("disconnect called on non-connected edge!"); + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gr_basic_block.cc b/gnuradio-runtime/lib/gr_basic_block.cc deleted file mode 100644 index 83f6c07c87..0000000000 --- a/gnuradio-runtime/lib/gr_basic_block.cc +++ /dev/null @@ -1,226 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2012 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_basic_block.h> -#include <gr_block_registry.h> -#include <stdexcept> -#include <sstream> -#include <iostream> - -static long s_next_id = 0; -static long s_ncurrently_allocated = 0; - -long -gr_basic_block_ncurrently_allocated() -{ - return s_ncurrently_allocated; -} - -gr_basic_block::gr_basic_block(const std::string &name, - gr_io_signature_sptr input_signature, - gr_io_signature_sptr output_signature) - : d_name(name), - d_input_signature(input_signature), - d_output_signature(output_signature), - d_unique_id(s_next_id++), - d_symbolic_id(global_block_registry.block_register(this)), - d_symbol_name(global_block_registry.register_symbolic_name(this)), - d_color(WHITE), - d_rpc_set(false), - message_subscribers(pmt::make_dict()) -{ - s_ncurrently_allocated++; -} - -gr_basic_block::~gr_basic_block() -{ - s_ncurrently_allocated--; - global_block_registry.block_unregister(this); -} - -gr_basic_block_sptr -gr_basic_block::to_basic_block() -{ - return shared_from_this(); -} - -void -gr_basic_block::set_block_alias(std::string name) -{ - global_block_registry.register_symbolic_name(this, name); -} - -// ** Message passing interface ** - -// - register a new input message port -void -gr_basic_block::message_port_register_in(pmt::pmt_t port_id) -{ - if(!pmt::is_symbol(port_id)) { - throw std::runtime_error("message_port_register_in: bad port id"); - } - msg_queue[port_id] = msg_queue_t(); - msg_queue_ready[port_id] = boost::shared_ptr<boost::condition_variable>(new boost::condition_variable()); -} - -pmt::pmt_t -gr_basic_block::message_ports_in() -{ - pmt::pmt_t port_names = pmt::make_vector(msg_queue.size(), pmt::PMT_NIL); - msg_queue_map_itr itr = msg_queue.begin(); - for(size_t i = 0; i < msg_queue.size(); i++) { - pmt::vector_set(port_names, i, (*itr).first); - itr++; - } - return port_names; -} - -// - register a new output message port -void -gr_basic_block::message_port_register_out(pmt::pmt_t port_id) -{ - if(!pmt::is_symbol(port_id)) { - throw std::runtime_error("message_port_register_out: bad port id"); - } - if(pmt::dict_has_key(message_subscribers, port_id)) { - throw std::runtime_error("message_port_register_out: port already in use"); - } - message_subscribers = pmt::dict_add(message_subscribers, port_id, pmt::PMT_NIL); -} - -pmt::pmt_t -gr_basic_block::message_ports_out() -{ - size_t len = pmt::length(message_subscribers); - pmt::pmt_t port_names = pmt::make_vector(len, pmt::PMT_NIL); - pmt::pmt_t keys = pmt::dict_keys(message_subscribers); - for(size_t i = 0; i < len; i++) { - pmt::vector_set(port_names, i, pmt::nth(i, keys)); - } - return port_names; -} - -// - publish a message on a message port -void gr_basic_block::message_port_pub(pmt::pmt_t port_id, pmt::pmt_t msg) -{ - if(!pmt::dict_has_key(message_subscribers, port_id)) { - throw std::runtime_error("port does not exist"); - } - - pmt::pmt_t currlist = pmt::dict_ref(message_subscribers, port_id, pmt::PMT_NIL); - // iterate through subscribers on port - while(pmt::is_pair(currlist)) { - pmt::pmt_t target = pmt::car(currlist); - - pmt::pmt_t block = pmt::car(target); - pmt::pmt_t port = pmt::cdr(target); - - currlist = pmt::cdr(currlist); - gr_basic_block_sptr blk = global_block_registry.block_lookup(block); - //blk->post(msg); - blk->post(port, msg); - } -} - -// - subscribe to a message port -void -gr_basic_block::message_port_sub(pmt::pmt_t port_id, pmt::pmt_t target){ - if(!pmt::dict_has_key(message_subscribers, port_id)){ - std::stringstream ss; - ss << "Port does not exist: \"" << pmt::write_string(port_id) << "\" on block: " << pmt::write_string(target) << std::endl; - throw std::runtime_error(ss.str()); - } - pmt::pmt_t currlist = pmt::dict_ref(message_subscribers,port_id,pmt::PMT_NIL); - - // ignore re-adds of the same target - if(!pmt::list_has(currlist, target)) - message_subscribers = pmt::dict_add(message_subscribers,port_id,pmt::list_add(currlist,target)); -} - -void -gr_basic_block::message_port_unsub(pmt::pmt_t port_id, pmt::pmt_t target){ - if(!pmt::dict_has_key(message_subscribers, port_id)){ - std::stringstream ss; - ss << "Port does not exist: \"" << pmt::write_string(port_id) << "\" on block: " << pmt::write_string(target) << std::endl; - throw std::runtime_error(ss.str()); - } - - // ignore unsubs of unknown targets - pmt::pmt_t currlist = pmt::dict_ref(message_subscribers,port_id,pmt::PMT_NIL); - message_subscribers = pmt::dict_add(message_subscribers,port_id,pmt::list_rm(currlist,target)); -} - -void -gr_basic_block::_post(pmt::pmt_t which_port, pmt::pmt_t msg) -{ - insert_tail(which_port, msg); -} - -void -gr_basic_block::insert_tail(pmt::pmt_t which_port, pmt::pmt_t msg) -{ - gr::thread::scoped_lock guard(mutex); - - if( (msg_queue.find(which_port) == msg_queue.end()) || (msg_queue_ready.find(which_port) == msg_queue_ready.end())){ - std::cout << "target port = " << pmt::symbol_to_string(which_port) << std::endl; - throw std::runtime_error("attempted to insert_tail on invalid queue!"); - } - - msg_queue[which_port].push_back(msg); - msg_queue_ready[which_port]->notify_one(); - - // wake up thread if BLKD_IN or BLKD_OUT - global_block_registry.notify_blk(alias()); -} - -pmt::pmt_t -gr_basic_block::delete_head_nowait(pmt::pmt_t which_port) -{ - gr::thread::scoped_lock guard(mutex); - - if (empty_p(which_port)){ - return pmt::pmt_t(); - } - - pmt::pmt_t m(msg_queue[which_port].front()); - msg_queue[which_port].pop_front(); - - return m; -} - -pmt::pmt_t -gr_basic_block::delete_head_blocking(pmt::pmt_t which_port) -{ - gr::thread::scoped_lock guard(mutex); - - while (empty_p(which_port)){ - msg_queue_ready[which_port]->wait(guard); - } - - pmt::pmt_t m(msg_queue[which_port].front()); - msg_queue[which_port].pop_front(); - return m; -} diff --git a/gnuradio-runtime/lib/gr_block.cc b/gnuradio-runtime/lib/gr_block.cc deleted file mode 100644 index 2830a999ea..0000000000 --- a/gnuradio-runtime/lib/gr_block.cc +++ /dev/null @@ -1,687 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2009,2010,2013 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_block.h> -#include <gr_block_detail.h> -#include <stdexcept> -#include <iostream> -#include <gr_block_registry.h> -#include <gr_prefs.h> - -gr_block::gr_block (const std::string &name, - gr_io_signature_sptr input_signature, - gr_io_signature_sptr output_signature) - : gr_basic_block(name, input_signature, output_signature), - d_output_multiple (1), - d_output_multiple_set(false), - d_unaligned(0), - d_is_unaligned(false), - d_relative_rate (1.0), - d_history(1), - d_fixed_rate(false), - d_max_noutput_items_set(false), - d_max_noutput_items(0), - d_min_noutput_items(0), - d_tag_propagation_policy(TPP_ALL_TO_ALL), - d_pc_rpc_set(false), - d_max_output_buffer(std::max(output_signature->max_streams(),1), -1), - d_min_output_buffer(std::max(output_signature->max_streams(),1), -1) -{ - global_block_registry.register_primitive(alias(), this); - -#ifdef ENABLE_GR_LOG -#ifdef HAVE_LOG4CPP - gr_prefs *p = gr_prefs::singleton(); - std::string config_file = p->get_string("LOG", "log_config", ""); - std::string log_level = p->get_string("LOG", "log_level", "off"); - std::string log_file = p->get_string("LOG", "log_file", ""); - std::string debug_level = p->get_string("LOG", "debug_level", "off"); - std::string debug_file = p->get_string("LOG", "debug_file", ""); - - GR_CONFIG_LOGGER(config_file); - - GR_LOG_GETLOGGER(LOG, "gr_log." + alias()); - GR_LOG_SET_LEVEL(LOG, log_level); - if(log_file.size() > 0) { - if(log_file == "stdout") { - GR_LOG_ADD_CONSOLE_APPENDER(LOG, "cout","gr::log :%p: %c{1} - %m%n"); - } - else if(log_file == "stderr") { - GR_LOG_ADD_CONSOLE_APPENDER(LOG, "cerr","gr::log :%p: %c{1} - %m%n"); - } - else { - GR_LOG_ADD_FILE_APPENDER(LOG, log_file , true,"%r :%p: %c{1} - %m%n"); - } - } - d_logger = LOG; - - GR_LOG_GETLOGGER(DLOG, "gr_log_debug." + alias()); - GR_LOG_SET_LEVEL(DLOG, debug_level); - if(debug_file.size() > 0) { - if(debug_file == "stdout") { - GR_LOG_ADD_CONSOLE_APPENDER(DLOG, "cout","gr::debug :%p: %c{1} - %m%n"); - } - else if(debug_file == "stderr") { - GR_LOG_ADD_CONSOLE_APPENDER(DLOG, "cerr", "gr::debug :%p: %c{1} - %m%n"); - } - else { - GR_LOG_ADD_FILE_APPENDER(DLOG, debug_file, true, "%r :%p: %c{1} - %m%n"); - } - } - d_debug_logger = DLOG; -#endif /* HAVE_LOG4CPP */ -#else /* ENABLE_GR_LOG */ - d_logger = NULL; - d_debug_logger = NULL; -#endif /* ENABLE_GR_LOG */ -} - -gr_block::~gr_block () -{ - global_block_registry.unregister_primitive(alias()); -} - -// stub implementation: 1:1 - -void -gr_block::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - unsigned ninputs = ninput_items_required.size (); - for (unsigned i = 0; i < ninputs; i++) - ninput_items_required[i] = noutput_items + history() - 1; -} - -// default implementation - -bool -gr_block::start() -{ - return true; -} - -bool -gr_block::stop() -{ - return true; -} - -void -gr_block::set_output_multiple (int multiple) -{ - if (multiple < 1) - throw std::invalid_argument ("gr_block::set_output_multiple"); - - d_output_multiple_set = true; - d_output_multiple = multiple; -} - -void -gr_block::set_alignment (int multiple) -{ - if (multiple < 1) - throw std::invalid_argument ("gr_block::set_alignment_multiple"); - - d_output_multiple = multiple; -} - -void -gr_block::set_unaligned (int na) -{ - // unaligned value must be less than 0 and it doesn't make sense - // that it's larger than the alignment value. - if ((na < 0) || (na > d_output_multiple)) - throw std::invalid_argument ("gr_block::set_unaligned"); - - d_unaligned = na; -} - -void -gr_block::set_is_unaligned (bool u) -{ - d_is_unaligned = u; -} - -void -gr_block::set_relative_rate (double relative_rate) -{ - if (relative_rate < 0.0) - throw std::invalid_argument ("gr_block::set_relative_rate"); - - d_relative_rate = relative_rate; -} - - -void -gr_block::consume (int which_input, int how_many_items) -{ - d_detail->consume (which_input, how_many_items); -} - -void -gr_block::consume_each (int how_many_items) -{ - d_detail->consume_each (how_many_items); -} - -void -gr_block::produce (int which_output, int how_many_items) -{ - d_detail->produce (which_output, how_many_items); -} - -int -gr_block::fixed_rate_ninput_to_noutput(int ninput) -{ - throw std::runtime_error("Unimplemented"); -} - -int -gr_block::fixed_rate_noutput_to_ninput(int noutput) -{ - throw std::runtime_error("Unimplemented"); -} - -uint64_t -gr_block::nitems_read(unsigned int which_input) -{ - if(d_detail) { - return d_detail->nitems_read(which_input); - } - else { - //throw std::runtime_error("No block_detail associated with block yet"); - return 0; - } -} - -uint64_t -gr_block::nitems_written(unsigned int which_output) -{ - if(d_detail) { - return d_detail->nitems_written(which_output); - } - else { - //throw std::runtime_error("No block_detail associated with block yet"); - return 0; - } -} - -void -gr_block::add_item_tag(unsigned int which_output, - const gr_tag_t &tag) -{ - d_detail->add_item_tag(which_output, tag); -} - -void -gr_block::remove_item_tag(unsigned int which_input, - const gr_tag_t &tag) -{ - d_detail->remove_item_tag(which_input, tag); -} - -void -gr_block::get_tags_in_range(std::vector<gr_tag_t> &v, - unsigned int which_output, - uint64_t start, uint64_t end) -{ - d_detail->get_tags_in_range(v, which_output, start, end); -} - -void -gr_block::get_tags_in_range(std::vector<gr_tag_t> &v, - unsigned int which_output, - uint64_t start, uint64_t end, - const pmt::pmt_t &key) -{ - d_detail->get_tags_in_range(v, which_output, start, end, key); -} - -gr_block::tag_propagation_policy_t -gr_block::tag_propagation_policy() -{ - return d_tag_propagation_policy; -} - -void -gr_block::set_tag_propagation_policy(tag_propagation_policy_t p) -{ - d_tag_propagation_policy = p; -} - - -int -gr_block::max_noutput_items() -{ - return d_max_noutput_items; -} - -void -gr_block::set_max_noutput_items(int m) -{ - if(m <= 0) - throw std::runtime_error("gr_block::set_max_noutput_items: value for max_noutput_items must be greater than 0.\n"); - - d_max_noutput_items = m; - d_max_noutput_items_set = true; -} - -void -gr_block::unset_max_noutput_items() -{ - d_max_noutput_items_set = false; -} - -bool -gr_block::is_set_max_noutput_items() -{ - return d_max_noutput_items_set; -} - -void -gr_block::set_processor_affinity(const std::vector<int> &mask) -{ - d_affinity = mask; - if(d_detail) { - d_detail->set_processor_affinity(d_affinity); - } -} - -void -gr_block::unset_processor_affinity() -{ - d_affinity.clear(); - if(d_detail) { - d_detail->unset_processor_affinity(); - } -} - -float -gr_block::pc_noutput_items() -{ - if(d_detail) { - return d_detail->pc_noutput_items(); - } - else { - return 0; - } -} - -float -gr_block::pc_noutput_items_avg() -{ - if(d_detail) { - return d_detail->pc_noutput_items_avg(); - } - else { - return 0; - } -} - -float -gr_block::pc_noutput_items_var() -{ - if(d_detail) { - return d_detail->pc_noutput_items_var(); - } - else { - return 0; - } -} - -float -gr_block::pc_nproduced() -{ - if(d_detail) { - return d_detail->pc_nproduced(); - } - else { - return 0; - } -} - -float -gr_block::pc_nproduced_avg() -{ - if(d_detail) { - return d_detail->pc_nproduced_avg(); - } - else { - return 0; - } -} - -float -gr_block::pc_nproduced_var() -{ - if(d_detail) { - return d_detail->pc_nproduced_var(); - } - else { - return 0; - } -} - -float -gr_block::pc_input_buffers_full(int which) -{ - if(d_detail) { - return d_detail->pc_input_buffers_full(static_cast<size_t>(which)); - } - else { - return 0; - } -} - -float -gr_block::pc_input_buffers_full_avg(int which) -{ - if(d_detail) { - return d_detail->pc_input_buffers_full_avg(static_cast<size_t>(which)); - } - else { - return 0; - } -} - -float -gr_block::pc_input_buffers_full_var(int which) -{ - if(d_detail) { - return d_detail->pc_input_buffers_full_var(static_cast<size_t>(which)); - } - else { - return 0; - } -} - -std::vector<float> -gr_block::pc_input_buffers_full() -{ - if(d_detail) { - return d_detail->pc_input_buffers_full(); - } - else { - return std::vector<float>(1,0); - } -} - -std::vector<float> -gr_block::pc_input_buffers_full_avg() -{ - if(d_detail) { - return d_detail->pc_input_buffers_full_avg(); - } - else { - return std::vector<float>(1,0); - } -} - -std::vector<float> -gr_block::pc_input_buffers_full_var() -{ - if(d_detail) { - return d_detail->pc_input_buffers_full_var(); - } - else { - return std::vector<float>(1,0); - } -} - -float -gr_block::pc_output_buffers_full(int which) -{ - if(d_detail) { - return d_detail->pc_output_buffers_full(static_cast<size_t>(which)); - } - else { - return 0; - } -} - -float -gr_block::pc_output_buffers_full_avg(int which) -{ - if(d_detail) { - return d_detail->pc_output_buffers_full_avg(static_cast<size_t>(which)); - } - else { - return 0; - } -} - -float -gr_block::pc_output_buffers_full_var(int which) -{ - if(d_detail) { - return d_detail->pc_output_buffers_full_var(static_cast<size_t>(which)); - } - else { - return 0; - } -} - -std::vector<float> -gr_block::pc_output_buffers_full() -{ - if(d_detail) { - return d_detail->pc_output_buffers_full(); - } - else { - return std::vector<float>(1,0); - } -} - -std::vector<float> -gr_block::pc_output_buffers_full_avg() -{ - if(d_detail) { - return d_detail->pc_output_buffers_full_avg(); - } - else { - return std::vector<float>(1,0); - } -} - -std::vector<float> -gr_block::pc_output_buffers_full_var() -{ - if(d_detail) { - return d_detail->pc_output_buffers_full_var(); - } - else { - return std::vector<float>(1,0); - } -} - -float -gr_block::pc_work_time() -{ - if(d_detail) { - return d_detail->pc_work_time(); - } - else { - return 0; - } -} - -float -gr_block::pc_work_time_avg() -{ - if(d_detail) { - return d_detail->pc_work_time_avg(); - } - else { - return 0; - } -} - -float -gr_block::pc_work_time_var() -{ - if(d_detail) { - return d_detail->pc_work_time_var(); - } - else { - return 0; - } -} - -void -gr_block::reset_perf_counters() -{ - if(d_detail) { - d_detail->reset_perf_counters(); - } -} - -void -gr_block::setup_pc_rpc() -{ - d_pc_rpc_set = true; -#ifdef GR_CTRLPORT - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( - alias(), "noutput_items", &gr_block::pc_noutput_items, - pmt::mp(0), pmt::mp(32768), pmt::mp(0), - "", "noutput items", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( - alias(), "avg noutput_items", &gr_block::pc_noutput_items_avg, - pmt::mp(0), pmt::mp(32768), pmt::mp(0), - "", "Average noutput items", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( - alias(), "var noutput_items", &gr_block::pc_noutput_items_var, - pmt::mp(0), pmt::mp(32768), pmt::mp(0), - "", "Var. noutput items", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( - alias(), "nproduced", &gr_block::pc_nproduced, - pmt::mp(0), pmt::mp(32768), pmt::mp(0), - "", "items produced", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( - alias(), "avg nproduced", &gr_block::pc_nproduced_avg, - pmt::mp(0), pmt::mp(32768), pmt::mp(0), - "", "Average items produced", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( - alias(), "var nproduced", &gr_block::pc_nproduced_var, - pmt::mp(0), pmt::mp(32768), pmt::mp(0), - "", "Var. items produced", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( - alias(), "work time", &gr_block::pc_work_time, - pmt::mp(0), pmt::mp(1e9), pmt::mp(0), - "", "clock cycles in call to work", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( - alias(), "avg work time", &gr_block::pc_work_time_avg, - pmt::mp(0), pmt::mp(1e9), pmt::mp(0), - "", "Average clock cycles in call to work", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, float>( - alias(), "var work time", &gr_block::pc_work_time_var, - pmt::mp(0), pmt::mp(1e9), pmt::mp(0), - "", "Var. clock cycles in call to work", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( - alias(), "input \% full", &gr_block::pc_input_buffers_full, - pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), - "", "how full input buffers are", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( - alias(), "avg input \% full", &gr_block::pc_input_buffers_full_avg, - pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), - "", "Average of how full input buffers are", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( - alias(), "var input \% full", &gr_block::pc_input_buffers_full_var, - pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), - "", "Var. of how full input buffers are", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( - alias(), "output \% full", &gr_block::pc_output_buffers_full, - pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), - "", "how full output buffers are", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( - alias(), "avg output \% full", &gr_block::pc_output_buffers_full_avg, - pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), - "", "Average of how full output buffers are", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); - - d_rpc_vars.push_back( - rpcbasic_sptr(new rpcbasic_register_get<gr_block, std::vector<float> >( - alias(), "var output \% full", &gr_block::pc_output_buffers_full_var, - pmt::make_c32vector(0,0), pmt::make_c32vector(0,1), pmt::make_c32vector(0,0), - "", "Var. of how full output buffers are", RPC_PRIVLVL_MIN, - DISPTIME | DISPOPTSTRIP))); -#endif /* GR_CTRLPORT */ -} - -std::ostream& -operator << (std::ostream& os, const gr_block *m) -{ - os << "<gr_block " << m->name() << " (" << m->unique_id() << ")>"; - return os; -} - -int -gr_block::general_work(int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - throw std::runtime_error("gr_block::general_work() not implemented"); - return 0; -} diff --git a/gnuradio-runtime/lib/gr_block_detail.cc b/gnuradio-runtime/lib/gr_block_detail.cc deleted file mode 100644 index 7098113301..0000000000 --- a/gnuradio-runtime/lib/gr_block_detail.cc +++ /dev/null @@ -1,473 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2009,2010,2013 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_block_detail.h> -#include <gr_buffer.h> -#include <iostream> - -static long s_ncurrently_allocated = 0; - -long -gr_block_detail_ncurrently_allocated () -{ - return s_ncurrently_allocated; -} - -gr_block_detail::gr_block_detail (unsigned int ninputs, unsigned int noutputs) - : d_produce_or(0), - d_ninputs (ninputs), d_noutputs (noutputs), - d_input (ninputs), d_output (noutputs), - d_done (false), - d_ins_noutput_items(0), - d_avg_noutput_items(0), - d_var_noutput_items(0), - d_ins_nproduced(0), - d_avg_nproduced(0), - d_var_nproduced(0), - d_ins_input_buffers_full(ninputs, 0), - d_avg_input_buffers_full(ninputs, 0), - d_var_input_buffers_full(ninputs, 0), - d_ins_output_buffers_full(noutputs, 0), - d_avg_output_buffers_full(noutputs, 0), - d_var_output_buffers_full(noutputs, 0), - d_ins_work_time(0), - d_avg_work_time(0), - d_var_work_time(0), - d_pc_counter(0) -{ - s_ncurrently_allocated++; -} - -gr_block_detail::~gr_block_detail () -{ - // should take care of itself - s_ncurrently_allocated--; -} - -void -gr_block_detail::set_input (unsigned int which, gr_buffer_reader_sptr reader) -{ - if (which >= d_ninputs) - throw std::invalid_argument ("gr_block_detail::set_input"); - - d_input[which] = reader; -} - -void -gr_block_detail::set_output (unsigned int which, gr_buffer_sptr buffer) -{ - if (which >= d_noutputs) - throw std::invalid_argument ("gr_block_detail::set_output"); - - d_output[which] = buffer; -} - -gr_block_detail_sptr -gr_make_block_detail (unsigned int ninputs, unsigned int noutputs) -{ - return gr_block_detail_sptr (new gr_block_detail (ninputs, noutputs)); -} - -void -gr_block_detail::set_done (bool done) -{ - d_done = done; - for (unsigned int i = 0; i < d_noutputs; i++) - d_output[i]->set_done (done); - - for (unsigned int i = 0; i < d_ninputs; i++) - d_input[i]->set_done (done); -} - -void -gr_block_detail::consume (int which_input, int how_many_items) -{ - if (how_many_items > 0) { - input (which_input)->update_read_pointer (how_many_items); - } -} - - -void -gr_block_detail::consume_each (int how_many_items) -{ - if (how_many_items > 0) { - for (int i = 0; i < ninputs (); i++) { - d_input[i]->update_read_pointer (how_many_items); - } - } -} - -void -gr_block_detail::produce (int which_output, int how_many_items) -{ - if (how_many_items > 0){ - d_output[which_output]->update_write_pointer (how_many_items); - d_produce_or |= how_many_items; - } -} - -void -gr_block_detail::produce_each (int how_many_items) -{ - if (how_many_items > 0) { - for (int i = 0; i < noutputs (); i++) { - d_output[i]->update_write_pointer (how_many_items); - } - d_produce_or |= how_many_items; - } -} - - -uint64_t -gr_block_detail::nitems_read(unsigned int which_input) -{ - if(which_input >= d_ninputs) - throw std::invalid_argument ("gr_block_detail::n_input_items"); - return d_input[which_input]->nitems_read(); -} - -uint64_t -gr_block_detail::nitems_written(unsigned int which_output) -{ - if(which_output >= d_noutputs) - throw std::invalid_argument ("gr_block_detail::n_output_items"); - return d_output[which_output]->nitems_written(); -} - -void -gr_block_detail::add_item_tag(unsigned int which_output, const gr_tag_t &tag) -{ - if(!pmt::is_symbol(tag.key)) { - throw pmt::wrong_type("gr_block_detail::add_item_tag key", tag.key); - } - else { - // Add tag to gr_buffer's deque tags - d_output[which_output]->add_item_tag(tag); - } -} - -void -gr_block_detail::remove_item_tag(unsigned int which_input, const gr_tag_t &tag) -{ - if(!pmt::is_symbol(tag.key)) { - throw pmt::wrong_type("gr_block_detail::add_item_tag key", tag.key); - } - else { - // Add tag to gr_buffer's deque tags - d_input[which_input]->buffer()->remove_item_tag(tag); - } -} - -void -gr_block_detail::get_tags_in_range(std::vector<gr_tag_t> &v, - unsigned int which_input, - uint64_t abs_start, - uint64_t abs_end) -{ - // get from gr_buffer_reader's deque of tags - d_input[which_input]->get_tags_in_range(v, abs_start, abs_end); -} - -void -gr_block_detail::get_tags_in_range(std::vector<gr_tag_t> &v, - unsigned int which_input, - uint64_t abs_start, - uint64_t abs_end, - const pmt::pmt_t &key) -{ - std::vector<gr_tag_t> found_items; - - v.resize(0); - - // get from gr_buffer_reader's deque of tags - d_input[which_input]->get_tags_in_range(found_items, abs_start, abs_end); - - // Filter further by key name - pmt::pmt_t itemkey; - std::vector<gr_tag_t>::iterator itr; - for(itr = found_items.begin(); itr != found_items.end(); itr++) { - itemkey = (*itr).key; - if(pmt::eqv(key, itemkey)) { - v.push_back(*itr); - } - } -} - -void -gr_block_detail::set_processor_affinity(const std::vector<int> &mask) -{ - if(threaded) { - try { - gr::thread::thread_bind_to_processor(thread, mask); - } - catch (std::runtime_error e) { - std::cerr << "set_processor_affinity: invalid mask." << std::endl;; - } - } -} - -void -gr_block_detail::unset_processor_affinity() -{ - if(threaded) { - gr::thread::thread_unbind(thread); - } -} - -void -gr_block_detail::start_perf_counters() -{ - d_start_of_work = gr::high_res_timer_now(); -} - -void -gr_block_detail::stop_perf_counters(int noutput_items, int nproduced) -{ - d_end_of_work = gr::high_res_timer_now(); - gr::high_res_timer_type diff = d_end_of_work - d_start_of_work; - - if(d_pc_counter == 0) { - d_ins_work_time = diff; - d_avg_work_time = diff; - d_var_work_time = 0; - d_ins_nproduced = nproduced; - d_avg_nproduced = nproduced; - d_var_nproduced = 0; - d_ins_noutput_items = noutput_items; - d_avg_noutput_items = noutput_items; - d_var_noutput_items = 0; - for(size_t i=0; i < d_input.size(); i++) { - float pfull = static_cast<float>(d_input[i]->items_available()) / - static_cast<float>(d_input[i]->max_possible_items_available()); - d_ins_input_buffers_full[i] = pfull; - d_avg_input_buffers_full[i] = pfull; - d_var_input_buffers_full[i] = 0; - } - for(size_t i=0; i < d_output.size(); i++) { - float pfull = 1.0f - static_cast<float>(d_output[i]->space_available()) / - static_cast<float>(d_output[i]->bufsize()); - d_ins_output_buffers_full[i] = pfull; - d_avg_output_buffers_full[i] = pfull; - d_var_output_buffers_full[i] = 0; - } - } - else { - float d = diff - d_avg_work_time; - d_ins_work_time = diff; - d_avg_work_time = d_avg_work_time + d/d_pc_counter; - d_var_work_time = d_var_work_time + d*d; - - d = nproduced - d_avg_nproduced; - d_ins_nproduced = nproduced; - d_avg_nproduced = d_avg_nproduced + d/d_pc_counter; - d_var_nproduced = d_var_nproduced + d*d; - - d = noutput_items - d_avg_noutput_items; - d_ins_noutput_items = noutput_items; - d_avg_noutput_items = d_avg_noutput_items + d/d_pc_counter; - d_var_noutput_items = d_var_noutput_items + d*d; - - for(size_t i=0; i < d_input.size(); i++) { - float pfull = static_cast<float>(d_input[i]->items_available()) / - static_cast<float>(d_input[i]->max_possible_items_available()); - - d = pfull - d_avg_input_buffers_full[i]; - d_ins_input_buffers_full[i] = pfull; - d_avg_input_buffers_full[i] = d_avg_input_buffers_full[i] + d/d_pc_counter; - d_var_input_buffers_full[i] = d_var_input_buffers_full[i] + d*d; - } - - for(size_t i=0; i < d_output.size(); i++) { - float pfull = 1.0f - static_cast<float>(d_output[i]->space_available()) / - static_cast<float>(d_output[i]->bufsize()); - - d = pfull - d_avg_output_buffers_full[i]; - d_ins_output_buffers_full[i] = pfull; - d_avg_output_buffers_full[i] = d_avg_output_buffers_full[i] + d/d_pc_counter; - d_var_output_buffers_full[i] = d_var_output_buffers_full[i] + d*d; - } - } - - d_pc_counter++; -} - -void -gr_block_detail::reset_perf_counters() -{ - d_pc_counter = 0; -} - -float -gr_block_detail::pc_noutput_items() -{ - return d_ins_noutput_items; -} - -float -gr_block_detail::pc_nproduced() -{ - return d_ins_nproduced; -} - -float -gr_block_detail::pc_input_buffers_full(size_t which) -{ - if(which < d_ins_input_buffers_full.size()) - return d_ins_input_buffers_full[which]; - else - return 0; -} - -std::vector<float> -gr_block_detail::pc_input_buffers_full() -{ - return d_ins_input_buffers_full; -} - -float -gr_block_detail::pc_output_buffers_full(size_t which) -{ - if(which < d_ins_output_buffers_full.size()) - return d_ins_output_buffers_full[which]; - else - return 0; -} - -std::vector<float> -gr_block_detail::pc_output_buffers_full() -{ - return d_ins_output_buffers_full; -} - -float -gr_block_detail::pc_work_time() -{ - return d_ins_work_time; -} - -float -gr_block_detail::pc_noutput_items_avg() -{ - return d_avg_noutput_items; -} - -float -gr_block_detail::pc_nproduced_avg() -{ - return d_avg_nproduced; -} - -float -gr_block_detail::pc_input_buffers_full_avg(size_t which) -{ - if(which < d_avg_input_buffers_full.size()) - return d_avg_input_buffers_full[which]; - else - return 0; -} - -std::vector<float> -gr_block_detail::pc_input_buffers_full_avg() -{ - return d_avg_input_buffers_full; -} - -float -gr_block_detail::pc_output_buffers_full_avg(size_t which) -{ - if(which < d_avg_output_buffers_full.size()) - return d_avg_output_buffers_full[which]; - else - return 0; -} - -std::vector<float> -gr_block_detail::pc_output_buffers_full_avg() -{ - return d_avg_output_buffers_full; -} - -float -gr_block_detail::pc_work_time_avg() -{ - return d_avg_work_time; -} - - -float -gr_block_detail::pc_noutput_items_var() -{ - return d_var_noutput_items/(d_pc_counter-1); -} - -float -gr_block_detail::pc_nproduced_var() -{ - return d_var_nproduced/(d_pc_counter-1); -} - -float -gr_block_detail::pc_input_buffers_full_var(size_t which) -{ - if(which < d_avg_input_buffers_full.size()) - return d_var_input_buffers_full[which]/(d_pc_counter-1); - else - return 0; -} - -std::vector<float> -gr_block_detail::pc_input_buffers_full_var() -{ - std::vector<float> var(d_avg_input_buffers_full.size(), 0); - for(size_t i = 0; i < d_avg_input_buffers_full.size(); i++) - var[i] = d_avg_input_buffers_full[i]/(d_pc_counter-1); - return var; -} - -float -gr_block_detail::pc_output_buffers_full_var(size_t which) -{ - if(which < d_avg_output_buffers_full.size()) - return d_var_output_buffers_full[which]/(d_pc_counter-1); - else - return 0; -} - -std::vector<float> -gr_block_detail::pc_output_buffers_full_var() -{ - std::vector<float> var(d_avg_output_buffers_full.size(), 0); - for(size_t i = 0; i < d_avg_output_buffers_full.size(); i++) - var[i] = d_avg_output_buffers_full[i]/(d_pc_counter-1); - return var; -} - -float -gr_block_detail::pc_work_time_var() -{ - return d_var_work_time/(d_pc_counter-1); -} diff --git a/gnuradio-runtime/lib/gr_block_executor.cc b/gnuradio-runtime/lib/gr_block_executor.cc deleted file mode 100644 index cfef406412..0000000000 --- a/gnuradio-runtime/lib/gr_block_executor.cc +++ /dev/null @@ -1,487 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2008,2009,2010 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_block_executor.h> -#include <gr_block.h> -#include <gr_block_detail.h> -#include <gr_buffer.h> -#include <gr_prefs.h> -#include <boost/thread.hpp> -#include <boost/format.hpp> -#include <iostream> -#include <limits> -#include <assert.h> -#include <stdio.h> - -// must be defined to either 0 or 1 -#define ENABLE_LOGGING 0 - -#if (ENABLE_LOGGING) -#define LOG(x) do { x; } while(0) -#else -#define LOG(x) do {;} while(0) -#endif - -static int which_scheduler = 0; - -inline static unsigned int -round_up (unsigned int n, unsigned int multiple) -{ - return ((n + multiple - 1) / multiple) * multiple; -} - -inline static unsigned int -round_down (unsigned int n, unsigned int multiple) -{ - return (n / multiple) * multiple; -} - -// -// Return minimum available write space in all our downstream buffers -// or -1 if we're output blocked and the output we're blocked -// on is done. -// -static int -min_available_space (gr_block_detail *d, int output_multiple, int min_noutput_items) -{ - int min_space = std::numeric_limits<int>::max(); - if (min_noutput_items == 0) - min_noutput_items = 1; - for (int i = 0; i < d->noutputs (); i++){ - gr::thread::scoped_lock guard(*d->output(i)->mutex()); - int avail_n = round_down(d->output(i)->space_available(), output_multiple); - int best_n = round_down(d->output(i)->bufsize()/2, output_multiple); - if (best_n < min_noutput_items) - throw std::runtime_error("Buffer too small for min_noutput_items"); - int n = std::min(avail_n, best_n); - if (n < min_noutput_items){ // We're blocked on output. - if (d->output(i)->done()){ // Downstream is done, therefore we're done. - return -1; - } - return 0; - } - min_space = std::min (min_space, n); - } - return min_space; -} - -static bool -propagate_tags(gr_block::tag_propagation_policy_t policy, gr_block_detail *d, - const std::vector<uint64_t> &start_nitems_read, double rrate, - std::vector<gr_tag_t> &rtags) -{ - // Move tags downstream - // if a sink, we don't need to move downstream - if(d->sink_p()) { - return true; - } - - switch(policy) { - case gr_block::TPP_DONT: - return true; - break; - case gr_block::TPP_ALL_TO_ALL: - // every tag on every input propogates to everyone downstream - for(int i = 0; i < d->ninputs(); i++) { - d->get_tags_in_range(rtags, i, start_nitems_read[i], - d->nitems_read(i)); - - std::vector<gr_tag_t>::iterator t; - if(rrate == 1.0) { - for(t = rtags.begin(); t != rtags.end(); t++) { - for(int o = 0; o < d->noutputs(); o++) - d->output(o)->add_item_tag(*t); - } - } - else { - for(t = rtags.begin(); t != rtags.end(); t++) { - gr_tag_t new_tag = *t; - new_tag.offset *= rrate; - for(int o = 0; o < d->noutputs(); o++) - d->output(o)->add_item_tag(new_tag); - } - } - } - break; - case gr_block::TPP_ONE_TO_ONE: - // tags from input i only go to output i - // this requires d->ninputs() == d->noutputs; this is checked when this - // type of tag-propagation system is selected in gr_block_detail - if(d->ninputs() == d->noutputs()) { - for(int i = 0; i < d->ninputs(); i++) { - d->get_tags_in_range(rtags, i, start_nitems_read[i], - d->nitems_read(i)); - - std::vector<gr_tag_t>::iterator t; - for(t = rtags.begin(); t != rtags.end(); t++) { - gr_tag_t new_tag = *t; - new_tag.offset *= rrate; - d->output(i)->add_item_tag(new_tag); - } - } - } - else { - std::cerr << "Error: gr_block_executor: propagation_policy 'ONE-TO-ONE' requires ninputs == noutputs" << std::endl; - return false; - } - - break; - default: - return true; - } - return true; -} - -gr_block_executor::gr_block_executor (gr_block_sptr block, int max_noutput_items) - : d_block(block), d_log(0), d_max_noutput_items(max_noutput_items) -{ - if (ENABLE_LOGGING){ - std::string name = str(boost::format("sst-%03d.log") % which_scheduler++); - d_log = new std::ofstream(name.c_str()); - std::unitbuf(*d_log); // make it unbuffered... - *d_log << "gr_block_executor: " - << d_block << std::endl; - } - -#ifdef GR_PERFORMANCE_COUNTERS - gr_prefs *prefs = gr_prefs::singleton(); - d_use_pc = prefs->get_bool("PerfCounters", "on", false); -#endif /* GR_PERFORMANCE_COUNTERS */ - - d_block->start(); // enable any drivers, etc. -} - -gr_block_executor::~gr_block_executor () -{ - if (ENABLE_LOGGING) - delete d_log; - - d_block->stop(); // stop any drivers, etc. -} - -gr_block_executor::state -gr_block_executor::run_one_iteration() -{ - int noutput_items; - int max_items_avail; - int max_noutput_items = d_max_noutput_items; - int new_alignment=0; - int alignment_state=-1; - - gr_block *m = d_block.get(); - gr_block_detail *d = m->detail().get(); - - LOG(*d_log << std::endl << m); - - if (d->done()){ - assert(0); - return DONE; - } - - if (d->source_p ()){ - d_ninput_items_required.resize (0); - d_ninput_items.resize (0); - d_input_items.resize (0); - d_input_done.resize(0); - d_output_items.resize (d->noutputs ()); - d_start_nitems_read.resize(0); - - // determine the minimum available output space - noutput_items = min_available_space (d, m->output_multiple (), m->min_noutput_items ()); - noutput_items = std::min(noutput_items, max_noutput_items); - LOG(*d_log << " source\n noutput_items = " << noutput_items << std::endl); - if (noutput_items == -1) // we're done - goto were_done; - - if (noutput_items == 0){ // we're output blocked - LOG(*d_log << " BLKD_OUT\n"); - return BLKD_OUT; - } - - goto setup_call_to_work; // jump to common code - } - - else if (d->sink_p ()){ - d_ninput_items_required.resize (d->ninputs ()); - d_ninput_items.resize (d->ninputs ()); - d_input_items.resize (d->ninputs ()); - d_input_done.resize(d->ninputs()); - d_output_items.resize (0); - d_start_nitems_read.resize(d->ninputs()); - LOG(*d_log << " sink\n"); - - max_items_avail = 0; - for (int i = 0; i < d->ninputs (); i++){ - { - /* - * Acquire the mutex and grab local copies of items_available and done. - */ - gr::thread::scoped_lock guard(*d->input(i)->mutex()); - d_ninput_items[i] = d->input(i)->items_available(); - d_input_done[i] = d->input(i)->done(); - } - - LOG(*d_log << " d_ninput_items[" << i << "] = " << d_ninput_items[i] << std::endl); - LOG(*d_log << " d_input_done[" << i << "] = " << d_input_done[i] << std::endl); - - if (d_ninput_items[i] < m->output_multiple() && d_input_done[i]) - goto were_done; - - max_items_avail = std::max (max_items_avail, d_ninput_items[i]); - } - - // take a swag at how much output we can sink - noutput_items = (int) (max_items_avail * m->relative_rate ()); - noutput_items = round_down (noutput_items, m->output_multiple ()); - noutput_items = std::min(noutput_items, max_noutput_items); - LOG(*d_log << " max_items_avail = " << max_items_avail << std::endl); - LOG(*d_log << " noutput_items = " << noutput_items << std::endl); - - if (noutput_items == 0){ // we're blocked on input - LOG(*d_log << " BLKD_IN\n"); - return BLKD_IN; - } - - goto try_again; // Jump to code shared with regular case. - } - - else { - // do the regular thing - d_ninput_items_required.resize (d->ninputs ()); - d_ninput_items.resize (d->ninputs ()); - d_input_items.resize (d->ninputs ()); - d_input_done.resize(d->ninputs()); - d_output_items.resize (d->noutputs ()); - d_start_nitems_read.resize(d->ninputs()); - - max_items_avail = 0; - for (int i = 0; i < d->ninputs (); i++){ - { - /* - * Acquire the mutex and grab local copies of items_available and done. - */ - gr::thread::scoped_lock guard(*d->input(i)->mutex()); - d_ninput_items[i] = d->input(i)->items_available (); - d_input_done[i] = d->input(i)->done(); - } - max_items_avail = std::max (max_items_avail, d_ninput_items[i]); - } - - // determine the minimum available output space - noutput_items = min_available_space (d, m->output_multiple (), m->min_noutput_items ()); - if (ENABLE_LOGGING){ - *d_log << " regular "; - if (m->relative_rate() >= 1.0) - *d_log << "1:" << m->relative_rate() << std::endl; - else - *d_log << 1.0/m->relative_rate() << ":1\n"; - *d_log << " max_items_avail = " << max_items_avail << std::endl; - *d_log << " noutput_items = " << noutput_items << std::endl; - } - if (noutput_items == -1) // we're done - goto were_done; - - if (noutput_items == 0){ // we're output blocked - LOG(*d_log << " BLKD_OUT\n"); - return BLKD_OUT; - } - - try_again: - if (m->fixed_rate()){ - // try to work it forward starting with max_items_avail. - // We want to try to consume all the input we've got. - int reqd_noutput_items = m->fixed_rate_ninput_to_noutput(max_items_avail); - - // only test this if we specifically set the output_multiple - if(m->output_multiple_set()) - reqd_noutput_items = round_down(reqd_noutput_items, m->output_multiple()); - - if (reqd_noutput_items > 0 && reqd_noutput_items <= noutput_items) - noutput_items = reqd_noutput_items; - - // if we need this many outputs, overrule the max_noutput_items setting - max_noutput_items = std::max(m->output_multiple(), max_noutput_items); - } - noutput_items = std::min(noutput_items, max_noutput_items); - - // Check if we're still unaligned; use up items until we're - // aligned again. Otherwise, make sure we set the alignment - // requirement. - if(!m->output_multiple_set()) { - if(m->is_unaligned()) { - // When unaligned, don't just set noutput_items to the remaining - // samples to meet alignment; this causes too much overhead in - // requiring a premature call back here. Set the maximum amount - // of samples to handle unalignment and get us back aligned. - if(noutput_items >= m->unaligned()) { - noutput_items = round_up(noutput_items, m->alignment()) \ - - (m->alignment() - m->unaligned()); - new_alignment = 0; - } - else { - new_alignment = m->unaligned() - noutput_items; - } - alignment_state = 0; - } - else if(noutput_items < m->alignment()) { - // if we don't have enough for an aligned call, keep track of - // misalignment, set unaligned flag, and proceed. - new_alignment = m->alignment() - noutput_items; - m->set_unaligned(new_alignment); - m->set_is_unaligned(true); - alignment_state = 1; - } - else { - // enough to round down to the nearest alignment and process. - noutput_items = round_down(noutput_items, m->alignment()); - m->set_is_unaligned(false); - alignment_state = 2; - } - } - - // ask the block how much input they need to produce noutput_items - m->forecast (noutput_items, d_ninput_items_required); - - // See if we've got sufficient input available - - int i; - for (i = 0; i < d->ninputs (); i++) - if (d_ninput_items_required[i] > d_ninput_items[i]) // not enough - break; - - if (i < d->ninputs ()){ // not enough input on input[i] - // if we can, try reducing the size of our output request - if (noutput_items > m->output_multiple ()){ - noutput_items /= 2; - noutput_items = round_up (noutput_items, m->output_multiple ()); - goto try_again; - } - - // We're blocked on input - LOG(*d_log << " BLKD_IN\n"); - if (d_input_done[i]) // If the upstream block is done, we're done - goto were_done; - - // Is it possible to ever fulfill this request? - if (d_ninput_items_required[i] > d->input(i)->max_possible_items_available ()){ - // Nope, never going to happen... - std::cerr << "\nsched: <gr_block " << m->name() - << " (" << m->unique_id() << ")>" - << " is requesting more input data\n" - << " than we can provide.\n" - << " ninput_items_required = " - << d_ninput_items_required[i] << "\n" - << " max_possible_items_available = " - << d->input(i)->max_possible_items_available() << "\n" - << " If this is a filter, consider reducing the number of taps.\n"; - goto were_done; - } - - // If we were made unaligned in this round but return here without - // processing; reset the unalignment claim before next entry. - if(alignment_state == 1) { - m->set_unaligned(0); - m->set_is_unaligned(false); - } - return BLKD_IN; - } - - // We've got enough data on each input to produce noutput_items. - // Finish setting up the call to work. - - for (int i = 0; i < d->ninputs (); i++) - d_input_items[i] = d->input(i)->read_pointer(); - - setup_call_to_work: - - d->d_produce_or = 0; - for (int i = 0; i < d->noutputs (); i++) - d_output_items[i] = d->output(i)->write_pointer(); - - // determine where to start looking for new tags - for (int i = 0; i < d->ninputs(); i++) - d_start_nitems_read[i] = d->nitems_read(i); - -#ifdef GR_PERFORMANCE_COUNTERS - if(d_use_pc) - d->start_perf_counters(); -#endif /* GR_PERFORMANCE_COUNTERS */ - - // Do the actual work of the block - int n = m->general_work (noutput_items, d_ninput_items, - d_input_items, d_output_items); - -#ifdef GR_PERFORMANCE_COUNTERS - if(d_use_pc) - d->stop_perf_counters(noutput_items, n); -#endif /* GR_PERFORMANCE_COUNTERS */ - - LOG(*d_log << " general_work: noutput_items = " << noutput_items - << " result = " << n << std::endl); - - // Adjust number of unaligned items left to process - if(m->is_unaligned()) { - m->set_unaligned(new_alignment); - m->set_is_unaligned(m->unaligned() != 0); - } - - if(!propagate_tags(m->tag_propagation_policy(), d, - d_start_nitems_read, m->relative_rate(), - d_returned_tags)) - goto were_done; - - if (n == gr_block::WORK_DONE) - goto were_done; - - if (n != gr_block::WORK_CALLED_PRODUCE) - d->produce_each (n); // advance write pointers - - if (d->d_produce_or > 0) // block produced something - return READY; - - // We didn't produce any output even though we called general_work. - // We have (most likely) consumed some input. - - /* - // If this is a source, it's broken. - if (d->source_p()){ - std::cerr << "gr_block_executor: source " << m - << " produced no output. We're marking it DONE.\n"; - // FIXME maybe we ought to raise an exception... - goto were_done; - } - */ - - // Have the caller try again... - return READY_NO_OUTPUT; - } - assert (0); - - were_done: - LOG(*d_log << " were_done\n"); - d->set_done (true); - return DONE; -} diff --git a/gnuradio-runtime/lib/gr_block_executor.h b/gnuradio-runtime/lib/gr_block_executor.h deleted file mode 100644 index 7d5c4949a3..0000000000 --- a/gnuradio-runtime/lib/gr_block_executor.h +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2008 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_BLOCK_EXECUTOR_H -#define INCLUDED_GR_BLOCK_EXECUTOR_H - -#include <gr_runtime_api.h> -#include <gr_runtime_types.h> -#include <fstream> -#include <gr_tags.h> - -//class gr_block_executor; -//typedef boost::shared_ptr<gr_block_executor> gr_block_executor_sptr; - - -/*! - * \brief Manage the execution of a single block. - * \ingroup internal - */ - -class GR_RUNTIME_API gr_block_executor { -protected: - gr_block_sptr d_block; // The block we're trying to run - std::ofstream *d_log; - - // These are allocated here so we don't have to on each iteration - - gr_vector_int d_ninput_items_required; - gr_vector_int d_ninput_items; - gr_vector_const_void_star d_input_items; - std::vector<bool> d_input_done; - gr_vector_void_star d_output_items; - std::vector<uint64_t> d_start_nitems_read; //stores where tag counts are before work - std::vector<gr_tag_t> d_returned_tags; - int d_max_noutput_items; - -#ifdef GR_PERFORMANCE_COUNTERS - bool d_use_pc; -#endif /* GR_PERFORMANCE_COUNTERS */ - - public: - gr_block_executor(gr_block_sptr block, int max_noutput_items=100000); - ~gr_block_executor (); - - enum state { - READY, // We made progress; everything's cool. - READY_NO_OUTPUT, // We consumed some input, but produced no output. - BLKD_IN, // no progress; we're blocked waiting for input data. - BLKD_OUT, // no progress; we're blocked waiting for output buffer space. - DONE, // we're done; don't call me again. - }; - - /* - * \brief Run one iteration. - */ - state run_one_iteration(); -}; - -#endif /* INCLUDED_GR_BLOCK_EXECUTOR_H */ diff --git a/gnuradio-runtime/lib/gr_block_registry.cc b/gnuradio-runtime/lib/gr_block_registry.cc deleted file mode 100644 index a80673691a..0000000000 --- a/gnuradio-runtime/lib/gr_block_registry.cc +++ /dev/null @@ -1,98 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012-2013 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_basic_block.h> -#include <gr_block_registry.h> -#include <gr_tpb_detail.h> -#include <gr_block_detail.h> -#include <gr_block.h> -#include <stdio.h> - -gr_block_registry global_block_registry; - -gr_block_registry::gr_block_registry(){ - d_ref_map = pmt::make_dict(); -} - -long gr_block_registry::block_register(gr_basic_block* block){ - if(d_map.find(block->name()) == d_map.end()){ - d_map[block->name()] = blocksubmap_t(); - d_map[block->name()][0] = block; - return 0; - } else { - for(size_t i=0; i<=d_map[block->name()].size(); i++){ - if(d_map[block->name()].find(i) == d_map[block->name()].end()){ - d_map[block->name()][i] = block; - return i; - } - } - } - throw std::runtime_error("should not reach this"); -} - -void gr_block_registry::block_unregister(gr_basic_block* block){ - d_map[block->name()].erase( d_map[block->name()].find(block->symbolic_id())); - d_ref_map = pmt::dict_delete(d_ref_map, pmt::intern(block->symbol_name())); - if(block->alias_set()){ - d_ref_map = pmt::dict_delete(d_ref_map, pmt::intern(block->alias())); - } -} - -std::string gr_block_registry::register_symbolic_name(gr_basic_block* block){ - std::stringstream ss; - ss << block->name() << block->symbolic_id(); - //std::cout << "register_symbolic_name: " << ss.str() << std::endl; - register_symbolic_name(block, ss.str()); - return ss.str(); -} - -void gr_block_registry::register_symbolic_name(gr_basic_block* block, std::string name){ - if(pmt::dict_has_key(d_ref_map, pmt::intern(name))){ - throw std::runtime_error("symbol already exists, can not re-use!"); - } - d_ref_map = pmt::dict_add(d_ref_map, pmt::intern(name), pmt::make_any(block)); -} - -gr_basic_block_sptr gr_block_registry::block_lookup(pmt::pmt_t symbol){ - pmt::pmt_t ref = pmt::dict_ref(d_ref_map, symbol, pmt::PMT_NIL); - if(pmt::eq(ref, pmt::PMT_NIL)){ - throw std::runtime_error("block lookup failed! block not found!"); - } - gr_basic_block* blk = boost::any_cast<gr_basic_block*>( pmt::any_ref(ref) ); - return blk->shared_from_this(); -} - - -void gr_block_registry::register_primitive(std::string blk, gr_block* ref){ - primitive_map[blk] = ref; -} - -void gr_block_registry::unregister_primitive(std::string blk){ - primitive_map.erase(primitive_map.find(blk)); -} - -void gr_block_registry::notify_blk(std::string blk){ - if(primitive_map.find(blk) == primitive_map.end()){ return; } - if(primitive_map[blk]->detail().get()) - primitive_map[blk]->detail()->d_tpb.notify_msg(); -} - diff --git a/gnuradio-runtime/lib/gr_buffer.cc b/gnuradio-runtime/lib/gr_buffer.cc deleted file mode 100644 index bdce5b4036..0000000000 --- a/gnuradio-runtime/lib/gr_buffer.cc +++ /dev/null @@ -1,347 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2009,2010 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_buffer.h> -#include <gr_vmcircbuf.h> -#include <gr_math.h> -#include <stdexcept> -#include <iostream> -#include <assert.h> -#include <algorithm> -#include <boost/math/common_factor_rt.hpp> - -static long s_buffer_count = 0; // counts for debugging storage mgmt -static long s_buffer_reader_count = 0; - -// ---------------------------------------------------------------------------- -// Notes on storage management -// -// Pretty much all the fundamental classes are now using the -// shared_ptr stuff for automatic reference counting. To ensure that -// no mistakes are made, we make the constructors for classes private, -// and then provide a free factory function that returns a smart -// pointer to the desired class. -// -// gr_buffer and gr_buffer_reader are no exceptions. However, they -// both want pointers to each other, and unless we do something, we'll -// never delete any of them because of the circular structure. -// They'll always have a reference count of at least one. We could -// use boost::weak_ptr's from gr_buffer to gr_buffer_reader but that -// introduces it's own problems. (gr_buffer_reader's destructor needs -// to call gr_buffer::drop_reader, but has no easy way to get a -// shared_ptr to itself.) -// -// Instead, we solve this problem by having gr_buffer hold a raw -// pointer to gr_buffer_reader in its d_reader vector. -// gr_buffer_reader's destructor calls gr_buffer::drop_reader, so -// we're never left with an dangling pointer. gr_buffer_reader still -// has a shared_ptr to the buffer ensuring that the buffer doesn't go -// away under it. However, when the reference count of a -// gr_buffer_reader goes to zero, we can successfully reclaim it. -// ---------------------------------------------------------------------------- - - -/* - * Compute the minimum number of buffer items that work (i.e., - * address space wrap-around works). To work is to satisfy this - * contraint for integer buffer_size and k: - * - * type_size * nitems == k * page_size - */ -static long -minimum_buffer_items (long type_size, long page_size) -{ - return page_size / boost::math::gcd (type_size, page_size); -} - - -gr_buffer::gr_buffer (int nitems, size_t sizeof_item, gr_block_sptr link) - : d_base (0), d_bufsize (0), d_vmcircbuf (0), - d_sizeof_item (sizeof_item), d_link(link), - d_write_index (0), d_abs_write_offset(0), d_done (false), - d_last_min_items_read(0) -{ - if (!allocate_buffer (nitems, sizeof_item)) - throw std::bad_alloc (); - - s_buffer_count++; -} - -gr_buffer_sptr -gr_make_buffer (int nitems, size_t sizeof_item, gr_block_sptr link) -{ - return gr_buffer_sptr (new gr_buffer (nitems, sizeof_item, link)); -} - -gr_buffer::~gr_buffer () -{ - delete d_vmcircbuf; - assert (d_readers.size() == 0); - s_buffer_count--; -} - -/*! - * sets d_vmcircbuf, d_base, d_bufsize. - * returns true iff successful. - */ -bool -gr_buffer::allocate_buffer (int nitems, size_t sizeof_item) -{ - int orig_nitems = nitems; - - // Any buffersize we come up with must be a multiple of min_nitems. - - int granularity = gr_vmcircbuf_sysconfig::granularity (); - int min_nitems = minimum_buffer_items (sizeof_item, granularity); - - // Round-up nitems to a multiple of min_nitems. - - if (nitems % min_nitems != 0) - nitems = ((nitems / min_nitems) + 1) * min_nitems; - - // If we rounded-up a whole bunch, give the user a heads up. - // This only happens if sizeof_item is not a power of two. - - if (nitems > 2 * orig_nitems && nitems * (int) sizeof_item > granularity){ - std::cerr << "gr_buffer::allocate_buffer: warning: tried to allocate\n" - << " " << orig_nitems << " items of size " - << sizeof_item << ". Due to alignment requirements\n" - << " " << nitems << " were allocated. If this isn't OK, consider padding\n" - << " your structure to a power-of-two bytes.\n" - << " On this platform, our allocation granularity is " << granularity << " bytes.\n"; - } - - d_bufsize = nitems; - d_vmcircbuf = gr_vmcircbuf_sysconfig::make (d_bufsize * d_sizeof_item); - if (d_vmcircbuf == 0){ - std::cerr << "gr_buffer::allocate_buffer: failed to allocate buffer of size " - << d_bufsize * d_sizeof_item / 1024 << " KB\n"; - return false; - } - - d_base = (char *) d_vmcircbuf->pointer_to_first_copy (); - return true; -} - - -int -gr_buffer::space_available () -{ - if (d_readers.empty ()) - return d_bufsize - 1; // See comment below - - else { - - // Find out the maximum amount of data available to our readers - - int most_data = d_readers[0]->items_available (); - uint64_t min_items_read = d_readers[0]->nitems_read(); - for (size_t i = 1; i < d_readers.size (); i++) { - most_data = std::max (most_data, d_readers[i]->items_available ()); - min_items_read = std::min(min_items_read, d_readers[i]->nitems_read()); - } - - if(min_items_read != d_last_min_items_read) { - prune_tags(d_last_min_items_read); - d_last_min_items_read = min_items_read; - } - - // The -1 ensures that the case d_write_index == d_read_index is - // unambiguous. It indicates that there is no data for the reader - - return d_bufsize - most_data - 1; - } -} - -void * -gr_buffer::write_pointer () -{ - return &d_base[d_write_index * d_sizeof_item]; -} - -void -gr_buffer::update_write_pointer (int nitems) -{ - gr::thread::scoped_lock guard(*mutex()); - d_write_index = index_add (d_write_index, nitems); - d_abs_write_offset += nitems; -} - -void -gr_buffer::set_done (bool done) -{ - gr::thread::scoped_lock guard(*mutex()); - d_done = done; -} - -gr_buffer_reader_sptr -gr_buffer_add_reader (gr_buffer_sptr buf, int nzero_preload, gr_block_sptr link) -{ - if (nzero_preload < 0) - throw std::invalid_argument("gr_buffer_add_reader: nzero_preload must be >= 0"); - - gr_buffer_reader_sptr r (new gr_buffer_reader (buf, - buf->index_sub(buf->d_write_index, - nzero_preload), - link)); - buf->d_readers.push_back (r.get ()); - - return r; -} - -void -gr_buffer::drop_reader (gr_buffer_reader *reader) -{ - // isn't C++ beautiful... GAG! - - std::vector<gr_buffer_reader *>::iterator result = - std::find (d_readers.begin (), d_readers.end (), reader); - - if (result == d_readers.end ()) - throw std::invalid_argument ("gr_buffer::drop_reader"); // we didn't find it... - - d_readers.erase (result); -} - -void -gr_buffer::add_item_tag(const gr_tag_t &tag) -{ - gr::thread::scoped_lock guard(*mutex()); - d_item_tags.push_back(tag); -} - -void -gr_buffer::remove_item_tag(const gr_tag_t &tag) -{ - gr::thread::scoped_lock guard(*mutex()); - for (std::deque<gr_tag_t>::iterator it = d_item_tags.begin(); it != d_item_tags.end(); ++it) { - if (*it == tag) { - d_item_tags.erase(it); - break; - } - } -} - -void -gr_buffer::prune_tags(uint64_t max_time) -{ - /* NOTE: this function _should_ lock the mutex before editing - d_item_tags. In practice, this function is only called at - runtime by min_available_space in gr_block_executor.cc, - which locks the mutex itself. - - If this function is used elsewhere, remember to lock the - buffer's mutex al la the scoped_lock line below. - */ - //gr::thread::scoped_lock guard(*mutex()); - std::deque<gr_tag_t>::iterator itr = d_item_tags.begin(); - - uint64_t item_time; - - // Since tags are not guarenteed to be in any particular order, - // we need to erase here instead of pop_front. An erase in the - // middle invalidates all iterators; so this resets the iterator - // to find more. Mostly, we wil be erasing from the front and - // therefore lose little time this way. - while(itr != d_item_tags.end()) { - item_time = (*itr).offset; - if(item_time < max_time) { - d_item_tags.erase(itr); - itr = d_item_tags.begin(); - } - else - itr++; - } -} - -long -gr_buffer_ncurrently_allocated () -{ - return s_buffer_count; -} - -// ---------------------------------------------------------------------------- - -gr_buffer_reader::gr_buffer_reader(gr_buffer_sptr buffer, unsigned int read_index, - gr_block_sptr link) - : d_buffer(buffer), d_read_index(read_index), d_abs_read_offset(0), d_link(link) -{ - s_buffer_reader_count++; -} - -gr_buffer_reader::~gr_buffer_reader () -{ - d_buffer->drop_reader(this); - s_buffer_reader_count--; -} - -int -gr_buffer_reader::items_available () const -{ - return d_buffer->index_sub (d_buffer->d_write_index, d_read_index); -} - -const void * -gr_buffer_reader::read_pointer () -{ - return &d_buffer->d_base[d_read_index * d_buffer->d_sizeof_item]; -} - -void -gr_buffer_reader::update_read_pointer (int nitems) -{ - gr::thread::scoped_lock guard(*mutex()); - d_read_index = d_buffer->index_add (d_read_index, nitems); - d_abs_read_offset += nitems; -} - -void -gr_buffer_reader::get_tags_in_range(std::vector<gr_tag_t> &v, - uint64_t abs_start, - uint64_t abs_end) -{ - gr::thread::scoped_lock guard(*mutex()); - - v.resize(0); - std::deque<gr_tag_t>::iterator itr = d_buffer->get_tags_begin(); - - uint64_t item_time; - while(itr != d_buffer->get_tags_end()) { - item_time = (*itr).offset; - - if((item_time >= abs_start) && (item_time < abs_end)) { - v.push_back(*itr); - } - - itr++; - } -} - -long -gr_buffer_reader_ncurrently_allocated () -{ - return s_buffer_reader_count; -} diff --git a/gnuradio-runtime/lib/gr_circular_file.cc b/gnuradio-runtime/lib/gr_circular_file.cc deleted file mode 100644 index 6f710c49b1..0000000000 --- a/gnuradio-runtime/lib/gr_circular_file.cc +++ /dev/null @@ -1,203 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2002,2010 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_circular_file.h> - -#include <unistd.h> -#ifdef HAVE_SYS_MMAN_H -#include <sys/mman.h> -#endif -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <fcntl.h> -#include <stdio.h> -#include <assert.h> -#include <stdlib.h> - -#include <algorithm> -#include <stdio.h> -#include <string.h> - -#ifdef HAVE_IO_H -#include <io.h> -#endif - -static const int HEADER_SIZE = 4096; -static const int HEADER_MAGIC = 0xEB021026; - -static const int HD_MAGIC = 0; -static const int HD_HEADER_SIZE = 1; // integer offsets into header -static const int HD_BUFFER_SIZE = 2; -static const int HD_BUFFER_BASE = 3; -static const int HD_BUFFER_CURRENT = 4; - -gr_circular_file::gr_circular_file (const char *filename, - bool writable, int size) - : d_fd (-1), d_header (0), d_buffer (0), d_mapped_size (0), d_bytes_read (0) -{ - int mm_prot; - if (writable){ -#ifdef HAVE_MMAP - mm_prot = PROT_READ | PROT_WRITE; -#endif - d_fd = open (filename, O_CREAT | O_RDWR | O_TRUNC, 0664); - if (d_fd < 0){ - perror (filename); - exit (1); - } -#ifdef HAVE_MMAP /* FIXME */ - if(ftruncate (d_fd, size + HEADER_SIZE) != 0) { - perror (filename); - exit (1); - } -#endif - } - else { -#ifdef HAVE_MMAP - mm_prot = PROT_READ; -#endif - d_fd = open (filename, O_RDONLY); - if (d_fd < 0){ - perror (filename); - exit (1); - } - } - - struct stat statbuf; - if (fstat (d_fd, &statbuf) < 0){ - perror (filename); - exit (1); - } - - if (statbuf.st_size < HEADER_SIZE){ - fprintf (stderr, "%s: file too small to be circular buffer\n", filename); - exit (1); - } - - d_mapped_size = statbuf.st_size; -#ifdef HAVE_MMAP - void *p = mmap (0, d_mapped_size, mm_prot, MAP_SHARED, d_fd, 0); - if (p == MAP_FAILED){ - perror ("gr_circular_file: mmap failed"); - exit (1); - } - - d_header = (int *) p; -#else - perror ("gr_circular_file: mmap unsupported by this system"); - exit (1); -#endif - - if (writable){ // init header - - if (size < 0){ - fprintf (stderr, "gr_circular_buffer: size must be > 0 when writable\n"); - exit (1); - } - - d_header[HD_MAGIC] = HEADER_MAGIC; - d_header[HD_HEADER_SIZE] = HEADER_SIZE; - d_header[HD_BUFFER_SIZE] = size; - d_header[HD_BUFFER_BASE] = HEADER_SIZE; // right after header - d_header[HD_BUFFER_CURRENT] = 0; - } - - // sanity check (the asserts are a bit unforgiving...) - - assert (d_header[HD_MAGIC] == HEADER_MAGIC); - assert (d_header[HD_HEADER_SIZE] == HEADER_SIZE); - assert (d_header[HD_BUFFER_SIZE] > 0); - assert (d_header[HD_BUFFER_BASE] >= d_header[HD_HEADER_SIZE]); - assert (d_header[HD_BUFFER_BASE] + d_header[HD_BUFFER_SIZE] <= d_mapped_size); - assert (d_header[HD_BUFFER_CURRENT] >= 0 && - d_header[HD_BUFFER_CURRENT] < d_header[HD_BUFFER_SIZE]); - - d_bytes_read = 0; - d_buffer = (unsigned char *) d_header + d_header[HD_BUFFER_BASE]; -} - -gr_circular_file::~gr_circular_file () -{ -#ifdef HAVE_MMAP - if (munmap ((char *) d_header, d_mapped_size) < 0){ - perror ("gr_circular_file: munmap"); - exit (1); - } -#endif - close (d_fd); -} - -bool -gr_circular_file::write (void *vdata, int nbytes) -{ - unsigned char *data = (unsigned char *) vdata; - int buffer_size = d_header[HD_BUFFER_SIZE]; - int buffer_current = d_header[HD_BUFFER_CURRENT]; - - while (nbytes > 0){ - int n = std::min (nbytes, buffer_size - buffer_current); - memcpy (d_buffer + buffer_current, data, n); - - buffer_current += n; - if (buffer_current >= buffer_size) - buffer_current = 0; - - data += n; - nbytes -= n; - } - - d_header[HD_BUFFER_CURRENT] = buffer_current; - return true; -} - -int -gr_circular_file::read (void *vdata, int nbytes) -{ - unsigned char *data = (unsigned char *) vdata; - int buffer_current = d_header[HD_BUFFER_CURRENT]; - int buffer_size = d_header[HD_BUFFER_SIZE]; - int total = 0; - - nbytes = std::min (nbytes, buffer_size - d_bytes_read); - - while (nbytes > 0){ - int offset = (buffer_current + d_bytes_read) % buffer_size; - int n = std::min (nbytes, buffer_size - offset); - memcpy (data, d_buffer + offset, n); - data += n; - d_bytes_read += n; - total += n; - nbytes -= n; - } - return total; -} - -void -gr_circular_file::reset_read_pointer () -{ - d_bytes_read = 0; -} diff --git a/gnuradio-runtime/lib/gr_circular_file.h b/gnuradio-runtime/lib/gr_circular_file.h deleted file mode 100644 index 2b61bf2711..0000000000 --- a/gnuradio-runtime/lib/gr_circular_file.h +++ /dev/null @@ -1,60 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2002 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 _GR_CIRCULAR_FILE_H_ -#define _GR_CIRCULAR_FILE_H_ - -#include <gr_runtime_api.h> - -/* - * writes input data into a circular buffer on disk. - * - * the file contains a fixed header: - * 0x0000: int32 magic (0xEB021026) - * 0x0004: int32 size in bytes of header (constant 4096) - * 0x0008: int32 size in bytes of circular buffer (not including header) - * 0x000C: int32 file offset to beginning of circular buffer - * 0x0010: int32 byte offset from beginning of circular buffer to - * current start of data - * - */ -class GR_RUNTIME_API gr_circular_file { - int d_fd; - int *d_header; - unsigned char *d_buffer; - int d_mapped_size; - int d_bytes_read; - -public: - gr_circular_file (const char *filename, bool writable = false, int size = 0); - ~gr_circular_file (); - - bool write (void *data, int nbytes); - - // returns # of bytes actually read or 0 if end of buffer, or -1 on error. - int read (void *data, int nbytes); - - // reset read pointer to beginning of buffer. - void reset_read_pointer (); -}; - -#endif /* _GR_CIRCULAR_FILE_H_ */
\ No newline at end of file diff --git a/gnuradio-runtime/lib/gr_dispatcher.cc b/gnuradio-runtime/lib/gr_dispatcher.cc deleted file mode 100644 index 96ebe9ad8b..0000000000 --- a/gnuradio-runtime/lib/gr_dispatcher.cc +++ /dev/null @@ -1,193 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_dispatcher.h> -#include <math.h> -#include <errno.h> -#include <stdio.h> - -#ifdef HAVE_SELECT -# ifdef HAVE_SYS_SELECT_H -# include <sys/select.h> -# else -# ifdef HAVE_SYS_TIME_H -# include <sys/time.h> -# endif -# ifdef HAVE_SYS_TYPES_H -# include <sys/types.h> -# endif -# ifdef HAVE_UNISTD_H -# include <unistd.h> -# endif -# endif -#endif - - -static gr_dispatcher_sptr s_singleton; - -gr_dispatcher_sptr -gr_make_dispatcher() -{ - return gr_dispatcher_sptr(new gr_dispatcher()); -} - -gr_dispatcher_sptr -gr_dispatcher_singleton() -{ - if (s_singleton) - return s_singleton; - - s_singleton = gr_make_dispatcher(); - return s_singleton; -} - -#if !defined(HAVE_SELECT) // Stub it out - -gr_dispatcher::gr_dispatcher() -{ -} - -gr_dispatcher::~gr_dispatcher() -{ -} - -bool -gr_dispatcher::add_handler(gr_select_handler_sptr handler) -{ - return true; -} - -bool -gr_dispatcher::del_handler(gr_select_handler_sptr handler) -{ - return true; -} - -bool -gr_dispatcher::del_handler(gr_select_handler *handler) -{ - return true; -} - -void -gr_dispatcher::loop(double timeout) -{ -} - -#else // defined(HAVE_SELECT) - -gr_dispatcher::gr_dispatcher() - : d_handler(FD_SETSIZE), d_max_index(-1) -{ -} - -gr_dispatcher::~gr_dispatcher() -{ -} - -bool -gr_dispatcher::add_handler(gr_select_handler_sptr handler) -{ - int fd = handler->fd(); - if (fd < 0 || fd >= FD_SETSIZE) - return false; - - d_max_index = std::max(d_max_index, fd); - d_handler[fd] = handler; - return true; -} - -bool -gr_dispatcher::del_handler(gr_select_handler_sptr handler) -{ - return del_handler(handler.get()); -} - -bool -gr_dispatcher::del_handler(gr_select_handler *handler) -{ - int fd = handler->fd(); - if (fd < 0 || fd >= FD_SETSIZE) - return false; - - d_handler[fd].reset(); - - if (fd == d_max_index){ - int i; - for (i = fd - 1; i >= 0 && !d_handler[i]; i--) - ; - d_max_index = i; - } - return true; -} - - -void -gr_dispatcher::loop(double timeout) -{ - struct timeval master; - struct timeval tmp; - fd_set rd_set; - fd_set wr_set; - - double secs = floor (timeout); - master.tv_sec = (long) secs; - master.tv_usec = (long) ((timeout - secs) * 1e6); - - while (d_max_index >= 0){ - FD_ZERO(&rd_set); - FD_ZERO(&wr_set); - - for (int i = 0; i <= d_max_index; i++){ - if (d_handler[i] && d_handler[i]->readable()) - FD_SET(i, &rd_set); - if (d_handler[i] && d_handler[i]->writable()) - FD_SET(i, &wr_set); - } - - tmp = master; - int retval = select(d_max_index+1, &rd_set, &wr_set, 0, &tmp); - if (retval == 0) // timed out with nothing ready - continue; - if (retval < 0){ - if (errno == EINTR) - continue; - perror ("gr_dispatcher/select"); - return; - } - - for (int i = 0; i <= d_max_index; i++){ - if (FD_ISSET(i, &rd_set)) - if (d_handler[i]) - d_handler[i]->handle_read(); - if (FD_ISSET(i, &wr_set)) - if (d_handler[i]) - d_handler[i]->handle_write(); - } - } -} - -#endif diff --git a/gnuradio-runtime/lib/gr_error_handler.cc b/gnuradio-runtime/lib/gr_error_handler.cc deleted file mode 100644 index 448682966e..0000000000 --- a/gnuradio-runtime/lib/gr_error_handler.cc +++ /dev/null @@ -1,244 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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. - */ -/* - * This code is based on error.cc from the "Click Modular Router". - * Original copyright follows: - */ -/* - * error.{cc,hh} -- flexible classes for error reporting - * Eddie Kohler - * - * Copyright (c) 1999-2000 Massachusetts Institute of Technology - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), - * to deal in the Software without restriction, subject to the conditions - * listed in the Click LICENSE file. These conditions include: you must - * preserve this copyright notice, and you cannot mention the copyright - * holders in advertising related to the Software without their permission. - * The Software is provided WITHOUT ANY WARRANTY, EXPRESS OR IMPLIED. This - * notice is a summary of the Click LICENSE file; the license in that file is - * legally binding. - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gr_error_handler.h> -#include <assert.h> -#include <stdexcept> -#include <unistd.h> - -#ifdef HAVE_IO_H -#include <io.h> -#endif - -static gr_error_handler *s_default_handler = 0; -static gr_error_handler *s_silent_handler = 0; - -bool -gr_error_handler::has_default_handler() -{ - return s_default_handler != 0; -} - -void -gr_error_handler::set_default_handler(gr_error_handler *errh) -{ - s_default_handler = errh; -} - -gr_error_handler * -gr_error_handler::default_handler() -{ - assert (s_default_handler != 0); - return s_default_handler; -} - -gr_error_handler * -gr_error_handler::silent_handler() -{ - assert (s_silent_handler != 0); - return s_silent_handler; -} - -// ---------------------------------------------------------------- - -gr_error_handler::~gr_error_handler() -{ - // nop -} - -void -gr_error_handler::debug(const char *format, ...) -{ - va_list val; - va_start(val, format); - verror(ERR_DEBUG, format, val); - va_end(val); -} - -void -gr_error_handler::message(const char *format, ...) -{ - va_list val; - va_start(val, format); - verror(ERR_MESSAGE, format, val); - va_end(val); -} - -void -gr_error_handler::warning(const char *format, ...) -{ - va_list val; - va_start(val, format); - verror(ERR_WARNING, format, val); - va_end(val); -} - -void -gr_error_handler::error(const char *format, ...) -{ - va_list val; - va_start(val, format); - verror(ERR_ERROR, format, val); - va_end(val); -} - -void -gr_error_handler::fatal(const char *format, ...) -{ - va_list val; - va_start(val, format); - verror(ERR_FATAL, format, val); - va_end(val); -} - -void -gr_error_handler::verror(seriousness s, const char *format, va_list val) -{ - std::string text = make_text(s, format, val); - handle_text(s, text); - count_error(s); -} - -void -gr_error_handler::verror_text(seriousness s, const std::string &text) -{ - // text is already made - handle_text(s, text); - count_error(s); -} - -std::string -gr_error_handler::make_text(seriousness s, const char *format, va_list val) -{ - char text_buf[4096]; - vsnprintf(text_buf, sizeof(text_buf), format, val); - text_buf[sizeof(text_buf)-1] = 0; - return text_buf; -} - -// ---------------------------------------------------------------- - -void -gr_base_error_handler::count_error(seriousness s) -{ - if (s < ERR_WARNING) - /* do nothing */; - else if (s < ERR_ERROR) - d_nwarnings++; - else - d_nerrors++; -} - -// ---------------------------------------------------------------- - -gr_file_error_handler::gr_file_error_handler(FILE *file) - : d_file(file), d_fd(-1) -{ -} - -gr_file_error_handler::gr_file_error_handler(int file_descriptor) -{ - d_fd = dup(file_descriptor); // so we can fclose it - if (d_fd == -1){ - perror("gr_file_error_handler:dup"); - throw std::invalid_argument("gr_file_error_handler:dup"); - } - d_file = fdopen(d_fd, "w"); - if (d_file == 0){ - perror("gr_file_error_handler:fdopen"); - throw std::invalid_argument("gr_file_error_handler:fdopen"); - } -} - -gr_file_error_handler::~gr_file_error_handler() -{ - if (d_fd != -1){ - fclose(d_file); - } -} - -void -gr_file_error_handler::handle_text(seriousness s, const std::string &text) -{ - if (text.length() <= 0) - return; - - fwrite(text.data(), 1, text.length(), d_file); - if (text[text.length()-1] != '\n') - fwrite("\n", 1, 1, d_file); - - if (d_fd != -1) - fflush(d_file); // keep synced with any other users of fd -} - - -// ---------------------------------------------------------------- -// static error handlers -// - -class gr_silent_error_handler : public gr_base_error_handler -{ -public: - gr_silent_error_handler() {} - void handle_text(seriousness s, const std::string &str); -}; - -void -gr_silent_error_handler::handle_text(seriousness s, const std::string &str) -{ - // nop -} - -class force_init { -public: - force_init() - { - s_default_handler = new gr_file_error_handler(stdout); - s_silent_handler = new gr_silent_error_handler(); - } -}; - -static force_init kludge; diff --git a/gnuradio-runtime/lib/gr_fast_atan2f.cc b/gnuradio-runtime/lib/gr_fast_atan2f.cc deleted file mode 100644 index 8b7bfea12e..0000000000 --- a/gnuradio-runtime/lib/gr_fast_atan2f.cc +++ /dev/null @@ -1,199 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_math.h> // declaration is in here -#include <cmath> - -#define REAL float - -/***************************************************************************/ -/* Constant definitions */ -/***************************************************************************/ - -#define TAN_MAP_RES 0.003921569 /* (smallest non-zero value in table) */ -#define RAD_PER_DEG 0.017453293 -#define TAN_MAP_SIZE 256 - -/* arctangents from 0 to pi/4 radians */ -static REAL -fast_atan_table[257] = { - 0.000000e+00, 3.921549e-03, 7.842976e-03, 1.176416e-02, - 1.568499e-02, 1.960533e-02, 2.352507e-02, 2.744409e-02, - 3.136226e-02, 3.527947e-02, 3.919560e-02, 4.311053e-02, - 4.702413e-02, 5.093629e-02, 5.484690e-02, 5.875582e-02, - 6.266295e-02, 6.656816e-02, 7.047134e-02, 7.437238e-02, - 7.827114e-02, 8.216752e-02, 8.606141e-02, 8.995267e-02, - 9.384121e-02, 9.772691e-02, 1.016096e-01, 1.054893e-01, - 1.093658e-01, 1.132390e-01, 1.171087e-01, 1.209750e-01, - 1.248376e-01, 1.286965e-01, 1.325515e-01, 1.364026e-01, - 1.402496e-01, 1.440924e-01, 1.479310e-01, 1.517652e-01, - 1.555948e-01, 1.594199e-01, 1.632403e-01, 1.670559e-01, - 1.708665e-01, 1.746722e-01, 1.784728e-01, 1.822681e-01, - 1.860582e-01, 1.898428e-01, 1.936220e-01, 1.973956e-01, - 2.011634e-01, 2.049255e-01, 2.086818e-01, 2.124320e-01, - 2.161762e-01, 2.199143e-01, 2.236461e-01, 2.273716e-01, - 2.310907e-01, 2.348033e-01, 2.385093e-01, 2.422086e-01, - 2.459012e-01, 2.495869e-01, 2.532658e-01, 2.569376e-01, - 2.606024e-01, 2.642600e-01, 2.679104e-01, 2.715535e-01, - 2.751892e-01, 2.788175e-01, 2.824383e-01, 2.860514e-01, - 2.896569e-01, 2.932547e-01, 2.968447e-01, 3.004268e-01, - 3.040009e-01, 3.075671e-01, 3.111252e-01, 3.146752e-01, - 3.182170e-01, 3.217506e-01, 3.252758e-01, 3.287927e-01, - 3.323012e-01, 3.358012e-01, 3.392926e-01, 3.427755e-01, - 3.462497e-01, 3.497153e-01, 3.531721e-01, 3.566201e-01, - 3.600593e-01, 3.634896e-01, 3.669110e-01, 3.703234e-01, - 3.737268e-01, 3.771211e-01, 3.805064e-01, 3.838825e-01, - 3.872494e-01, 3.906070e-01, 3.939555e-01, 3.972946e-01, - 4.006244e-01, 4.039448e-01, 4.072558e-01, 4.105574e-01, - 4.138496e-01, 4.171322e-01, 4.204054e-01, 4.236689e-01, - 4.269229e-01, 4.301673e-01, 4.334021e-01, 4.366272e-01, - 4.398426e-01, 4.430483e-01, 4.462443e-01, 4.494306e-01, - 4.526070e-01, 4.557738e-01, 4.589307e-01, 4.620778e-01, - 4.652150e-01, 4.683424e-01, 4.714600e-01, 4.745676e-01, - 4.776654e-01, 4.807532e-01, 4.838312e-01, 4.868992e-01, - 4.899573e-01, 4.930055e-01, 4.960437e-01, 4.990719e-01, - 5.020902e-01, 5.050985e-01, 5.080968e-01, 5.110852e-01, - 5.140636e-01, 5.170320e-01, 5.199904e-01, 5.229388e-01, - 5.258772e-01, 5.288056e-01, 5.317241e-01, 5.346325e-01, - 5.375310e-01, 5.404195e-01, 5.432980e-01, 5.461666e-01, - 5.490251e-01, 5.518738e-01, 5.547124e-01, 5.575411e-01, - 5.603599e-01, 5.631687e-01, 5.659676e-01, 5.687566e-01, - 5.715357e-01, 5.743048e-01, 5.770641e-01, 5.798135e-01, - 5.825531e-01, 5.852828e-01, 5.880026e-01, 5.907126e-01, - 5.934128e-01, 5.961032e-01, 5.987839e-01, 6.014547e-01, - 6.041158e-01, 6.067672e-01, 6.094088e-01, 6.120407e-01, - 6.146630e-01, 6.172755e-01, 6.198784e-01, 6.224717e-01, - 6.250554e-01, 6.276294e-01, 6.301939e-01, 6.327488e-01, - 6.352942e-01, 6.378301e-01, 6.403565e-01, 6.428734e-01, - 6.453808e-01, 6.478788e-01, 6.503674e-01, 6.528466e-01, - 6.553165e-01, 6.577770e-01, 6.602282e-01, 6.626701e-01, - 6.651027e-01, 6.675261e-01, 6.699402e-01, 6.723452e-01, - 6.747409e-01, 6.771276e-01, 6.795051e-01, 6.818735e-01, - 6.842328e-01, 6.865831e-01, 6.889244e-01, 6.912567e-01, - 6.935800e-01, 6.958943e-01, 6.981998e-01, 7.004964e-01, - 7.027841e-01, 7.050630e-01, 7.073330e-01, 7.095943e-01, - 7.118469e-01, 7.140907e-01, 7.163258e-01, 7.185523e-01, - 7.207701e-01, 7.229794e-01, 7.251800e-01, 7.273721e-01, - 7.295557e-01, 7.317307e-01, 7.338974e-01, 7.360555e-01, - 7.382053e-01, 7.403467e-01, 7.424797e-01, 7.446045e-01, - 7.467209e-01, 7.488291e-01, 7.509291e-01, 7.530208e-01, - 7.551044e-01, 7.571798e-01, 7.592472e-01, 7.613064e-01, - 7.633576e-01, 7.654008e-01, 7.674360e-01, 7.694633e-01, - 7.714826e-01, 7.734940e-01, 7.754975e-01, 7.774932e-01, - 7.794811e-01, 7.814612e-01, 7.834335e-01, 7.853983e-01, - 7.853983e-01 - }; - - -/***************************************************************************** -Function: Arc tangent - -Syntax: angle = fast_atan2(y, x); -REAL y y component of input vector -REAL x x component of input vector -REAL angle angle of vector (x, y) in radians - -Description: This function calculates the angle of the vector (x,y) based -on a table lookup and linear interpolation. The table uses -a 256 point table covering -45 to +45 degrees and uses -symetry to determine the final angle value in the range of --180 to 180 degrees. Note that this function uses the small -angle approximation for values close to zero. This routine -calculates the arc tangent with an average error of -+/- 0.045 degrees. -*****************************************************************************/ - -REAL -gr_fast_atan2f(REAL y, REAL x) -{ - REAL x_abs, y_abs, z; - REAL alpha, angle, base_angle; - int index; - - /* don't divide by zero! */ // FIXME could get hosed with -0.0 - if ((y == 0.0) && (x == 0.0)) - return 0.0; - - /* normalize to +/- 45 degree range */ - y_abs = fabs(y); - x_abs = fabs(x); - //z = (y_abs < x_abs ? y_abs / x_abs : x_abs / y_abs); - if (y_abs < x_abs) - z = y_abs / x_abs; - else - z = x_abs / y_abs; - - /* when ratio approaches the table resolution, the angle is */ - /* best approximated with the argument itself... */ - if (z < TAN_MAP_RES) - base_angle = z; - else { - /* find index and interpolation value */ - alpha = z * (REAL) TAN_MAP_SIZE - .5; - index = (int) alpha; - alpha -= (REAL) index; - /* determine base angle based on quadrant and */ - /* add or subtract table value from base angle based on quadrant */ - base_angle = fast_atan_table[index]; - base_angle += - (fast_atan_table[index + 1] - fast_atan_table[index]) * alpha; - } - - if (x_abs > y_abs) { /* -45 -> 45 or 135 -> 225 */ - if (x >= 0.0) { /* -45 -> 45 */ - if (y >= 0.0) - angle = base_angle; /* 0 -> 45, angle OK */ - else - angle = -base_angle; /* -45 -> 0, angle = -angle */ - } else { /* 135 -> 180 or 180 -> -135 */ - angle = 3.14159265358979323846; - if (y >= 0.0) - angle -= base_angle; /* 135 -> 180, angle = 180 - angle */ - else - angle = base_angle - angle; /* 180 -> -135, angle = angle - 180 */ - } - } else { /* 45 -> 135 or -135 -> -45 */ - if (y >= 0.0) { /* 45 -> 135 */ - angle = 1.57079632679489661923; - if (x >= 0.0) - angle -= base_angle; /* 45 -> 90, angle = 90 - angle */ - else - angle += base_angle; /* 90 -> 135, angle = 90 + angle */ - } else { /* -135 -> -45 */ - angle = -1.57079632679489661923; - if (x >= 0.0) - angle += base_angle; /* -90 -> -45, angle = -90 + angle */ - else - angle -= base_angle; /* -135 -> -90, angle = -90 - angle */ - } - } - -#ifdef ZERO_TO_TWOPI - if (angle < 0) - return (angle + TWOPI); - else - return (angle); -#else - return (angle); -#endif -} - diff --git a/gnuradio-runtime/lib/gr_feval.cc b/gnuradio-runtime/lib/gr_feval.cc deleted file mode 100644 index 89f09984cf..0000000000 --- a/gnuradio-runtime/lib/gr_feval.cc +++ /dev/null @@ -1,132 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_feval.h> - -gr_feval_dd::~gr_feval_dd(){} - -double -gr_feval_dd::eval(double x) -{ - return 0; -} - -double -gr_feval_dd::calleval(double x) -{ - return eval(x); -} - -// ---------------------------------------------------------------- - -gr_feval_cc::~gr_feval_cc(){} - -gr_complex -gr_feval_cc::eval(gr_complex x) -{ - return 0; -} - -gr_complex -gr_feval_cc::calleval(gr_complex x) -{ - return eval(x); -} - -// ---------------------------------------------------------------- - -gr_feval_ll::~gr_feval_ll(){} - -long -gr_feval_ll::eval(long x) -{ - return 0; -} - -long -gr_feval_ll::calleval(long x) -{ - return eval(x); -} - -// ---------------------------------------------------------------- - -gr_feval::~gr_feval(){} - -void -gr_feval::eval(void) -{ - // nop -} - -void -gr_feval::calleval(void) -{ - eval(); -} - -// ---------------------------------------------------------------- - -gr_feval_p::~gr_feval_p(){} - -void -gr_feval_p::eval(pmt::pmt_t x) -{ - // nop -} - -void -gr_feval_p::calleval(pmt::pmt_t x) -{ - eval(x); -} - -/* - * Trivial examples showing C++ (transparently) calling Python - */ -double -gr_feval_dd_example(gr_feval_dd *f, double x) -{ - return f->calleval(x); -} - -gr_complex -gr_feval_cc_example(gr_feval_cc *f, gr_complex x) -{ - return f->calleval(x); -} - -long -gr_feval_ll_example(gr_feval_ll *f, long x) -{ - return f->calleval(x); -} - -void -gr_feval_example(gr_feval *f) -{ - f->calleval(); -} diff --git a/gnuradio-runtime/lib/gr_flat_flowgraph.cc b/gnuradio-runtime/lib/gr_flat_flowgraph.cc deleted file mode 100644 index de1e227ef0..0000000000 --- a/gnuradio-runtime/lib/gr_flat_flowgraph.cc +++ /dev/null @@ -1,427 +0,0 @@ -/* -*- 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_flat_flowgraph.h> -#include <gr_block_detail.h> -#include <gr_io_signature.h> -#include <gr_buffer.h> -#include <gr_prefs.h> -#include <volk/volk.h> -#include <iostream> -#include <map> -#include <boost/format.hpp> - -#define GR_FLAT_FLOWGRAPH_DEBUG 0 - -// 32Kbyte buffer size between blocks -#define GR_FIXED_BUFFER_SIZE (32*(1L<<10)) - -static const unsigned int s_fixed_buffer_size = GR_FIXED_BUFFER_SIZE; - -gr_flat_flowgraph_sptr -gr_make_flat_flowgraph() -{ - return gr_flat_flowgraph_sptr(new gr_flat_flowgraph()); -} - -gr_flat_flowgraph::gr_flat_flowgraph() -{ -} - -gr_flat_flowgraph::~gr_flat_flowgraph() -{ -} - -void -gr_flat_flowgraph::setup_connections() -{ - gr_basic_block_vector_t blocks = calc_used_blocks(); - - // Assign block details to blocks - for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) - cast_to_block_sptr(*p)->set_detail(allocate_block_detail(*p)); - - // Connect inputs to outputs for each block - for(gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { - connect_block_inputs(*p); - - gr_block_sptr block = cast_to_block_sptr(*p); - block->set_unaligned(0); - block->set_is_unaligned(false); - } - - // Connect message ports connetions - for(gr_msg_edge_viter_t i = d_msg_edges.begin(); i != d_msg_edges.end(); i++){ - if(GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << boost::format("flat_fg connecting msg primitives: (%s, %s)->(%s, %s)\n") % - i->src().block() % i->src().port() % - i->dst().block() % i->dst().port(); - i->src().block()->message_port_sub( i->src().port(), pmt::cons(i->dst().block()->alias_pmt(), i->dst().port()) ); - } - -} - -gr_block_detail_sptr -gr_flat_flowgraph::allocate_block_detail(gr_basic_block_sptr block) -{ - int ninputs = calc_used_ports(block, true).size(); - int noutputs = calc_used_ports(block, false).size(); - gr_block_detail_sptr detail = gr_make_block_detail(ninputs, noutputs); - - gr_block_sptr grblock = cast_to_block_sptr(block); - if(!grblock) - throw std::runtime_error("allocate_block_detail found non-gr_block"); - - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "Creating block detail for " << block << std::endl; - - for (int i = 0; i < noutputs; i++) { - grblock->expand_minmax_buffer(i); - - gr_buffer_sptr buffer = allocate_buffer(block, i); - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "Allocated buffer for output " << block << ":" << i << std::endl; - detail->set_output(i, buffer); - - // Update the block's max_output_buffer based on what was actually allocated. - grblock->set_max_output_buffer(i, buffer->bufsize()); - } - - return detail; -} - -gr_buffer_sptr -gr_flat_flowgraph::allocate_buffer(gr_basic_block_sptr block, int port) -{ - gr_block_sptr grblock = cast_to_block_sptr(block); - if (!grblock) - throw std::runtime_error("allocate_buffer found non-gr_block"); - int item_size = block->output_signature()->sizeof_stream_item(port); - - // *2 because we're now only filling them 1/2 way in order to - // increase the available parallelism when using the TPB scheduler. - // (We're double buffering, where we used to single buffer) - int nitems = s_fixed_buffer_size * 2 / item_size; - - // Make sure there are at least twice the output_multiple no. of items - if (nitems < 2*grblock->output_multiple()) // Note: this means output_multiple() - nitems = 2*grblock->output_multiple(); // can't be changed by block dynamically - - // If any downstream blocks are decimators and/or have a large output_multiple, - // ensure we have a buffer at least twice their decimation factor*output_multiple - gr_basic_block_vector_t blocks = calc_downstream_blocks(block, port); - - // limit buffer size if indicated - if(grblock->max_output_buffer(port) > 0) { -// std::cout << "constraining output items to " << block->max_output_buffer(port) << "\n"; - nitems = std::min((long)nitems, (long)grblock->max_output_buffer(port)); - nitems -= nitems%grblock->output_multiple(); - if( nitems < 1 ) - throw std::runtime_error("problems allocating a buffer with the given max output buffer constraint!"); - } - else if(grblock->min_output_buffer(port) > 0) { - nitems = std::max((long)nitems, (long)grblock->min_output_buffer(port)); - nitems -= nitems%grblock->output_multiple(); - if( nitems < 1 ) - throw std::runtime_error("problems allocating a buffer with the given min output buffer constraint!"); - } - - for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { - gr_block_sptr dgrblock = cast_to_block_sptr(*p); - if (!dgrblock) - throw std::runtime_error("allocate_buffer found non-gr_block"); - - double decimation = (1.0/dgrblock->relative_rate()); - int multiple = dgrblock->output_multiple(); - int history = dgrblock->history(); - nitems = std::max(nitems, static_cast<int>(2*(decimation*multiple+history))); - } - -// std::cout << "gr_make_buffer(" << nitems << ", " << item_size << ", " << grblock << "\n"; - return gr_make_buffer(nitems, item_size, grblock); -} - -void -gr_flat_flowgraph::connect_block_inputs(gr_basic_block_sptr block) -{ - gr_block_sptr grblock = cast_to_block_sptr(block); - if (!grblock) - throw std::runtime_error("connect_block_inputs found non-gr_block"); - - // Get its detail and edges that feed into it - gr_block_detail_sptr detail = grblock->detail(); - gr_edge_vector_t in_edges = calc_upstream_edges(block); - - // For each edge that feeds into it - for (gr_edge_viter_t e = in_edges.begin(); e != in_edges.end(); e++) { - // Set the buffer reader on the destination port to the output - // buffer on the source port - int dst_port = e->dst().port(); - int src_port = e->src().port(); - gr_basic_block_sptr src_block = e->src().block(); - gr_block_sptr src_grblock = cast_to_block_sptr(src_block); - if (!src_grblock) - throw std::runtime_error("connect_block_inputs found non-gr_block"); - gr_buffer_sptr src_buffer = src_grblock->detail()->output(src_port); - - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "Setting input " << dst_port << " from edge " << (*e) << std::endl; - - detail->set_input(dst_port, gr_buffer_add_reader(src_buffer, grblock->history()-1, grblock)); - } -} - -void -gr_flat_flowgraph::merge_connections(gr_flat_flowgraph_sptr old_ffg) -{ - // Allocate block details if needed. Only new blocks that aren't pruned out - // by flattening will need one; existing blocks still in the new flowgraph will - // already have one. - for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { - gr_block_sptr block = cast_to_block_sptr(*p); - - if (!block->detail()) { - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "merge: allocating new detail for block " << (*p) << std::endl; - block->set_detail(allocate_block_detail(block)); - } - else - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "merge: reusing original detail for block " << (*p) << std::endl; - } - - // Calculate the old edges that will be going away, and clear the buffer readers - // on the RHS. - for (gr_edge_viter_t old_edge = old_ffg->d_edges.begin(); old_edge != old_ffg->d_edges.end(); old_edge++) { - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "merge: testing old edge " << (*old_edge) << "..."; - - gr_edge_viter_t new_edge; - for (new_edge = d_edges.begin(); new_edge != d_edges.end(); new_edge++) - if (new_edge->src() == old_edge->src() && - new_edge->dst() == old_edge->dst()) - break; - - if (new_edge == d_edges.end()) { // not found in new edge list - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "not in new edge list" << std::endl; - // zero the buffer reader on RHS of old edge - gr_block_sptr block(cast_to_block_sptr(old_edge->dst().block())); - int port = old_edge->dst().port(); - block->detail()->set_input(port, gr_buffer_reader_sptr()); - } - else { - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "found in new edge list" << std::endl; - } - } - - // Now connect inputs to outputs, reusing old buffer readers if they exist - for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { - gr_block_sptr block = cast_to_block_sptr(*p); - - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "merge: merging " << (*p) << "..."; - - if (old_ffg->has_block_p(*p)) { - // Block exists in old flow graph - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "used in old flow graph" << std::endl; - gr_block_detail_sptr detail = block->detail(); - - // Iterate through the inputs and see what needs to be done - int ninputs = calc_used_ports(block, true).size(); // Might be different now - for (int i = 0; i < ninputs; i++) { - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "Checking input " << block << ":" << i << "..."; - gr_edge edge = calc_upstream_edge(*p, i); - - // Fish out old buffer reader and see if it matches correct buffer from edge list - gr_block_sptr src_block = cast_to_block_sptr(edge.src().block()); - gr_block_detail_sptr src_detail = src_block->detail(); - gr_buffer_sptr src_buffer = src_detail->output(edge.src().port()); - gr_buffer_reader_sptr old_reader; - if (i < detail->ninputs()) // Don't exceed what the original detail has - old_reader = detail->input(i); - - // If there's a match, use it - if (old_reader && (src_buffer == old_reader->buffer())) { - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "matched, reusing" << std::endl; - } - else { - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "needs a new reader" << std::endl; - - // Create new buffer reader and assign - detail->set_input(i, gr_buffer_add_reader(src_buffer, block->history()-1, block)); - } - } - } - else { - // Block is new, it just needs buffer readers at this point - if (GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << "new block" << std::endl; - connect_block_inputs(block); - - // Make sure all buffers are aligned - setup_buffer_alignment(block); - } - - // Now deal with the fact that the block details might have changed numbers of - // inputs and outputs vs. in the old flowgraph. - } -} - -void -gr_flat_flowgraph::setup_buffer_alignment(gr_block_sptr block) -{ - const int alignment = volk_get_alignment(); - for(int i = 0; i < block->detail()->ninputs(); i++) { - void *r = (void*)block->detail()->input(i)->read_pointer(); - unsigned long int ri = (unsigned long int)r % alignment; - //std::cerr << "reader: " << r << " alignment: " << ri << std::endl; - if(ri != 0) { - size_t itemsize = block->detail()->input(i)->get_sizeof_item(); - block->detail()->input(i)->update_read_pointer(alignment-ri/itemsize); - } - block->set_unaligned(0); - block->set_is_unaligned(false); - } - - for(int i = 0; i < block->detail()->noutputs(); i++) { - void *w = (void*)block->detail()->output(i)->write_pointer(); - unsigned long int wi = (unsigned long int)w % alignment; - //std::cerr << "writer: " << w << " alignment: " << wi << std::endl; - if(wi != 0) { - size_t itemsize = block->detail()->output(i)->get_sizeof_item(); - block->detail()->output(i)->update_write_pointer(alignment-wi/itemsize); - } - block->set_unaligned(0); - block->set_is_unaligned(false); - } -} - -std::string -gr_flat_flowgraph::edge_list() -{ - std::stringstream s; - for(gr_edge_viter_t e = d_edges.begin(); e != d_edges.end(); e++) - s << (*e) << std::endl; - return s.str(); -} - -void gr_flat_flowgraph::dump() -{ - for (gr_edge_viter_t e = d_edges.begin(); e != d_edges.end(); e++) - std::cout << " edge: " << (*e) << std::endl; - - for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { - std::cout << " block: " << (*p) << std::endl; - gr_block_detail_sptr detail = cast_to_block_sptr(*p)->detail(); - std::cout << " detail @" << detail << ":" << std::endl; - - int ni = detail->ninputs(); - int no = detail->noutputs(); - for (int i = 0; i < no; i++) { - gr_buffer_sptr buffer = detail->output(i); - std::cout << " output " << i << ": " << buffer << std::endl; - } - - for (int i = 0; i < ni; i++) { - gr_buffer_reader_sptr reader = detail->input(i); - std::cout << " reader " << i << ": " << reader - << " reading from buffer=" << reader->buffer() << std::endl; - } - } - -} - -gr_block_vector_t -gr_flat_flowgraph::make_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(cast_to_block_sptr(*p)); - } - - return result; -} - - -void gr_flat_flowgraph::clear_endpoint(const gr_msg_endpoint &e, bool is_src){ - for(size_t i=0; i<d_msg_edges.size(); i++){ - if(is_src){ - if(d_msg_edges[i].src() == e){ - d_msg_edges.erase(d_msg_edges.begin() + i); - i--; - } - } else { - if(d_msg_edges[i].dst() == e){ - d_msg_edges.erase(d_msg_edges.begin() + i); - i--; - } - } - } -} - -void gr_flat_flowgraph::replace_endpoint(const gr_msg_endpoint &e, const gr_msg_endpoint &r, bool is_src){ - size_t n_replr(0); - if(GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << boost::format("gr_flat_flowgraph::replace_endpoint( %s, %s, %d )\n") % e.block()% r.block()% is_src; - for(size_t i=0; i<d_msg_edges.size(); i++){ - if(is_src){ - if(d_msg_edges[i].src() == e){ - if(GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << boost::format("gr_flat_flowgraph::replace_endpoint() flattening to ( %s, %s )\n") % r.block()% d_msg_edges[i].dst().block(); - d_msg_edges.push_back( gr_msg_edge(r, d_msg_edges[i].dst() ) ); - n_replr++; - } - } else { - if(d_msg_edges[i].dst() == e){ - if(GR_FLAT_FLOWGRAPH_DEBUG) - std::cout << boost::format("gr_flat_flowgraph::replace_endpoint() flattening to ( %s, %s )\n") % r.block()% d_msg_edges[i].dst().block(); - d_msg_edges.push_back( gr_msg_edge(d_msg_edges[i].src(), r ) ); - n_replr++; - } - } - } -} - -void -gr_flat_flowgraph::enable_pc_rpc() -{ -#ifdef GR_PERFORMANCE_COUNTERS - if(gr_prefs::singleton()->get_bool("PerfCounters", "on", false)) { - gr_basic_block_viter_t p; - for(p = d_blocks.begin(); p != d_blocks.end(); p++) { - gr_block_sptr block = cast_to_block_sptr(*p); - if(!block->is_pc_rpc_set()) - block->setup_pc_rpc(); - } - } -#endif /* GR_PERFORMANCE_COUNTERS */ -} diff --git a/gnuradio-runtime/lib/gr_flat_flowgraph.h b/gnuradio-runtime/lib/gr_flat_flowgraph.h deleted file mode 100644 index 9c47a77e23..0000000000 --- a/gnuradio-runtime/lib/gr_flat_flowgraph.h +++ /dev/null @@ -1,89 +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_FLAT_FLOWGRAPH_H -#define INCLUDED_GR_FLAT_FLOWGRAPH_H - -#include <gr_runtime_api.h> -#include <gr_flowgraph.h> -#include <gr_block.h> - -// Create a shared pointer to a heap allocated gr_flat_flowgraph -// (types defined in gr_runtime_types.h) -GR_RUNTIME_API gr_flat_flowgraph_sptr gr_make_flat_flowgraph(); - -/*! - *\brief Class specializing gr_flat_flowgraph that has all nodes - * as gr_blocks, with no hierarchy - * \ingroup internal - */ -class GR_RUNTIME_API gr_flat_flowgraph : public gr_flowgraph -{ -public: - friend GR_RUNTIME_API gr_flat_flowgraph_sptr gr_make_flat_flowgraph(); - - // Destruct an arbitrary gr_flat_flowgraph - ~gr_flat_flowgraph(); - - // Wire gr_blocks together in new flat_flowgraph - void setup_connections(); - - // Merge applicable connections from existing flat flowgraph - void merge_connections(gr_flat_flowgraph_sptr sfg); - - // Return a string list of edges - std::string edge_list(); - - void dump(); - - /*! - * Make a vector of gr_block from a vector of gr_basic_block - */ - static gr_block_vector_t make_block_vector(gr_basic_block_vector_t &blocks); - - void replace_endpoint(const gr_msg_endpoint &e, const gr_msg_endpoint &r, bool is_src); - void clear_endpoint(const gr_msg_endpoint &e, bool is_src); - - /*! - * Enables export of perf. counters to ControlPort on all blocks in - * the flowgraph. - */ - void enable_pc_rpc(); - -private: - gr_flat_flowgraph(); - - gr_block_detail_sptr allocate_block_detail(gr_basic_block_sptr block); - gr_buffer_sptr allocate_buffer(gr_basic_block_sptr block, int port); - void connect_block_inputs(gr_basic_block_sptr block); - - /* When reusing a flowgraph's blocks, this call makes sure all of the - * buffer's are aligned at the machine's alignment boundary and tells - * the blocks that they are aligned. - * - * Called from both setup_connections and merge_connections for - * start and restarts. - */ - void setup_buffer_alignment(gr_block_sptr block); -}; - -#endif /* INCLUDED_GR_FLAT_FLOWGRAPH_H */ diff --git a/gnuradio-runtime/lib/gr_flowgraph.cc b/gnuradio-runtime/lib/gr_flowgraph.cc deleted file mode 100644 index 28cd693171..0000000000 --- a/gnuradio-runtime/lib/gr_flowgraph.cc +++ /dev/null @@ -1,514 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007,2011 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_flowgraph.h> -#include <gr_io_signature.h> -#include <stdexcept> -#include <sstream> -#include <iterator> - -#define GR_FLOWGRAPH_DEBUG 0 - -gr_edge::~gr_edge() -{ -} - -gr_flowgraph_sptr gr_make_flowgraph() -{ - return gr_flowgraph_sptr(new gr_flowgraph()); -} - -gr_flowgraph::gr_flowgraph() -{ -} - -gr_flowgraph::~gr_flowgraph() -{ -} - -template<class T> -static -std::vector<T> -unique_vector(std::vector<T> v) -{ - std::vector<T> result; - std::insert_iterator<std::vector<T> > inserter(result, result.begin()); - - sort(v.begin(), v.end()); - unique_copy(v.begin(), v.end(), inserter); - return result; -} - -void -gr_flowgraph::connect(const gr_endpoint &src, const gr_endpoint &dst) -{ - check_valid_port(src.block()->output_signature(), src.port()); - check_valid_port(dst.block()->input_signature(), dst.port()); - check_dst_not_used(dst); - check_type_match(src, dst); - - // All ist klar, Herr Kommisar - d_edges.push_back(gr_edge(src,dst)); -} - -void -gr_flowgraph::disconnect(const gr_endpoint &src, const gr_endpoint &dst) -{ - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { - if (src == p->src() && dst == p->dst()) { - d_edges.erase(p); - return; - } - } - - std::stringstream msg; - msg << "cannot disconnect edge " << gr_edge(src, dst) << ", not found"; - throw std::invalid_argument(msg.str()); -} - -void -gr_flowgraph::validate() -{ - d_blocks = calc_used_blocks(); - - for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { - std::vector<int> used_ports; - int ninputs, noutputs; - - if (GR_FLOWGRAPH_DEBUG) - std::cout << "Validating block: " << (*p) << std::endl; - - used_ports = calc_used_ports(*p, true); // inputs - ninputs = used_ports.size(); - check_contiguity(*p, used_ports, true); // inputs - - used_ports = calc_used_ports(*p, false); // outputs - noutputs = used_ports.size(); - check_contiguity(*p, used_ports, false); // outputs - - if (!((*p)->check_topology(ninputs, noutputs))) { - std::stringstream msg; - msg << "check topology failed on " << (*p) - << " using ninputs=" << ninputs - << ", noutputs=" << noutputs; - throw std::runtime_error(msg.str()); - } - } -} - -void -gr_flowgraph::clear() -{ - // Boost shared pointers will deallocate as needed - d_blocks.clear(); - d_edges.clear(); -} - -void -gr_flowgraph::check_valid_port(gr_io_signature_sptr sig, int port) -{ - std::stringstream msg; - - if (port < 0) { - msg << "negative port number " << port << " is invalid"; - throw std::invalid_argument(msg.str()); - } - - int max = sig->max_streams(); - if (max != gr_io_signature::IO_INFINITE && port >= max) { - msg << "port number " << port << " exceeds max of "; - if (max == 0) - msg << "(none)"; - else - msg << max-1; - throw std::invalid_argument(msg.str()); - } -} - -void -gr_flowgraph::check_valid_port(const gr_msg_endpoint &e) -{ - if (GR_FLOWGRAPH_DEBUG) - std::cout << "check_valid_port( " << e.block() << ", " << e.port() << ")\n"; - - if(!e.block()->has_msg_port(e.port())) - throw std::invalid_argument("invalid msg port in connect() or disconnect()"); -} - -void -gr_flowgraph::check_dst_not_used(const gr_endpoint &dst) -{ - // A destination is in use if it is already on the edge list - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) - if (p->dst() == dst) { - std::stringstream msg; - msg << "destination already in use by edge " << (*p); - throw std::invalid_argument(msg.str()); - } -} - -void -gr_flowgraph::check_type_match(const gr_endpoint &src, const gr_endpoint &dst) -{ - int src_size = src.block()->output_signature()->sizeof_stream_item(src.port()); - int dst_size = dst.block()->input_signature()->sizeof_stream_item(dst.port()); - - if (src_size != dst_size) { - std::stringstream msg; - msg << "itemsize mismatch: " << src << " using " << src_size - << ", " << dst << " using " << dst_size; - throw std::invalid_argument(msg.str()); - } -} - -gr_basic_block_vector_t -gr_flowgraph::calc_used_blocks() -{ - gr_basic_block_vector_t tmp; - - // make sure free standing message blocks are included - for (gr_msg_edge_viter_t p = d_msg_edges.begin(); p != d_msg_edges.end(); p++) { -// for now only blocks receiving messages get a thread context - uncomment to allow senders to also obtain one -// tmp.push_back(p->src().block()); - tmp.push_back(p->dst().block()); - } - - // Collect all blocks in the edge list - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { - tmp.push_back(p->src().block()); - tmp.push_back(p->dst().block()); - } - - return unique_vector<gr_basic_block_sptr>(tmp); -} - -std::vector<int> -gr_flowgraph::calc_used_ports(gr_basic_block_sptr block, bool check_inputs) -{ - std::vector<int> tmp; - - // Collect all seen ports - gr_edge_vector_t edges = calc_connections(block, check_inputs); - for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) { - if (check_inputs == true) - tmp.push_back(p->dst().port()); - else - tmp.push_back(p->src().port()); - } - - return unique_vector<int>(tmp); -} - -gr_edge_vector_t -gr_flowgraph::calc_connections(gr_basic_block_sptr block, bool check_inputs) -{ - gr_edge_vector_t result; - - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { - if (check_inputs) { - if (p->dst().block() == block) - result.push_back(*p); - } - else { - if (p->src().block() == block) - result.push_back(*p); - } - } - - return result; // assumes no duplicates -} - -void -gr_flowgraph::check_contiguity(gr_basic_block_sptr block, - const std::vector<int> &used_ports, - bool check_inputs) -{ - std::stringstream msg; - - gr_io_signature_sptr sig = - check_inputs ? block->input_signature() : block->output_signature(); - - int nports = used_ports.size(); - int min_ports = sig->min_streams(); - int max_ports = sig->max_streams(); - - if (nports == 0 && min_ports == 0) - return; - - if (nports < min_ports) { - msg << block << ": insufficient connected " - << (check_inputs ? "input ports " : "output ports ") - << "(" << min_ports << " needed, " << nports << " connected)"; - throw std::runtime_error(msg.str()); - } - - if (nports > max_ports && max_ports != gr_io_signature::IO_INFINITE) { - msg << block << ": too many connected " - << (check_inputs ? "input ports " : "output ports ") - << "(" << max_ports << " allowed, " << nports << " connected)"; - throw std::runtime_error(msg.str()); - } - - if (used_ports[nports-1]+1 != nports) { - for (int i = 0; i < nports; i++) { - if (used_ports[i] != i) { - msg << block << ": missing connection " - << (check_inputs ? "to input port " : "from output port ") - << i; - throw std::runtime_error(msg.str()); - } - } - } -} - -gr_basic_block_vector_t -gr_flowgraph::calc_downstream_blocks(gr_basic_block_sptr block, int port) -{ - gr_basic_block_vector_t tmp; - - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) - if (p->src() == gr_endpoint(block, port)) - tmp.push_back(p->dst().block()); - - return unique_vector<gr_basic_block_sptr>(tmp); -} - -gr_basic_block_vector_t -gr_flowgraph::calc_downstream_blocks(gr_basic_block_sptr block) -{ - gr_basic_block_vector_t tmp; - - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) - if (p->src().block() == block) - tmp.push_back(p->dst().block()); - - return unique_vector<gr_basic_block_sptr>(tmp); -} - -gr_edge_vector_t -gr_flowgraph::calc_upstream_edges(gr_basic_block_sptr block) -{ - gr_edge_vector_t result; - - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) - if (p->dst().block() == block) - result.push_back(*p); - - return result; // Assume no duplicates -} - -bool -gr_flowgraph::has_block_p(gr_basic_block_sptr block) -{ - gr_basic_block_viter_t result; - result = std::find(d_blocks.begin(), d_blocks.end(), block); - return (result != d_blocks.end()); -} - -gr_edge -gr_flowgraph::calc_upstream_edge(gr_basic_block_sptr block, int port) -{ - gr_edge result; - - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { - if (p->dst() == gr_endpoint(block, port)) { - result = (*p); - break; - } - } - - return result; -} - -std::vector<gr_basic_block_vector_t> -gr_flowgraph::partition() -{ - std::vector<gr_basic_block_vector_t> result; - gr_basic_block_vector_t blocks = calc_used_blocks(); - gr_basic_block_vector_t graph; - - while (blocks.size() > 0) { - graph = calc_reachable_blocks(blocks[0], blocks); - assert(graph.size()); - result.push_back(topological_sort(graph)); - - for (gr_basic_block_viter_t p = graph.begin(); p != graph.end(); p++) - blocks.erase(find(blocks.begin(), blocks.end(), *p)); - } - - return result; -} - -gr_basic_block_vector_t -gr_flowgraph::calc_reachable_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks) -{ - gr_basic_block_vector_t result; - - // Mark all blocks as unvisited - for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) - (*p)->set_color(gr_basic_block::WHITE); - - // Recursively mark all reachable blocks - reachable_dfs_visit(block, blocks); - - // Collect all the blocks that have been visited - for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) - if ((*p)->color() == gr_basic_block::BLACK) - result.push_back(*p); - - return result; -} - -// Recursively mark all reachable blocks from given block and block list -void -gr_flowgraph::reachable_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks) -{ - // Mark the current one as visited - block->set_color(gr_basic_block::BLACK); - - // Recurse into adjacent vertices - gr_basic_block_vector_t adjacent = calc_adjacent_blocks(block, blocks); - - for (gr_basic_block_viter_t p = adjacent.begin(); p != adjacent.end(); p++) - if ((*p)->color() == gr_basic_block::WHITE) - reachable_dfs_visit(*p, blocks); -} - -// Return a list of block adjacent to a given block along any edge -gr_basic_block_vector_t -gr_flowgraph::calc_adjacent_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks) -{ - gr_basic_block_vector_t tmp; - - // Find any blocks that are inputs or outputs - for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) { - if (p->src().block() == block) - tmp.push_back(p->dst().block()); - if (p->dst().block() == block) - tmp.push_back(p->src().block()); - } - - return unique_vector<gr_basic_block_sptr>(tmp); -} - -gr_basic_block_vector_t -gr_flowgraph::topological_sort(gr_basic_block_vector_t &blocks) -{ - gr_basic_block_vector_t tmp; - gr_basic_block_vector_t result; - tmp = sort_sources_first(blocks); - - // Start 'em all white - for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) - (*p)->set_color(gr_basic_block::WHITE); - - for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) { - if ((*p)->color() == gr_basic_block::WHITE) - topological_dfs_visit(*p, result); - } - - reverse(result.begin(), result.end()); - return result; -} - -gr_basic_block_vector_t -gr_flowgraph::sort_sources_first(gr_basic_block_vector_t &blocks) -{ - gr_basic_block_vector_t sources, nonsources, result; - - for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { - if (source_p(*p)) - sources.push_back(*p); - else - nonsources.push_back(*p); - } - - for (gr_basic_block_viter_t p = sources.begin(); p != sources.end(); p++) - result.push_back(*p); - - for (gr_basic_block_viter_t p = nonsources.begin(); p != nonsources.end(); p++) - result.push_back(*p); - - return result; -} - -bool -gr_flowgraph::source_p(gr_basic_block_sptr block) -{ - return (calc_upstream_edges(block).size() == 0); -} - -void -gr_flowgraph::topological_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &output) -{ - block->set_color(gr_basic_block::GREY); - gr_basic_block_vector_t blocks(calc_downstream_blocks(block)); - - for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { - switch ((*p)->color()) { - case gr_basic_block::WHITE: - topological_dfs_visit(*p, output); - break; - - case gr_basic_block::GREY: - throw std::runtime_error("flow graph has loops!"); - - case gr_basic_block::BLACK: - continue; - - default: - throw std::runtime_error("invalid color on block!"); - } - } - - block->set_color(gr_basic_block::BLACK); - output.push_back(block); -} - -void gr_flowgraph::connect(const gr_msg_endpoint &src, const gr_msg_endpoint &dst){ - check_valid_port(src); - check_valid_port(dst); - for (gr_msg_edge_viter_t p = d_msg_edges.begin(); p != d_msg_edges.end(); p++) { - if(p->src() == src && p->dst() == dst){ - throw std::runtime_error("connect called on already connected edge!"); - } - } - d_msg_edges.push_back(gr_msg_edge(src,dst)); -} - -void gr_flowgraph::disconnect(const gr_msg_endpoint &src, const gr_msg_endpoint &dst){ - check_valid_port(src); - check_valid_port(dst); - for (gr_msg_edge_viter_t p = d_msg_edges.begin(); p != d_msg_edges.end(); p++) { - if(p->src() == src && p->dst() == dst){ - d_msg_edges.erase(p); - return; - } - } - throw std::runtime_error("disconnect called on non-connected edge!"); -} - - diff --git a/gnuradio-runtime/lib/gr_hier_block2.cc b/gnuradio-runtime/lib/gr_hier_block2.cc deleted file mode 100644 index 9e924fdaf5..0000000000 --- a/gnuradio-runtime/lib/gr_hier_block2.cc +++ /dev/null @@ -1,153 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2007,2008 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_hier_block2.h> -#include <gr_io_signature.h> -#include <gr_hier_block2_detail.h> -#include <iostream> - -#define GR_HIER_BLOCK2_DEBUG 0 - - -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 gnuradio::get_initial_sptr(new gr_hier_block2(name, input_signature, output_signature)); -} - -gr_hier_block2::gr_hier_block2(const std::string &name, - gr_io_signature_sptr input_signature, - gr_io_signature_sptr output_signature) - : gr_basic_block(name, input_signature, output_signature), - d_detail(new gr_hier_block2_detail(this)), - hier_message_ports_in(pmt::PMT_NIL), - hier_message_ports_out(pmt::PMT_NIL) -{ - // This bit of magic ensures that self() works in the constructors of derived classes. - gnuradio::detail::sptr_magic::create_and_stash_initial_sptr(this); -} - -gr_hier_block2::~gr_hier_block2() -{ - delete d_detail; -} - -gr_hier_block2::opaque_self -gr_hier_block2::self() -{ - return shared_from_this(); -} - -gr_hier_block2_sptr -gr_hier_block2::to_hier_block2() -{ - return cast_to_hier_block2_sptr(shared_from_this()); -} - -void -gr_hier_block2::connect(gr_basic_block_sptr block) -{ - d_detail->connect(block); -} - -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); -} - -void -gr_hier_block2::msg_connect(gr_basic_block_sptr src, pmt::pmt_t srcport, - gr_basic_block_sptr dst, pmt::pmt_t dstport) -{ - if(!pmt::is_symbol(srcport)){throw std::runtime_error("bad port id"); } - d_detail->msg_connect(src, srcport, dst, dstport); -} - -void -gr_hier_block2::msg_connect(gr_basic_block_sptr src, std::string srcport, - gr_basic_block_sptr dst, std::string dstport) -{ - d_detail->msg_connect(src, pmt::mp(srcport), dst, pmt::mp(dstport)); -} - -void -gr_hier_block2::msg_disconnect(gr_basic_block_sptr src, pmt::pmt_t srcport, - gr_basic_block_sptr dst, pmt::pmt_t dstport) -{ - if(!pmt::is_symbol(srcport)){throw std::runtime_error("bad port id"); } - d_detail->msg_disconnect(src, srcport, dst, dstport); -} - -void -gr_hier_block2::msg_disconnect(gr_basic_block_sptr src, std::string srcport, - gr_basic_block_sptr dst, std::string dstport) -{ - d_detail->msg_disconnect(src, pmt::mp(srcport), dst, pmt::mp(dstport)); -} - -void -gr_hier_block2::disconnect(gr_basic_block_sptr block) -{ - d_detail->disconnect(block); -} - -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); -} - -void -gr_hier_block2::disconnect_all() -{ - d_detail->disconnect_all(); -} - -void -gr_hier_block2::lock() -{ - d_detail->lock(); -} - -void -gr_hier_block2::unlock() -{ - d_detail->unlock(); -} - - -gr_flat_flowgraph_sptr -gr_hier_block2::flatten() const -{ - gr_flat_flowgraph_sptr new_ffg = gr_make_flat_flowgraph(); - d_detail->flatten_aux(new_ffg); - return new_ffg; -} diff --git a/gnuradio-runtime/lib/gr_hier_block2_detail.cc b/gnuradio-runtime/lib/gr_hier_block2_detail.cc deleted file mode 100644 index c8564f6698..0000000000 --- a/gnuradio-runtime/lib/gr_hier_block2_detail.cc +++ /dev/null @@ -1,641 +0,0 @@ -/* - * Copyright 2006,2007,2009 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_hier_block2_detail.h> -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <stdexcept> -#include <sstream> -#include <boost/format.hpp> - -#define GR_HIER_BLOCK2_DETAIL_DEBUG 0 - -gr_hier_block2_detail::gr_hier_block2_detail(gr_hier_block2 *owner) : - d_owner(owner), - d_parent_detail(0), - d_fg(gr_make_flowgraph()) -{ - int min_inputs = owner->input_signature()->min_streams(); - int max_inputs = owner->input_signature()->max_streams(); - int min_outputs = owner->output_signature()->min_streams(); - int max_outputs = owner->output_signature()->max_streams(); - - if (max_inputs == gr_io_signature::IO_INFINITE || - max_outputs == gr_io_signature::IO_INFINITE || - (min_inputs != max_inputs) ||(min_outputs != max_outputs) ) { - std::stringstream msg; - msg << "Hierarchical blocks do not yet support arbitrary or" - << " variable numbers of inputs or outputs (" << d_owner->name() << ")"; - throw std::runtime_error(msg.str()); - } - - d_inputs = std::vector<gr_endpoint_vector_t>(max_inputs); - d_outputs = gr_endpoint_vector_t(max_outputs); -} - - -gr_hier_block2_detail::~gr_hier_block2_detail() -{ - d_owner = 0; // Don't use delete, we didn't allocate -} - -void -gr_hier_block2_detail::connect(gr_basic_block_sptr block) -{ - std::stringstream msg; - - // Check if duplicate - if (std::find(d_blocks.begin(), d_blocks.end(), block) != d_blocks.end()) { - msg << "Block " << block << " already connected."; - throw std::invalid_argument(msg.str()); - } - - // Check if has inputs or outputs - if (block->input_signature()->max_streams() != 0 || - block->output_signature()->max_streams() != 0) { - msg << "Block " << block << " must not have any input or output ports"; - throw std::invalid_argument(msg.str()); - } - - gr_hier_block2_sptr hblock(cast_to_hier_block2_sptr(block)); - - if (hblock && hblock.get() != d_owner) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "connect: block is hierarchical, setting parent to " << this << std::endl; - hblock->d_detail->d_parent_detail = this; - } - - d_blocks.push_back(block); -} - -void -gr_hier_block2_detail::connect(gr_basic_block_sptr src, int src_port, - gr_basic_block_sptr dst, int dst_port) -{ - std::stringstream msg; - - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "connecting: " << gr_endpoint(src, src_port) - << " -> " << gr_endpoint(dst, dst_port) << std::endl; - - if (src.get() == dst.get()) - throw std::invalid_argument("connect: src and destination blocks cannot be the same"); - - gr_hier_block2_sptr src_block(cast_to_hier_block2_sptr(src)); - gr_hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst)); - - if (src_block && src.get() != d_owner) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "connect: src is hierarchical, setting parent to " << this << std::endl; - src_block->d_detail->d_parent_detail = this; - } - - if (dst_block && dst.get() != d_owner) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "connect: dst is hierarchical, setting parent to " << this << std::endl; - dst_block->d_detail->d_parent_detail = this; - } - - // Connections to block inputs or outputs - int max_port; - if (src.get() == d_owner) { - max_port = src->input_signature()->max_streams(); - if ((max_port != -1 && (src_port >= max_port)) || src_port < 0) { - msg << "source port " << src_port << " out of range for " << src; - throw std::invalid_argument(msg.str()); - } - - return connect_input(src_port, dst_port, dst); - } - - if (dst.get() == d_owner) { - max_port = dst->output_signature()->max_streams(); - if ((max_port != -1 && (dst_port >= max_port)) || dst_port < 0) { - msg << "destination port " << dst_port << " out of range for " << dst; - throw std::invalid_argument(msg.str()); - } - - return connect_output(dst_port, src_port, src); - } - - // Internal connections - d_fg->connect(src, src_port, dst, dst_port); - - // TODO: connects to NC -} - -void -gr_hier_block2_detail::msg_connect(gr_basic_block_sptr src, pmt::pmt_t srcport, - gr_basic_block_sptr dst, pmt::pmt_t dstport) -{ - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "connecting message port..." << std::endl; - - // register the subscription -// this is done later... -// src->message_port_sub(srcport, pmt::cons(dst->alias_pmt(), dstport)); - - // add block uniquely to list to internal blocks - if (std::find(d_blocks.begin(), d_blocks.end(), dst) == d_blocks.end()){ - d_blocks.push_back(src); - d_blocks.push_back(dst); - } - - bool hier_out = (d_owner == src.get()) && src->message_port_is_hier_out(srcport);; - bool hier_in = (d_owner == dst.get()) && dst->message_port_is_hier_in(dstport); - - gr_hier_block2_sptr src_block(cast_to_hier_block2_sptr(src)); - gr_hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst)); - - if (src_block && src.get() != d_owner) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "connect: src is hierarchical, setting parent to " << this << std::endl; - src_block->d_detail->d_parent_detail = this; - } - - if (dst_block && dst.get() != d_owner) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "connect: dst is hierarchical, setting parent to " << this << std::endl; - dst_block->d_detail->d_parent_detail = this; - } - - // add edge for this message connection - if(GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << boost::format("connect( (%s, %s, %d), (%s, %s, %d) )\n") % - src % srcport % hier_out % - dst % dstport % hier_in; - d_fg->connect( gr_msg_endpoint(src, srcport, hier_out), gr_msg_endpoint(dst, dstport, hier_in)); -} - -void -gr_hier_block2_detail::msg_disconnect(gr_basic_block_sptr src, pmt::pmt_t srcport, - gr_basic_block_sptr dst, pmt::pmt_t dstport) -{ - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "disconnecting message port..." << std::endl; - - // unregister the subscription - if already subscribed - src->message_port_unsub(srcport, pmt::cons(dst->alias_pmt(), dstport)); - - // remove edge for this message connection - bool hier_out = (d_owner == src.get()) && src->message_port_is_hier_out(srcport);; - bool hier_in = (d_owner == dst.get()) && dst->message_port_is_hier_in(dstport); - d_fg->disconnect( gr_msg_endpoint(src, srcport, hier_out), gr_msg_endpoint(dst, dstport, hier_in)); -} - -void -gr_hier_block2_detail::disconnect(gr_basic_block_sptr block) -{ - // Check on singleton list - for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { - if (*p == block) { - d_blocks.erase(p); - - gr_hier_block2_sptr hblock(cast_to_hier_block2_sptr(block)); - if (block && block.get() != d_owner) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "disconnect: block is hierarchical, clearing parent" << std::endl; - hblock->d_detail->d_parent_detail = 0; - } - - return; - } - } - - // Otherwise find all edges containing block - gr_edge_vector_t edges, tmp = d_fg->edges(); - gr_edge_vector_t::iterator p; - for (p = tmp.begin(); p != tmp.end(); p++) { - if ((*p).src().block() == block || (*p).dst().block() == block) { - edges.push_back(*p); - - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "disconnect: block found in edge " << (*p) << std::endl; - } - } - - if (edges.size() == 0) { - std::stringstream msg; - msg << "cannot disconnect block " << block << ", not found"; - throw std::invalid_argument(msg.str()); - } - - for (p = edges.begin(); p != edges.end(); p++) { - disconnect((*p).src().block(), (*p).src().port(), - (*p).dst().block(), (*p).dst().port()); - } -} - -void -gr_hier_block2_detail::disconnect(gr_basic_block_sptr src, int src_port, - gr_basic_block_sptr dst, int dst_port) -{ - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "disconnecting: " << gr_endpoint(src, src_port) - << " -> " << gr_endpoint(dst, dst_port) << std::endl; - - if (src.get() == dst.get()) - throw std::invalid_argument("disconnect: source and destination blocks cannot be the same"); - - gr_hier_block2_sptr src_block(cast_to_hier_block2_sptr(src)); - gr_hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst)); - - if (src_block && src.get() != d_owner) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "disconnect: src is hierarchical, clearing parent" << std::endl; - src_block->d_detail->d_parent_detail = 0; - } - - if (dst_block && dst.get() != d_owner) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "disconnect: dst is hierarchical, clearing parent" << std::endl; - dst_block->d_detail->d_parent_detail = 0; - } - - if (src.get() == d_owner) - return disconnect_input(src_port, dst_port, dst); - - if (dst.get() == d_owner) - return disconnect_output(dst_port, src_port, src); - - // Internal connections - d_fg->disconnect(src, src_port, dst, dst_port); -} - -void -gr_hier_block2_detail::connect_input(int my_port, int port, gr_basic_block_sptr block) -{ - std::stringstream msg; - - if (my_port < 0 || my_port >= (signed)d_inputs.size()) { - msg << "input port " << my_port << " out of range for " << block; - throw std::invalid_argument(msg.str()); - } - - gr_endpoint_vector_t &endps = d_inputs[my_port]; - gr_endpoint endp(block, port); - - gr_endpoint_viter_t p = std::find(endps.begin(), endps.end(), endp); - if (p != endps.end()) { - msg << "external input port " << my_port << " already wired to " << endp; - throw std::invalid_argument(msg.str()); - } - - endps.push_back(endp); -} - -void -gr_hier_block2_detail::connect_output(int my_port, int port, gr_basic_block_sptr block) -{ - std::stringstream msg; - - if (my_port < 0 || my_port >= (signed)d_outputs.size()) { - msg << "output port " << my_port << " out of range for " << block; - throw std::invalid_argument(msg.str()); - } - - if (d_outputs[my_port].block()) { - msg << "external output port " << my_port << " already connected from " - << d_outputs[my_port]; - throw std::invalid_argument(msg.str()); - } - - d_outputs[my_port] = gr_endpoint(block, port); -} - -void -gr_hier_block2_detail::disconnect_input(int my_port, int port, gr_basic_block_sptr block) -{ - std::stringstream msg; - - if (my_port < 0 || my_port >= (signed)d_inputs.size()) { - msg << "input port number " << my_port << " out of range for " << block; - throw std::invalid_argument(msg.str()); - } - - gr_endpoint_vector_t &endps = d_inputs[my_port]; - gr_endpoint endp(block, port); - - gr_endpoint_viter_t p = std::find(endps.begin(), endps.end(), endp); - if (p == endps.end()) { - msg << "external input port " << my_port << " not connected to " << endp; - throw std::invalid_argument(msg.str()); - } - - endps.erase(p); -} - -void -gr_hier_block2_detail::disconnect_output(int my_port, int port, gr_basic_block_sptr block) -{ - std::stringstream msg; - - if (my_port < 0 || my_port >= (signed)d_outputs.size()) { - msg << "output port number " << my_port << " out of range for " << block; - throw std::invalid_argument(msg.str()); - } - - if (d_outputs[my_port].block() != block) { - msg << "block " << block << " not assigned to output " - << my_port << ", can't disconnect"; - throw std::invalid_argument(msg.str()); - } - - d_outputs[my_port] = gr_endpoint(); -} - -gr_endpoint_vector_t -gr_hier_block2_detail::resolve_port(int port, bool is_input) -{ - std::stringstream msg; - - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "Resolving port " << port << " as an " - << (is_input ? "input" : "output") - << " of " << d_owner->name() << std::endl; - - gr_endpoint_vector_t result; - - if (is_input) { - if (port < 0 || port >= (signed)d_inputs.size()) { - msg << "resolve_port: hierarchical block '" << d_owner->name() - << "': input " << port << " is out of range"; - throw std::runtime_error(msg.str()); - } - - if (d_inputs[port].empty()) { - msg << "resolve_port: hierarchical block '" << d_owner->name() - << "': input " << port << " is not connected internally"; - throw std::runtime_error(msg.str()); - } - - gr_endpoint_vector_t &endps = d_inputs[port]; - gr_endpoint_viter_t p; - for (p = endps.begin(); p != endps.end(); p++) { - gr_endpoint_vector_t tmp = resolve_endpoint(*p, true); - std::copy(tmp.begin(), tmp.end(), back_inserter(result)); - } - } - else { - if (port < 0 || port >= (signed)d_outputs.size()) { - msg << "resolve_port: hierarchical block '" << d_owner->name() - << "': output " << port << " is out of range"; - throw std::runtime_error(msg.str()); - } - - if (d_outputs[port] == gr_endpoint()) { - msg << "resolve_port: hierarchical block '" << d_owner->name() - << "': output " << port << " is not connected internally"; - throw std::runtime_error(msg.str()); - } - - result = resolve_endpoint(d_outputs[port], false); - } - - if (result.empty()) { - msg << "resolve_port: hierarchical block '" << d_owner->name() - << "': unable to resolve " - << (is_input ? "input port " : "output port ") - << port; - throw std::runtime_error(msg.str()); - } - - return result; -} - -void -gr_hier_block2_detail::disconnect_all() -{ - d_fg->clear(); - d_blocks.clear(); - d_inputs.clear(); - d_outputs.clear(); -} - -gr_endpoint_vector_t -gr_hier_block2_detail::resolve_endpoint(const gr_endpoint &endp, bool is_input) const -{ - std::stringstream msg; - gr_endpoint_vector_t result; - - // Check if endpoint is a leaf node - if (cast_to_block_sptr(endp.block())) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "Block " << endp.block() << " is a leaf node, returning." << std::endl; - result.push_back(endp); - return result; - } - - // Check if endpoint is a hierarchical block - gr_hier_block2_sptr hier_block2(cast_to_hier_block2_sptr(endp.block())); - if (hier_block2) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "Resolving endpoint " << endp << " as an " - << (is_input ? "input" : "output") - << ", recursing" << std::endl; - return hier_block2->d_detail->resolve_port(endp.port(), is_input); - } - - msg << "unable to resolve" << (is_input ? " input " : " output ") - << "endpoint " << endp; - throw std::runtime_error(msg.str()); -} - -void -gr_hier_block2_detail::flatten_aux(gr_flat_flowgraph_sptr sfg) const -{ - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << " ** Flattening " << d_owner->name() << std::endl; - - // Add my edges to the flow graph, resolving references to actual endpoints - gr_edge_vector_t edges = d_fg->edges(); - gr_msg_edge_vector_t msg_edges = d_fg->msg_edges(); - gr_edge_viter_t p; - gr_msg_edge_viter_t q,u; - - // Only run setup_rpc if ControlPort config param is enabled. - bool ctrlport_on = gr_prefs::singleton()->get_bool("ControlPort", "on", false); - - // For every block (gr_block and gr_hier_block2), set up the RPC - // interface. - for(p = edges.begin(); p != edges.end(); p++) { - gr_basic_block_sptr b; - b = p->src().block(); - - if(ctrlport_on) { - if(!b->is_rpc_set()) { - b->setup_rpc(); - b->rpc_set(); - } - } - - b = p->dst().block(); - if(ctrlport_on) { - if(!b->is_rpc_set()) { - b->setup_rpc(); - b->rpc_set(); - } - } - } - - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "Flattening stream connections: " << std::endl; - - for (p = edges.begin(); p != edges.end(); p++) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "Flattening edge " << (*p) << std::endl; - - gr_endpoint_vector_t src_endps = resolve_endpoint(p->src(), false); - gr_endpoint_vector_t dst_endps = resolve_endpoint(p->dst(), true); - - gr_endpoint_viter_t s, d; - for (s = src_endps.begin(); s != src_endps.end(); s++) { - for (d = dst_endps.begin(); d != dst_endps.end(); d++) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << (*s) << "->" << (*d) << std::endl; - sfg->connect(*s, *d); - } - } - } - - // loop through flattening hierarchical connections - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "Flattening msg connections: " << std::endl; - - - std::vector<std::pair<gr_msg_endpoint, bool> > resolved_endpoints; - for(q = msg_edges.begin(); q != msg_edges.end(); q++) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << boost::format(" flattening edge ( %s, %s, %d) -> ( %s, %s, %d)\n") % q->src().block() % q->src().port() % q->src().is_hier() % q->dst().block() % q->dst().port() % q->dst().is_hier(); - - bool normal_connection = true; - - // resolve existing connections to hier ports - if(q->dst().is_hier()){ - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << boost::format(" resolve hier output (%s, %s)") % q->dst().block() % q->dst().port() << std::endl; - sfg->replace_endpoint( q->dst(), q->src(), true ); - resolved_endpoints.push_back(std::pair<gr_msg_endpoint, bool>(q->dst(),true)); - normal_connection = false; - } - - if(q->src().is_hier()){ - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << boost::format(" resolve hier input (%s, %s)") % q->src().block() % q->src().port() << std::endl; - sfg->replace_endpoint( q->src(), q->dst(), false ); - resolved_endpoints.push_back(std::pair<gr_msg_endpoint, bool>(q->src(),false)); - normal_connection = false; - } - - // propogate non hier connections through - if(normal_connection){ - sfg->connect( q->src(), q->dst() ); - } - } - for(std::vector<std::pair<gr_msg_endpoint, bool> >::iterator it = resolved_endpoints.begin(); it != resolved_endpoints.end(); it++){ - sfg->clear_endpoint( (*it).first, (*it).second ); - } - -/* // connect primitive edges in the new fg - for(q = msg_edges.begin(); q != msg_edges.end(); q++) { - if( (!q->src().is_hier()) && (!q->dst().is_hier()) ){ - sfg->connect( q->src(), q->dst() ); - } else { - std::cout << "not connecting hier connection!" << std::endl; - } - }*/ - - // Construct unique list of blocks used either in edges, inputs, - // outputs, or by themselves. I still hate STL. - gr_basic_block_vector_t blocks; // unique list of used blocks - gr_basic_block_vector_t tmp = d_fg->calc_used_blocks(); - - // First add the list of singleton blocks - std::vector<gr_basic_block_sptr>::const_iterator b; // Because flatten_aux is const - for (b = d_blocks.begin(); b != d_blocks.end(); b++) - tmp.push_back(*b); - - // Now add the list of connected input blocks - std::stringstream msg; - for (unsigned int i = 0; i < d_inputs.size(); i++) { - if (d_inputs[i].size() == 0) { - msg << "In hierarchical block " << d_owner->name() << ", input " << i - << " is not connected internally"; - throw std::runtime_error(msg.str()); - } - - for (unsigned int j = 0; j < d_inputs[i].size(); j++) - tmp.push_back(d_inputs[i][j].block()); - } - - for (unsigned int i = 0; i < d_outputs.size(); i++) { - gr_basic_block_sptr blk = d_outputs[i].block(); - if (!blk) { - msg << "In hierarchical block " << d_owner->name() << ", output " << i - << " is not connected internally"; - throw std::runtime_error(msg.str()); - } - tmp.push_back(blk); - } - sort(tmp.begin(), tmp.end()); - - std::insert_iterator<gr_basic_block_vector_t> inserter(blocks, blocks.begin()); - unique_copy(tmp.begin(), tmp.end(), inserter); - - // Recurse hierarchical children - for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { - gr_hier_block2_sptr hier_block2(cast_to_hier_block2_sptr(*p)); - if (hier_block2 && (hier_block2.get() != d_owner)) { - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "flatten_aux: recursing into hierarchical block " << hier_block2 << std::endl; - hier_block2->d_detail->flatten_aux(sfg); - } - } -} - -void -gr_hier_block2_detail::lock() -{ - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "lock: entered in " << this << std::endl; - - if (d_parent_detail) - d_parent_detail->lock(); - else - d_owner->lock(); -} - -void -gr_hier_block2_detail::unlock() -{ - if (GR_HIER_BLOCK2_DETAIL_DEBUG) - std::cout << "unlock: entered in " << this << std::endl; - - if (d_parent_detail) - d_parent_detail->unlock(); - else - d_owner->unlock(); -} - diff --git a/gnuradio-runtime/lib/gr_hier_block2_detail.h b/gnuradio-runtime/lib/gr_hier_block2_detail.h deleted file mode 100644 index d08fe20ac0..0000000000 --- a/gnuradio-runtime/lib/gr_hier_block2_detail.h +++ /dev/null @@ -1,74 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2007,2009 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_HIER_BLOCK2_DETAIL_H -#define INCLUDED_GR_HIER_BLOCK2_DETAIL_H - -#include <gr_runtime_api.h> -#include <gr_hier_block2.h> -#include <gr_flat_flowgraph.h> -#include <boost/utility.hpp> - -/*! - * \ingroup internal - */ -class GR_RUNTIME_API gr_hier_block2_detail : boost::noncopyable -{ -public: - gr_hier_block2_detail(gr_hier_block2 *owner); - ~gr_hier_block2_detail(); - - void connect(gr_basic_block_sptr block); - void connect(gr_basic_block_sptr src, int src_port, - gr_basic_block_sptr dst, int dst_port); - void msg_connect(gr_basic_block_sptr src, pmt::pmt_t srcport, - gr_basic_block_sptr dst, pmt::pmt_t dstport); - void msg_disconnect(gr_basic_block_sptr src, pmt::pmt_t srcport, - gr_basic_block_sptr dst, pmt::pmt_t dstport); - void disconnect(gr_basic_block_sptr block); - void disconnect(gr_basic_block_sptr, int src_port, - gr_basic_block_sptr, int dst_port); - void disconnect_all(); - void lock(); - void unlock(); - void flatten_aux(gr_flat_flowgraph_sptr sfg) const; - -private: - - // Private implementation data - gr_hier_block2 *d_owner; - gr_hier_block2_detail *d_parent_detail; - gr_flowgraph_sptr d_fg; - std::vector<gr_endpoint_vector_t> d_inputs; // Multiple internal endpoints per external input - gr_endpoint_vector_t d_outputs; // Single internal endpoint per external output - gr_basic_block_vector_t d_blocks; - - - void connect_input(int my_port, int port, gr_basic_block_sptr block); - void connect_output(int my_port, int port, gr_basic_block_sptr block); - void disconnect_input(int my_port, int port, gr_basic_block_sptr block); - void disconnect_output(int my_port, int port, gr_basic_block_sptr block); - - gr_endpoint_vector_t resolve_port(int port, bool is_input); - gr_endpoint_vector_t resolve_endpoint(const gr_endpoint &endp, bool is_input) const; -}; - -#endif /* INCLUDED_GR_HIER_BLOCK2_DETAIL_H */ diff --git a/gnuradio-runtime/lib/gr_io_signature.cc b/gnuradio-runtime/lib/gr_io_signature.cc deleted file mode 100644 index 6ac9acd17d..0000000000 --- a/gnuradio-runtime/lib/gr_io_signature.cc +++ /dev/null @@ -1,112 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,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_io_signature.h> -#include <stdexcept> -#include <iostream> - -gr_io_signature_sptr -gr_make_io_signaturev(int min_streams, int max_streams, - const std::vector<int> &sizeof_stream_items) -{ - return gr_io_signature_sptr (new gr_io_signature (min_streams, max_streams, - sizeof_stream_items)); -} - -gr_io_signature_sptr -gr_make_io_signature(int min_streams, int max_streams, - int sizeof_stream_item) -{ - std::vector<int> sizeof_items(1); - sizeof_items[0] = sizeof_stream_item; - return gr_make_io_signaturev(min_streams, max_streams, sizeof_items); -} - -gr_io_signature_sptr -gr_make_io_signature2(int min_streams, int max_streams, - int sizeof_stream_item1, - int sizeof_stream_item2) -{ - std::vector<int> sizeof_items(2); - sizeof_items[0] = sizeof_stream_item1; - sizeof_items[1] = sizeof_stream_item2; - return gr_make_io_signaturev(min_streams, max_streams, sizeof_items); -} - -gr_io_signature_sptr -gr_make_io_signature3(int min_streams, int max_streams, - int sizeof_stream_item1, - int sizeof_stream_item2, - int sizeof_stream_item3) -{ - std::vector<int> sizeof_items(3); - sizeof_items[0] = sizeof_stream_item1; - sizeof_items[1] = sizeof_stream_item2; - sizeof_items[2] = sizeof_stream_item3; - return gr_make_io_signaturev(min_streams, max_streams, sizeof_items); -} - -// ------------------------------------------------------------------------ - - -gr_io_signature::gr_io_signature (int min_streams, int max_streams, - const std::vector<int> &sizeof_stream_items) -{ - if (min_streams < 0 - || (max_streams != IO_INFINITE && max_streams < min_streams)) - throw std::invalid_argument ("gr_io_signature(1)"); - - if (sizeof_stream_items.size() < 1) - throw std::invalid_argument("gr_io_signature(2)"); - - for (size_t i = 0; i < sizeof_stream_items.size(); i++){ - if (max_streams != 0 && sizeof_stream_items[i] < 1) - throw std::invalid_argument("gr_io_signature(3)"); - } - - d_min_streams = min_streams; - d_max_streams = max_streams; - d_sizeof_stream_item = sizeof_stream_items; -} - -gr_io_signature::~gr_io_signature () -{ -} - -int -gr_io_signature::sizeof_stream_item (int _index) const -{ - if (_index < 0) - throw std::invalid_argument ("gr_io_signature::sizeof_stream_item"); - - size_t index = _index; - return d_sizeof_stream_item[std::min(index, d_sizeof_stream_item.size() - 1)]; -} - -std::vector<int> -gr_io_signature::sizeof_stream_items() const -{ - return d_sizeof_stream_item; -} diff --git a/gnuradio-runtime/lib/gr_local_sighandler.cc b/gnuradio-runtime/lib/gr_local_sighandler.cc deleted file mode 100644 index fb31742e13..0000000000 --- a/gnuradio-runtime/lib/gr_local_sighandler.cc +++ /dev/null @@ -1,187 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_local_sighandler.h> -#include <stdexcept> -#include <stdio.h> -#include <string.h> - - -gr_local_sighandler::gr_local_sighandler (int signum, - void (*new_handler)(int)) - : d_signum (signum) -{ -#ifdef HAVE_SIGACTION - struct sigaction new_action; - memset (&new_action, 0, sizeof (new_action)); - - new_action.sa_handler = new_handler; - sigemptyset (&new_action.sa_mask); - new_action.sa_flags = 0; - - if (sigaction (d_signum, &new_action, &d_old_action) < 0){ - perror ("sigaction (install new)"); - throw std::runtime_error ("sigaction"); - } -#endif -} - -gr_local_sighandler::~gr_local_sighandler () -{ -#ifdef HAVE_SIGACTION - if (sigaction (d_signum, &d_old_action, 0) < 0){ - perror ("sigaction (restore old)"); - throw std::runtime_error ("sigaction"); - } -#endif -} - -void -gr_local_sighandler::throw_signal (int signum) -{ - throw gr_signal (signum); -} - -/* - * Semi-hideous way to may a signal number into a signal name - */ - -#define SIGNAME(x) case x: return #x - -std::string -gr_signal::name () const -{ - char tmp[128]; - - switch (signal ()){ -#ifdef SIGHUP - SIGNAME (SIGHUP); -#endif -#ifdef SIGINT - SIGNAME (SIGINT); -#endif -#ifdef SIGQUIT - SIGNAME (SIGQUIT); -#endif -#ifdef SIGILL - SIGNAME (SIGILL); -#endif -#ifdef SIGTRAP - SIGNAME (SIGTRAP); -#endif -#ifdef SIGABRT - SIGNAME (SIGABRT); -#endif -#ifdef SIGBUS - SIGNAME (SIGBUS); -#endif -#ifdef SIGFPE - SIGNAME (SIGFPE); -#endif -#ifdef SIGKILL - SIGNAME (SIGKILL); -#endif -#ifdef SIGUSR1 - SIGNAME (SIGUSR1); -#endif -#ifdef SIGSEGV - SIGNAME (SIGSEGV); -#endif -#ifdef SIGUSR2 - SIGNAME (SIGUSR2); -#endif -#ifdef SIGPIPE - SIGNAME (SIGPIPE); -#endif -#ifdef SIGALRM - SIGNAME (SIGALRM); -#endif -#ifdef SIGTERM - SIGNAME (SIGTERM); -#endif -#ifdef SIGSTKFLT - SIGNAME (SIGSTKFLT); -#endif -#ifdef SIGCHLD - SIGNAME (SIGCHLD); -#endif -#ifdef SIGCONT - SIGNAME (SIGCONT); -#endif -#ifdef SIGSTOP - SIGNAME (SIGSTOP); -#endif -#ifdef SIGTSTP - SIGNAME (SIGTSTP); -#endif -#ifdef SIGTTIN - SIGNAME (SIGTTIN); -#endif -#ifdef SIGTTOU - SIGNAME (SIGTTOU); -#endif -#ifdef SIGURG - SIGNAME (SIGURG); -#endif -#ifdef SIGXCPU - SIGNAME (SIGXCPU); -#endif -#ifdef SIGXFSZ - SIGNAME (SIGXFSZ); -#endif -#ifdef SIGVTALRM - SIGNAME (SIGVTALRM); -#endif -#ifdef SIGPROF - SIGNAME (SIGPROF); -#endif -#ifdef SIGWINCH - SIGNAME (SIGWINCH); -#endif -#ifdef SIGIO - SIGNAME (SIGIO); -#endif -#ifdef SIGPWR - SIGNAME (SIGPWR); -#endif -#ifdef SIGSYS - SIGNAME (SIGSYS); -#endif - default: -#if defined (HAVE_SNPRINTF) -#if defined (SIGRTMIN) && defined (SIGRTMAX) - if (signal () >= SIGRTMIN && signal () <= SIGRTMAX){ - snprintf (tmp, sizeof (tmp), "SIGRTMIN + %d", signal ()); - return tmp; - } -#endif - snprintf (tmp, sizeof (tmp), "SIGNAL %d", signal ()); - return tmp; -#else - return "Unknown signal"; -#endif - } -} diff --git a/gnuradio-runtime/lib/gr_logger.cc b/gnuradio-runtime/lib/gr_logger.cc deleted file mode 100644 index 6da4a6d914..0000000000 --- a/gnuradio-runtime/lib/gr_logger.cc +++ /dev/null @@ -1,295 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2012 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. - */ - -/******************************************************************************* -* Author: Mark Plett -* Description: -* The gr_log module wraps the log4cpp library for logging in gnuradio. -*******************************************************************************/ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <gr_logger.h> -#include <stdexcept> -#include <algorithm> - -#ifdef ENABLE_GR_LOG -#ifdef HAVE_LOG4CPP - -/**************************** BEGIN LOG4CPP HELPERS ***************************/ -/* Logger config class. This is a singleton that controls how log4cpp is configured - * If watch_period>0 a thread is started to watch teh config file for changes. - */ - -// Getters of logger_config -logger_config& -logger_config::get_instance(void){ - static logger_config instance; - return instance; -}; - -std::string -logger_config::get_filename(){ - logger_config& in=get_instance(); - return in.filename; -}; - -unsigned int -logger_config::get_watch_period(){ - logger_config& in=get_instance(); - return in.watch_period; -}; - -// Method to watch config file for changes -void logger_config::watch_file(std::string filename,unsigned int watch_period){ - std::time_t last_write(boost::filesystem::last_write_time(filename)); - std::time_t current_time(0); - while(true){ - try{ - current_time = boost::filesystem::last_write_time(filename); - if(current_time>last_write){ - std::cout<<"GNURadio Reloading logger configuration:"<<filename<<std::endl; - last_write = current_time; -// Should we wipe out all old configuration or just add the new? Just adding... -// logger_reset_config(); - logger_load_config(filename); - }; - boost::this_thread::sleep(boost::posix_time::time_duration(0,0,watch_period,0)); - } - catch(const boost::thread_interrupted&){ - std::cout<<"GNURadio leaving logger config file watch."<<std::endl; - break; - }; - }; -}; - -// Method to load the confifuration. It only loads if the filename or watch has changed -void logger_config::load_config(std::string filename,unsigned int watch_period){ - logger_config& instance = get_instance(); -// Only reconfigure if filename or watch has changed - if(instance.filename!=filename || watch_period!=instance.watch_period){ - instance.filename = filename; - instance.watch_period = watch_period; -// Stop any file watching thread - if(instance.watch_thread!=NULL) stop_watch(); -// Load configuration - std::cout<<"GNURadio Loading logger configuration:"<<instance.filename<<std::endl; - logger_load_config(instance.filename); -// Start watch if required - if(instance.watch_period>0){ - instance.watch_thread = new boost::thread(watch_file,instance.filename,instance.watch_period); - } - }; -}; - -// Method to stop the watcher thread -void logger_config::stop_watch(){ - logger_config& instance = get_instance(); - if(instance.watch_thread){ - instance.watch_thread->interrupt(); - instance.watch_thread->join(); - delete(instance.watch_thread); - instance.watch_thread=NULL; - }; -}; - -// Method to reset logger configuration -void -logger_config::reset_config(void){ - logger_config& instance = get_instance(); - stop_watch(); - std::vector<log4cpp::Category*> *loggers = log4cpp::Category::getCurrentCategories(); - std::vector<log4cpp::Category*>::iterator logger = loggers->begin(); -// We can't destroy categories but we can neuter them by removing all appenders. - for (;logger!=loggers->end();logger++){ - (*logger)->removeAllAppenders(); - }; - instance.filename=std::string(""); - instance.watch_period=0; -} - -/***************** Functions to call log4cpp methods *************************/ - -gr_logger_ptr -logger_get_logger(std::string name) -{ - if(log4cpp::Category::exists(name)){ - gr_logger_ptr logger = &log4cpp::Category::getInstance(name); - return logger; - } - else - { - gr_logger_ptr logger = &log4cpp::Category::getInstance(name); - logger->setPriority(log4cpp::Priority::NOTSET); - return logger; - }; -}; - -void -logger_load_config(const std::string &config_filename) -{ - if(config_filename.size() != 0) { - try - { - log4cpp::PropertyConfigurator::configure(config_filename); - } - catch( log4cpp::ConfigureFailure &e ) - { - std::cout << "Logger config failed :" << e.what() << std::endl; - } - }; -} - -void -logger_set_level(gr_logger_ptr logger, const std::string &level) -{ - std::string nocase = level; - std::transform(level.begin(), level.end(), nocase.begin(), ::tolower); - - if(nocase == "off" || nocase == "notset") - logger_set_level(logger, log4cpp::Priority::NOTSET); - else if(nocase == "all" || nocase == "debug") - logger_set_level(logger, log4cpp::Priority::DEBUG); - else if(nocase == "info") - logger_set_level(logger, log4cpp::Priority::INFO); - else if(nocase == "notice") - logger_set_level(logger, log4cpp::Priority::NOTICE); - else if(nocase == "warn") - logger_set_level(logger, log4cpp::Priority::WARN); - else if(nocase == "error") - logger_set_level(logger, log4cpp::Priority::ERROR); - else if(nocase == "crit") - logger_set_level(logger, log4cpp::Priority::CRIT); - else if(nocase == "alert") - logger_set_level(logger, log4cpp::Priority::ALERT); - else if(nocase=="fatal") - logger_set_level(logger, log4cpp::Priority::FATAL); - else if(nocase == "emerg") - logger_set_level(logger, log4cpp::Priority::EMERG); - else - throw std::runtime_error("logger_set_level: Bad level type.\n"); -} - -void -logger_set_level(gr_logger_ptr logger, log4cpp::Priority::Value level) -{ - logger->setPriority(level); -} - -void -logger_get_level(gr_logger_ptr logger, std::string &level) -{ - log4cpp::Priority::Value levelPtr = logger->getPriority(); - if(levelPtr == log4cpp::Priority::NOTSET) level = "noset"; - if(levelPtr == log4cpp::Priority::DEBUG) level = "debug"; - if(levelPtr == log4cpp::Priority::INFO) level = "info"; - if(levelPtr == log4cpp::Priority::NOTICE) level = "notice"; - if(levelPtr == log4cpp::Priority::WARN) level = "warn"; - if(levelPtr == log4cpp::Priority::ERROR) level = "error"; - if(levelPtr == log4cpp::Priority::CRIT) level = "crit"; - if(levelPtr == log4cpp::Priority::ALERT) level = "alert"; - if(levelPtr == log4cpp::Priority::FATAL) level = "fatal"; - if(levelPtr == log4cpp::Priority::EMERG) level = "emerg"; -}; - -void -logger_get_level(gr_logger_ptr logger,log4cpp::Priority::Value level) -{ - level = logger->getPriority(); -} - -void -logger_add_console_appender(gr_logger_ptr logger,std::string target,std::string pattern) -{ - - log4cpp::PatternLayout* layout = new log4cpp::PatternLayout(); - log4cpp::Appender* app; - if(target=="stdout") - app = new log4cpp::OstreamAppender("ConsoleAppender::",&std::cout); - else - app = new log4cpp::OstreamAppender("ConsoleAppender::",&std::cerr); - - layout->setConversionPattern(pattern); - app->setLayout(layout); - logger->setAppender(app); - -} - -void -logger_add_file_appender(gr_logger_ptr logger,std::string filename,bool append,std::string pattern) -{ - - log4cpp::PatternLayout* layout = new log4cpp::PatternLayout(); - log4cpp::Appender* app = new - log4cpp::FileAppender("FileAppender::"+filename, - filename); - layout->setConversionPattern(pattern); - app->setLayout(layout); - logger->setAppender(app); - -} - -void -logger_add_rollingfile_appender(gr_logger_ptr logger,std::string filename, - size_t filesize,int bkup_index,bool append,mode_t mode,std::string pattern) -{ - log4cpp::PatternLayout* layout = new log4cpp::PatternLayout(); - log4cpp::Appender* app = new - log4cpp::RollingFileAppender("RollFileAppender::"+filename,filename,filesize,bkup_index,append,mode); - layout->setConversionPattern(pattern); - app->setLayout(layout); - logger->setAppender(app); -} - -std::vector<std::string> -logger_get_logger_names(void){ - std::vector<std::string> names; - std::vector<log4cpp::Category*> *loggers = log4cpp::Category::getCurrentCategories(); - std::vector<log4cpp::Category*>::iterator logger = loggers->begin(); - - for (;logger!=loggers->end();logger++){ - names.push_back((*logger)->getName()); - }; - return names; - -} - -#endif /* HAVE_LOG4CPP */ - -/****** Start Methods to provide Python the capabilities of the macros ********/ -void gr_logger_config(const std::string config_filename, unsigned int watch_period){ - GR_CONFIG_AND_WATCH_LOGGER(config_filename,watch_period); -}; -std::vector<std::string> gr_logger_get_logger_names(void){ - std::vector<std::string> names; - GR_GET_LOGGER_NAMES(names); - return names; -}; -void gr_logger_reset_config(void){ - GR_RESET_CONFIGURATION(); -}; - -// Remaining capability provided by gr_logger class in gr_logger.h - -#endif /* ENABLE_GR_LOGGER */ diff --git a/gnuradio-runtime/lib/gr_message.cc b/gnuradio-runtime/lib/gr_message.cc deleted file mode 100644 index a99dcd7653..0000000000 --- a/gnuradio-runtime/lib/gr_message.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_message.h> -#include <assert.h> -#include <string.h> - -static long s_ncurrently_allocated = 0; - -gr_message_sptr -gr_make_message (long type, double arg1, double arg2, size_t length) -{ - return gr_message_sptr (new gr_message (type, arg1, arg2, length)); -} - -gr_message_sptr -gr_make_message_from_string(const std::string s, long type, double arg1, double arg2) -{ - gr_message_sptr m = gr_make_message(type, arg1, arg2, s.size()); - memcpy(m->msg(), s.data(), s.size()); - return m; -} - - -gr_message::gr_message (long type, double arg1, double arg2, size_t length) - : d_type(type), d_arg1(arg1), d_arg2(arg2) -{ - if (length == 0) - d_buf_start = d_msg_start = d_msg_end = d_buf_end = 0; - else { - d_buf_start = new unsigned char [length]; - d_msg_start = d_buf_start; - d_msg_end = d_buf_end = d_buf_start + length; - } - s_ncurrently_allocated++; -} - -gr_message::~gr_message () -{ - assert (d_next == 0); - delete [] d_buf_start; - d_msg_start = d_msg_end = d_buf_end = 0; - s_ncurrently_allocated--; -} - -std::string -gr_message::to_string() const -{ - return std::string((char *)d_msg_start, length()); -} - -long -gr_message_ncurrently_allocated () -{ - return s_ncurrently_allocated; -} diff --git a/gnuradio-runtime/lib/gr_misc.cc b/gnuradio-runtime/lib/gr_misc.cc deleted file mode 100644 index 1ed2a03d7f..0000000000 --- a/gnuradio-runtime/lib/gr_misc.cc +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_misc.h> - -unsigned int -gr_rounduppow2(unsigned int n) -{ - int i; - for (i=0;((n-1)>>i) != 0;i++) - ; - return 1<<i; -} - -// ---------------------------------------------------------------- - -void -gr_zero_vector(std::vector<float> &v) -{ - for(unsigned int i=0; i < v.size(); i++) - v[i] = 0; -} - -void -gr_zero_vector(std::vector<double> &v) -{ - for(unsigned int i=0; i < v.size(); i++) - v[i] = 0; -} - -void -gr_zero_vector(std::vector<int> &v) -{ - for(unsigned int i=0; i < v.size(); i++) - v[i] = 0; -} - -void -gr_zero_vector(std::vector<gr_complex> &v) -{ - for(unsigned int i=0; i < v.size(); i++) - v[i] = 0; -} diff --git a/gnuradio-runtime/lib/gr_msg_queue.cc b/gnuradio-runtime/lib/gr_msg_queue.cc deleted file mode 100644 index 03bbe046a4..0000000000 --- a/gnuradio-runtime/lib/gr_msg_queue.cc +++ /dev/null @@ -1,125 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005,2009 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_msg_queue.h> -#include <stdexcept> - -gr_msg_queue_sptr -gr_make_msg_queue(unsigned int limit) -{ - return gr_msg_queue_sptr (new gr_msg_queue(limit)); -} - -gr_msg_queue::gr_msg_queue(unsigned int limit) - : d_not_empty(), d_not_full(), - /*d_head(0), d_tail(0),*/ d_count(0), d_limit(limit) -{ -} - -gr_msg_queue::~gr_msg_queue() -{ - flush (); -} - -void -gr_msg_queue::insert_tail(gr_message_sptr msg) -{ - if (msg->d_next) - throw std::invalid_argument("gr_msg_queue::insert_tail: msg already in queue"); - - gr::thread::scoped_lock guard(d_mutex); - - while (full_p()) - d_not_full.wait(guard); - - if (d_tail == 0){ - d_tail = d_head = msg; - //msg->d_next = 0; - msg->d_next.reset(); - } - else { - d_tail->d_next = msg; - d_tail = msg; - //msg->d_next = 0; - msg->d_next.reset(); - } - d_count++; - d_not_empty.notify_one(); -} - -gr_message_sptr -gr_msg_queue::delete_head() -{ - gr::thread::scoped_lock guard(d_mutex); - gr_message_sptr m; - - while ((m = d_head) == 0) - d_not_empty.wait(guard); - - d_head = m->d_next; - if (d_head == 0){ - //d_tail = 0; - d_tail.reset(); - } - - d_count--; - // m->d_next = 0; - m->d_next.reset(); - d_not_full.notify_one(); - return m; -} - -gr_message_sptr -gr_msg_queue::delete_head_nowait() -{ - gr::thread::scoped_lock guard(d_mutex); - gr_message_sptr m; - - if ((m = d_head) == 0){ - //return 0; - return gr_message_sptr(); - } - - d_head = m->d_next; - if (d_head == 0){ - //d_tail = 0; - d_tail.reset(); - } - - d_count--; - //m->d_next = 0; - m->d_next.reset(); - d_not_full.notify_one(); - return m; -} - -void -gr_msg_queue::flush() -{ - gr_message_sptr m; - - while ((m = delete_head_nowait ()) != 0) - ; -} diff --git a/gnuradio-runtime/lib/gr_preferences.cc b/gnuradio-runtime/lib/gr_preferences.cc deleted file mode 100644 index a0f5616603..0000000000 --- a/gnuradio-runtime/lib/gr_preferences.cc +++ /dev/null @@ -1,108 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003,2010,2011 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_preferences.h> -#include <gr_sys_paths.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <unistd.h> -#include <string.h> - -#include <boost/filesystem/operations.hpp> -#include <boost/filesystem/path.hpp> -namespace fs = boost::filesystem; - -/* - * The simplest thing that could possibly work: - * the key is the filename; the value is the file contents. - */ - -static const char * -pathname (const char *key) -{ - static fs::path path; - path = fs::path(gr_appdata_path()) / ".gnuradio" / "prefs" / key; - return path.string().c_str(); -} - -static void -ensure_dir_path () -{ - fs::path path = fs::path(gr_appdata_path()) / ".gnuradio"; - if (!fs::is_directory(path)) fs::create_directory(path); - - path = path / "prefs"; - if (!fs::is_directory(path)) fs::create_directory(path); -} - -const char * -gr_preferences::get (const char *key) -{ - static char buf[1024]; - - FILE *fp = fopen (pathname (key), "r"); - if (fp == 0) { - perror (pathname (key)); - return 0; - } - - memset (buf, 0, sizeof (buf)); - size_t ret = fread (buf, 1, sizeof (buf) - 1, fp); - if(ret == 0) { - if(ferror(fp) != 0) { - perror (pathname (key)); - fclose (fp); - return 0; - } - } - fclose (fp); - return buf; -} - -void -gr_preferences::set (const char *key, const char *value) -{ - ensure_dir_path (); - - FILE *fp = fopen (pathname (key), "w"); - if (fp == 0){ - perror (pathname (key)); - return; - } - - size_t ret = fwrite (value, 1, strlen (value), fp); - if(ret == 0) { - if(ferror(fp) != 0) { - perror (pathname (key)); - fclose (fp); - return; - } - } - fclose (fp); -}; diff --git a/gnuradio-runtime/lib/gr_prefs.cc b/gnuradio-runtime/lib/gr_prefs.cc deleted file mode 100644 index 8a79c3335f..0000000000 --- a/gnuradio-runtime/lib/gr_prefs.cc +++ /dev/null @@ -1,391 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2013 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_prefs.h> -#include <gr_sys_paths.h> -#include <gr_constants.h> -#include <algorithm> - -#include <boost/filesystem/operations.hpp> -#include <boost/filesystem/path.hpp> -#include <boost/filesystem/fstream.hpp> -namespace fs = boost::filesystem; - -/* - * Stub implementations - */ - -static gr_prefs s_default_singleton; -static gr_prefs *s_singleton = &s_default_singleton; - -gr_prefs * -gr_prefs::singleton() -{ - return s_singleton; -} - -void -gr_prefs::set_singleton(gr_prefs *p) -{ - s_singleton = p; -} - -gr_prefs::gr_prefs() -{ - _read_files(); -} - -gr_prefs::~gr_prefs() -{ - // nop -} - -std::vector<std::string> -gr_prefs::_sys_prefs_filenames() -{ - std::vector<std::string> fnames; - - fs::path dir = gr_prefsdir(); - if(!fs::is_directory(dir)) - return fnames; - - fs::directory_iterator diritr(dir); - while(diritr != fs::directory_iterator()) { - fs::path p = *diritr++; - if(p.extension() != ".swp") - fnames.push_back(p.string()); - } - std::sort(fnames.begin(), fnames.end()); - - // Find if there is a ~/.gnuradio/config.conf file and add this to - // the end of the file list to override any preferences in the - // installed path config files. - fs::path homedir = fs::path(gr_appdata_path()); - homedir = homedir/".gnuradio/config.conf"; - if(fs::exists(homedir)) { - fnames.push_back(homedir.string()); - } - - return fnames; -} - -void -gr_prefs::_read_files() -{ - std::string config; - - std::vector<std::string> filenames = _sys_prefs_filenames(); - std::vector<std::string>::iterator sitr; - char tmp[1024]; - for(sitr = filenames.begin(); sitr != filenames.end(); sitr++) { - fs::ifstream fin(*sitr); - while(!fin.eof()) { - fin.getline(tmp, 1024); - std::string t(tmp); - // ignore empty lines or lines of just comments - if((t.size() > 0) && (t[0] != '#')) { - // remove any comments in the line - size_t hash = t.find("#"); - - // Use hash marks at the end of each segment as a delimiter - config += t.substr(0, hash) + '#'; - } - } - fin.close(); - } - - // Remove all whitespace. - config.erase(std::remove_if(config.begin(), config.end(), ::isspace), config.end()); - - // Convert the string into a map - _convert_to_map(config); -} - -void -gr_prefs::_convert_to_map(const std::string &conf) -{ - // Convert the string into an map of maps - // Map is structured as {section name: map of options} - // And options map is simply: {option name: option value} - std::string sub = conf; - size_t sec_start = sub.find("["); - while(sec_start != std::string::npos) { - sub = sub.substr(sec_start); - - size_t sec_end = sub.find("]"); - if(sec_end == std::string::npos) - throw std::runtime_error("Config file error: Mismatched section label.\n"); - - std::string sec = sub.substr(1, sec_end-1); - size_t next_sec_start = sub.find("[", sec_end); - std::string subsec = sub.substr(sec_end+1, next_sec_start-sec_end-2); - - std::transform(sec.begin(), sec.end(), sec.begin(), ::tolower); - - std::map<std::string, std::string> options_map = d_config_map[sec]; - size_t next_opt = 0; - size_t next_val = 0; - next_opt = subsec.find("#"); - while(next_opt < subsec.size()-1) { - next_val = subsec.find("=", next_opt); - std::string option = subsec.substr(next_opt+1, next_val-next_opt-1); - - next_opt = subsec.find("#", next_val); - std::string value = subsec.substr(next_val+1, next_opt-next_val-1); - - std::transform(option.begin(), option.end(), option.begin(), ::tolower); - options_map[option] = value; - } - - d_config_map[sec] = options_map; - - sec_start = sub.find("[", sec_end); - } -} - -std::string -gr_prefs::to_string() -{ - gr_config_map_itr sections; - gr_config_map_elem_itr options; - std::stringstream s; - - for(sections = d_config_map.begin(); sections != d_config_map.end(); sections++) { - s << "[" << sections->first << "]" << std::endl; - for(options = sections->second.begin(); options != sections->second.end(); options++) { - s << options->first << " = " << options->second << std::endl; - } - s << std::endl; - } - - return s.str(); -} - -void -gr_prefs::save() -{ - std::string conf = to_string(); - - fs::path homedir = fs::path(gr_appdata_path()); - homedir = homedir/".gnuradio/config.conf"; - fs::ofstream fout(homedir); - fout << conf; - fout.close(); -} - -char * -gr_prefs::option_to_env(std::string section, std::string option) -{ - std::stringstream envname; - std::string secname=section, optname=option; - - std::transform(section.begin(), section.end(), secname.begin(), ::toupper); - std::transform(option.begin(), option.end(), optname.begin(), ::toupper); - envname << "GR_CONF_" << secname << "_" << optname; - - return getenv(envname.str().c_str()); -} - -bool -gr_prefs::has_section(const std::string §ion) -{ - std::string s = section; - std::transform(section.begin(), section.end(), s.begin(), ::tolower); - return d_config_map.count(s) > 0; -} - -bool -gr_prefs::has_option(const std::string §ion, const std::string &option) -{ - if(option_to_env(section, option)) - return true; - - if(has_section(section)) { - std::string s = section; - std::transform(section.begin(), section.end(), s.begin(), ::tolower); - - std::string o = option; - std::transform(option.begin(), option.end(), o.begin(), ::tolower); - - gr_config_map_itr sec = d_config_map.find(s); - return sec->second.count(o) > 0; - } - else { - return false; - } -} - -const std::string -gr_prefs::get_string(const std::string §ion, const std::string &option, - const std::string &default_val) -{ - char *env = option_to_env(section, option); - if(env) - return std::string(env); - - if(has_option(section, option)) { - std::string s = section; - std::transform(section.begin(), section.end(), s.begin(), ::tolower); - - std::string o = option; - std::transform(option.begin(), option.end(), o.begin(), ::tolower); - - gr_config_map_itr sec = d_config_map.find(s); - gr_config_map_elem_itr opt = sec->second.find(o); - return opt->second; - } - else { - return default_val; - } -} - -void -gr_prefs::set_string(const std::string §ion, const std::string &option, - const std::string &val) -{ - std::string s = section; - std::transform(section.begin(), section.end(), s.begin(), ::tolower); - - std::string o = option; - std::transform(option.begin(), option.end(), o.begin(), ::tolower); - - std::map<std::string, std::string> opt_map = d_config_map[s]; - - opt_map[o] = val; - - d_config_map[s] = opt_map; -} - -bool -gr_prefs::get_bool(const std::string §ion, const std::string &option, bool default_val) -{ - if(has_option(section, option)) { - std::string str = get_string(section, option, ""); - if(str == "") { - return default_val; - } - std::transform(str.begin(), str.end(), str.begin(), ::tolower); - if((str == "true") || (str == "on") || (str == "1")) - return true; - else if((str == "false") || (str == "off") || (str == "0")) - return false; - else - return default_val; - } - else { - return default_val; - } -} - -void -gr_prefs::set_bool(const std::string §ion, const std::string &option, bool val) -{ - std::string s = section; - std::transform(section.begin(), section.end(), s.begin(), ::tolower); - - std::string o = option; - std::transform(option.begin(), option.end(), o.begin(), ::tolower); - - std::map<std::string, std::string> opt_map = d_config_map[s]; - - std::stringstream sstr; - sstr << (val == true); - opt_map[o] = sstr.str(); - - d_config_map[s] = opt_map; -} - -long -gr_prefs::get_long(const std::string §ion, const std::string &option, long default_val) -{ - if(has_option(section, option)) { - std::string str = get_string(section, option, ""); - if(str == "") { - return default_val; - } - std::stringstream sstr(str); - long n; - sstr >> n; - return n; - } - else { - return default_val; - } -} - -void -gr_prefs::set_long(const std::string §ion, const std::string &option, long val) -{ - std::string s = section; - std::transform(section.begin(), section.end(), s.begin(), ::tolower); - - std::string o = option; - std::transform(option.begin(), option.end(), o.begin(), ::tolower); - - std::map<std::string, std::string> opt_map = d_config_map[s]; - - std::stringstream sstr; - sstr << val; - opt_map[o] = sstr.str(); - - d_config_map[s] = opt_map; -} - -double -gr_prefs::get_double(const std::string §ion, const std::string &option, double default_val) -{ - if(has_option(section, option)) { - std::string str = get_string(section, option, ""); - if(str == "") { - return default_val; - } - std::stringstream sstr(str); - double n; - sstr >> n; - return n; - } - else { - return default_val; - } -} - -void -gr_prefs::set_double(const std::string §ion, const std::string &option, double val) -{ - std::string s = section; - std::transform(section.begin(), section.end(), s.begin(), ::tolower); - - std::string o = option; - std::transform(option.begin(), option.end(), o.begin(), ::tolower); - - std::map<std::string, std::string> opt_map = d_config_map[s]; - - std::stringstream sstr; - sstr << val; - opt_map[o] = sstr.str(); - - d_config_map[s] = opt_map; -} diff --git a/gnuradio-runtime/lib/gr_random.cc b/gnuradio-runtime/lib/gr_random.cc deleted file mode 100644 index 323839acc7..0000000000 --- a/gnuradio-runtime/lib/gr_random.cc +++ /dev/null @@ -1,183 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2002 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. - */ - -/* - * Copyright 1997 Massachusetts Institute of Technology - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation, and that the name of M.I.T. not be used in advertising or - * publicity pertaining to distribution of the software without specific, - * written prior permission. M.I.T. makes no representations about the - * suitability of this software for any purpose. It is provided "as is" - * without express or implied warranty. - * - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <math.h> -#include <gr_random.h> - -#define IA 16807 -#define IM 2147483647 -#define AM (1.0/IM) -#define IQ 127773 -#define IR 2836 -#define NDIV (1+(IM-1)/NTAB) -#define EPS 1.2e-7 -#define RNMX (1.0-EPS) - - -gr_random::gr_random (long seed) -{ - reseed (seed); -} - -void -gr_random::reseed (long seed) -{ - d_seed = seed; - d_iy = 0; - for (int i = 0; i < NTAB; i++) - d_iv[i] = 0; - d_iset = 0; - d_gset = 0; -} - -/* - * This looks like it returns a uniform random deviate between 0.0 and 1.0 - * It looks similar to code from "Numerical Recipes in C". - */ -float gr_random::ran1() -{ - int j; - long k; - float temp; - - if (d_seed <= 0 || !d_iy) { - if (-d_seed < 1) - d_seed=1; - else - d_seed = -d_seed; - for (j=NTAB+7;j>=0;j--) { - k=d_seed/IQ; - d_seed=IA*(d_seed-k*IQ)-IR*k; - if (d_seed < 0) - d_seed += IM; - if (j < NTAB) - d_iv[j] = d_seed; - } - d_iy=d_iv[0]; - } - k=(d_seed)/IQ; - d_seed=IA*(d_seed-k*IQ)-IR*k; - if (d_seed < 0) - d_seed += IM; - j=d_iy/NDIV; - d_iy=d_iv[j]; - d_iv[j] = d_seed; - temp=AM * d_iy; - if (temp > RNMX) - temp = RNMX; - return temp; -} - -/* - * Returns a normally distributed deviate with zero mean and variance 1. - * Also looks like it's from "Numerical Recipes in C". - */ -float gr_random::gasdev() -{ - float fac,rsq,v1,v2; - d_iset = 1 - d_iset; - if (d_iset) { - do { - v1=2.0*ran1()-1.0; - v2=2.0*ran1()-1.0; - rsq=v1*v1+v2*v2; - } while (rsq >= 1.0 || rsq == 0.0); - fac= sqrt(-2.0*log(rsq)/rsq); - d_gset=v1*fac; - return v2*fac; - } - return d_gset; -} - -/* - * Copied from The KC7WW / OH2BNS Channel Simulator - * FIXME Need to check how good this is at some point - */ - -float gr_random::laplacian() -{ - float z = ran1(); - if (z < 0.5) - return log(2.0 * z) / M_SQRT2; - else - return -log(2.0 * (1.0 - z)) / M_SQRT2; -} - -/* - * Copied from The KC7WW / OH2BNS Channel Simulator - * FIXME Need to check how good this is at some point - */ - - // 5 => scratchy, 8 => Geiger - -float gr_random::impulse(float factor = 5) -{ - float z = -M_SQRT2 * log(ran1()); - if (fabsf(z) <= factor) - return 0.0; - else - return z; -} - -/* - * Complex rayleigh is really gaussian I and gaussian Q - * It can also be generated by real rayleigh magnitude and - * uniform random angle - * Adapted from The KC7WW / OH2BNS Channel Simulator - * FIXME Need to check how good this is at some point - */ - -gr_complex gr_random::rayleigh_complex() -{ - return gr_complex(gasdev(),gasdev()); -} - -/* Other option - mag = rayleigh(); - ang = 2.0 * M_PI * RNG(); - *Rx = rxx * cos(z); - *Iy = rxx * sin(z); -*/ - - -float gr_random::rayleigh() -{ - return sqrt(-2.0 * log(ran1())); -} diff --git a/gnuradio-runtime/lib/gr_random.h b/gnuradio-runtime/lib/gr_random.h deleted file mode 100644 index 783c05f920..0000000000 --- a/gnuradio-runtime/lib/gr_random.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2002 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_RANDOM_H -#define INCLUDED_GR_RANDOM_H - -#include <gr_runtime_api.h> -#include <gr_complex.h> - -/*! - * \brief pseudo random number generator - * \ingroup math_blk - */ -class GR_RUNTIME_API gr_random { -protected: - static const int NTAB = 32; - long d_seed; - long d_iy; - long d_iv[NTAB]; - int d_iset; - float d_gset; - - -public: - gr_random (long seed=3021); - - void reseed (long seed); - - /*! - * \brief uniform random deviate in the range [0.0, 1.0) - */ - float ran1 (); - - /*! - * \brief normally distributed deviate with zero mean and variance 1 - */ - float gasdev (); - - float laplacian (); - float impulse (float factor); - float rayleigh (); - gr_complex rayleigh_complex (); -}; - -#endif /* INCLUDED_GR_RANDOM_H */ - diff --git a/gnuradio-runtime/lib/gr_realtime.cc b/gnuradio-runtime/lib/gr_realtime.cc deleted file mode 100644 index d7a7eab5ba..0000000000 --- a/gnuradio-runtime/lib/gr_realtime.cc +++ /dev/null @@ -1,33 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2007,2008 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_realtime.h> - -gr_rt_status_t -gr_enable_realtime_scheduling() -{ - return gr_enable_realtime_scheduling(); -} diff --git a/gnuradio-runtime/lib/gr_reverse.h b/gnuradio-runtime/lib/gr_reverse.h deleted file mode 100644 index aa8619619f..0000000000 --- a/gnuradio-runtime/lib/gr_reverse.h +++ /dev/null @@ -1,34 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_REVERSE_H -#define INCLUDED_GR_REVERSE_H - -#include <gr_runtime_api.h> -#include <vector> -#include <gr_complex.h> - -// reverse the order of taps -std::vector<float> gr_reverse (const std::vector<float> &taps); -std::vector<gr_complex> gr_reverse (const std::vector<gr_complex> &taps); - - -#endif /* INCLUDED_GR_REVERSE_H */ diff --git a/gnuradio-runtime/lib/gr_scheduler.h b/gnuradio-runtime/lib/gr_scheduler.h deleted file mode 100644 index 097f575c21..0000000000 --- a/gnuradio-runtime/lib/gr_scheduler.h +++ /dev/null @@ -1,65 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifndef INCLUDED_GR_SCHEDULER_H -#define INCLUDED_GR_SCHEDULER_H - -#include <gr_runtime_api.h> -#include <boost/utility.hpp> -#include <gr_block.h> -#include <gr_flat_flowgraph.h> - - -class gr_scheduler; -typedef boost::shared_ptr<gr_scheduler> gr_scheduler_sptr; - - -/*! - * \brief Abstract scheduler that takes a flattened flow graph and runs it. - * - * Preconditions: details, buffers and buffer readers have been assigned. - */ -class GR_RUNTIME_API gr_scheduler : boost::noncopyable -{ - -public: - /*! - * \brief Construct a scheduler and begin evaluating the graph. - * - * The scheduler will continue running until all blocks until they - * report that they are done or the stop method is called. - */ - gr_scheduler(gr_flat_flowgraph_sptr ffg, int max_noutput_items); - - virtual ~gr_scheduler(); - - /*! - * \brief Tell the scheduler to stop executing. - */ - virtual void stop() = 0; - - /*! - * \brief Block until the graph is done. - */ - virtual void wait() = 0; -}; - -#endif /* INCLUDED_GR_SCHEDULER_H */ diff --git a/gnuradio-runtime/lib/gr_scheduler_sts.cc b/gnuradio-runtime/lib/gr_scheduler_sts.cc deleted file mode 100644 index 10f01edaf6..0000000000 --- a/gnuradio-runtime/lib/gr_scheduler_sts.cc +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <gr_scheduler_sts.h> -#include <gr_single_threaded_scheduler.h> -#include <thread/thread_body_wrapper.h> - -class sts_container -{ - gr_block_vector_t d_blocks; - -public: - - sts_container(gr_block_vector_t blocks) - : d_blocks(blocks) {} - - void operator()() - { - gr_make_single_threaded_scheduler(d_blocks)->run(); - } -}; - - -gr_scheduler_sptr -gr_scheduler_sts::make(gr_flat_flowgraph_sptr ffg, int max_noutput_items) -{ - return gr_scheduler_sptr(new gr_scheduler_sts(ffg, max_noutput_items)); -} - -gr_scheduler_sts::gr_scheduler_sts(gr_flat_flowgraph_sptr ffg, int max_noutput_items) - : gr_scheduler(ffg, max_noutput_items) -{ - // Split the flattened flow graph into discrete partitions, each - // of which is topologically sorted. - - std::vector<gr_basic_block_vector_t> graphs = ffg->partition(); - - // For each partition, create a thread to evaluate it using - // an instance of the gr_single_threaded_scheduler - - for (std::vector<gr_basic_block_vector_t>::iterator p = graphs.begin(); - p != graphs.end(); p++) { - - gr_block_vector_t blocks = gr_flat_flowgraph::make_block_vector(*p); - d_threads.create_thread( - gr::thread::thread_body_wrapper<sts_container>(sts_container(blocks), - "single-threaded-scheduler")); - } -} - -gr_scheduler_sts::~gr_scheduler_sts() -{ - stop(); -} - -void -gr_scheduler_sts::stop() -{ - d_threads.interrupt_all(); -} - -void -gr_scheduler_sts::wait() -{ - d_threads.join_all(); -} diff --git a/gnuradio-runtime/lib/gr_scheduler_sts.h b/gnuradio-runtime/lib/gr_scheduler_sts.h deleted file mode 100644 index af98c6d8ba..0000000000 --- a/gnuradio-runtime/lib/gr_scheduler_sts.h +++ /dev/null @@ -1,63 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef INCLUDED_GR_SCHEDULER_STS_H -#define INCLUDED_GR_SCHEDULER_STS_H - -#include <gr_runtime_api.h> -#include <gr_scheduler.h> -#include <thread/thread_group.h> - -/*! - * \brief Concrete scheduler that uses the single_threaded_scheduler - */ -class GR_RUNTIME_API gr_scheduler_sts : public gr_scheduler -{ - gr::thread::thread_group d_threads; - -protected: - /*! - * \brief Construct a scheduler and begin evaluating the graph. - * - * The scheduler will continue running until all blocks until they - * report that they are done or the stop method is called. - */ - gr_scheduler_sts(gr_flat_flowgraph_sptr ffg, int max_noutput_items); - -public: - static gr_scheduler_sptr make(gr_flat_flowgraph_sptr ffg, int max_noutput_items); - - ~gr_scheduler_sts(); - - /*! - * \brief Tell the scheduler to stop executing. - */ - void stop(); - - /*! - * \brief Block until the graph is done. - */ - void wait(); -}; - - - - -#endif /* INCLUDED_GR_SCHEDULER_STS_H */ diff --git a/gnuradio-runtime/lib/gr_scheduler_tpb.cc b/gnuradio-runtime/lib/gr_scheduler_tpb.cc deleted file mode 100644 index e67078632f..0000000000 --- a/gnuradio-runtime/lib/gr_scheduler_tpb.cc +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <gr_scheduler_tpb.h> -#include <gr_tpb_thread_body.h> -#include <thread/thread_body_wrapper.h> -#include <sstream> - -/* - * You know, a lambda expression would be sooo much easier... - */ -class tpb_container -{ - gr_block_sptr d_block; - int d_max_noutput_items; - -public: - tpb_container(gr_block_sptr block, int max_noutput_items) - : d_block(block), d_max_noutput_items(max_noutput_items) {} - - void operator()() - { - gr_tpb_thread_body body(d_block, d_max_noutput_items); - } -}; - - -gr_scheduler_sptr -gr_scheduler_tpb::make(gr_flat_flowgraph_sptr ffg, int max_noutput_items) -{ - return gr_scheduler_sptr(new gr_scheduler_tpb(ffg, max_noutput_items)); -} - -gr_scheduler_tpb::gr_scheduler_tpb(gr_flat_flowgraph_sptr ffg, int max_noutput_items) - : gr_scheduler(ffg, max_noutput_items) -{ - // Get a topologically sorted vector of all the blocks in use. - // Being topologically sorted probably isn't going to matter, but - // there's a non-zero chance it might help... - - gr_basic_block_vector_t used_blocks = ffg->calc_used_blocks(); - used_blocks = ffg->topological_sort(used_blocks); - gr_block_vector_t blocks = gr_flat_flowgraph::make_block_vector(used_blocks); - - // Ensure that the done flag is clear on all blocks - - for (size_t i = 0; i < blocks.size(); i++){ - blocks[i]->detail()->set_done(false); - } - - // Fire off a thead for each block - - for (size_t i = 0; i < blocks.size(); i++){ - std::stringstream name; - name << "thread-per-block[" << i << "]: " << blocks[i]; - - // If set, use internal value instead of global value - if(blocks[i]->is_set_max_noutput_items()) - max_noutput_items = blocks[i]->max_noutput_items(); - - d_threads.create_thread( - gr::thread::thread_body_wrapper<tpb_container>(tpb_container(blocks[i], max_noutput_items), - name.str())); - } -} - -gr_scheduler_tpb::~gr_scheduler_tpb() -{ - stop(); -} - -void -gr_scheduler_tpb::stop() -{ - d_threads.interrupt_all(); -} - -void -gr_scheduler_tpb::wait() -{ - d_threads.join_all(); -} diff --git a/gnuradio-runtime/lib/gr_scheduler_tpb.h b/gnuradio-runtime/lib/gr_scheduler_tpb.h deleted file mode 100644 index 4ab7bb16d2..0000000000 --- a/gnuradio-runtime/lib/gr_scheduler_tpb.h +++ /dev/null @@ -1,61 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008 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 this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifndef INCLUDED_GR_SCHEDULER_TPB_H -#define INCLUDED_GR_SCHEDULER_TPB_H - -#include <gr_runtime_api.h> -#include <gr_scheduler.h> -#include <thread/thread_group.h> - -/*! - * \brief Concrete scheduler that uses a kernel thread-per-block - */ -class GR_RUNTIME_API gr_scheduler_tpb : public gr_scheduler -{ - gr::thread::thread_group d_threads; - -protected: - /*! - * \brief Construct a scheduler and begin evaluating the graph. - * - * The scheduler will continue running until all blocks until they - * report that they are done or the stop method is called. - */ - gr_scheduler_tpb(gr_flat_flowgraph_sptr ffg, int max_noutput_items); - -public: - static gr_scheduler_sptr make(gr_flat_flowgraph_sptr ffg, int max_noutput_items=100000); - - ~gr_scheduler_tpb(); - - /*! - * \brief Tell the scheduler to stop executing. - */ - void stop(); - - /*! - * \brief Block until the graph is done. - */ - void wait(); -}; - - -#endif /* INCLUDED_GR_SCHEDULER_TPB_H */ diff --git a/gnuradio-runtime/lib/gr_single_threaded_scheduler.cc b/gnuradio-runtime/lib/gr_single_threaded_scheduler.cc deleted file mode 100644 index 1bb9e9b0a8..0000000000 --- a/gnuradio-runtime/lib/gr_single_threaded_scheduler.cc +++ /dev/null @@ -1,364 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_single_threaded_scheduler.h> -#include <gr_block.h> -#include <gr_block_detail.h> -#include <gr_buffer.h> -#include <boost/thread.hpp> -#include <boost/format.hpp> -#include <iostream> -#include <limits> -#include <assert.h> -#include <stdio.h> - -// must be defined to either 0 or 1 -#define ENABLE_LOGGING 0 - -#if (ENABLE_LOGGING) -#define LOG(x) do { x; } while(0) -#else -#define LOG(x) do {;} while(0) -#endif - -static int which_scheduler = 0; - -gr_single_threaded_scheduler_sptr -gr_make_single_threaded_scheduler (const std::vector<gr_block_sptr> &blocks) -{ - return - gr_single_threaded_scheduler_sptr (new gr_single_threaded_scheduler (blocks)); -} - -gr_single_threaded_scheduler::gr_single_threaded_scheduler ( - const std::vector<gr_block_sptr> &blocks) - : d_blocks (blocks), d_enabled (true), d_log(0) -{ - if (ENABLE_LOGGING){ - std::string name = str(boost::format("sst-%d.log") % which_scheduler++); - d_log = new std::ofstream(name.c_str()); - *d_log << "gr_single_threaded_scheduler: " - << d_blocks.size () - << " blocks\n"; - } -} - -gr_single_threaded_scheduler::~gr_single_threaded_scheduler () -{ - if (ENABLE_LOGGING) - delete d_log; -} - -void -gr_single_threaded_scheduler::run () -{ - // d_enabled = true; // KLUDGE - main_loop (); -} - -void -gr_single_threaded_scheduler::stop () -{ - if (0) - std::cout << "gr_singled_threaded_scheduler::stop() " - << this << std::endl; - d_enabled = false; -} - -inline static unsigned int -round_up (unsigned int n, unsigned int multiple) -{ - return ((n + multiple - 1) / multiple) * multiple; -} - -inline static unsigned int -round_down (unsigned int n, unsigned int multiple) -{ - return (n / multiple) * multiple; -} - -// -// Return minimum available write space in all our downstream buffers -// or -1 if we're output blocked and the output we're blocked -// on is done. -// -static int -min_available_space (gr_block_detail *d, int output_multiple) -{ - int min_space = std::numeric_limits<int>::max(); - - for (int i = 0; i < d->noutputs (); i++){ - int n = round_down (d->output(i)->space_available (), output_multiple); - if (n == 0){ // We're blocked on output. - if (d->output(i)->done()){ // Downstream is done, therefore we're done. - return -1; - } - return 0; - } - min_space = std::min (min_space, n); - } - return min_space; -} - -void -gr_single_threaded_scheduler::main_loop () -{ - static const int DEFAULT_CAPACITY = 16; - - int noutput_items; - gr_vector_int ninput_items_required (DEFAULT_CAPACITY); - gr_vector_int ninput_items (DEFAULT_CAPACITY); - gr_vector_const_void_star input_items (DEFAULT_CAPACITY); - gr_vector_void_star output_items (DEFAULT_CAPACITY); - unsigned int bi; - unsigned int nalive; - int max_items_avail; - bool made_progress_last_pass; - bool making_progress; - - for (unsigned i = 0; i < d_blocks.size (); i++) - d_blocks[i]->detail()->set_done (false); // reset any done flags - - for (unsigned i = 0; i < d_blocks.size (); i++) // enable any drivers, etc. - d_blocks[i]->start(); - - - bi = 0; - made_progress_last_pass = true; - making_progress = false; - - // Loop while there are still blocks alive - - nalive = d_blocks.size (); - while (d_enabled && nalive > 0){ - - if (boost::this_thread::interruption_requested()) - break; - - gr_block *m = d_blocks[bi].get (); - gr_block_detail *d = m->detail().get (); - - LOG(*d_log << std::endl << m); - - if (d->done ()) - goto next_block; - - if (d->source_p ()){ - // Invoke sources as a last resort. As long as the previous pass - // made progress, don't call a source. - if (made_progress_last_pass){ - LOG(*d_log << " Skipping source\n"); - goto next_block; - } - - ninput_items_required.resize (0); - ninput_items.resize (0); - input_items.resize (0); - output_items.resize (d->noutputs ()); - - // determine the minimum available output space - noutput_items = min_available_space (d, m->output_multiple ()); - LOG(*d_log << " source\n noutput_items = " << noutput_items << std::endl); - if (noutput_items == -1) // we're done - goto were_done; - - if (noutput_items == 0){ // we're output blocked - LOG(*d_log << " BLKD_OUT\n"); - goto next_block; - } - - goto setup_call_to_work; // jump to common code - } - - else if (d->sink_p ()){ - ninput_items_required.resize (d->ninputs ()); - ninput_items.resize (d->ninputs ()); - input_items.resize (d->ninputs ()); - output_items.resize (0); - LOG(*d_log << " sink\n"); - - max_items_avail = 0; - for (int i = 0; i < d->ninputs (); i++){ - ninput_items[i] = d->input(i)->items_available(); - //if (ninput_items[i] == 0 && d->input(i)->done()) - if (ninput_items[i] < m->output_multiple() && d->input(i)->done()) - goto were_done; - - max_items_avail = std::max (max_items_avail, ninput_items[i]); - } - - // take a swag at how much output we can sink - noutput_items = (int) (max_items_avail * m->relative_rate ()); - noutput_items = round_down (noutput_items, m->output_multiple ()); - LOG(*d_log << " max_items_avail = " << max_items_avail << std::endl); - LOG(*d_log << " noutput_items = " << noutput_items << std::endl); - - if (noutput_items == 0){ // we're blocked on input - LOG(*d_log << " BLKD_IN\n"); - goto next_block; - } - - goto try_again; // Jump to code shared with regular case. - } - - else { - // do the regular thing - ninput_items_required.resize (d->ninputs ()); - ninput_items.resize (d->ninputs ()); - input_items.resize (d->ninputs ()); - output_items.resize (d->noutputs ()); - - max_items_avail = 0; - for (int i = 0; i < d->ninputs (); i++){ - ninput_items[i] = d->input(i)->items_available (); - max_items_avail = std::max (max_items_avail, ninput_items[i]); - } - - // determine the minimum available output space - noutput_items = min_available_space (d, m->output_multiple ()); - if (ENABLE_LOGGING){ - *d_log << " regular "; - if (m->relative_rate() >= 1.0) - *d_log << "1:" << m->relative_rate() << std::endl; - else - *d_log << 1.0/m->relative_rate() << ":1\n"; - *d_log << " max_items_avail = " << max_items_avail << std::endl; - *d_log << " noutput_items = " << noutput_items << std::endl; - } - if (noutput_items == -1) // we're done - goto were_done; - - if (noutput_items == 0){ // we're output blocked - LOG(*d_log << " BLKD_OUT\n"); - goto next_block; - } - -#if 0 - // Compute best estimate of noutput_items that we can really use. - noutput_items = - std::min ((unsigned) noutput_items, - std::max ((unsigned) m->output_multiple(), - round_up ((unsigned) (max_items_avail * m->relative_rate()), - m->output_multiple ()))); - - LOG(*d_log << " revised noutput_items = " << noutput_items << std::endl); -#endif - - try_again: - if (m->fixed_rate()){ - // try to work it forward starting with max_items_avail. - // We want to try to consume all the input we've got. - int reqd_noutput_items = m->fixed_rate_ninput_to_noutput(max_items_avail); - reqd_noutput_items = round_up(reqd_noutput_items, m->output_multiple()); - if (reqd_noutput_items > 0 && reqd_noutput_items <= noutput_items) - noutput_items = reqd_noutput_items; - } - - // ask the block how much input they need to produce noutput_items - m->forecast (noutput_items, ninput_items_required); - - // See if we've got sufficient input available - - int i; - for (i = 0; i < d->ninputs (); i++) - if (ninput_items_required[i] > ninput_items[i]) // not enough - break; - - if (i < d->ninputs ()){ // not enough input on input[i] - // if we can, try reducing the size of our output request - if (noutput_items > m->output_multiple ()){ - noutput_items /= 2; - noutput_items = round_up (noutput_items, m->output_multiple ()); - goto try_again; - } - - // We're blocked on input - LOG(*d_log << " BLKD_IN\n"); - if (d->input(i)->done()) // If the upstream block is done, we're done - goto were_done; - - // Is it possible to ever fulfill this request? - if (ninput_items_required[i] > d->input(i)->max_possible_items_available ()){ - // Nope, never going to happen... - std::cerr << "\nsched: <gr_block " << m->name() - << " (" << m->unique_id() << ")>" - << " is requesting more input data\n" - << " than we can provide.\n" - << " ninput_items_required = " - << ninput_items_required[i] << "\n" - << " max_possible_items_available = " - << d->input(i)->max_possible_items_available() << "\n" - << " If this is a filter, consider reducing the number of taps.\n"; - goto were_done; - } - - goto next_block; - } - - // We've got enough data on each input to produce noutput_items. - // Finish setting up the call to work. - - for (int i = 0; i < d->ninputs (); i++) - input_items[i] = d->input(i)->read_pointer(); - - setup_call_to_work: - - for (int i = 0; i < d->noutputs (); i++) - output_items[i] = d->output(i)->write_pointer(); - - // Do the actual work of the block - int n = m->general_work (noutput_items, ninput_items, - input_items, output_items); - LOG(*d_log << " general_work: noutput_items = " << noutput_items - << " result = " << n << std::endl); - - if (n == -1) // block is done - goto were_done; - - d->produce_each (n); // advance write pointers - if (n > 0) - making_progress = true; - - goto next_block; - } - assert (0); - - were_done: - LOG(*d_log << " were_done\n"); - d->set_done (true); - nalive--; - - next_block: - if (++bi >= d_blocks.size ()){ - bi = 0; - made_progress_last_pass = making_progress; - making_progress = false; - } - } - - for (unsigned i = 0; i < d_blocks.size (); i++) // disable any drivers, etc. - d_blocks[i]->stop(); -} diff --git a/gnuradio-runtime/lib/gr_sync_block.cc b/gnuradio-runtime/lib/gr_sync_block.cc deleted file mode 100644 index 94efcdc8ee..0000000000 --- a/gnuradio-runtime/lib/gr_sync_block.cc +++ /dev/null @@ -1,68 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_sync_block.h> - -gr_sync_block::gr_sync_block (const std::string &name, - gr_io_signature_sptr input_signature, - gr_io_signature_sptr output_signature) - : gr_block(name, input_signature, output_signature) -{ - set_fixed_rate(true); -} - - -void -gr_sync_block::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - unsigned ninputs = ninput_items_required.size(); - for (unsigned i = 0; i < ninputs; i++) - ninput_items_required[i] = fixed_rate_noutput_to_ninput (noutput_items); -} - -int -gr_sync_block::fixed_rate_noutput_to_ninput(int noutput_items) -{ - return noutput_items + history() - 1; -} - -int -gr_sync_block::fixed_rate_ninput_to_noutput(int ninput_items) -{ - return std::max(0, ninput_items - (int)history() + 1); -} - -int -gr_sync_block::general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - int r = work (noutput_items, input_items, output_items); - if (r > 0) - consume_each (r); - return r; -} diff --git a/gnuradio-runtime/lib/gr_sync_decimator.cc b/gnuradio-runtime/lib/gr_sync_decimator.cc deleted file mode 100644 index a0f907db53..0000000000 --- a/gnuradio-runtime/lib/gr_sync_decimator.cc +++ /dev/null @@ -1,69 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_sync_decimator.h> - -gr_sync_decimator::gr_sync_decimator (const std::string &name, - gr_io_signature_sptr input_signature, - gr_io_signature_sptr output_signature, - unsigned decimation) - : gr_sync_block (name, input_signature, output_signature) -{ - set_decimation (decimation); -} - -void -gr_sync_decimator::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - unsigned ninputs = ninput_items_required.size (); - for (unsigned i = 0; i < ninputs; i++) - ninput_items_required[i] = fixed_rate_noutput_to_ninput(noutput_items); -} - -int -gr_sync_decimator::fixed_rate_noutput_to_ninput(int noutput_items) -{ - return noutput_items * decimation() + history() - 1; -} - -int -gr_sync_decimator::fixed_rate_ninput_to_noutput(int ninput_items) -{ - return std::max(0, ninput_items - (int)history() + 1) / decimation(); -} - -int -gr_sync_decimator::general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - int r = work (noutput_items, input_items, output_items); - if (r > 0) - consume_each (r * decimation ()); - return r; -} - diff --git a/gnuradio-runtime/lib/gr_sync_interpolator.cc b/gnuradio-runtime/lib/gr_sync_interpolator.cc deleted file mode 100644 index ece873c14a..0000000000 --- a/gnuradio-runtime/lib/gr_sync_interpolator.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004,2008 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_sync_interpolator.h> - -gr_sync_interpolator::gr_sync_interpolator (const std::string &name, - gr_io_signature_sptr input_signature, - gr_io_signature_sptr output_signature, - unsigned interpolation) - : gr_sync_block (name, input_signature, output_signature) -{ - set_interpolation (interpolation); -} - -void -gr_sync_interpolator::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - unsigned ninputs = ninput_items_required.size (); - for (unsigned i = 0; i < ninputs; i++) - ninput_items_required[i] = fixed_rate_noutput_to_ninput(noutput_items); -} - -int -gr_sync_interpolator::fixed_rate_noutput_to_ninput(int noutput_items) -{ - return noutput_items / interpolation() + history() - 1; -} - -int -gr_sync_interpolator::fixed_rate_ninput_to_noutput(int ninput_items) -{ - return std::max(0, ninput_items - (int)history() + 1) * interpolation(); -} - -int -gr_sync_interpolator::general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - int r = work (noutput_items, input_items, output_items); - if (r > 0) - consume_each (r / interpolation ()); - return r; -} - - diff --git a/gnuradio-runtime/lib/gr_tagged_stream_block.cc b/gnuradio-runtime/lib/gr_tagged_stream_block.cc deleted file mode 100644 index a60515f481..0000000000 --- a/gnuradio-runtime/lib/gr_tagged_stream_block.cc +++ /dev/null @@ -1,146 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2013 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 <boost/format.hpp> -#include <gr_tagged_stream_block.h> - -gr_tagged_stream_block::gr_tagged_stream_block (const std::string &name, - gr_io_signature_sptr input_signature, - gr_io_signature_sptr output_signature, - const std::string &length_tag_key) - : gr_block(name, input_signature, output_signature), - d_length_tag_key(pmt::string_to_symbol(length_tag_key)), - d_n_input_items_reqd(input_signature->min_streams(), 0), - d_length_tag_key_str(length_tag_key) -{ -} - - -// This is evil hackery: We trick the scheduler into creating the right number of input items -void -gr_tagged_stream_block::forecast (int noutput_items, gr_vector_int &ninput_items_required) -{ - unsigned ninputs = ninput_items_required.size(); - for (unsigned i = 0; i < ninputs; i++) { - if (i < d_n_input_items_reqd.size() && d_n_input_items_reqd[i] != 0) { - ninput_items_required[i] = d_n_input_items_reqd[i]; - } else { - // If there's no item, there's no tag--so there must at least be one! - ninput_items_required[i] = std::max(1, (int) std::floor((double) noutput_items / relative_rate() + 0.5)); - } - } -} - - -void -gr_tagged_stream_block::parse_length_tags( - const std::vector<std::vector<gr_tag_t> > &tags, - gr_vector_int &n_input_items_reqd -){ - for (unsigned i = 0; i < tags.size(); i++) { - for (unsigned k = 0; k < tags[i].size(); k++) { - if (tags[i][k].key == d_length_tag_key) { - n_input_items_reqd[i] = pmt::to_long(tags[i][k].value); - remove_item_tag(i, tags[i][k]); - } - } - } -} - - -int -gr_tagged_stream_block::calculate_output_stream_length(const gr_vector_int &ninput_items) -{ - int noutput_items = *std::max_element(ninput_items.begin(), ninput_items.end()); - return (int) std::floor(relative_rate() * noutput_items + 0.5); -} - - -void -gr_tagged_stream_block::update_length_tags(int n_produced, int n_ports) -{ - for (int i = 0; i < n_ports; i++) { - add_item_tag(i, nitems_written(i), - d_length_tag_key, - pmt::from_long(n_produced) - ); - } - return; -} - - -int -gr_tagged_stream_block::general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) -{ - if (d_length_tag_key_str.empty()) { - return work(noutput_items, ninput_items, input_items, output_items); - } - - if (d_n_input_items_reqd[0] == 0) { // Otherwise, it's already set from a previous call - std::vector<std::vector<gr_tag_t> > tags(input_items.size(), std::vector<gr_tag_t>()); - for (unsigned i = 0; i < input_items.size(); i++) { - get_tags_in_range(tags[i], i, nitems_read(i), nitems_read(i)+1); - } - d_n_input_items_reqd.assign(input_items.size(), -1); - parse_length_tags(tags, d_n_input_items_reqd); - } - for (unsigned i = 0; i < input_items.size(); i++) { - if (d_n_input_items_reqd[i] == -1) { - GR_LOG_FATAL(d_logger, boost::format("Missing a required length tag on port %1% at item #%2%") % i % nitems_read(i)); - throw std::runtime_error("Missing length tag."); - } - if (d_n_input_items_reqd[i] > ninput_items[i]) { - return 0; - } - } - - int min_output_size = calculate_output_stream_length(d_n_input_items_reqd); - if (noutput_items < min_output_size) { - set_min_noutput_items(min_output_size); - return 0; - } - set_min_noutput_items(1); - - // WORK CALLED HERE // - int n_produced = work(noutput_items, d_n_input_items_reqd, input_items, output_items); - ////////////////////// - - if (n_produced == WORK_DONE) { - return n_produced; - } - for (int i = 0; i < (int) d_n_input_items_reqd.size(); i++) { - consume(i, d_n_input_items_reqd[i]); - } - update_length_tags(n_produced, output_items.size()); - - d_n_input_items_reqd.assign(input_items.size(), 0); - - return n_produced; -} - diff --git a/gnuradio-runtime/lib/gr_test.cc b/gnuradio-runtime/lib/gr_test.cc deleted file mode 100644 index cd5ef83611..0000000000 --- a/gnuradio-runtime/lib/gr_test.cc +++ /dev/null @@ -1,177 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006,2008,2010 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_test.h> -#include <gr_io_signature.h> -#include <stdexcept> -#include <iostream> -#include <string.h> - -gr_test_sptr gr_make_test (const std::string &name, - int min_inputs, int max_inputs, unsigned int sizeof_input_item, - int min_outputs, int max_outputs, unsigned int sizeof_output_item, - unsigned int history,unsigned int output_multiple,double relative_rate, - bool fixed_rate,gr_consume_type_t cons_type, gr_produce_type_t prod_type) -{ - return gnuradio::get_initial_sptr(new gr_test (name, min_inputs,max_inputs,sizeof_input_item, - min_outputs,max_outputs,sizeof_output_item, - history,output_multiple,relative_rate,fixed_rate,cons_type, prod_type)); -} - - gr_test::gr_test (const std::string &name,int min_inputs, int max_inputs, unsigned int sizeof_input_item, - int min_outputs, int max_outputs, unsigned int sizeof_output_item, - unsigned int history,unsigned int output_multiple,double relative_rate, - bool fixed_rate,gr_consume_type_t cons_type, gr_produce_type_t prod_type): gr_block (name, - gr_make_io_signature (min_inputs, max_inputs, sizeof_input_item), - gr_make_io_signature (min_outputs, max_outputs, sizeof_output_item)), - d_sizeof_input_item(sizeof_input_item), - d_sizeof_output_item(sizeof_output_item), - d_check_topology(true), - d_consume_type(cons_type), - d_min_consume(0), - d_max_consume(0), - d_produce_type(prod_type), - d_min_produce(0), - d_max_produce(0) - { - set_history(history); - set_output_multiple(output_multiple); - set_relative_rate(relative_rate); - set_fixed_rate(fixed_rate); - } - -int -gr_test::general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items) - { - //touch all inputs and outputs to detect segfaults - unsigned ninputs = input_items.size (); - unsigned noutputs= output_items.size(); - for (unsigned i = 0; i < ninputs; i++) - { - char * in=(char *)input_items[i]; - if (ninput_items[i]< (int)(noutput_items+history())) - { - std::cerr << "ERROR: ninput_items[" << i << "] < noutput_items+history()" << std::endl; - std::cerr << "ninput_items[" << i << "] = " << ninput_items[i] << std::endl; - std::cerr << "noutput_items+history() = " << noutput_items+history() << std::endl; - std::cerr << "noutput_items = " << noutput_items << std::endl; - std::cerr << "history() = " << history() << std::endl; - throw std::runtime_error ("gr_test"); - } else - { - for (int j=0;j<ninput_items[i];j++) - { - //Touch every available input_item - //We use a class variable to avoid the compiler to optimize this away - for(unsigned int k=0;k<d_sizeof_input_item;k++) - d_temp= in[j*d_sizeof_input_item+k]; - } - switch (d_consume_type) - { - case CONSUME_NOUTPUT_ITEMS: - consume(i,noutput_items); - break; - case CONSUME_NOUTPUT_ITEMS_LIMIT_MAX: - consume(i,std::min(noutput_items,d_max_consume)); - break; - case CONSUME_NOUTPUT_ITEMS_LIMIT_MIN: - consume(i,std::min(std::max(noutput_items,d_min_consume),ninput_items[i])); - break; - case CONSUME_ALL_AVAILABLE: - consume(i,ninput_items[i]); - break; - case CONSUME_ALL_AVAILABLE_LIMIT_MAX: - consume(i,std::min(ninput_items[i],d_max_consume)); - break; -/* //This could result in segfault, uncomment if you want to test this - case CONSUME_ALL_AVAILABLE_LIMIT_MIN: - consume(i,std::max(ninput_items[i],d_max_consume)); - break;*/ - case CONSUME_ZERO: - consume(i,0); - break; - case CONSUME_ONE: - consume(i,1); - break; - case CONSUME_MINUS_ONE: - consume(i,-1); - break; - default: - consume(i,noutput_items); - } - } - } - for (unsigned i = 0; i < noutputs; i++) - { - char * out=(char *)output_items[i]; - { - for (int j=0;j<noutput_items;j++) - { - //Touch every available output_item - for(unsigned int k=0;k<d_sizeof_output_item;k++) - out[j*d_sizeof_input_item+k]=0; - } - } - } - //Now copy input to output until max ninputs or max noutputs is reached - int common_nports=std::min(ninputs,noutputs); - if(d_sizeof_output_item==d_sizeof_input_item) - for (int i = 0; i < common_nports; i++) - { - memcpy(output_items[i],input_items[i],noutput_items*d_sizeof_input_item); - } - int noutput_items_produced=0; - switch (d_produce_type){ - case PRODUCE_NOUTPUT_ITEMS: - noutput_items_produced=noutput_items; - break; - case PRODUCE_NOUTPUT_ITEMS_LIMIT_MAX: - noutput_items_produced=std::min(noutput_items,d_max_produce); - break; -/* //This could result in segfault, uncomment if you want to test this - case PRODUCE_NOUTPUT_ITEMS_LIMIT_MIN: - noutput_items_produced=std::max(noutput_items,d_min_produce); - break;*/ - case PRODUCE_ZERO: - noutput_items_produced=0; - break; - case PRODUCE_ONE: - noutput_items_produced=1; - break; - case PRODUCE_MINUS_ONE: - noutput_items_produced=-1; - break; - default: - noutput_items_produced=noutput_items; - } - return noutput_items_produced; - } - - - diff --git a/gnuradio-runtime/lib/gr_test.h b/gnuradio-runtime/lib/gr_test.h deleted file mode 100644 index 2276ab1967..0000000000 --- a/gnuradio-runtime/lib/gr_test.h +++ /dev/null @@ -1,195 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2006 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_TEST_H -#define INCLUDED_GR_TEST_H - -#include <gr_runtime_api.h> -#include <gr_block.h> -#include <string> -#include "gr_test_types.h" - -class gr_test; -typedef boost::shared_ptr<gr_test> gr_test_sptr; - -// public constructor -GR_RUNTIME_API gr_test_sptr gr_make_test (const std::string &name=std::string("gr_test"), - int min_inputs=1, int max_inputs=1, unsigned int sizeof_input_item=1, - int min_outputs=1, int max_outputs=1, unsigned int sizeof_output_item=1, - unsigned int history=1,unsigned int output_multiple=1,double relative_rate=1.0, - bool fixed_rate=true,gr_consume_type_t cons_type=CONSUME_NOUTPUT_ITEMS, gr_produce_type_t prod_type=PRODUCE_NOUTPUT_ITEMS); - -/*! - * \brief Test class for testing runtime system (setting up buffers and such.) - * \ingroup misc - * - * This block does not do any usefull actual data processing. - * It just exposes setting all standard block parameters using the contructor or public methods. - * - * This block can be usefull when testing the runtime system. - * You can force this block to have a large history, decimation - * factor and/or large output_multiple. - * The runtime system should detect this and create large enough buffers - * all through the signal chain. - */ -class GR_RUNTIME_API gr_test : public gr_block { - - public: - - ~gr_test (){} - -int general_work (int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items); - // ---------------------------------------------------------------- - // override these to define your behavior - // ---------------------------------------------------------------- - - /*! - * \brief Estimate input requirements given output request - * - * \param noutput_items number of output items to produce - * \param ninput_items_required number of input items required on each input stream - * - * Given a request to product \p noutput_items, estimate the number of - * data items required on each input stream. The estimate doesn't have - * to be exact, but should be close. - */ - void forecast (int noutput_items, - gr_vector_int &ninput_items_required) - { - unsigned ninputs = ninput_items_required.size (); - for (unsigned i = 0; i < ninputs; i++) - ninput_items_required[i] = (int)((double)noutput_items / relative_rate()) + (int)history(); - } - - - /*! - * \brief Force check topology to return true or false. - * - * \param check_topology value to return when check_topology is called (true or false) - * default check_topology returns true - * - */ - void set_check_topology (bool check_topology){ d_check_topology=check_topology;} - - /*! - * \brief Confirm that ninputs and noutputs is an acceptable combination. - * - * \param ninputs number of input streams connected - * \param noutputs number of output streams connected - * - * \returns true if this is a valid configuration for this block. - * - * This function is called by the runtime system whenever the - * topology changes. Most classes do not need to override this. - * This check is in addition to the constraints specified by the input - * and output gr_io_signatures. - */ - bool check_topology (int ninputs, int noutputs) { return d_check_topology;} - - // ---------------------------------------------------------------- - /* - * The following two methods provide special case info to the - * scheduler in the event that a block has a fixed input to output - * ratio. gr_sync_block, gr_sync_decimator and gr_sync_interpolator - * override these. If you're fixed rate, subclass one of those. - */ - /*! - * \brief Given ninput samples, return number of output samples that will be produced. - * N.B. this is only defined if fixed_rate returns true. - * Generally speaking, you don't need to override this. - */ - int fixed_rate_ninput_to_noutput(int ninput) { return (int)((double)ninput/relative_rate()); } - - /*! - * \brief Given noutput samples, return number of input samples required to produce noutput. - * N.B. this is only defined if fixed_rate returns true. - */ - int fixed_rate_noutput_to_ninput(int noutput) { return (int)((double)noutput*relative_rate()); } - - /*! - * \brief Set if fixed rate should return true. - * N.B. This is normally a private method but we make it available here as public. - */ - void set_fixed_rate_public(bool fixed_rate){ set_fixed_rate(fixed_rate);} - - /*! - * \brief Set the consume pattern. - * - * \param cons_type which consume pattern to use - */ - void set_consume_type (gr_consume_type_t cons_type) { d_consume_type=cons_type;} - - /*! - * \brief Set the consume limit. - * - * \param limit min or maximum items to consume (depending on consume_type) - */ - void set_consume_limit (unsigned int limit) { d_min_consume=limit; d_max_consume=limit;} - - /*! - * \brief Set the produce pattern. - * - * \param prod_type which produce pattern to use - */ - void set_produce_type (gr_produce_type_t prod_type) { d_produce_type=prod_type;} - - /*! - * \brief Set the produce limit. - * - * \param limit min or maximum items to produce (depending on produce_type) - */ - void set_produce_limit (unsigned int limit) { d_min_produce=limit; d_max_produce=limit;} - - // ---------------------------------------------------------------------------- - - - - protected: - unsigned int d_sizeof_input_item; - unsigned int d_sizeof_output_item; - bool d_check_topology; - char d_temp; - gr_consume_type_t d_consume_type; - int d_min_consume; - int d_max_consume; - gr_produce_type_t d_produce_type; - int d_min_produce; - int d_max_produce; - gr_test (const std::string &name,int min_inputs, int max_inputs, unsigned int sizeof_input_item, - int min_outputs, int max_outputs, unsigned int sizeof_output_item, - unsigned int history,unsigned int output_multiple,double relative_rate, - bool fixed_rate,gr_consume_type_t cons_type, gr_produce_type_t prod_type); - - - - friend GR_RUNTIME_API gr_test_sptr gr_make_test (const std::string &name,int min_inputs, int max_inputs, unsigned int sizeof_input_item, - int min_outputs, int max_outputs, unsigned int sizeof_output_item, - unsigned int history,unsigned int output_multiple,double relative_rate, - bool fixed_rate,gr_consume_type_t cons_type, gr_produce_type_t prod_type); -}; - - - -#endif /* INCLUDED_GR_TEST_H */ diff --git a/gnuradio-runtime/lib/gr_top_block.cc b/gnuradio-runtime/lib/gr_top_block.cc deleted file mode 100644 index 362057aadb..0000000000 --- a/gnuradio-runtime/lib/gr_top_block.cc +++ /dev/null @@ -1,162 +0,0 @@ -/* -*- 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 <unistd.h> -#include <gr_top_block.h> -#include <gr_top_block_impl.h> -#include <gr_io_signature.h> -#include <gr_prefs.h> -#include <iostream> - -gr_top_block_sptr -gr_make_top_block(const std::string &name) -{ - return gnuradio::get_initial_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() -{ - stop(); - wait(); - - delete d_impl; -} - -void -gr_top_block::start(int max_noutput_items) -{ - d_impl->start(max_noutput_items); - - if(gr_prefs::singleton()->get_bool("ControlPort", "on", false)) { - setup_rpc(); - } -} - -void -gr_top_block::stop() -{ - d_impl->stop(); -} - -void -gr_top_block::wait() -{ - d_impl->wait(); -} - -void -gr_top_block::run(int max_noutput_items) -{ - start(max_noutput_items); - wait(); -} - -void -gr_top_block::lock() -{ - d_impl->lock(); -} - -void -gr_top_block::unlock() -{ - d_impl->unlock(); -} - -std::string -gr_top_block::edge_list() -{ - return d_impl->edge_list(); -} - -void -gr_top_block::dump() -{ - d_impl->dump(); -} - -int -gr_top_block::max_noutput_items() -{ - return d_impl->max_noutput_items(); -} - -void -gr_top_block::set_max_noutput_items(int nmax) -{ - d_impl->set_max_noutput_items(nmax); -} - -gr_top_block_sptr -gr_top_block::to_top_block() -{ - return cast_to_top_block_sptr(shared_from_this()); -} - -void -gr_top_block::setup_rpc() -{ -#ifdef GR_CTRLPORT - if(is_rpc_set()) return; - // Getters - add_rpc_variable( - rpcbasic_sptr(new rpcbasic_register_get<gr_top_block, int>( - alias(), "max noutput_items", - &gr_top_block::max_noutput_items, - pmt::mp(0), pmt::mp(8192), pmt::mp(8192), - "items", "Max number of output items", - RPC_PRIVLVL_MIN, DISPNULL))); - - if(gr_prefs::singleton()->get_bool("ControlPort", "edges_list", false)) { - add_rpc_variable( - rpcbasic_sptr(new rpcbasic_register_get<gr_top_block, std::string>( - alias(), "edge list", - &gr_top_block::edge_list, - pmt::mp(""), pmt::mp(""), pmt::mp(""), - "edges", "List of edges in the graph", - RPC_PRIVLVL_MIN, DISPNULL))); - } - - // Setters - add_rpc_variable( - rpcbasic_sptr(new rpcbasic_register_set<gr_top_block, int>( - alias(), "max noutput_items", - &gr_top_block::set_max_noutput_items, - pmt::mp(0), pmt::mp(8192), pmt::mp(8192), - "items", "Max number of output items", - RPC_PRIVLVL_MIN, DISPNULL))); - rpc_set(); -#endif /* GR_CTRLPORT */ -} diff --git a/gnuradio-runtime/lib/gr_top_block_impl.cc b/gnuradio-runtime/lib/gr_top_block_impl.cc deleted file mode 100644 index ef645ea57d..0000000000 --- a/gnuradio-runtime/lib/gr_top_block_impl.cc +++ /dev/null @@ -1,211 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007,2008 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_sts.h> -#include <gr_scheduler_tpb.h> -#include <gr_prefs.h> - -#include <stdexcept> -#include <iostream> -#include <string.h> -#include <unistd.h> -#include <stdlib.h> - -#define GR_TOP_BLOCK_IMPL_DEBUG 0 - - -typedef gr_scheduler_sptr (*scheduler_maker)(gr_flat_flowgraph_sptr ffg, - int max_noutput_items); - -static struct scheduler_table { - const char *name; - scheduler_maker f; -} scheduler_table[] = { - { "TPB", gr_scheduler_tpb::make }, // first entry is default - { "STS", gr_scheduler_sts::make } -}; - -static gr_scheduler_sptr -make_scheduler(gr_flat_flowgraph_sptr ffg, int max_noutput_items) -{ - static scheduler_maker factory = 0; - - if (factory == 0){ - char *v = getenv("GR_SCHEDULER"); - if (!v) - factory = scheduler_table[0].f; // use default - else { - for (size_t i = 0; i < sizeof(scheduler_table)/sizeof(scheduler_table[0]); i++){ - if (strcmp(v, scheduler_table[i].name) == 0){ - factory = scheduler_table[i].f; - break; - } - } - if (factory == 0){ - std::cerr << "warning: Invalid GR_SCHEDULER environment variable value \"" - << v << "\". Using \"" << scheduler_table[0].name << "\"\n"; - factory = scheduler_table[0].f; - } - } - } - return factory(ffg, max_noutput_items); -} - - -gr_top_block_impl::gr_top_block_impl(gr_top_block *owner) - : d_owner(owner), d_ffg(), - d_state(IDLE), d_lock_count(0) -{ -} - -gr_top_block_impl::~gr_top_block_impl() -{ - d_owner = 0; -} - -void -gr_top_block_impl::start(int max_noutput_items) -{ - gr::thread::scoped_lock l(d_mutex); - - d_max_noutput_items = max_noutput_items; - - if (d_state != IDLE) - throw std::runtime_error("top_block::start: top block already running or wait() not called after previous stop()"); - - if (d_lock_count > 0) - throw std::runtime_error("top_block::start: can't start with flow graph locked"); - - // Create new flat flow graph by flattening hierarchy - d_ffg = d_owner->flatten(); - - // Validate new simple flow graph and wire it up - d_ffg->validate(); - d_ffg->setup_connections(); - - // Only export perf. counters if ControlPort config param is enabled - // and if the PerfCounter option 'export' is turned on. - gr_prefs *p = gr_prefs::singleton(); - if(p->get_bool("ControlPort", "on", false) && p->get_bool("PerfCounters", "export", false)) - d_ffg->enable_pc_rpc(); - - d_scheduler = make_scheduler(d_ffg, d_max_noutput_items); - d_state = RUNNING; -} - -void -gr_top_block_impl::stop() -{ - if (d_scheduler) - d_scheduler->stop(); -} - - -void -gr_top_block_impl::wait() -{ - if (d_scheduler) - d_scheduler->wait(); - - d_state = IDLE; -} - -// 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() -{ - gr::thread::scoped_lock lock(d_mutex); - d_lock_count++; -} - -void -gr_top_block_impl::unlock() -{ - gr::thread::scoped_lock lock(d_mutex); - - if (d_lock_count <= 0){ - d_lock_count = 0; // fix it, then complain - throw std::runtime_error("unpaired unlock() call"); - } - - d_lock_count--; - if (d_lock_count > 0 || d_state == IDLE) // nothing to do - return; - - restart(); -} - -/* - * restart is called with d_mutex held - */ -void -gr_top_block_impl::restart() -{ - stop(); // Stop scheduler and wait for completion - wait(); - - // Create new simple flow graph - gr_flat_flowgraph_sptr new_ffg = d_owner->flatten(); - new_ffg->validate(); // check consistency, sanity, etc - new_ffg->merge_connections(d_ffg); // reuse buffers, etc - d_ffg = new_ffg; - - // Create a new scheduler to execute it - d_scheduler = make_scheduler(d_ffg, d_max_noutput_items); - d_state = RUNNING; -} - -std::string -gr_top_block_impl::edge_list() -{ - if(d_ffg) - return d_ffg->edge_list(); - else - return ""; -} - -void -gr_top_block_impl::dump() -{ - if (d_ffg) - d_ffg->dump(); -} - -int -gr_top_block_impl::max_noutput_items() -{ - return d_max_noutput_items; -} - -void -gr_top_block_impl::set_max_noutput_items(int nmax) -{ - d_max_noutput_items = nmax; -} diff --git a/gnuradio-runtime/lib/gr_top_block_impl.h b/gnuradio-runtime/lib/gr_top_block_impl.h deleted file mode 100644 index 345a33152f..0000000000 --- a/gnuradio-runtime/lib/gr_top_block_impl.h +++ /dev/null @@ -1,88 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2007,2008 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_runtime_api.h> -#include <gr_scheduler.h> -#include <thread/thread.h> - -/*! - *\brief Abstract implementation details of gr_top_block - * \ingroup internal - * - * The actual implementation of gr_top_block. Separate class allows - * decoupling of changes from dependent classes. - * - */ -class GR_RUNTIME_API gr_top_block_impl -{ -public: - gr_top_block_impl(gr_top_block *owner); - ~gr_top_block_impl(); - - // Create and start scheduler threads - void start(int max_noutput_items=100000000); - - // 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(); - - // Return a string list of edges - std::string edge_list(); - - // Dump the flowgraph to stdout - void dump(); - - // Get the number of max noutput_items in the flowgraph - int max_noutput_items(); - - // Set the maximum number of noutput_items in the flowgraph - void set_max_noutput_items(int nmax); - -protected: - - enum tb_state { IDLE, RUNNING }; - - gr_top_block *d_owner; - gr_flat_flowgraph_sptr d_ffg; - gr_scheduler_sptr d_scheduler; - - gr::thread::mutex d_mutex; // protects d_state and d_lock_count - tb_state d_state; - int d_lock_count; - int d_max_noutput_items; - -private: - void restart(); -}; - -#endif /* INCLUDED_GR_TOP_BLOCK_IMPL_H */ diff --git a/gnuradio-runtime/lib/gr_tpb_detail.cc b/gnuradio-runtime/lib/gr_tpb_detail.cc deleted file mode 100644 index 46eb6bbe0d..0000000000 --- a/gnuradio-runtime/lib/gr_tpb_detail.cc +++ /dev/null @@ -1,70 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008,2009 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 this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <gr_tpb_detail.h> -#include <gr_block.h> -#include <gr_block_detail.h> -#include <gr_buffer.h> - -using namespace pmt; - -/* - * We assume that no worker threads are ever running when the - * graph structure is being manipulated, thus it's safe for us to poke - * around in our neighbors w/o holding any locks. - */ - -void -gr_tpb_detail::notify_upstream(gr_block_detail *d) -{ - // For each of our inputs, tell the guy upstream that we've consumed - // some input, and that he most likely has more output buffer space - // available. - - for (size_t i = 0; i < d->d_input.size(); i++){ - // Can you say, "pointer chasing?" - d->d_input[i]->buffer()->link()->detail()->d_tpb.set_output_changed(); - } -} - -void -gr_tpb_detail::notify_downstream(gr_block_detail *d) -{ - // For each of our outputs, tell the guys downstream that they have - // new input available. - - for (size_t i = 0; i < d->d_output.size(); i++){ - gr_buffer_sptr buf = d->d_output[i]; - for (size_t j = 0, k = buf->nreaders(); j < k; j++) - buf->reader(j)->link()->detail()->d_tpb.set_input_changed(); - } -} - -void -gr_tpb_detail::notify_neighbors(gr_block_detail *d) -{ - notify_downstream(d); - notify_upstream(d); -} - diff --git a/gnuradio-runtime/lib/gr_tpb_thread_body.cc b/gnuradio-runtime/lib/gr_tpb_thread_body.cc deleted file mode 100644 index 11934dbf09..0000000000 --- a/gnuradio-runtime/lib/gr_tpb_thread_body.cc +++ /dev/null @@ -1,151 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2008,2009,2011 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 this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif -#include <gr_tpb_thread_body.h> -#include <gr_prefs.h> -#include <iostream> -#include <boost/thread.hpp> -#include <pmt/pmt.h> -#include <boost/foreach.hpp> - -using namespace pmt; - -gr_tpb_thread_body::gr_tpb_thread_body(gr_block_sptr block, int max_noutput_items) - : d_exec(block, max_noutput_items) -{ - //std::cerr << "gr_tpb_thread_body: " << block << std::endl; - - gr_block_detail *d = block->detail().get(); - gr_block_executor::state s; - pmt_t msg; - - d->threaded = true; - d->thread = gr::thread::get_current_thread_id(); - - gr_prefs *p = gr_prefs::singleton(); - size_t max_nmsgs = static_cast<size_t>(p->get_long("DEFAULT", "max_messages", 100)); - - // Set thread affinity if it was set before fg was started. - if(block->processor_affinity().size() > 0) { - gr::thread::thread_bind_to_processor(d->thread, block->processor_affinity()); - } - - while (1){ - boost::this_thread::interruption_point(); - - // handle any queued up messages - //BOOST_FOREACH( pmt::pmt_t port, block->msg_queue.keys() ) - - BOOST_FOREACH( gr_basic_block::msg_queue_map_t::value_type &i, block->msg_queue ) - { - // Check if we have a message handler attached before getting - // any messages. This is mostly a protection for the unknown - // startup sequence of the threads. - if(block->has_msg_handler(i.first)) { - while ((msg = block->delete_head_nowait(i.first))){ - block->dispatch_msg(i.first,msg); - } - } - else { - // If we don't have a handler but are building up messages, - // prune the queue from the front to keep memory in check. - if(block->nmsgs(i.first) > max_nmsgs) - msg = block->delete_head_nowait(i.first); - } - } - - d->d_tpb.clear_changed(); - // run one iteration if we are a connected stream block - if(d->noutputs() >0 || d->ninputs()>0){ - s = d_exec.run_one_iteration(); - } else { - s = gr_block_executor::BLKD_IN; - } - - switch(s){ - case gr_block_executor::READY: // Tell neighbors we made progress. - d->d_tpb.notify_neighbors(d); - break; - - case gr_block_executor::READY_NO_OUTPUT: // Notify upstream only - d->d_tpb.notify_upstream(d); - break; - - case gr_block_executor::DONE: // Game over. - d->d_tpb.notify_neighbors(d); - return; - - case gr_block_executor::BLKD_IN: // Wait for input. - { - gr::thread::scoped_lock guard(d->d_tpb.mutex); - while (!d->d_tpb.input_changed){ - - // wait for input or message - while(!d->d_tpb.input_changed && block->empty_p()) - d->d_tpb.input_cond.wait(guard); - - // handle all pending messages - BOOST_FOREACH( gr_basic_block::msg_queue_map_t::value_type &i, block->msg_queue ) - { - while ((msg = block->delete_head_nowait(i.first))){ - guard.unlock(); // release lock while processing msg - block->dispatch_msg(i.first, msg); - guard.lock(); - } - } - } - } - break; - - - case gr_block_executor::BLKD_OUT: // Wait for output buffer space. - { - gr::thread::scoped_lock guard(d->d_tpb.mutex); - while (!d->d_tpb.output_changed){ - - // wait for output room or message - while(!d->d_tpb.output_changed && block->empty_p()) - d->d_tpb.output_cond.wait(guard); - - // handle all pending messages - BOOST_FOREACH( gr_basic_block::msg_queue_map_t::value_type &i, block->msg_queue ) - { - while ((msg = block->delete_head_nowait(i.first))){ - guard.unlock(); // release lock while processing msg - block->dispatch_msg(i.first,msg); - guard.lock(); - } - } - } - } - break; - - default: - assert(0); - } - } -} - -gr_tpb_thread_body::~gr_tpb_thread_body() -{ -} diff --git a/gnuradio-runtime/lib/gr_vco.h b/gnuradio-runtime/lib/gr_vco.h deleted file mode 100644 index 3ceaf15dd4..0000000000 --- a/gnuradio-runtime/lib/gr_vco.h +++ /dev/null @@ -1,94 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2005 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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 _GR_VCO_H_ -#define _GR_VCO_H_ - - -#include <vector> -#include <gr_sincos.h> -#include <cmath> -#include <gr_complex.h> - -/*! - * \brief base class template for Voltage Controlled Oscillator (VCO) - * \ingroup misc - */ - -//FIXME Eventually generalize this to fixed point - -template<class o_type, class i_type> -class gr_vco { -public: - gr_vco () : d_phase (0) {} - - virtual ~gr_vco () {} - - // radians - void set_phase (double angle) { - d_phase = angle; - } - - void adjust_phase (double delta_phase) { - d_phase += delta_phase; - if (fabs (d_phase) > M_PI){ - - while (d_phase > M_PI) - d_phase -= 2*M_PI; - - while (d_phase < -M_PI) - d_phase += 2*M_PI; - } - } - - double get_phase () const { return d_phase; } - - // compute sin and cos for current phase angle - void sincos (float *sinx, float *cosx) const; - - // compute cos or sin for current phase angle - float cos () const { return std::cos (d_phase); } - float sin () const { return std::sin (d_phase); } - - // compute a block at a time - void cos (float *output, const float *input, int noutput_items, double k, double ampl = 1.0); - -protected: - double d_phase; -}; - -template<class o_type, class i_type> -void -gr_vco<o_type,i_type>::sincos (float *sinx, float *cosx) const -{ - gr_sincosf (d_phase, sinx, cosx); -} - -template<class o_type, class i_type> -void -gr_vco<o_type,i_type>::cos (float *output, const float *input, int noutput_items, double k, double ampl) -{ - for (int i = 0; i < noutput_items; i++){ - output[i] = cos() * ampl; - adjust_phase(input[i] * k); - } -} -#endif /* _GR_VCO_H_ */ diff --git a/gnuradio-runtime/lib/gr_vmcircbuf.cc b/gnuradio-runtime/lib/gr_vmcircbuf.cc deleted file mode 100644 index 522d9515d0..0000000000 --- a/gnuradio-runtime/lib/gr_vmcircbuf.cc +++ /dev/null @@ -1,295 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003 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_vmcircbuf.h> -#include <assert.h> -#include <stdexcept> -#include <gr_preferences.h> -#include <stdio.h> -#include <string.h> -#include <gr_local_sighandler.h> -#include <vector> -#include <boost/format.hpp> - -// all the factories we know about -#include <gr_vmcircbuf_createfilemapping.h> -#include <gr_vmcircbuf_sysv_shm.h> -#include <gr_vmcircbuf_mmap_shm_open.h> -#include <gr_vmcircbuf_mmap_tmpfile.h> - -static const char *FACTORY_PREF_KEY = "gr_vmcircbuf_default_factory"; - -gr_vmcircbuf::~gr_vmcircbuf () -{ -} - -gr_vmcircbuf_factory::~gr_vmcircbuf_factory () -{ -} - -// ---------------------------------------------------------------- - -static gr_vmcircbuf_factory *s_default_factory = 0; - -gr_vmcircbuf_factory * -gr_vmcircbuf_sysconfig::get_default_factory () -{ - if (s_default_factory) - return s_default_factory; - - bool verbose = false; - - std::vector<gr_vmcircbuf_factory *> all = all_factories (); - - const char *name = gr_preferences::get (FACTORY_PREF_KEY); - - if (name){ - for (unsigned int i = 0; i < all.size (); i++){ - if (strcmp (name, all[i]->name ()) == 0){ - s_default_factory = all[i]; - if (verbose) - fprintf (stderr, "gr_vmcircbuf_sysconfig: using %s\n", - s_default_factory->name ()); - return s_default_factory; - } - } - } - - // either we don't have a default, or the default named is not in our - // list of factories. Find the first factory that works. - - if (verbose) - fprintf (stderr, "gr_vmcircbuf_sysconfig: finding a working factory...\n"); - - for (unsigned int i = 0; i < all.size (); i++){ - if (test_factory (all[i], verbose)){ - set_default_factory (all[i]); - return s_default_factory; - } - } - - // We're screwed! - - fprintf (stderr, "gr_vmcircbuf_sysconfig: unable to find a working factory!\n"); - throw std::runtime_error ("gr_vmcircbuf_sysconfig"); -} - -std::vector<gr_vmcircbuf_factory *> -gr_vmcircbuf_sysconfig::all_factories () -{ - std::vector<gr_vmcircbuf_factory *> result; - - result.push_back (gr_vmcircbuf_createfilemapping_factory::singleton ()); -#ifdef TRY_SHM_VMCIRCBUF - result.push_back (gr_vmcircbuf_sysv_shm_factory::singleton ()); - result.push_back (gr_vmcircbuf_mmap_shm_open_factory::singleton ()); -#endif - result.push_back (gr_vmcircbuf_mmap_tmpfile_factory::singleton ()); - - return result; -} - -void -gr_vmcircbuf_sysconfig::set_default_factory (gr_vmcircbuf_factory *f) -{ - gr_preferences::set (FACTORY_PREF_KEY, f->name ()); - s_default_factory = f; -} - - -// ------------------------------------------------------------------------ -// test code for vmcircbuf factories -// ------------------------------------------------------------------------ - -static void -init_buffer (gr_vmcircbuf *c, int counter, int size) -{ - unsigned int *p = (unsigned int *) c->pointer_to_first_copy (); - for (unsigned int i = 0; i < size / sizeof (int); i++) - p[i] = counter + i; -} - -static bool -check_mapping (gr_vmcircbuf *c, int counter, int size, const char *msg, bool verbose) -{ - bool ok = true; - - if (verbose) - fprintf (stderr, "... %s", msg); - - unsigned int *p1 = (unsigned int *) c->pointer_to_first_copy (); - unsigned int *p2 = (unsigned int *) c->pointer_to_second_copy (); - - // fprintf (stderr, "p1 = %p, p2 = %p\n", p1, p2); - - for (unsigned int i = 0; i < size / sizeof (int); i++){ - if (p1[i] != counter + i){ - ok = false; - if (verbose) - fprintf (stderr, " p1[%d] == %u, expected %u\n", i, p1[i], counter + i); - break; - } - if (p2[i] != counter + i){ - if (verbose) - fprintf (stderr, " p2[%d] == %u, expected %u\n", i, p2[i], counter + i); - ok = false; - break; - } - } - - if (ok && verbose){ - fprintf (stderr, " OK\n"); - } - return ok; -} - -static const char * -memsize (int size) -{ - static std::string buf; - if (size >= (1 << 20)){ - buf = str(boost::format("%dMB") % (size / (1 << 20))); - } - else if (size >= (1 << 10)){ - buf = str(boost::format("%dKB") % (size / (1 << 10))); - } - else { - buf = str(boost::format("%d") % size); - } - return buf.c_str(); -} - -static bool -test_a_bunch (gr_vmcircbuf_factory *factory, int n, int size, int *start_ptr, bool verbose) -{ - bool ok = true; - std::vector<int> counter(n); - std::vector<gr_vmcircbuf *> c(n); - int cum_size = 0; - - for (int i = 0; i < n; i++){ - counter[i] = *start_ptr; - *start_ptr += size; - if ((c[i] = factory->make (size)) == 0){ - if (verbose) - fprintf (stderr, - "Failed to allocate gr_vmcircbuf number %d of size %d (cum = %s)\n", - i + 1, size, memsize (cum_size)); - return false; - } - init_buffer (c[i], counter[i], size); - cum_size += size; - } - - for (int i = 0; i < n; i++){ - std::string msg = str(boost::format("test_a_bunch_%dx%s[%d]") % n % memsize (size) % i); - ok &= check_mapping (c[i], counter[i], size, msg.c_str(), verbose); - } - - for (int i = 0; i < n; i++){ - delete c[i]; - c[i] = 0; - } - - return ok; -} - -static bool -standard_tests (gr_vmcircbuf_factory *f, int verbose) -{ - if (verbose >= 1) - fprintf (stderr, "Testing %s...\n", f->name ()); - - bool v = verbose >= 2; - int granularity = f->granularity (); - int start = 0; - bool ok = true; - - ok &= test_a_bunch (f, 1, 1 * granularity, &start, v); // 1 x 4KB = 4KB - - if (ok){ - ok &= test_a_bunch (f, 64, 4 * granularity, &start, v); // 64 x 16KB = 1MB - ok &= test_a_bunch (f, 4, 4 * (1L << 20), &start, v); // 4 x 4MB = 16MB -// ok &= test_a_bunch (f, 256, 256 * (1L << 10), &start, v); // 256 x 256KB = 64MB - } - - if (verbose >= 1) - fprintf (stderr, "....... %s: %s", f->name (), ok ? "OK\n" : "Doesn't work\n"); - - return ok; -} - -bool -gr_vmcircbuf_sysconfig::test_factory (gr_vmcircbuf_factory *f, int verbose) -{ - // Install local signal handlers for SIGSEGV and SIGBUS. - // If something goes wrong, these signals may be invoked. - -#ifdef SIGSEGV - gr_local_sighandler sigsegv (SIGSEGV, gr_local_sighandler::throw_signal); -#endif -#ifdef SIGBUS - gr_local_sighandler sigbus (SIGBUS, gr_local_sighandler::throw_signal); -#endif -#ifdef SIGSYS - gr_local_sighandler sigsys (SIGSYS, gr_local_sighandler::throw_signal); -#endif - - try { - return standard_tests (f, verbose); - } - catch (gr_signal &sig){ - if (verbose){ - fprintf (stderr, "....... %s: %s", f->name (), "Doesn't work\n"); - fprintf (stderr, - "gr_vmcircbuf_factory::test_factory (%s): caught %s\n", - f->name (), sig.name().c_str()); - return false; - } - } - catch (...){ - if (verbose){ - fprintf (stderr, "....... %s: %s", f->name (), "Doesn't work\n"); - fprintf (stderr, - "gr_vmcircbuf_factory::test_factory (%s): some kind of uncaught exception\n", - f->name ()); - } - return false; - } - return false; // never gets here. shut compiler up. -} - -bool -gr_vmcircbuf_sysconfig::test_all_factories (int verbose) -{ - bool ok = false; - - std::vector<gr_vmcircbuf_factory *> all = all_factories (); - - for (unsigned int i = 0; i < all.size (); i++) - ok |= test_factory (all[i], verbose); - - return ok; -} diff --git a/gnuradio-runtime/lib/gr_vmcircbuf.h b/gnuradio-runtime/lib/gr_vmcircbuf.h deleted file mode 100644 index e7f492a8bd..0000000000 --- a/gnuradio-runtime/lib/gr_vmcircbuf.h +++ /dev/null @@ -1,122 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003 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 _GR_VMCIRCBUF_H_ -#define _GR_VMCIRCBUF_H_ - -#include <gr_runtime_api.h> -#include <vector> - -/*! - * \brief abstract class to implement doubly mapped virtual memory circular buffers - * \ingroup internal - */ -class GR_RUNTIME_API gr_vmcircbuf { - protected: - int d_size; - char *d_base; - - // CREATORS - gr_vmcircbuf (int size) : d_size (size), d_base (0) {}; - - public: - virtual ~gr_vmcircbuf (); - - // ACCESSORS - void *pointer_to_first_copy () const { return d_base; } - void *pointer_to_second_copy () const { return d_base + d_size; } -}; - -/*! - * \brief abstract factory for creating circular buffers - */ -class GR_RUNTIME_API gr_vmcircbuf_factory { - protected: - gr_vmcircbuf_factory () {}; - virtual ~gr_vmcircbuf_factory (); - - public: - - /*! - * \brief return name of this factory - */ - virtual const char *name () const = 0; - - /*! - * \brief return granularity of mapping, typically equal to page size - */ - virtual int granularity () = 0; - - /*! - * \brief return a gr_vmcircbuf, or 0 if unable. - * - * Call this to create a doubly mapped circular buffer. - */ - virtual gr_vmcircbuf *make (int size) = 0; -}; - -/* - * \brief pulls together all implementations of gr_vmcircbuf - */ -class GR_RUNTIME_API gr_vmcircbuf_sysconfig { - public: - - /* - * \brief return the single instance of the default factory. - * - * returns the default factory to use if it's already defined, - * else find the first working factory and use it. - */ - static gr_vmcircbuf_factory *get_default_factory (); - - - static int granularity () { return get_default_factory()->granularity(); } - static gr_vmcircbuf *make (int size) { return get_default_factory()->make(size); } - - - // N.B. not all factories are guaranteed to work. - // It's too hard to check everything at config time, so we check at runtime - static std::vector<gr_vmcircbuf_factory *> all_factories (); - - // make this factory the default - static void set_default_factory (gr_vmcircbuf_factory *f); - - /*! - * \brief Does this factory really work? - * - * verbose = 0: silent - * verbose = 1: names of factories tested and results - * verbose = 2: all intermediate results - */ - static bool test_factory (gr_vmcircbuf_factory *f, int verbose); - - /*! - * \brief Test all factories, return true if at least one of them works - * verbose = 0: silent - * verbose = 1: names of factories tested and results - * verbose = 2: all intermediate results - */ - static bool test_all_factories (int verbose); -}; - - -#endif /* _GR_VMCIRCBUF_H_ */ diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_createfilemapping.cc b/gnuradio-runtime/lib/gr_vmcircbuf_createfilemapping.cc deleted file mode 100644 index 1b4d9700a5..0000000000 --- a/gnuradio-runtime/lib/gr_vmcircbuf_createfilemapping.cc +++ /dev/null @@ -1,204 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003,2005,2011 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 <stdexcept> -#include <assert.h> -#include <unistd.h> -#include <fcntl.h> -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_MMAN_H -#include <sys/mman.h> -#endif -#include <errno.h> -#include <stdio.h> -#include <gr_pagesize.h> -#include <gr_vmcircbuf_createfilemapping.h> -#include <boost/format.hpp> - -#ifdef HAVE_CREATEFILEMAPPING -// Print Windows error (could/should be global?) -static void -werror( char *where, DWORD last_error ) -{ - char buf[1024]; - - FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - last_error, - 0, // default language - buf, - sizeof(buf)/sizeof(TCHAR), // buffer size - NULL ); - fprintf( stderr, "%s: Error %d: %s", where, last_error, buf ); - return; -} -#endif - - -gr_vmcircbuf_createfilemapping::gr_vmcircbuf_createfilemapping (int size) - : gr_vmcircbuf (size) -{ -#if !defined(HAVE_CREATEFILEMAPPING) - fprintf (stderr, "%s: createfilemapping is not available\n",__FUNCTION__); - throw std::runtime_error ("gr_vmcircbuf_createfilemapping"); -#else - static int s_seg_counter = 0; - - if (size <= 0 || (size % gr_pagesize ()) != 0){ - fprintf (stderr, "gr_vmcircbuf_createfilemapping: invalid size = %d\n", size); - throw std::runtime_error ("gr_vmcircbuf_createfilemapping"); - } - - std::string seg_name = str(boost::format("/gnuradio-%d-%d") % getpid () % s_seg_counter); - - d_handle = CreateFileMapping(INVALID_HANDLE_VALUE, // use paging file - NULL, // default security - PAGE_READWRITE, // read/write access - 0, // max. object size - size, // buffer size - seg_name.c_str()); // name of mapping object - - s_seg_counter++; - if (d_handle == NULL || d_handle == INVALID_HANDLE_VALUE){ - std::string msg = str(boost::format( - "gr_vmcircbuf_mmap_createfilemapping: CreateFileMapping [%s]") % - seg_name ); - werror((char *) msg.c_str(), GetLastError() ); - throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping"); - } - - // Allocate virtual memory of the needed size, then free it so we can use it - LPVOID first_tmp; - first_tmp = VirtualAlloc( NULL, 2*size, MEM_RESERVE, PAGE_NOACCESS ); - if (first_tmp == NULL){ - werror( "gr_vmcircbuf_mmap_createfilemapping: VirtualAlloc", GetLastError()); - CloseHandle(d_handle); // cleanup - throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping"); - } - - if (VirtualFree(first_tmp, 0, MEM_RELEASE) == 0){ - werror( "gr_vmcircbuf_mmap_createfilemapping: VirtualFree", GetLastError()); - CloseHandle(d_handle); // cleanup - throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping"); - } - - d_first_copy = MapViewOfFileEx((HANDLE)d_handle, // handle to map object - FILE_MAP_WRITE, // read/write permission - 0, - 0, - size, - first_tmp); - if (d_first_copy != first_tmp){ - werror( "gr_vmcircbuf_mmap_createfilemapping: MapViewOfFileEx(1)", GetLastError()); - CloseHandle(d_handle); // cleanup - throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping"); - } - - d_second_copy = MapViewOfFileEx((HANDLE)d_handle, // handle to map object - FILE_MAP_WRITE, // read/write permission - 0, - 0, - size, - (char *)first_tmp + size);//(LPVOID) ((char *)d_first_copy + size)); - - if (d_second_copy != (char *)first_tmp + size){ - werror( "gr_vmcircbuf_mmap_createfilemapping: MapViewOfFileEx(2)", GetLastError()); - UnmapViewOfFile(d_first_copy); - CloseHandle(d_handle); // cleanup - throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping"); - } - -#ifdef DEBUG - fprintf (stderr,"gr_vmcircbuf_mmap_createfilemapping: contiguous? mmap %p %p %p %p\n", - (char *)d_first_copy, (char *)d_second_copy, size, (char *)d_first_copy + size); -#endif - - // Now remember the important stuff - d_base = (char *) d_first_copy; - d_size = size; -#endif /*HAVE_CREATEFILEMAPPING*/ -} - -gr_vmcircbuf_createfilemapping::~gr_vmcircbuf_createfilemapping () -{ -#ifdef HAVE_CREATEFILEMAPPING - if (UnmapViewOfFile(d_first_copy) == 0) - { - werror("gr_vmcircbuf_createfilemapping: UnmapViewOfFile(d_first_copy)", GetLastError()); - } - d_base=NULL; - if (UnmapViewOfFile(d_second_copy) == 0) - { - werror("gr_vmcircbuf_createfilemapping: UnmapViewOfFile(d_second_copy)", GetLastError()); - } - //d_second=NULL; - CloseHandle(d_handle); -#endif -} - -// ---------------------------------------------------------------- -// The factory interface -// ---------------------------------------------------------------- - - -gr_vmcircbuf_factory *gr_vmcircbuf_createfilemapping_factory::s_the_factory = 0; - -gr_vmcircbuf_factory * -gr_vmcircbuf_createfilemapping_factory::singleton () -{ - if (s_the_factory) - return s_the_factory; - s_the_factory = new gr_vmcircbuf_createfilemapping_factory (); - return s_the_factory; -} - -int -gr_vmcircbuf_createfilemapping_factory::granularity () -{ -#ifdef HAVE_CREATEFILEMAPPING - // return 65536;//TODO, check, is this needed or can we just use gr_pagesize() - SYSTEM_INFO system_info; - GetSystemInfo(&system_info); - //fprintf(stderr,"win32 AllocationGranularity %p\n",(int)system_info.dwAllocationGranularity); - return (int)system_info.dwAllocationGranularity; -#else - return gr_pagesize (); -#endif -} - -gr_vmcircbuf * -gr_vmcircbuf_createfilemapping_factory::make (int size) -{ - try - { - return new gr_vmcircbuf_createfilemapping (size); - } - catch (...) - { - return 0; - } -} diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_createfilemapping.h b/gnuradio-runtime/lib/gr_vmcircbuf_createfilemapping.h deleted file mode 100644 index a4bb5cbe92..0000000000 --- a/gnuradio-runtime/lib/gr_vmcircbuf_createfilemapping.h +++ /dev/null @@ -1,76 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003,2005 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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 _GR_VMCIRCBUF_CREATEFILEMAPPING_H_ -#define _GR_VMCIRCBUF_CREATEFILEMAPPING_H_ - -#include <gr_runtime_api.h> -#include <gr_vmcircbuf.h> - -#ifdef HAVE_CREATEFILEMAPPING -#include <windows.h> -#endif -/*! - * \brief concrete class to implement circular buffers with mmap and shm_open - * \ingroup internal - */ -class GR_RUNTIME_API gr_vmcircbuf_createfilemapping : public gr_vmcircbuf -{ - public: - // CREATORS - gr_vmcircbuf_createfilemapping (int size); - virtual ~gr_vmcircbuf_createfilemapping (); -#ifdef HAVE_CREATEFILEMAPPING - private: - HANDLE d_handle; - LPVOID d_first_copy; - LPVOID d_second_copy; -#endif -}; - -/*! - * \brief concrete factory for circular buffers built using mmap and shm_open - */ -class GR_RUNTIME_API gr_vmcircbuf_createfilemapping_factory : public gr_vmcircbuf_factory -{ - private: - static gr_vmcircbuf_factory *s_the_factory; - - public: - static gr_vmcircbuf_factory *singleton (); - - virtual const char *name () const { return "gr_vmcircbuf_createfilemapping_factory"; } - - /*! - * \brief return granularity of mapping, typically equal to page size - */ - virtual int granularity (); - - /*! - * \brief return a gr_vmcircbuf, or 0 if unable. - * - * Call this to create a doubly mapped circular buffer. - */ - virtual gr_vmcircbuf *make (int size); -}; - -#endif /* _GR_VMCIRCBUF_CREATEFILEMAPPING_H_ */ diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_mmap_shm_open.cc b/gnuradio-runtime/lib/gr_vmcircbuf_mmap_shm_open.cc deleted file mode 100644 index 3d170081d0..0000000000 --- a/gnuradio-runtime/lib/gr_vmcircbuf_mmap_shm_open.cc +++ /dev/null @@ -1,205 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003,2011 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_vmcircbuf_mmap_shm_open.h> -#include <stdexcept> -#include <assert.h> -#include <unistd.h> -#include <fcntl.h> -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_MMAN_H -#include <sys/mman.h> -#endif -#include <errno.h> -#include <stdio.h> -#include <gr_pagesize.h> -#include <gr_sys_paths.h> - - -gr_vmcircbuf_mmap_shm_open::gr_vmcircbuf_mmap_shm_open (int size) - : gr_vmcircbuf (size) -{ -#if !defined(HAVE_MMAP) || !defined(HAVE_SHM_OPEN) - fprintf (stderr, "gr_vmcircbuf_mmap_shm_open: mmap or shm_open is not available\n"); - throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); -#else - static int s_seg_counter = 0; - - if (size <= 0 || (size % gr_pagesize ()) != 0){ - fprintf (stderr, "gr_vmcircbuf_mmap_shm_open: invalid size = %d\n", size); - throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); - } - - int shm_fd = -1; - char seg_name[1024]; - static bool portable_format = true; - - // open a new named shared memory segment - - while (1){ - if (portable_format){ - - // This is the POSIX recommended "portable format". - // Of course the "portable format" doesn't work on some systems... - - snprintf (seg_name, sizeof (seg_name), - "/gnuradio-%d-%d", getpid (), s_seg_counter); - } - else { - - // Where the "portable format" doesn't work, we try building - // a full filesystem pathname pointing into a suitable temporary directory. - - snprintf (seg_name, sizeof (seg_name), - "%s/gnuradio-%d-%d", gr_tmp_path (), getpid (), s_seg_counter); - } - - shm_fd = shm_open (seg_name, O_RDWR | O_CREAT | O_EXCL, 0600); - if (shm_fd == -1 && errno == EACCES && portable_format){ - portable_format = false; - continue; // try again using "non-portable format" - } - - s_seg_counter++; - - if (shm_fd == -1){ - if (errno == EEXIST) // Named segment already exists (shouldn't happen). Try again - continue; - - char msg[1024]; - snprintf (msg, sizeof (msg), "gr_vmcircbuf_mmap_shm_open: shm_open [%s]", seg_name); - perror (msg); - throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); - } - break; - } - - // We've got a new shared memory segment fd open. - // Now set it's length to 2x what we really want and mmap it in. - - if (ftruncate (shm_fd, (off_t) 2 * size) == -1){ - close (shm_fd); // cleanup - perror ("gr_vmcircbuf_mmap_shm_open: ftruncate (1)"); - throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); - } - - void *first_copy = mmap (0, 2 * size, - PROT_READ | PROT_WRITE, MAP_SHARED, - shm_fd, (off_t) 0); - - if (first_copy == MAP_FAILED){ - close (shm_fd); // cleanup - perror ("gr_vmcircbuf_mmap_shm_open: mmap (1)"); - throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); - } - - // unmap the 2nd half - if (munmap ((char *) first_copy + size, size) == -1){ - close (shm_fd); // cleanup - perror ("gr_vmcircbuf_mmap_shm_open: munmap (1)"); - throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); - } - - // map the first half into the now available hole where the - // second half used to be. - - void *second_copy = mmap ((char *) first_copy + size, size, - PROT_READ | PROT_WRITE, MAP_SHARED, - shm_fd, (off_t) 0); - - if (second_copy == MAP_FAILED){ - close (shm_fd); // cleanup - perror ("gr_vmcircbuf_mmap_shm_open: mmap (2)"); - throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); - } - -#if 0 // OS/X doesn't allow you to resize the segment - - // cut the shared memory segment down to size - if (ftruncate (shm_fd, (off_t) size) == -1){ - close (shm_fd); // cleanup - perror ("gr_vmcircbuf_mmap_shm_open: ftruncate (2)"); - throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); - } -#endif - - close (shm_fd); // fd no longer needed. The mapping is retained. - - if (shm_unlink (seg_name) == -1){ // unlink the seg_name. - perror ("gr_vmcircbuf_mmap_shm_open: shm_unlink"); - throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open"); - } - - // Now remember the important stuff - - d_base = (char *) first_copy; - d_size = size; -#endif -} - -gr_vmcircbuf_mmap_shm_open::~gr_vmcircbuf_mmap_shm_open () -{ -#if defined(HAVE_MMAP) - if (munmap (d_base, 2 * d_size) == -1){ - perror ("gr_vmcircbuf_mmap_shm_open: munmap (2)"); - } -#endif -} - -// ---------------------------------------------------------------- -// The factory interface -// ---------------------------------------------------------------- - - -gr_vmcircbuf_factory *gr_vmcircbuf_mmap_shm_open_factory::s_the_factory = 0; - -gr_vmcircbuf_factory * -gr_vmcircbuf_mmap_shm_open_factory::singleton () -{ - if (s_the_factory) - return s_the_factory; - - s_the_factory = new gr_vmcircbuf_mmap_shm_open_factory (); - return s_the_factory; -} - -int -gr_vmcircbuf_mmap_shm_open_factory::granularity () -{ - return gr_pagesize (); -} - -gr_vmcircbuf * -gr_vmcircbuf_mmap_shm_open_factory::make (int size) -{ - try { - return new gr_vmcircbuf_mmap_shm_open (size); - } - catch (...){ - return 0; - } -} diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_mmap_shm_open.h b/gnuradio-runtime/lib/gr_vmcircbuf_mmap_shm_open.h deleted file mode 100644 index d35df80839..0000000000 --- a/gnuradio-runtime/lib/gr_vmcircbuf_mmap_shm_open.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003 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 _GR_VMCIRCBUF_MMAP_SHM_OPEN_H_ -#define _GR_VMCIRCBUF_MMAP_SHM_OPEN_H_ - -#include <gr_runtime_api.h> -#include <gr_vmcircbuf.h> - -/*! - * \brief concrete class to implement circular buffers with mmap and shm_open - * \ingroup internal - */ -class GR_RUNTIME_API gr_vmcircbuf_mmap_shm_open : public gr_vmcircbuf { - public: - - // CREATORS - - gr_vmcircbuf_mmap_shm_open (int size); - virtual ~gr_vmcircbuf_mmap_shm_open (); -}; - -/*! - * \brief concrete factory for circular buffers built using mmap and shm_open - */ -class GR_RUNTIME_API gr_vmcircbuf_mmap_shm_open_factory : public gr_vmcircbuf_factory { - private: - static gr_vmcircbuf_factory *s_the_factory; - - public: - static gr_vmcircbuf_factory *singleton (); - - virtual const char *name () const { return "gr_vmcircbuf_mmap_shm_open_factory"; } - - /*! - * \brief return granularity of mapping, typically equal to page size - */ - virtual int granularity (); - - /*! - * \brief return a gr_vmcircbuf, or 0 if unable. - * - * Call this to create a doubly mapped circular buffer. - */ - virtual gr_vmcircbuf *make (int size); -}; - -#endif /* _GR_VMCIRCBUF_MMAP_SHM_OPEN_H_ */ diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_mmap_tmpfile.cc b/gnuradio-runtime/lib/gr_vmcircbuf_mmap_tmpfile.cc deleted file mode 100644 index 35de64699e..0000000000 --- a/gnuradio-runtime/lib/gr_vmcircbuf_mmap_tmpfile.cc +++ /dev/null @@ -1,197 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003,2011 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_vmcircbuf_mmap_tmpfile.h> -#include <stdexcept> -#include <assert.h> -#include <unistd.h> -#include <stdlib.h> -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_MMAN_H -#include <sys/mman.h> -#endif -#include <fcntl.h> -#include <errno.h> -#include <stdio.h> -#include <string.h> -#include <gr_pagesize.h> -#include <gr_sys_paths.h> - -gr_vmcircbuf_mmap_tmpfile::gr_vmcircbuf_mmap_tmpfile (int size) - : gr_vmcircbuf (size) -{ -#if !defined(HAVE_MMAP) - fprintf (stderr, "gr_vmcircbuf_mmap_tmpfile: mmap or mkstemp is not available\n"); - throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); -#else - - if (size <= 0 || (size % gr_pagesize ()) != 0){ - fprintf (stderr, "gr_vmcircbuf_mmap_tmpfile: invalid size = %d\n", size); - throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); - } - - int seg_fd = -1; - char seg_name[1024]; - - static int s_seg_counter = 0; - - - // open a temporary file that we'll map in a bit later - - while (1){ - snprintf (seg_name, sizeof (seg_name), - "%s/gnuradio-%d-%d-XXXXXX", gr_tmp_path (), getpid (), s_seg_counter); - s_seg_counter++; - - seg_fd = open (seg_name, O_RDWR | O_CREAT | O_EXCL, 0600); - if (seg_fd == -1){ - if (errno == EEXIST) // File already exists (shouldn't happen). Try again - continue; - - char msg[1024]; - snprintf (msg, sizeof (msg), - "gr_vmcircbuf_mmap_tmpfile: open [%s]", seg_name); - perror (msg); - throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); - } - break; - } - - if (unlink (seg_name) == -1){ - perror ("gr_vmcircbuf_mmap_tmpfile: unlink"); - throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); - } - - // We've got a valid file descriptor to a tmp file. - // Now set it's length to 2x what we really want and mmap it in. - - if (ftruncate (seg_fd, (off_t) 2 * size) == -1){ - close (seg_fd); // cleanup - perror ("gr_vmcircbuf_mmap_tmpfile: ftruncate (1)"); - throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); - } - - void *first_copy = mmap (0, 2 * size, - PROT_READ | PROT_WRITE, MAP_SHARED, - seg_fd, (off_t) 0); - - if (first_copy == MAP_FAILED){ - close (seg_fd); // cleanup - perror ("gr_vmcircbuf_mmap_tmpfile: mmap (1)"); - throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); - } - - // unmap the 2nd half - if (munmap ((char *) first_copy + size, size) == -1){ - close (seg_fd); // cleanup - perror ("gr_vmcircbuf_mmap_tmpfile: munmap (1)"); - throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); - } - - // map the first half into the now available hole where the - // second half used to be. - - void *second_copy = mmap ((char *) first_copy + size, size, - PROT_READ | PROT_WRITE, MAP_SHARED, - seg_fd, (off_t) 0); - - if (second_copy == MAP_FAILED){ - munmap(first_copy, size); // cleanup - close (seg_fd); - perror ("gr_vmcircbuf_mmap_tmpfile: mmap (2)"); - throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); - } - - // check for contiguity - if ((char *) second_copy != (char *) first_copy + size){ - munmap(first_copy, size); // cleanup - munmap(second_copy, size); - close (seg_fd); - perror ("gr_vmcircbuf_mmap_tmpfile: non-contiguous second copy"); - throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); - } - - // cut the tmp file down to size - if (ftruncate (seg_fd, (off_t) size) == -1){ - munmap(first_copy, size); // cleanup - munmap(second_copy, size); - close (seg_fd); - perror ("gr_vmcircbuf_mmap_tmpfile: ftruncate (2)"); - throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile"); - } - - close (seg_fd); // fd no longer needed. The mapping is retained. - - // Now remember the important stuff - - d_base = (char *) first_copy; - d_size = size; -#endif -} - -gr_vmcircbuf_mmap_tmpfile::~gr_vmcircbuf_mmap_tmpfile () -{ -#if defined(HAVE_MMAP) - if (munmap (d_base, 2 * d_size) == -1){ - perror ("gr_vmcircbuf_mmap_tmpfile: munmap (2)"); - } -#endif -} - -// ---------------------------------------------------------------- -// The factory interface -// ---------------------------------------------------------------- - - -gr_vmcircbuf_factory *gr_vmcircbuf_mmap_tmpfile_factory::s_the_factory = 0; - -gr_vmcircbuf_factory * -gr_vmcircbuf_mmap_tmpfile_factory::singleton () -{ - if (s_the_factory) - return s_the_factory; - - s_the_factory = new gr_vmcircbuf_mmap_tmpfile_factory (); - return s_the_factory; -} - -int -gr_vmcircbuf_mmap_tmpfile_factory::granularity () -{ - return gr_pagesize (); -} - -gr_vmcircbuf * -gr_vmcircbuf_mmap_tmpfile_factory::make (int size) -{ - try { - return new gr_vmcircbuf_mmap_tmpfile (size); - } - catch (...){ - return 0; - } -} diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_mmap_tmpfile.h b/gnuradio-runtime/lib/gr_vmcircbuf_mmap_tmpfile.h deleted file mode 100644 index cd865734f2..0000000000 --- a/gnuradio-runtime/lib/gr_vmcircbuf_mmap_tmpfile.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003 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 _GR_VMCIRCBUF_MMAP_TMPFILE_H_ -#define _GR_VMCIRCBUF_MMAP_TMPFILE_H_ - -#include <gr_runtime_api.h> -#include <gr_vmcircbuf.h> - -/*! - * \brief concrete class to implement circular buffers with mmap and shm_open - * \ingroup internal - */ -class GR_RUNTIME_API gr_vmcircbuf_mmap_tmpfile : public gr_vmcircbuf { - public: - - // CREATORS - - gr_vmcircbuf_mmap_tmpfile (int size); - virtual ~gr_vmcircbuf_mmap_tmpfile (); -}; - -/*! - * \brief concrete factory for circular buffers built using mmap and shm_open - */ -class GR_RUNTIME_API gr_vmcircbuf_mmap_tmpfile_factory : public gr_vmcircbuf_factory { - private: - static gr_vmcircbuf_factory *s_the_factory; - - public: - static gr_vmcircbuf_factory *singleton (); - - virtual const char *name () const { return "gr_vmcircbuf_mmap_tmpfile_factory"; } - - /*! - * \brief return granularity of mapping, typically equal to page size - */ - virtual int granularity (); - - /*! - * \brief return a gr_vmcircbuf, or 0 if unable. - * - * Call this to create a doubly mapped circular buffer. - */ - virtual gr_vmcircbuf *make (int size); -}; - -#endif /* _GR_VMCIRCBUF_MMAP_TMPFILE_H_ */ diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_sysv_shm.cc b/gnuradio-runtime/lib/gr_vmcircbuf_sysv_shm.cc deleted file mode 100644 index d9cf75e70f..0000000000 --- a/gnuradio-runtime/lib/gr_vmcircbuf_sysv_shm.cc +++ /dev/null @@ -1,194 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003 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_vmcircbuf_sysv_shm.h> -#include <stdexcept> -#include <assert.h> -#include <unistd.h> -#include <stdlib.h> -#include <fcntl.h> -#ifdef HAVE_SYS_IPC_H -#include <sys/ipc.h> -#endif -#ifdef HAVE_SYS_SHM_H -#include <sys/shm.h> -#endif -#include <errno.h> -#include <stdio.h> -#include <gr_pagesize.h> - - -gr_vmcircbuf_sysv_shm::gr_vmcircbuf_sysv_shm (int size) - : gr_vmcircbuf (size) -{ -#if !defined(HAVE_SYS_SHM_H) - fprintf (stderr, "gr_vmcircbuf_sysv_shm: sysv shared memory is not available\n"); - throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); -#else - - int pagesize = gr_pagesize(); - - if (size <= 0 || (size % pagesize) != 0){ - fprintf (stderr, "gr_vmcircbuf_sysv_shm: invalid size = %d\n", size); - throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); - } - - int shmid_guard = -1; - int shmid1 = -1; - int shmid2 = -1; - - // We use this as a guard page. We'll map it read-only on both ends of the buffer. - // Ideally we'd map it no access, but I don't think that's possible with SysV - if ((shmid_guard = shmget (IPC_PRIVATE, pagesize, IPC_CREAT | 0400)) == -1){ - perror ("gr_vmcircbuf_sysv_shm: shmget (0)"); - throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); - } - - if ((shmid2 = shmget (IPC_PRIVATE, 2 * size + 2 * pagesize, IPC_CREAT | 0700)) == -1){ - perror ("gr_vmcircbuf_sysv_shm: shmget (1)"); - shmctl (shmid_guard, IPC_RMID, 0); - throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); - } - - if ((shmid1 = shmget (IPC_PRIVATE, size, IPC_CREAT | 0700)) == -1){ - perror ("gr_vmcircbuf_sysv_shm: shmget (2)"); - shmctl (shmid_guard, IPC_RMID, 0); - shmctl (shmid2, IPC_RMID, 0); - throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); - } - - void *first_copy = shmat (shmid2, 0, 0); - if (first_copy == (void *) -1){ - perror ("gr_vmcircbuf_sysv_shm: shmat (1)"); - shmctl (shmid_guard, IPC_RMID, 0); - shmctl (shmid2, IPC_RMID, 0); - shmctl (shmid1, IPC_RMID, 0); - throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); - } - - shmctl (shmid2, IPC_RMID, 0); - - // There may be a race between our detach and attach. - // - // If the system allocates all shared memory segments at the same - // virtual addresses in all processes and if the system allocates - // some other segment to first_copy or first_copoy + size between - // our detach and attach, the attaches below could fail [I've never - // seen it fail for this reason]. - - shmdt (first_copy); - - // first read-only guard page - if (shmat (shmid_guard, first_copy, SHM_RDONLY) == (void *) -1){ - perror ("gr_vmcircbuf_sysv_shm: shmat (2)"); - shmctl (shmid_guard, IPC_RMID, 0); - shmctl (shmid1, IPC_RMID, 0); - throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); - } - - // first copy - if (shmat (shmid1, (char *) first_copy + pagesize, 0) == (void *) -1){ - perror ("gr_vmcircbuf_sysv_shm: shmat (3)"); - shmctl (shmid_guard, IPC_RMID, 0); - shmctl (shmid1, IPC_RMID, 0); - shmdt (first_copy); - throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); - } - - // second copy - if (shmat (shmid1, (char *) first_copy + pagesize + size, 0) == (void *) -1){ - perror ("gr_vmcircbuf_sysv_shm: shmat (4)"); - shmctl (shmid_guard, IPC_RMID, 0); - shmctl (shmid1, IPC_RMID, 0); - shmdt ((char *)first_copy + pagesize); - throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); - } - - // second read-only guard page - if (shmat (shmid_guard, (char *) first_copy + pagesize + 2 * size, SHM_RDONLY) == (void *) -1){ - perror ("gr_vmcircbuf_sysv_shm: shmat (5)"); - shmctl (shmid_guard, IPC_RMID, 0); - shmctl (shmid1, IPC_RMID, 0); - shmdt (first_copy); - shmdt ((char *)first_copy + pagesize); - shmdt ((char *)first_copy + pagesize + size); - throw std::runtime_error ("gr_vmcircbuf_sysv_shm"); - } - - shmctl (shmid1, IPC_RMID, 0); - shmctl (shmid_guard, IPC_RMID, 0); - - // Now remember the important stuff - - d_base = (char *) first_copy + pagesize; - d_size = size; -#endif -} - -gr_vmcircbuf_sysv_shm::~gr_vmcircbuf_sysv_shm () -{ -#if defined(HAVE_SYS_SHM_H) - if (shmdt (d_base - gr_pagesize()) == -1 - || shmdt (d_base) == -1 - || shmdt (d_base + d_size) == -1 - || shmdt (d_base + 2 * d_size) == -1){ - perror ("gr_vmcircbuf_sysv_shm: shmdt (2)"); - } -#endif -} - -// ---------------------------------------------------------------- -// The factory interface -// ---------------------------------------------------------------- - - -gr_vmcircbuf_factory *gr_vmcircbuf_sysv_shm_factory::s_the_factory = 0; - -gr_vmcircbuf_factory * -gr_vmcircbuf_sysv_shm_factory::singleton () -{ - if (s_the_factory) - return s_the_factory; - - s_the_factory = new gr_vmcircbuf_sysv_shm_factory (); - return s_the_factory; -} - -int -gr_vmcircbuf_sysv_shm_factory::granularity () -{ - return gr_pagesize (); -} - -gr_vmcircbuf * -gr_vmcircbuf_sysv_shm_factory::make (int size) -{ - try { - return new gr_vmcircbuf_sysv_shm (size); - } - catch (...){ - return 0; - } -} diff --git a/gnuradio-runtime/lib/gr_vmcircbuf_sysv_shm.h b/gnuradio-runtime/lib/gr_vmcircbuf_sysv_shm.h deleted file mode 100644 index abebd93f1c..0000000000 --- a/gnuradio-runtime/lib/gr_vmcircbuf_sysv_shm.h +++ /dev/null @@ -1,67 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003 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 _GR_VMCIRCBUF_SYSV_SHM_H_ -#define _GR_VMCIRCBUF_SYSV_SHM_H_ - -#include <gr_runtime_api.h> -#include <gr_vmcircbuf.h> - -/*! - * \brief concrete class to implement circular buffers with mmap and shm_open - * \ingroup internal - */ -class GR_RUNTIME_API gr_vmcircbuf_sysv_shm : public gr_vmcircbuf { - public: - - // CREATORS - - gr_vmcircbuf_sysv_shm (int size); - virtual ~gr_vmcircbuf_sysv_shm (); -}; - -/*! - * \brief concrete factory for circular buffers built using mmap and shm_open - */ -class GR_RUNTIME_API gr_vmcircbuf_sysv_shm_factory : public gr_vmcircbuf_factory { - private: - static gr_vmcircbuf_factory *s_the_factory; - - public: - static gr_vmcircbuf_factory *singleton (); - - virtual const char *name () const { return "gr_vmcircbuf_sysv_shm_factory"; } - - /*! - * \brief return granularity of mapping, typically equal to page size - */ - virtual int granularity (); - - /*! - * \brief return a gr_vmcircbuf, or 0 if unable. - * - * Call this to create a doubly mapped circular buffer. - */ - virtual gr_vmcircbuf *make (int size); -}; - -#endif /* _GR_VMCIRCBUF_SYSV_SHM_H_ */ diff --git a/gnuradio-runtime/lib/gri_debugger_hook.cc b/gnuradio-runtime/lib/gri_debugger_hook.cc deleted file mode 100644 index d9270c435f..0000000000 --- a/gnuradio-runtime/lib/gri_debugger_hook.cc +++ /dev/null @@ -1,29 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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 <gri_debugger_hook.h> - -void -gri_debugger_hook () -{ - // nop. set a breakpoint here -} diff --git a/gnuradio-runtime/lib/hier_block2.cc b/gnuradio-runtime/lib/hier_block2.cc new file mode 100644 index 0000000000..f26da18e54 --- /dev/null +++ b/gnuradio-runtime/lib/hier_block2.cc @@ -0,0 +1,160 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006-2008,2013 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 <gnuradio/hier_block2.h> +#include <gnuradio/io_signature.h> +#include "hier_block2_detail.h" +#include <iostream> + +namespace gr { + +#define GR_HIER_BLOCK2_DEBUG 0 + + hier_block2_sptr + make_hier_block2(const std::string &name, + gr::io_signature::sptr input_signature, + gr::io_signature::sptr output_signature) + { + return gnuradio::get_initial_sptr + (new hier_block2(name, input_signature, output_signature)); + } + + hier_block2::hier_block2(const std::string &name, + gr::io_signature::sptr input_signature, + gr::io_signature::sptr output_signature) + : basic_block(name, input_signature, output_signature), + d_detail(new hier_block2_detail(this)), + hier_message_ports_in(pmt::PMT_NIL), + hier_message_ports_out(pmt::PMT_NIL) + { + // This bit of magic ensures that self() works in the constructors of derived classes. + gnuradio::detail::sptr_magic::create_and_stash_initial_sptr(this); + } + + hier_block2::~hier_block2() + { + delete d_detail; + } + + hier_block2::opaque_self + hier_block2::self() + { + return shared_from_this(); + } + + hier_block2_sptr + hier_block2::to_hier_block2() + { + return cast_to_hier_block2_sptr(shared_from_this()); + } + + void + hier_block2::connect(basic_block_sptr block) + { + d_detail->connect(block); + } + + void + hier_block2::connect(basic_block_sptr src, int src_port, + basic_block_sptr dst, int dst_port) + { + d_detail->connect(src, src_port, dst, dst_port); + } + + void + hier_block2::msg_connect(basic_block_sptr src, pmt::pmt_t srcport, + basic_block_sptr dst, pmt::pmt_t dstport) + { + if(!pmt::is_symbol(srcport)) { + throw std::runtime_error("bad port id"); + } + d_detail->msg_connect(src, srcport, dst, dstport); + } + + void + hier_block2::msg_connect(basic_block_sptr src, std::string srcport, + basic_block_sptr dst, std::string dstport) + { + d_detail->msg_connect(src, pmt::mp(srcport), dst, pmt::mp(dstport)); + } + + void + hier_block2::msg_disconnect(basic_block_sptr src, pmt::pmt_t srcport, + basic_block_sptr dst, pmt::pmt_t dstport) + { + if(!pmt::is_symbol(srcport)) { + throw std::runtime_error("bad port id"); + } + d_detail->msg_disconnect(src, srcport, dst, dstport); + } + + void + hier_block2::msg_disconnect(basic_block_sptr src, std::string srcport, + basic_block_sptr dst, std::string dstport) + { + d_detail->msg_disconnect(src, pmt::mp(srcport), dst, pmt::mp(dstport)); + } + + void + hier_block2::disconnect(basic_block_sptr block) + { + d_detail->disconnect(block); + } + + void + hier_block2::disconnect(basic_block_sptr src, int src_port, + basic_block_sptr dst, int dst_port) + { + d_detail->disconnect(src, src_port, dst, dst_port); + } + + void + hier_block2::disconnect_all() + { + d_detail->disconnect_all(); + } + + void + hier_block2::lock() + { + d_detail->lock(); + } + + void + hier_block2::unlock() + { + d_detail->unlock(); + } + + flat_flowgraph_sptr + hier_block2::flatten() const + { + flat_flowgraph_sptr new_ffg = make_flat_flowgraph(); + d_detail->flatten_aux(new_ffg); + return new_ffg; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/hier_block2_detail.cc b/gnuradio-runtime/lib/hier_block2_detail.cc new file mode 100644 index 0000000000..83207d978c --- /dev/null +++ b/gnuradio-runtime/lib/hier_block2_detail.cc @@ -0,0 +1,657 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2007,2009,2013 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 "hier_block2_detail.h" +#include <gnuradio/io_signature.h> +#include <gnuradio/prefs.h> +#include <stdexcept> +#include <sstream> +#include <boost/format.hpp> + +namespace gr { + +#define HIER_BLOCK2_DETAIL_DEBUG 0 + + hier_block2_detail::hier_block2_detail(hier_block2 *owner) + : d_owner(owner), + d_parent_detail(0), + d_fg(make_flowgraph()) + { + int min_inputs = owner->input_signature()->min_streams(); + int max_inputs = owner->input_signature()->max_streams(); + int min_outputs = owner->output_signature()->min_streams(); + int max_outputs = owner->output_signature()->max_streams(); + + if(max_inputs == io_signature::IO_INFINITE || + max_outputs == io_signature::IO_INFINITE || + (min_inputs != max_inputs) ||(min_outputs != max_outputs) ) { + std::stringstream msg; + msg << "Hierarchical blocks do not yet support arbitrary or" + << " variable numbers of inputs or outputs (" << d_owner->name() << ")"; + throw std::runtime_error(msg.str()); + } + + d_inputs = std::vector<endpoint_vector_t>(max_inputs); + d_outputs = endpoint_vector_t(max_outputs); + } + + hier_block2_detail::~hier_block2_detail() + { + d_owner = 0; // Don't use delete, we didn't allocate + } + + void + hier_block2_detail::connect(basic_block_sptr block) + { + std::stringstream msg; + + // Check if duplicate + if(std::find(d_blocks.begin(), d_blocks.end(), block) != d_blocks.end()) { + msg << "Block " << block << " already connected."; + throw std::invalid_argument(msg.str()); + } + + // Check if has inputs or outputs + if(block->input_signature()->max_streams() != 0 || + block->output_signature()->max_streams() != 0) { + msg << "Block " << block << " must not have any input or output ports"; + throw std::invalid_argument(msg.str()); + } + + hier_block2_sptr hblock(cast_to_hier_block2_sptr(block)); + + if(hblock && hblock.get() != d_owner) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connect: block is hierarchical, setting parent to " << this << std::endl; + hblock->d_detail->d_parent_detail = this; + } + + d_blocks.push_back(block); + } + + void + hier_block2_detail::connect(basic_block_sptr src, int src_port, + basic_block_sptr dst, int dst_port) + { + std::stringstream msg; + + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connecting: " << endpoint(src, src_port) + << " -> " << endpoint(dst, dst_port) << std::endl; + + if(src.get() == dst.get()) + throw std::invalid_argument("connect: src and destination blocks cannot be the same"); + + hier_block2_sptr src_block(cast_to_hier_block2_sptr(src)); + hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst)); + + if(src_block && src.get() != d_owner) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connect: src is hierarchical, setting parent to " << this << std::endl; + src_block->d_detail->d_parent_detail = this; + } + + if(dst_block && dst.get() != d_owner) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connect: dst is hierarchical, setting parent to " << this << std::endl; + dst_block->d_detail->d_parent_detail = this; + } + + // Connections to block inputs or outputs + int max_port; + if(src.get() == d_owner) { + max_port = src->input_signature()->max_streams(); + if((max_port != -1 && (src_port >= max_port)) || src_port < 0) { + msg << "source port " << src_port << " out of range for " << src; + throw std::invalid_argument(msg.str()); + } + + return connect_input(src_port, dst_port, dst); + } + + if(dst.get() == d_owner) { + max_port = dst->output_signature()->max_streams(); + if((max_port != -1 && (dst_port >= max_port)) || dst_port < 0) { + msg << "destination port " << dst_port << " out of range for " << dst; + throw std::invalid_argument(msg.str()); + } + + return connect_output(dst_port, src_port, src); + } + + // Internal connections + d_fg->connect(src, src_port, dst, dst_port); + + // TODO: connects to NC + } + + void + hier_block2_detail::msg_connect(basic_block_sptr src, pmt::pmt_t srcport, + basic_block_sptr dst, pmt::pmt_t dstport) + { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connecting message port..." << std::endl; + + // register the subscription + // this is done later... + // src->message_port_sub(srcport, pmt::cons(dst->alias_pmt(), dstport)); + + // add block uniquely to list to internal blocks + if(std::find(d_blocks.begin(), d_blocks.end(), dst) == d_blocks.end()){ + d_blocks.push_back(src); + d_blocks.push_back(dst); + } + + bool hier_out = (d_owner == src.get()) && src->message_port_is_hier_out(srcport);; + bool hier_in = (d_owner == dst.get()) && dst->message_port_is_hier_in(dstport); + + hier_block2_sptr src_block(cast_to_hier_block2_sptr(src)); + hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst)); + + if(src_block && src.get() != d_owner) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connect: src is hierarchical, setting parent to " << this << std::endl; + src_block->d_detail->d_parent_detail = this; + } + + if(dst_block && dst.get() != d_owner) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "connect: dst is hierarchical, setting parent to " << this << std::endl; + dst_block->d_detail->d_parent_detail = this; + } + + // add edge for this message connection + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << boost::format("connect( (%s, %s, %d), (%s, %s, %d) )\n") % \ + src % srcport % hier_out % + dst % dstport % hier_in; + d_fg->connect(msg_endpoint(src, srcport, hier_out), msg_endpoint(dst, dstport, hier_in)); + } + + void + hier_block2_detail::msg_disconnect(basic_block_sptr src, pmt::pmt_t srcport, + basic_block_sptr dst, pmt::pmt_t dstport) + { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "disconnecting message port..." << std::endl; + + // unregister the subscription - if already subscribed + src->message_port_unsub(srcport, pmt::cons(dst->alias_pmt(), dstport)); + + // remove edge for this message connection + bool hier_out = (d_owner == src.get()) && src->message_port_is_hier_out(srcport);; + bool hier_in = (d_owner == dst.get()) && dst->message_port_is_hier_in(dstport); + d_fg->disconnect(msg_endpoint(src, srcport, hier_out), msg_endpoint(dst, dstport, hier_in)); + } + + void + hier_block2_detail::disconnect(basic_block_sptr block) + { + // Check on singleton list + for(basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) { + if(*p == block) { + d_blocks.erase(p); + + hier_block2_sptr hblock(cast_to_hier_block2_sptr(block)); + if(block && block.get() != d_owner) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "disconnect: block is hierarchical, clearing parent" << std::endl; + hblock->d_detail->d_parent_detail = 0; + } + + return; + } + } + + // Otherwise find all edges containing block + edge_vector_t edges, tmp = d_fg->edges(); + edge_vector_t::iterator p; + for(p = tmp.begin(); p != tmp.end(); p++) { + if((*p).src().block() == block || (*p).dst().block() == block) { + edges.push_back(*p); + + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "disconnect: block found in edge " << (*p) << std::endl; + } + } + + if(edges.size() == 0) { + std::stringstream msg; + msg << "cannot disconnect block " << block << ", not found"; + throw std::invalid_argument(msg.str()); + } + + for(p = edges.begin(); p != edges.end(); p++) { + disconnect((*p).src().block(), (*p).src().port(), + (*p).dst().block(), (*p).dst().port()); + } + } + + void + hier_block2_detail::disconnect(basic_block_sptr src, int src_port, + basic_block_sptr dst, int dst_port) + { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "disconnecting: " << endpoint(src, src_port) + << " -> " << endpoint(dst, dst_port) << std::endl; + + if(src.get() == dst.get()) + throw std::invalid_argument("disconnect: source and destination blocks cannot be the same"); + + hier_block2_sptr src_block(cast_to_hier_block2_sptr(src)); + hier_block2_sptr dst_block(cast_to_hier_block2_sptr(dst)); + + if(src_block && src.get() != d_owner) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "disconnect: src is hierarchical, clearing parent" << std::endl; + src_block->d_detail->d_parent_detail = 0; + } + + if(dst_block && dst.get() != d_owner) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "disconnect: dst is hierarchical, clearing parent" << std::endl; + dst_block->d_detail->d_parent_detail = 0; + } + + if(src.get() == d_owner) + return disconnect_input(src_port, dst_port, dst); + + if(dst.get() == d_owner) + return disconnect_output(dst_port, src_port, src); + + // Internal connections + d_fg->disconnect(src, src_port, dst, dst_port); + } + + void + hier_block2_detail::connect_input(int my_port, int port, + basic_block_sptr block) + { + std::stringstream msg; + + if(my_port < 0 || my_port >= (signed)d_inputs.size()) { + msg << "input port " << my_port << " out of range for " << block; + throw std::invalid_argument(msg.str()); + } + + endpoint_vector_t &endps = d_inputs[my_port]; + endpoint endp(block, port); + + endpoint_viter_t p = std::find(endps.begin(), endps.end(), endp); + if(p != endps.end()) { + msg << "external input port " << my_port << " already wired to " << endp; + throw std::invalid_argument(msg.str()); + } + + endps.push_back(endp); + } + + void + hier_block2_detail::connect_output(int my_port, int port, + basic_block_sptr block) + { + std::stringstream msg; + + if(my_port < 0 || my_port >= (signed)d_outputs.size()) { + msg << "output port " << my_port << " out of range for " << block; + throw std::invalid_argument(msg.str()); + } + + if(d_outputs[my_port].block()) { + msg << "external output port " << my_port << " already connected from " + << d_outputs[my_port]; + throw std::invalid_argument(msg.str()); + } + + d_outputs[my_port] = endpoint(block, port); + } + + void + hier_block2_detail::disconnect_input(int my_port, int port, + basic_block_sptr block) + { + std::stringstream msg; + + if(my_port < 0 || my_port >= (signed)d_inputs.size()) { + msg << "input port number " << my_port << " out of range for " << block; + throw std::invalid_argument(msg.str()); + } + + endpoint_vector_t &endps = d_inputs[my_port]; + endpoint endp(block, port); + + endpoint_viter_t p = std::find(endps.begin(), endps.end(), endp); + if(p == endps.end()) { + msg << "external input port " << my_port << " not connected to " << endp; + throw std::invalid_argument(msg.str()); + } + + endps.erase(p); + } + + void + hier_block2_detail::disconnect_output(int my_port, int port, + basic_block_sptr block) + { + std::stringstream msg; + + if(my_port < 0 || my_port >= (signed)d_outputs.size()) { + msg << "output port number " << my_port << " out of range for " << block; + throw std::invalid_argument(msg.str()); + } + + if(d_outputs[my_port].block() != block) { + msg << "block " << block << " not assigned to output " + << my_port << ", can't disconnect"; + throw std::invalid_argument(msg.str()); + } + + d_outputs[my_port] = endpoint(); + } + + endpoint_vector_t + hier_block2_detail::resolve_port(int port, bool is_input) + { + std::stringstream msg; + + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Resolving port " << port << " as an " + << (is_input ? "input" : "output") + << " of " << d_owner->name() << std::endl; + + endpoint_vector_t result; + + if(is_input) { + if(port < 0 || port >= (signed)d_inputs.size()) { + msg << "resolve_port: hierarchical block '" << d_owner->name() + << "': input " << port << " is out of range"; + throw std::runtime_error(msg.str()); + } + + if(d_inputs[port].empty()) { + msg << "resolve_port: hierarchical block '" << d_owner->name() + << "': input " << port << " is not connected internally"; + throw std::runtime_error(msg.str()); + } + + endpoint_vector_t &endps = d_inputs[port]; + endpoint_viter_t p; + for(p = endps.begin(); p != endps.end(); p++) { + endpoint_vector_t tmp = resolve_endpoint(*p, true); + std::copy(tmp.begin(), tmp.end(), back_inserter(result)); + } + } + else { + if(port < 0 || port >= (signed)d_outputs.size()) { + msg << "resolve_port: hierarchical block '" << d_owner->name() + << "': output " << port << " is out of range"; + throw std::runtime_error(msg.str()); + } + + if(d_outputs[port] == endpoint()) { + msg << "resolve_port: hierarchical block '" << d_owner->name() + << "': output " << port << " is not connected internally"; + throw std::runtime_error(msg.str()); + } + + result = resolve_endpoint(d_outputs[port], false); + } + + if(result.empty()) { + msg << "resolve_port: hierarchical block '" << d_owner->name() + << "': unable to resolve " + << (is_input ? "input port " : "output port ") + << port; + throw std::runtime_error(msg.str()); + } + + return result; + } + + void + hier_block2_detail::disconnect_all() + { + d_fg->clear(); + d_blocks.clear(); + d_inputs.clear(); + d_outputs.clear(); + } + + endpoint_vector_t + hier_block2_detail::resolve_endpoint(const endpoint &endp, bool is_input) const + { + std::stringstream msg; + endpoint_vector_t result; + + // Check if endpoint is a leaf node + if(cast_to_block_sptr(endp.block())) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Block " << endp.block() << " is a leaf node, returning." << std::endl; + result.push_back(endp); + return result; + } + + // Check if endpoint is a hierarchical block + hier_block2_sptr hier_block2(cast_to_hier_block2_sptr(endp.block())); + if(hier_block2) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Resolving endpoint " << endp << " as an " + << (is_input ? "input" : "output") + << ", recursing" << std::endl; + return hier_block2->d_detail->resolve_port(endp.port(), is_input); + } + + msg << "unable to resolve" << (is_input ? " input " : " output ") + << "endpoint " << endp; + throw std::runtime_error(msg.str()); + } + + void + hier_block2_detail::flatten_aux(flat_flowgraph_sptr sfg) const + { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << " ** Flattening " << d_owner->name() << std::endl; + + // Add my edges to the flow graph, resolving references to actual endpoints + edge_vector_t edges = d_fg->edges(); + msg_edge_vector_t msg_edges = d_fg->msg_edges(); + edge_viter_t p; + msg_edge_viter_t q,u; + + // Only run setup_rpc if ControlPort config param is enabled. + bool ctrlport_on = prefs::singleton()->get_bool("ControlPort", "on", false); + + // For every block (gr::block and gr::hier_block2), set up the RPC + // interface. + for(p = edges.begin(); p != edges.end(); p++) { + basic_block_sptr b; + b = p->src().block(); + + if(ctrlport_on) { + if(!b->is_rpc_set()) { + b->setup_rpc(); + b->rpc_set(); + } + } + + b = p->dst().block(); + if(ctrlport_on) { + if(!b->is_rpc_set()) { + b->setup_rpc(); + b->rpc_set(); + } + } + } + + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Flattening stream connections: " << std::endl; + + for(p = edges.begin(); p != edges.end(); p++) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Flattening edge " << (*p) << std::endl; + + endpoint_vector_t src_endps = resolve_endpoint(p->src(), false); + endpoint_vector_t dst_endps = resolve_endpoint(p->dst(), true); + + endpoint_viter_t s, d; + for(s = src_endps.begin(); s != src_endps.end(); s++) { + for(d = dst_endps.begin(); d != dst_endps.end(); d++) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << (*s) << "->" << (*d) << std::endl; + sfg->connect(*s, *d); + } + } + } + + // loop through flattening hierarchical connections + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "Flattening msg connections: " << std::endl; + + std::vector<std::pair<msg_endpoint, bool> > resolved_endpoints; + for(q = msg_edges.begin(); q != msg_edges.end(); q++) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << boost::format(" flattening edge ( %s, %s, %d) -> ( %s, %s, %d)\n") % \ + q->src().block() % q->src().port() % q->src().is_hier() % q->dst().block() % \ + q->dst().port() % q->dst().is_hier(); + + bool normal_connection = true; + + // resolve existing connections to hier ports + if(q->dst().is_hier()) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << boost::format(" resolve hier output (%s, %s)") % \ + q->dst().block() % q->dst().port() << std::endl; + sfg->replace_endpoint( q->dst(), q->src(), true ); + resolved_endpoints.push_back(std::pair<msg_endpoint, bool>(q->dst(),true)); + normal_connection = false; + } + + if(q->src().is_hier()) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << boost::format(" resolve hier input (%s, %s)") % \ + q->src().block() % q->src().port() << std::endl; + sfg->replace_endpoint( q->src(), q->dst(), false ); + resolved_endpoints.push_back(std::pair<msg_endpoint, bool>(q->src(),false)); + normal_connection = false; + } + + // propogate non hier connections through + if(normal_connection){ + sfg->connect( q->src(), q->dst() ); + } + } + + for(std::vector<std::pair<msg_endpoint, bool> >::iterator it = resolved_endpoints.begin(); + it != resolved_endpoints.end(); it++) { + sfg->clear_endpoint((*it).first, (*it).second); + } + + /* + // connect primitive edges in the new fg + for(q = msg_edges.begin(); q != msg_edges.end(); q++) { + if((!q->src().is_hier()) && (!q->dst().is_hier())) { + sfg->connect(q->src(), q->dst()); + } + else { + std::cout << "not connecting hier connection!" << std::endl; + } + } + */ + + // Construct unique list of blocks used either in edges, inputs, + // outputs, or by themselves. I still hate STL. + basic_block_vector_t blocks; // unique list of used blocks + basic_block_vector_t tmp = d_fg->calc_used_blocks(); + + // First add the list of singleton blocks + std::vector<basic_block_sptr>::const_iterator b; // Because flatten_aux is const + for(b = d_blocks.begin(); b != d_blocks.end(); b++) + tmp.push_back(*b); + + // Now add the list of connected input blocks + std::stringstream msg; + for(unsigned int i = 0; i < d_inputs.size(); i++) { + if(d_inputs[i].size() == 0) { + msg << "In hierarchical block " << d_owner->name() << ", input " << i + << " is not connected internally"; + throw std::runtime_error(msg.str()); + } + + for(unsigned int j = 0; j < d_inputs[i].size(); j++) + tmp.push_back(d_inputs[i][j].block()); + } + + for(unsigned int i = 0; i < d_outputs.size(); i++) { + basic_block_sptr blk = d_outputs[i].block(); + if(!blk) { + msg << "In hierarchical block " << d_owner->name() << ", output " << i + << " is not connected internally"; + throw std::runtime_error(msg.str()); + } + tmp.push_back(blk); + } + sort(tmp.begin(), tmp.end()); + + std::insert_iterator<basic_block_vector_t> inserter(blocks, blocks.begin()); + unique_copy(tmp.begin(), tmp.end(), inserter); + + // Recurse hierarchical children + for(basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) { + hier_block2_sptr hier_block2(cast_to_hier_block2_sptr(*p)); + if(hier_block2 && (hier_block2.get() != d_owner)) { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "flatten_aux: recursing into hierarchical block " + << hier_block2 << std::endl; + hier_block2->d_detail->flatten_aux(sfg); + } + } + } + + void + hier_block2_detail::lock() + { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "lock: entered in " << this << std::endl; + + if(d_parent_detail) + d_parent_detail->lock(); + else + d_owner->lock(); + } + + void + hier_block2_detail::unlock() + { + if(HIER_BLOCK2_DETAIL_DEBUG) + std::cout << "unlock: entered in " << this << std::endl; + + if(d_parent_detail) + d_parent_detail->unlock(); + else + d_owner->unlock(); + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/hier_block2_detail.h b/gnuradio-runtime/lib/hier_block2_detail.h new file mode 100644 index 0000000000..99bf6e8ef1 --- /dev/null +++ b/gnuradio-runtime/lib/hier_block2_detail.h @@ -0,0 +1,77 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2007,2009,2013 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_HIER_BLOCK2_DETAIL_H +#define INCLUDED_GR_RUNTIME_HIER_BLOCK2_DETAIL_H + +#include <gnuradio/api.h> +#include <gnuradio/hier_block2.h> +#include <flat_flowgraph.h> +#include <boost/utility.hpp> + +namespace gr { + + /*! + * \ingroup internal + */ + class GR_RUNTIME_API hier_block2_detail : boost::noncopyable + { + public: + hier_block2_detail(hier_block2 *owner); + ~hier_block2_detail(); + + void connect(basic_block_sptr block); + void connect(basic_block_sptr src, int src_port, + basic_block_sptr dst, int dst_port); + void msg_connect(basic_block_sptr src, pmt::pmt_t srcport, + basic_block_sptr dst, pmt::pmt_t dstport); + void msg_disconnect(basic_block_sptr src, pmt::pmt_t srcport, + basic_block_sptr dst, pmt::pmt_t dstport); + void disconnect(basic_block_sptr block); + void disconnect(basic_block_sptr, int src_port, + basic_block_sptr, int dst_port); + void disconnect_all(); + void lock(); + void unlock(); + void flatten_aux(flat_flowgraph_sptr sfg) const; + + private: + // Private implementation data + hier_block2 *d_owner; + hier_block2_detail *d_parent_detail; + flowgraph_sptr d_fg; + std::vector<endpoint_vector_t> d_inputs; // Multiple internal endpoints per external input + endpoint_vector_t d_outputs; // Single internal endpoint per external output + basic_block_vector_t d_blocks; + + void connect_input(int my_port, int port, basic_block_sptr block); + void connect_output(int my_port, int port, basic_block_sptr block); + void disconnect_input(int my_port, int port, basic_block_sptr block); + void disconnect_output(int my_port, int port, basic_block_sptr block); + + endpoint_vector_t resolve_port(int port, bool is_input); + endpoint_vector_t resolve_endpoint(const endpoint &endp, bool is_input) const; + }; + +} /* namespace gr */ + +#endif /* INCLUDED_GR_RUNTIME_HIER_BLOCK2_DETAIL_H */ diff --git a/gnuradio-runtime/lib/io_signature.cc b/gnuradio-runtime/lib/io_signature.cc new file mode 100644 index 0000000000..ccfdf3c06b --- /dev/null +++ b/gnuradio-runtime/lib/io_signature.cc @@ -0,0 +1,117 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2007,2013 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 <gnuradio/io_signature.h> +#include <stdexcept> +#include <iostream> + +namespace gr { + + gr::io_signature::sptr + io_signature::makev(int min_streams, int max_streams, + const std::vector<int> &sizeof_stream_items) + { + return gr::io_signature::sptr + (new io_signature(min_streams, max_streams, + sizeof_stream_items)); + } + + gr::io_signature::sptr + io_signature::make(int min_streams, int max_streams, + int sizeof_stream_item) + { + std::vector<int> sizeof_items(1); + sizeof_items[0] = sizeof_stream_item; + return io_signature::makev(min_streams, max_streams, sizeof_items); + } + + gr::io_signature::sptr + io_signature::make2(int min_streams, int max_streams, + int sizeof_stream_item1, + int sizeof_stream_item2) + { + std::vector<int> sizeof_items(2); + sizeof_items[0] = sizeof_stream_item1; + sizeof_items[1] = sizeof_stream_item2; + return io_signature::makev(min_streams, max_streams, sizeof_items); + } + + gr::io_signature::sptr + io_signature::make3(int min_streams, int max_streams, + int sizeof_stream_item1, + int sizeof_stream_item2, + int sizeof_stream_item3) + { + std::vector<int> sizeof_items(3); + sizeof_items[0] = sizeof_stream_item1; + sizeof_items[1] = sizeof_stream_item2; + sizeof_items[2] = sizeof_stream_item3; + return io_signature::makev(min_streams, max_streams, sizeof_items); + } + + // ------------------------------------------------------------------------ + + io_signature::io_signature(int min_streams, int max_streams, + const std::vector<int> &sizeof_stream_items) + { + if(min_streams < 0 + || (max_streams != IO_INFINITE && max_streams < min_streams)) + throw std::invalid_argument ("gr::io_signature(1)"); + + if(sizeof_stream_items.size() < 1) + throw std::invalid_argument("gr::io_signature(2)"); + + for(size_t i = 0; i < sizeof_stream_items.size(); i++) { + if(max_streams != 0 && sizeof_stream_items[i] < 1) + throw std::invalid_argument("gr::io_signature(3)"); + } + + d_min_streams = min_streams; + d_max_streams = max_streams; + d_sizeof_stream_item = sizeof_stream_items; + } + + io_signature::~io_signature() + { + } + + int + io_signature::sizeof_stream_item(int _index) const + { + if(_index < 0) + throw std::invalid_argument("gr::io_signature::sizeof_stream_item"); + + size_t index = _index; + return d_sizeof_stream_item[std::min(index, d_sizeof_stream_item.size() - 1)]; + } + + std::vector<int> + io_signature::sizeof_stream_items() const + { + return d_sizeof_stream_item; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/local_sighandler.cc b/gnuradio-runtime/lib/local_sighandler.cc new file mode 100644 index 0000000000..ebd9bb1362 --- /dev/null +++ b/gnuradio-runtime/lib/local_sighandler.cc @@ -0,0 +1,189 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2013 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 "local_sighandler.h" +#include <stdexcept> +#include <stdio.h> +#include <string.h> + +namespace gr { + + local_sighandler::local_sighandler(int signum, + void (*new_handler)(int)) + : d_signum(signum) + { +#ifdef HAVE_SIGACTION + struct sigaction new_action; + memset(&new_action, 0, sizeof(new_action)); + + new_action.sa_handler = new_handler; + sigemptyset(&new_action.sa_mask); + new_action.sa_flags = 0; + + if(sigaction (d_signum, &new_action, &d_old_action) < 0) { + perror("sigaction (install new)"); + throw std::runtime_error("sigaction"); + } +#endif + } + + local_sighandler::~local_sighandler() + { +#ifdef HAVE_SIGACTION + if(sigaction (d_signum, &d_old_action, 0) < 0) { + perror("sigaction (restore old)"); + throw std::runtime_error("sigaction"); + } +#endif + } + + void + local_sighandler::throw_signal(int signum) + { + throw signal(signum); + } + + /* + * Semi-hideous way to may a signal number into a signal name + */ + #define SIGNAME(x) case x: return #x + + std::string + signal::name() const + { + char tmp[128]; + + switch(signum()) { +#ifdef SIGHUP + SIGNAME(SIGHUP); +#endif +#ifdef SIGINT + SIGNAME(SIGINT); +#endif +#ifdef SIGQUIT + SIGNAME(SIGQUIT); +#endif +#ifdef SIGILL + SIGNAME(SIGILL); +#endif +#ifdef SIGTRAP + SIGNAME(SIGTRAP); +#endif +#ifdef SIGABRT + SIGNAME(SIGABRT); +#endif +#ifdef SIGBUS + SIGNAME(SIGBUS); +#endif +#ifdef SIGFPE + SIGNAME(SIGFPE); +#endif +#ifdef SIGKILL + SIGNAME(SIGKILL); +#endif +#ifdef SIGUSR1 + SIGNAME(SIGUSR1); +#endif +#ifdef SIGSEGV + SIGNAME(SIGSEGV); +#endif +#ifdef SIGUSR2 + SIGNAME(SIGUSR2); +#endif +#ifdef SIGPIPE + SIGNAME(SIGPIPE); +#endif +#ifdef SIGALRM + SIGNAME(SIGALRM); +#endif +#ifdef SIGTERM + SIGNAME(SIGTERM); +#endif +#ifdef SIGSTKFLT + SIGNAME(SIGSTKFLT); +#endif +#ifdef SIGCHLD + SIGNAME(SIGCHLD); +#endif +#ifdef SIGCONT + SIGNAME(SIGCONT); +#endif +#ifdef SIGSTOP + SIGNAME(SIGSTOP); +#endif +#ifdef SIGTSTP + SIGNAME(SIGTSTP); +#endif +#ifdef SIGTTIN + SIGNAME(SIGTTIN); +#endif +#ifdef SIGTTOU + SIGNAME(SIGTTOU); +#endif +#ifdef SIGURG + SIGNAME(SIGURG); +#endif +#ifdef SIGXCPU + SIGNAME(SIGXCPU); +#endif +#ifdef SIGXFSZ + SIGNAME(SIGXFSZ); +#endif +#ifdef SIGVTALRM + SIGNAME(SIGVTALRM); +#endif +#ifdef SIGPROF + SIGNAME(SIGPROF); +#endif +#ifdef SIGWINCH + SIGNAME(SIGWINCH); +#endif +#ifdef SIGIO + SIGNAME(SIGIO); +#endif +#ifdef SIGPWR + SIGNAME(SIGPWR); +#endif +#ifdef SIGSYS + SIGNAME(SIGSYS); +#endif + default: +#if defined (HAVE_SNPRINTF) +#if defined (SIGRTMIN) && defined (SIGRTMAX) + if(signum() >= SIGRTMIN && signum() <= SIGRTMAX) { + snprintf(tmp, sizeof(tmp), "SIGRTMIN + %d", signum()); + return tmp; + } +#endif + snprintf(tmp, sizeof(tmp), "SIGNAL %d", signum()); + return tmp; +#else + return "Unknown signal"; +#endif + } + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gr_local_sighandler.h b/gnuradio-runtime/lib/local_sighandler.h index a49ee031ca..bd322e5b00 100644 --- a/gnuradio-runtime/lib/gr_local_sighandler.h +++ b/gnuradio-runtime/lib/local_sighandler.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2004,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -27,39 +27,48 @@ #include <signal.h> #endif -#include <gr_runtime_api.h> +#include <gnuradio/api.h> #include <string> -/*! - * \brief Get and set signal handler. - * - * \ingroup internal - * Constructor installs new handler, destructor reinstalls - * original value. - */ -class GR_RUNTIME_API gr_local_sighandler { - int d_signum; +namespace gr { + + /*! + * \brief Get and set signal handler. + * + * \ingroup internal + * Constructor installs new handler, destructor reinstalls + * original value. + */ + class GR_RUNTIME_API local_sighandler + { + private: + int d_signum; #ifdef HAVE_SIGACTION - struct sigaction d_old_action; + struct sigaction d_old_action; #endif -public: - gr_local_sighandler (int signum, void (*new_handler)(int)); - ~gr_local_sighandler (); - /* throw gr_signal (signum) */ - static void throw_signal (int signum); -}; + public: + local_sighandler(int signum, void (*new_handler)(int)); + ~local_sighandler(); -/*! - * \brief Representation of signal. - */ -class GR_RUNTIME_API gr_signal -{ - int d_signum; -public: - gr_signal (int signum) : d_signum (signum) {} - int signal () const { return d_signum; } - std::string name () const; -}; + /* throw gr_signal (signum) */ + static void throw_signal(int signum); + }; + + /*! + * \brief Representation of signal. + */ + class GR_RUNTIME_API signal + { + private: + int d_signum; + + public: + signal(int signum) : d_signum(signum) {} + int signum() const { return d_signum; } + std::string name() const; + }; + +} /* namespace gr */ #endif /* INCLUDED_GR_LOCAL_SIGHANDLER_H */ diff --git a/gnuradio-runtime/lib/logger.cc b/gnuradio-runtime/lib/logger.cc new file mode 100644 index 0000000000..dceb18471f --- /dev/null +++ b/gnuradio-runtime/lib/logger.cc @@ -0,0 +1,323 @@ +/* -*- c++ -*- */ +/* + * Copyright 2012 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. + */ + +/******************************************************************************* +* Author: Mark Plett +* Description: +* The gr_log module wraps the log4cpp library for logging in gnuradio. +*******************************************************************************/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gnuradio/logger.h> +#include <stdexcept> +#include <algorithm> + + +#ifdef ENABLE_GR_LOG +#ifdef HAVE_LOG4CPP + +namespace gr { + + bool logger_config::logger_configured(false); + + /************************ BEGIN LOG4CPP HELPERS ***********************/ + /* Logger config class. This is a singleton that controls how + * log4cpp is configured If watch_period>0 a thread is started to + * watch teh config file for changes. + */ + + // Getters of logger_config + logger_config& + logger_config::get_instance(void) + { + static logger_config instance; + return instance; + } + + std::string + logger_config::get_filename() + { + logger_config& in=get_instance(); + return in.filename; + } + + unsigned int + logger_config::get_watch_period() + { + logger_config& in=get_instance(); + return in.watch_period; + } + + // Method to watch config file for changes + void + logger_config::watch_file(std::string filename, unsigned int watch_period) + { + std::time_t last_write(boost::filesystem::last_write_time(filename)); + std::time_t current_time(0); + while(true) { + try { + current_time = boost::filesystem::last_write_time(filename); + if(current_time>last_write) { + std::cout<<"GNURadio Reloading logger configuration:"<<filename<<std::endl; + last_write = current_time; + // Should we wipe out all old configuration or just add the + // new? Just adding... logger_reset_config(); + logger_configured = logger_load_config(filename); + } + boost::this_thread::sleep(boost::posix_time::time_duration(0,0,watch_period,0)); + } + catch(const boost::thread_interrupted&) { + std::cout<<"GNURadio leaving logger config file watch."<<std::endl; + break; + } + } + } + + // Method to load the confifuration. It only loads if the filename + // or watch has changed + void + logger_config::load_config(std::string filename,unsigned int watch_period) + { + logger_config& instance = get_instance(); + // Only reconfigure if filename or watch has changed + if(!logger_configured) { + instance.filename = filename; + instance.watch_period = watch_period; + // Stop any file watching thread + if(instance.watch_thread!=NULL) + stop_watch(); + // Load configuration + std::cout<<"GNURadio Loading logger configuration:"<<instance.filename<<std::endl; + logger_configured = logger_load_config(instance.filename); + // Start watch if required + if(instance.watch_period>0) { + instance.watch_thread = new boost::thread(watch_file, instance.filename, + instance.watch_period); + } + } + } + + // Method to stop the watcher thread + void + logger_config::stop_watch() + { + logger_config& instance = get_instance(); + if(instance.watch_thread) { + instance.watch_thread->interrupt(); + instance.watch_thread->join(); + delete(instance.watch_thread); + instance.watch_thread=NULL; + } + } + + // Method to reset logger configuration + void + logger_config::reset_config(void) + { + logger_config& instance = get_instance(); + stop_watch(); + std::vector<log4cpp::Category*> *loggers = log4cpp::Category::getCurrentCategories(); + std::vector<log4cpp::Category*>::iterator logger = loggers->begin(); + // We can't destroy categories but we can neuter them by removing all appenders. + for(;logger!=loggers->end();logger++) { + (*logger)->removeAllAppenders(); + } + instance.filename = std::string(""); + instance.watch_period = 0; + logger_configured = false; + } + + /***************** Functions to call log4cpp methods *************************/ + + logger_ptr + logger_get_logger(std::string name) + { + if(log4cpp::Category::exists(name)) { + logger_ptr logger = &log4cpp::Category::getInstance(name); + return logger; + } + else { + logger_ptr logger = &log4cpp::Category::getInstance(name); + logger->setPriority(log4cpp::Priority::NOTSET); + return logger; + } + } + + bool + logger_load_config(const std::string &config_filename) + { + if(config_filename.size() != 0) { + try { + log4cpp::PropertyConfigurator::configure(config_filename); + return true; + } + catch(log4cpp::ConfigureFailure &e) { + std::cout << "Logger config failed :" << e.what() << std::endl; + } + } + return false; + } + + void + logger_set_level(logger_ptr logger, const std::string &level) + { + std::string nocase = level; + std::transform(level.begin(), level.end(), nocase.begin(), ::tolower); + + if(nocase == "off" || nocase == "notset") + logger_set_level(logger, log4cpp::Priority::NOTSET); + else if(nocase == "all" || nocase == "debug") + logger_set_level(logger, log4cpp::Priority::DEBUG); + else if(nocase == "info") + logger_set_level(logger, log4cpp::Priority::INFO); + else if(nocase == "notice") + logger_set_level(logger, log4cpp::Priority::NOTICE); + else if(nocase == "warn") + logger_set_level(logger, log4cpp::Priority::WARN); + else if(nocase == "error") + logger_set_level(logger, log4cpp::Priority::ERROR); + else if(nocase == "crit") + logger_set_level(logger, log4cpp::Priority::CRIT); + else if(nocase == "alert") + logger_set_level(logger, log4cpp::Priority::ALERT); + else if(nocase=="fatal") + logger_set_level(logger, log4cpp::Priority::FATAL); + else if(nocase == "emerg") + logger_set_level(logger, log4cpp::Priority::EMERG); + else + throw std::runtime_error("logger_set_level: Bad level type.\n"); + } + + void + logger_set_level(logger_ptr logger, log4cpp::Priority::Value level) + { + logger->setPriority(level); + } + + void + logger_get_level(logger_ptr logger, std::string &level) + { + log4cpp::Priority::Value levelPtr = logger->getPriority(); + if(levelPtr == log4cpp::Priority::NOTSET) level = "noset"; + if(levelPtr == log4cpp::Priority::DEBUG) level = "debug"; + if(levelPtr == log4cpp::Priority::INFO) level = "info"; + if(levelPtr == log4cpp::Priority::NOTICE) level = "notice"; + if(levelPtr == log4cpp::Priority::WARN) level = "warn"; + if(levelPtr == log4cpp::Priority::ERROR) level = "error"; + if(levelPtr == log4cpp::Priority::CRIT) level = "crit"; + if(levelPtr == log4cpp::Priority::ALERT) level = "alert"; + if(levelPtr == log4cpp::Priority::FATAL) level = "fatal"; + if(levelPtr == log4cpp::Priority::EMERG) level = "emerg"; + } + + void + logger_get_level(logger_ptr logger,log4cpp::Priority::Value level) + { + level = logger->getPriority(); + } + + void + logger_add_console_appender(logger_ptr logger, std::string target, std::string pattern) + { + log4cpp::PatternLayout* layout = new log4cpp::PatternLayout(); + log4cpp::Appender* app; + if(target=="stdout") + app = new log4cpp::OstreamAppender("ConsoleAppender::",&std::cout); + else + app = new log4cpp::OstreamAppender("ConsoleAppender::",&std::cerr); + + layout->setConversionPattern(pattern); + app->setLayout(layout); + logger->setAppender(*app); + } + + void + logger_add_file_appender(logger_ptr logger, std::string filename, + bool append, std::string pattern) + { + log4cpp::PatternLayout* layout = new log4cpp::PatternLayout(); + log4cpp::Appender* app = new + log4cpp::FileAppender("FileAppender::"+filename, + filename); + layout->setConversionPattern(pattern); + app->setLayout(layout); + logger->setAppender(app); + } + + void + logger_add_rollingfile_appender(logger_ptr logger, std::string filename, + size_t filesize, int bkup_index, bool append, + mode_t mode, std::string pattern) + { + log4cpp::PatternLayout* layout = new log4cpp::PatternLayout(); + log4cpp::Appender* app = new + log4cpp::RollingFileAppender("RollFileAppender::" + filename, filename, + filesize, bkup_index, append, mode); + layout->setConversionPattern(pattern); + app->setLayout(layout); + logger->setAppender(app); + } + + std::vector<std::string> + logger_get_logger_names(void) + { + std::vector<std::string> names; + std::vector<log4cpp::Category*> *loggers = log4cpp::Category::getCurrentCategories(); + std::vector<log4cpp::Category*>::iterator logger = loggers->begin(); + + for(;logger!=loggers->end();logger++) { + names.push_back((*logger)->getName()); + } + return names; + } + +} /* namespace gr */ + +#endif /* HAVE_LOG4CPP */ + +/****** Start Methods to provide Python the capabilities of the macros ********/ +void +gr_logger_config(const std::string config_filename, unsigned int watch_period) +{ + GR_CONFIG_AND_WATCH_LOGGER(config_filename, watch_period); +} + +std::vector<std::string> +gr_logger_get_logger_names(void) +{ + std::vector<std::string> names; + GR_GET_LOGGER_NAMES(names); + return names; +} + +void +gr_logger_reset_config(void) +{ + GR_RESET_CONFIGURATION(); +} + +// Remaining capability provided by gr::logger class in gnuradio/logger.h + +#endif /* ENABLE_GR_LOGGER */ diff --git a/gnuradio-runtime/lib/malloc16.h b/gnuradio-runtime/lib/malloc16.h index 90d1eca77a..05f80cbf4f 100644 --- a/gnuradio-runtime/lib/malloc16.h +++ b/gnuradio-runtime/lib/malloc16.h @@ -20,7 +20,7 @@ * Boston, MA 02110-1301, USA. */ -#include <gr_runtime_api.h> +#include <gnuradio/api.h> #ifdef __cplusplus extern "C" { diff --git a/gnuradio-runtime/lib/math/CMakeLists.txt b/gnuradio-runtime/lib/math/CMakeLists.txt new file mode 100644 index 0000000000..c95c84cecb --- /dev/null +++ b/gnuradio-runtime/lib/math/CMakeLists.txt @@ -0,0 +1,29 @@ +# Copyright 2010,2013 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. + +######################################################################## +# This file included, use CMake directory variables +######################################################################## + +list(APPEND gnuradio_runtime_sources + ${CMAKE_CURRENT_SOURCE_DIR}/fast_atan2f.cc + ${CMAKE_CURRENT_SOURCE_DIR}/fxpt.cc + ${CMAKE_CURRENT_SOURCE_DIR}/random.cc + ${CMAKE_CURRENT_SOURCE_DIR}/sincos.cc +) diff --git a/gnuradio-runtime/lib/math/fast_atan2f.cc b/gnuradio-runtime/lib/math/fast_atan2f.cc new file mode 100644 index 0000000000..3555cf50ec --- /dev/null +++ b/gnuradio-runtime/lib/math/fast_atan2f.cc @@ -0,0 +1,202 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2013 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 <gnuradio/math.h> // declaration is in here +#include <cmath> + +namespace gr { + + /***************************************************************************/ + /* Constant definitions */ + /***************************************************************************/ + + #define TAN_MAP_RES 0.003921569 /* (smallest non-zero value in table) */ + #define RAD_PER_DEG 0.017453293 + #define TAN_MAP_SIZE 256 + + /* arctangents from 0 to pi/4 radians */ + static float + fast_atan_table[257] = { + 0.000000e+00, 3.921549e-03, 7.842976e-03, 1.176416e-02, + 1.568499e-02, 1.960533e-02, 2.352507e-02, 2.744409e-02, + 3.136226e-02, 3.527947e-02, 3.919560e-02, 4.311053e-02, + 4.702413e-02, 5.093629e-02, 5.484690e-02, 5.875582e-02, + 6.266295e-02, 6.656816e-02, 7.047134e-02, 7.437238e-02, + 7.827114e-02, 8.216752e-02, 8.606141e-02, 8.995267e-02, + 9.384121e-02, 9.772691e-02, 1.016096e-01, 1.054893e-01, + 1.093658e-01, 1.132390e-01, 1.171087e-01, 1.209750e-01, + 1.248376e-01, 1.286965e-01, 1.325515e-01, 1.364026e-01, + 1.402496e-01, 1.440924e-01, 1.479310e-01, 1.517652e-01, + 1.555948e-01, 1.594199e-01, 1.632403e-01, 1.670559e-01, + 1.708665e-01, 1.746722e-01, 1.784728e-01, 1.822681e-01, + 1.860582e-01, 1.898428e-01, 1.936220e-01, 1.973956e-01, + 2.011634e-01, 2.049255e-01, 2.086818e-01, 2.124320e-01, + 2.161762e-01, 2.199143e-01, 2.236461e-01, 2.273716e-01, + 2.310907e-01, 2.348033e-01, 2.385093e-01, 2.422086e-01, + 2.459012e-01, 2.495869e-01, 2.532658e-01, 2.569376e-01, + 2.606024e-01, 2.642600e-01, 2.679104e-01, 2.715535e-01, + 2.751892e-01, 2.788175e-01, 2.824383e-01, 2.860514e-01, + 2.896569e-01, 2.932547e-01, 2.968447e-01, 3.004268e-01, + 3.040009e-01, 3.075671e-01, 3.111252e-01, 3.146752e-01, + 3.182170e-01, 3.217506e-01, 3.252758e-01, 3.287927e-01, + 3.323012e-01, 3.358012e-01, 3.392926e-01, 3.427755e-01, + 3.462497e-01, 3.497153e-01, 3.531721e-01, 3.566201e-01, + 3.600593e-01, 3.634896e-01, 3.669110e-01, 3.703234e-01, + 3.737268e-01, 3.771211e-01, 3.805064e-01, 3.838825e-01, + 3.872494e-01, 3.906070e-01, 3.939555e-01, 3.972946e-01, + 4.006244e-01, 4.039448e-01, 4.072558e-01, 4.105574e-01, + 4.138496e-01, 4.171322e-01, 4.204054e-01, 4.236689e-01, + 4.269229e-01, 4.301673e-01, 4.334021e-01, 4.366272e-01, + 4.398426e-01, 4.430483e-01, 4.462443e-01, 4.494306e-01, + 4.526070e-01, 4.557738e-01, 4.589307e-01, 4.620778e-01, + 4.652150e-01, 4.683424e-01, 4.714600e-01, 4.745676e-01, + 4.776654e-01, 4.807532e-01, 4.838312e-01, 4.868992e-01, + 4.899573e-01, 4.930055e-01, 4.960437e-01, 4.990719e-01, + 5.020902e-01, 5.050985e-01, 5.080968e-01, 5.110852e-01, + 5.140636e-01, 5.170320e-01, 5.199904e-01, 5.229388e-01, + 5.258772e-01, 5.288056e-01, 5.317241e-01, 5.346325e-01, + 5.375310e-01, 5.404195e-01, 5.432980e-01, 5.461666e-01, + 5.490251e-01, 5.518738e-01, 5.547124e-01, 5.575411e-01, + 5.603599e-01, 5.631687e-01, 5.659676e-01, 5.687566e-01, + 5.715357e-01, 5.743048e-01, 5.770641e-01, 5.798135e-01, + 5.825531e-01, 5.852828e-01, 5.880026e-01, 5.907126e-01, + 5.934128e-01, 5.961032e-01, 5.987839e-01, 6.014547e-01, + 6.041158e-01, 6.067672e-01, 6.094088e-01, 6.120407e-01, + 6.146630e-01, 6.172755e-01, 6.198784e-01, 6.224717e-01, + 6.250554e-01, 6.276294e-01, 6.301939e-01, 6.327488e-01, + 6.352942e-01, 6.378301e-01, 6.403565e-01, 6.428734e-01, + 6.453808e-01, 6.478788e-01, 6.503674e-01, 6.528466e-01, + 6.553165e-01, 6.577770e-01, 6.602282e-01, 6.626701e-01, + 6.651027e-01, 6.675261e-01, 6.699402e-01, 6.723452e-01, + 6.747409e-01, 6.771276e-01, 6.795051e-01, 6.818735e-01, + 6.842328e-01, 6.865831e-01, 6.889244e-01, 6.912567e-01, + 6.935800e-01, 6.958943e-01, 6.981998e-01, 7.004964e-01, + 7.027841e-01, 7.050630e-01, 7.073330e-01, 7.095943e-01, + 7.118469e-01, 7.140907e-01, 7.163258e-01, 7.185523e-01, + 7.207701e-01, 7.229794e-01, 7.251800e-01, 7.273721e-01, + 7.295557e-01, 7.317307e-01, 7.338974e-01, 7.360555e-01, + 7.382053e-01, 7.403467e-01, 7.424797e-01, 7.446045e-01, + 7.467209e-01, 7.488291e-01, 7.509291e-01, 7.530208e-01, + 7.551044e-01, 7.571798e-01, 7.592472e-01, 7.613064e-01, + 7.633576e-01, 7.654008e-01, 7.674360e-01, 7.694633e-01, + 7.714826e-01, 7.734940e-01, 7.754975e-01, 7.774932e-01, + 7.794811e-01, 7.814612e-01, 7.834335e-01, 7.853983e-01, + 7.853983e-01 + }; + + + /***************************************************************************** + Function: Arc tangent + + Syntax: angle = fast_atan2(y, x); + float y y component of input vector + float x x component of input vector + float angle angle of vector (x, y) in radians + + Description: This function calculates the angle of the vector (x,y) + based on a table lookup and linear interpolation. The table uses a + 256 point table covering -45 to +45 degrees and uses symetry to + determine the final angle value in the range of -180 to 180 + degrees. Note that this function uses the small angle approximation + for values close to zero. This routine calculates the arc tangent + with an average error of +/- 0.045 degrees. + *****************************************************************************/ + + float + fast_atan2f(float y, float x) + { + float x_abs, y_abs, z; + float alpha, angle, base_angle; + int index; + + /* don't divide by zero! */ // FIXME could get hosed with -0.0 + if((y == 0.0) && (x == 0.0)) + return 0.0; + + /* normalize to +/- 45 degree range */ + y_abs = fabsf(y); + x_abs = fabsf(x); + //z = (y_abs < x_abs ? y_abs / x_abs : x_abs / y_abs); + if(y_abs < x_abs) + z = y_abs / x_abs; + else + z = x_abs / y_abs; + + /* when ratio approaches the table resolution, the angle is */ + /* best approximated with the argument itself... */ + if(z < TAN_MAP_RES) + base_angle = z; + else { + /* find index and interpolation value */ + alpha = z * (float)TAN_MAP_SIZE - .5; + index = (int)alpha; + alpha -= (float)index; + /* determine base angle based on quadrant and */ + /* add or subtract table value from base angle based on quadrant */ + base_angle = fast_atan_table[index]; + base_angle += + (fast_atan_table[index + 1] - fast_atan_table[index]) * alpha; + } + + if(x_abs > y_abs) { /* -45 -> 45 or 135 -> 225 */ + if(x >= 0.0) { /* -45 -> 45 */ + if(y >= 0.0) + angle = base_angle; /* 0 -> 45, angle OK */ + else + angle = -base_angle; /* -45 -> 0, angle = -angle */ + } + else { /* 135 -> 180 or 180 -> -135 */ + angle = 3.14159265358979323846; + if(y >= 0.0) + angle -= base_angle; /* 135 -> 180, angle = 180 - angle */ + else + angle = base_angle - angle; /* 180 -> -135, angle = angle - 180 */ + } + } + else { /* 45 -> 135 or -135 -> -45 */ + if(y >= 0.0) { /* 45 -> 135 */ + angle = 1.57079632679489661923; + if(x >= 0.0) + angle -= base_angle; /* 45 -> 90, angle = 90 - angle */ + else + angle += base_angle; /* 90 -> 135, angle = 90 + angle */ + } + else { /* -135 -> -45 */ + angle = -1.57079632679489661923; + if(x >= 0.0) + angle += base_angle; /* -90 -> -45, angle = -90 + angle */ + else + angle -= base_angle; /* -135 -> -90, angle = -90 - angle */ + } + } + + #ifdef ZERO_TO_TWOPI + if (angle < 0) + return (angle + TWOPI); + else + return (angle); + #else + return (angle); + #endif + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gr_fxpt.cc b/gnuradio-runtime/lib/math/fxpt.cc index 2ea8520e6b..23fdda1241 100644 --- a/gnuradio-runtime/lib/gr_fxpt.cc +++ b/gnuradio-runtime/lib/math/fxpt.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2004,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,12 +24,15 @@ #include "config.h" #endif -#include <gr_fxpt.h> +#include <gnuradio/fxpt.h> -const float gr_fxpt::s_sine_table[1 << NBITS][2] = { -#include "sine_table.h" -}; +namespace gr { -const float gr_fxpt::PI = 3.14159265358979323846; -const float gr_fxpt::TWO_TO_THE_31 = 2147483648.0; + const float fxpt::s_sine_table[1 << NBITS][2] = { + #include "sine_table.h" + }; + const float fxpt::PI = 3.14159265358979323846; + const float fxpt::TWO_TO_THE_31 = 2147483648.0; + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gen_sine_table.py b/gnuradio-runtime/lib/math/gen_sine_table.py index d7d11eff11..d7d11eff11 100755 --- a/gnuradio-runtime/lib/gen_sine_table.py +++ b/gnuradio-runtime/lib/math/gen_sine_table.py diff --git a/gnuradio-runtime/lib/math/qa_fxpt.cc b/gnuradio-runtime/lib/math/qa_fxpt.cc new file mode 100644 index 0000000000..d368e7de82 --- /dev/null +++ b/gnuradio-runtime/lib/math/qa_fxpt.cc @@ -0,0 +1,102 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2013 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_fxpt.h> +#include <gnuradio/fxpt.h> +#include <cppunit/TestAssert.h> +#include <iostream> +#include <stdio.h> +#include <unistd.h> +#include <math.h> + +static const float SIN_COS_TOLERANCE = 1e-5; + +void +qa_fxpt::t0() +{ + CPPUNIT_ASSERT_DOUBLES_EQUAL(M_PI/2, gr::fxpt::fixed_to_float(0x40000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL(0.0, gr::fxpt::fixed_to_float(0x00000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-M_PI, gr::fxpt::fixed_to_float(0x80000000), SIN_COS_TOLERANCE); + + if(0) { + /* + * These are disabled because of some precision issues. + * + * Different compilers seem to have different opinions on whether + * the calulations are done single or double (or extended) + * precision. Any of the answers are fine for our real purpose, but + * sometimes the answer is off by a few bits at the bottom. + * Hence, the disabled check. + */ + CPPUNIT_ASSERT_EQUAL((gr_int32)0x40000000, gr::fxpt::float_to_fixed(M_PI/2)); + CPPUNIT_ASSERT_EQUAL((gr_int32)0, gr::fxpt::float_to_fixed(0)); + CPPUNIT_ASSERT_EQUAL((gr_int32)0x80000000, gr::fxpt::float_to_fixed(-M_PI)); + } +} + +void +qa_fxpt::t1() +{ + CPPUNIT_ASSERT_DOUBLES_EQUAL( 0, gr::fxpt::sin(0x00000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.707106781, gr::fxpt::sin(0x20000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL( 1, gr::fxpt::sin(0x40000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL( 0.707106781, gr::fxpt::sin(0x60000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL( 0, gr::fxpt::sin(0x7fffffff), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL( 0, gr::fxpt::sin(0x80000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL( 0, gr::fxpt::sin(0x80000001), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-1, gr::fxpt::sin(-0x40000000), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL(-0.707106781, gr::fxpt::sin(-0x20000000), SIN_COS_TOLERANCE); + + for(float p = -M_PI; p < M_PI; p += 2 * M_PI / 3600) { + float expected = sin(p); + float actual = gr::fxpt::sin(gr::fxpt::float_to_fixed (p)); + CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, SIN_COS_TOLERANCE); + } +} + +void +qa_fxpt::t2() +{ + for(float p = -M_PI; p < M_PI; p += 2 * M_PI / 3600) { + float expected = cos(p); + float actual = gr::fxpt::cos(gr::fxpt::float_to_fixed(p)); + CPPUNIT_ASSERT_DOUBLES_EQUAL(expected, actual, SIN_COS_TOLERANCE); + } +} + +void +qa_fxpt::t3() +{ + for(float p = -M_PI; p < M_PI; p += 2 * M_PI / 3600) { + float expected_sin = sin(p); + float expected_cos = cos(p); + float actual_sin; + float actual_cos; + gr::fxpt::sincos(gr::fxpt::float_to_fixed (p), &actual_sin, &actual_cos); + CPPUNIT_ASSERT_DOUBLES_EQUAL(expected_sin, actual_sin, SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL(expected_cos, actual_cos, SIN_COS_TOLERANCE); + } +} diff --git a/gnuradio-runtime/lib/qa_gr_fxpt.h b/gnuradio-runtime/lib/math/qa_fxpt.h index 72211563e7..58a6f02d1b 100644 --- a/gnuradio-runtime/lib/qa_gr_fxpt.h +++ b/gnuradio-runtime/lib/math/qa_fxpt.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2004,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -19,28 +19,27 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ + #ifndef INCLUDED_QA_GR_FXPT_H #define INCLUDED_QA_GR_FXPT_H - #include <cppunit/extensions/HelperMacros.h> #include <cppunit/TestCase.h> -class qa_gr_fxpt : public CppUnit::TestCase { - - CPPUNIT_TEST_SUITE (qa_gr_fxpt); - CPPUNIT_TEST (t0); - CPPUNIT_TEST (t1); - CPPUNIT_TEST (t2); - CPPUNIT_TEST (t3); - CPPUNIT_TEST_SUITE_END (); +class qa_fxpt : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(qa_fxpt); + CPPUNIT_TEST(t0); + CPPUNIT_TEST(t1); + CPPUNIT_TEST(t2); + CPPUNIT_TEST(t3); + CPPUNIT_TEST_SUITE_END(); private: - void t0 (); - void t1 (); - void t2 (); - void t3 (); - + void t0(); + void t1(); + void t2(); + void t3(); }; #endif /* INCLUDED_QA_GR_FXPT_H */ diff --git a/gnuradio-runtime/lib/qa_gr_fxpt_nco.cc b/gnuradio-runtime/lib/math/qa_fxpt_nco.cc index 6f208eac80..cf229d68be 100644 --- a/gnuradio-runtime/lib/qa_gr_fxpt_nco.cc +++ b/gnuradio-runtime/lib/math/qa_fxpt_nco.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2004,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,9 +23,10 @@ #ifdef HAVE_CONFIG_H #include <config.h> #endif -#include <qa_gr_fxpt_nco.h> -#include <gr_fxpt_nco.h> -#include <gr_nco.h> + +#include <qa_fxpt_nco.h> +#include <gnuradio/fxpt_nco.h> +#include <gnuradio/nco.h> #include <cppunit/TestAssert.h> #include <iostream> #include <stdio.h> @@ -45,59 +46,59 @@ static double max_d(double a, double b) } void -qa_gr_fxpt_nco::t0 () +qa_fxpt_nco::t0() { - gr_nco<float,float> ref_nco; - gr_fxpt_nco new_nco; + gr::nco<float,float> ref_nco; + gr::fxpt_nco new_nco; double max_error = 0, max_phase_error = 0; - ref_nco.set_freq ((float)(2 * M_PI / SIN_COS_FREQ)); - new_nco.set_freq ((float)(2 * M_PI / SIN_COS_FREQ)); + ref_nco.set_freq((float)(2 * M_PI / SIN_COS_FREQ)); + new_nco.set_freq((float)(2 * M_PI / SIN_COS_FREQ)); - CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_nco.get_freq(), new_nco.get_freq(), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL(ref_nco.get_freq(), new_nco.get_freq(), SIN_COS_TOLERANCE); - for (int i = 0; i < SIN_COS_BLOCK_SIZE; i++){ - float ref_sin = ref_nco.sin (); - float new_sin = new_nco.sin (); + for(int i = 0; i < SIN_COS_BLOCK_SIZE; i++) { + float ref_sin = ref_nco.sin(); + float new_sin = new_nco.sin(); //printf ("i = %6d\n", i); - CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_sin, new_sin, SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL(ref_sin, new_sin, SIN_COS_TOLERANCE); - max_error = max_d (max_error, ref_sin-new_sin); + max_error = max_d(max_error, ref_sin-new_sin); - float ref_cos = ref_nco.cos (); - float new_cos = new_nco.cos (); - CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_cos, new_cos, SIN_COS_TOLERANCE); + float ref_cos = ref_nco.cos(); + float new_cos = new_nco.cos(); + CPPUNIT_ASSERT_DOUBLES_EQUAL(ref_cos, new_cos, SIN_COS_TOLERANCE); - max_error = max_d (max_error, ref_cos-new_cos); + max_error = max_d(max_error, ref_cos-new_cos); - ref_nco.step (); - new_nco.step (); + ref_nco.step(); + new_nco.step(); - CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_nco.get_phase(), new_nco.get_phase(), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL(ref_nco.get_phase(), new_nco.get_phase(), SIN_COS_TOLERANCE); - max_phase_error = max_d (max_phase_error, ref_nco.get_phase()-new_nco.get_phase()); + max_phase_error = max_d(max_phase_error, ref_nco.get_phase()-new_nco.get_phase()); } // printf ("Fxpt max error %.9f, max phase error %.9f\n", max_error, max_phase_error); } void -qa_gr_fxpt_nco::t1 () +qa_fxpt_nco::t1() { - gr_nco<float,float> ref_nco; - gr_fxpt_nco new_nco; + gr::nco<float,float> ref_nco; + gr::fxpt_nco new_nco; gr_complex ref_block[SIN_COS_BLOCK_SIZE]; gr_complex new_block[SIN_COS_BLOCK_SIZE]; double max_error = 0; - ref_nco.set_freq ((float)(2 * M_PI / SIN_COS_FREQ)); - new_nco.set_freq ((float)(2 * M_PI / SIN_COS_FREQ)); + ref_nco.set_freq((float)(2 * M_PI / SIN_COS_FREQ)); + new_nco.set_freq((float)(2 * M_PI / SIN_COS_FREQ)); - CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_nco.get_freq(), new_nco.get_freq(), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL(ref_nco.get_freq(), new_nco.get_freq(), SIN_COS_TOLERANCE); - ref_nco.sincos ((gr_complex*)ref_block, SIN_COS_BLOCK_SIZE); - new_nco.sincos ((gr_complex*)new_block, SIN_COS_BLOCK_SIZE); + ref_nco.sincos((gr_complex*)ref_block, SIN_COS_BLOCK_SIZE); + new_nco.sincos((gr_complex*)new_block, SIN_COS_BLOCK_SIZE); - for (int i = 0; i < SIN_COS_BLOCK_SIZE; i++){ + for(int i = 0; i < SIN_COS_BLOCK_SIZE; i++) { CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_block[i].real(), new_block[i].real(), SIN_COS_TOLERANCE); max_error = max_d (max_error, ref_block[i].real()-new_block[i].real()); @@ -109,11 +110,11 @@ qa_gr_fxpt_nco::t1 () } void -qa_gr_fxpt_nco::t2 () +qa_fxpt_nco::t2() { } void -qa_gr_fxpt_nco::t3 () +qa_fxpt_nco::t3() { } diff --git a/gnuradio-runtime/lib/qa_gr_fxpt_nco.h b/gnuradio-runtime/lib/math/qa_fxpt_nco.h index 8998922bbb..1b2cdaede6 100644 --- a/gnuradio-runtime/lib/qa_gr_fxpt_nco.h +++ b/gnuradio-runtime/lib/math/qa_fxpt_nco.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2004,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -19,28 +19,27 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ + #ifndef INCLUDED_QA_GR_FXPT_NCO_H #define INCLUDED_QA_GR_FXPT_NCO_H - #include <cppunit/extensions/HelperMacros.h> #include <cppunit/TestCase.h> -class qa_gr_fxpt_nco : public CppUnit::TestCase { - - CPPUNIT_TEST_SUITE (qa_gr_fxpt_nco); - CPPUNIT_TEST (t0); - CPPUNIT_TEST (t1); - CPPUNIT_TEST (t2); - CPPUNIT_TEST (t3); - CPPUNIT_TEST_SUITE_END (); - - private: - void t0 (); - void t1 (); - void t2 (); - void t3 (); - +class qa_fxpt_nco : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(qa_fxpt_nco); + CPPUNIT_TEST(t0); + CPPUNIT_TEST(t1); + CPPUNIT_TEST(t2); + CPPUNIT_TEST(t3); + CPPUNIT_TEST_SUITE_END(); + +private: + void t0(); + void t1(); + void t2(); + void t3(); }; #endif /* INCLUDED_QA_GR_FXPT_NCO_H */ diff --git a/gnuradio-runtime/lib/qa_gr_fxpt_vco.cc b/gnuradio-runtime/lib/math/qa_fxpt_vco.cc index 5b6993a30c..ee9865e926 100644 --- a/gnuradio-runtime/lib/qa_gr_fxpt_vco.cc +++ b/gnuradio-runtime/lib/math/qa_fxpt_vco.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2005 Free Software Foundation, Inc. + * Copyright 2004,2005,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,9 +23,10 @@ #ifdef HAVE_CONFIG_H #include <config.h> #endif -#include <qa_gr_fxpt_vco.h> -#include <gr_fxpt_vco.h> -#include <gr_vco.h> + +#include <qa_fxpt_vco.h> +#include <gnuradio/fxpt_vco.h> +#include <vco.h> #include <cppunit/TestAssert.h> #include <iostream> #include <stdio.h> @@ -45,66 +46,65 @@ static double max_d(double a, double b) } void -qa_gr_fxpt_vco::t0 () +qa_fxpt_vco::t0() { - gr_vco<float,float> ref_vco; - gr_fxpt_vco new_vco; + gr::vco<float,float> ref_vco; + gr::fxpt_vco new_vco; double max_error = 0, max_phase_error = 0; float input[SIN_COS_BLOCK_SIZE]; - for (int i = 0; i < SIN_COS_BLOCK_SIZE; i++){ - input[i] = sin(double(i)); + for(int i = 0; i < SIN_COS_BLOCK_SIZE; i++) { + input[i] = sin(double(i)); } - for (int i = 0; i < SIN_COS_BLOCK_SIZE; i++){ - float ref_cos = ref_vco.cos (); - float new_cos = new_vco.cos (); - CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_cos, new_cos, SIN_COS_TOLERANCE); + for(int i = 0; i < SIN_COS_BLOCK_SIZE; i++) { + float ref_cos = ref_vco.cos(); + float new_cos = new_vco.cos(); + CPPUNIT_ASSERT_DOUBLES_EQUAL(ref_cos, new_cos, SIN_COS_TOLERANCE); - max_error = max_d (max_error, ref_cos-new_cos); + max_error = max_d(max_error, ref_cos-new_cos); - ref_vco.adjust_phase (input[i]); - new_vco.adjust_phase (input[i]); + ref_vco.adjust_phase(input[i]); + new_vco.adjust_phase(input[i]); - CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_vco.get_phase(), new_vco.get_phase(), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL(ref_vco.get_phase(), new_vco.get_phase(), SIN_COS_TOLERANCE); - max_phase_error = max_d (max_phase_error, ref_vco.get_phase()-new_vco.get_phase()); + max_phase_error = max_d(max_phase_error, ref_vco.get_phase()-new_vco.get_phase()); } // printf ("Fxpt max error %.9f, max phase error %.9f\n", max_error, max_phase_error); } - void -qa_gr_fxpt_vco::t1 () +qa_fxpt_vco::t1() { - gr_vco<float,float> ref_vco; - gr_fxpt_vco new_vco; + gr::vco<float,float> ref_vco; + gr::fxpt_vco new_vco; float ref_block[SIN_COS_BLOCK_SIZE]; float new_block[SIN_COS_BLOCK_SIZE]; float input[SIN_COS_BLOCK_SIZE]; double max_error = 0; - for (int i = 0; i < SIN_COS_BLOCK_SIZE; i++){ - input[i] = sin(double(i)); + for(int i = 0; i < SIN_COS_BLOCK_SIZE; i++) { + input[i] = sin(double(i)); } - ref_vco.cos (ref_block, input, SIN_COS_BLOCK_SIZE, SIN_COS_K, SIN_COS_AMPL); - new_vco.cos (new_block, input, SIN_COS_BLOCK_SIZE, SIN_COS_K, SIN_COS_AMPL); + ref_vco.cos(ref_block, input, SIN_COS_BLOCK_SIZE, SIN_COS_K, SIN_COS_AMPL); + new_vco.cos(new_block, input, SIN_COS_BLOCK_SIZE, SIN_COS_K, SIN_COS_AMPL); - for (int i = 0; i < SIN_COS_BLOCK_SIZE; i++){ - CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_block[i], new_block[i], SIN_COS_TOLERANCE); - max_error = max_d (max_error, ref_block[i]-new_block[i]); + for(int i = 0; i < SIN_COS_BLOCK_SIZE; i++) { + CPPUNIT_ASSERT_DOUBLES_EQUAL(ref_block[i], new_block[i], SIN_COS_TOLERANCE); + max_error = max_d(max_error, ref_block[i]-new_block[i]); } - CPPUNIT_ASSERT_DOUBLES_EQUAL (ref_vco.get_phase(), new_vco.get_phase(), SIN_COS_TOLERANCE); + CPPUNIT_ASSERT_DOUBLES_EQUAL(ref_vco.get_phase(), new_vco.get_phase(), SIN_COS_TOLERANCE); // printf ("Fxpt max error %.9f, max phase error %.9f\n", max_error, ref_vco.get_phase()-new_vco.get_phase()); } void -qa_gr_fxpt_vco::t2 () +qa_fxpt_vco::t2() { } void -qa_gr_fxpt_vco::t3 () +qa_fxpt_vco::t3() { } diff --git a/gnuradio-runtime/lib/qa_gr_fxpt_vco.h b/gnuradio-runtime/lib/math/qa_fxpt_vco.h index fab8022e36..72693f32e2 100644 --- a/gnuradio-runtime/lib/qa_gr_fxpt_vco.h +++ b/gnuradio-runtime/lib/math/qa_fxpt_vco.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2005 Free Software Foundation, Inc. + * Copyright 2004,2005,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -19,28 +19,27 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ + #ifndef INCLUDED_QA_GR_FXPT_VCO_H #define INCLUDED_QA_GR_FXPT_VCO_H - #include <cppunit/extensions/HelperMacros.h> #include <cppunit/TestCase.h> -class qa_gr_fxpt_vco : public CppUnit::TestCase { - - CPPUNIT_TEST_SUITE (qa_gr_fxpt_vco); - CPPUNIT_TEST (t0); - CPPUNIT_TEST (t1); - CPPUNIT_TEST (t2); - CPPUNIT_TEST (t3); - CPPUNIT_TEST_SUITE_END (); - - private: - void t0 (); - void t1 (); - void t2 (); - void t3 (); - +class qa_fxpt_vco : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(qa_fxpt_vco); + CPPUNIT_TEST(t0); + CPPUNIT_TEST(t1); + CPPUNIT_TEST(t2); + CPPUNIT_TEST(t3); + CPPUNIT_TEST_SUITE_END(); + +private: + void t0(); + void t1(); + void t2(); + void t3(); }; #endif /* INCLUDED_QA_GR_FXPT_VCO_H */ diff --git a/gnuradio-runtime/lib/qa_gr_math.cc b/gnuradio-runtime/lib/math/qa_math.cc index 74d51b536e..1fb43cc67f 100644 --- a/gnuradio-runtime/lib/qa_gr_math.cc +++ b/gnuradio-runtime/lib/math/qa_math.cc @@ -19,21 +19,21 @@ * Boston, MA 02110-1301, USA. */ -#include <gr_math.h> -#include <qa_gr_math.h> +#include <gnuradio/math.h> +#include <qa_math.h> #include <cppunit/TestAssert.h> #include <stdio.h> void -qa_gr_math::test_binary_slicer1 () +qa_math::test_binary_slicer1() { float x[5] = {-1, -0.5, 0, 0.5, 1.0}; unsigned int z[5] = {0, 0, 1, 1, 1}; unsigned int y; //printf("\nBinary\n"); - for (unsigned int i = 0; i < 5; i++) { - y = gr_binary_slicer(x[i]); + for(unsigned int i = 0; i < 5; i++) { + y = gr::binary_slicer(x[i]); //printf("in: %f out: %d desired: %d\n", x[i], y, z[i]); CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9); @@ -41,7 +41,7 @@ qa_gr_math::test_binary_slicer1 () //printf("\nBranchless Binary\n"); for (unsigned int i = 0; i < 5; i++) { - y = gr_branchless_binary_slicer(x[i]); + y = gr::branchless_binary_slicer(x[i]); //printf("in: %f out: %d desired: %d\n", x[i], y, z[i]); CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9); @@ -49,7 +49,7 @@ qa_gr_math::test_binary_slicer1 () } void -qa_gr_math::test_quad_0deg_slicer1 () +qa_math::test_quad_0deg_slicer1() { gr_complex x[4] = {gr_complex(1, 0), gr_complex(0, 1), @@ -61,7 +61,7 @@ qa_gr_math::test_quad_0deg_slicer1 () //printf("\nQuad0\n"); for (unsigned int i = 0; i < 4; i++) { - y = gr_quad_0deg_slicer(x[i]); + y = gr::quad_0deg_slicer(x[i]); //printf("in: %.4f+j%.4f out: %d desired: %d\n", x[i].real(), x[i].imag(), y, z[i]); CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9); @@ -69,7 +69,7 @@ qa_gr_math::test_quad_0deg_slicer1 () //printf("\nBranchless Quad0\n"); for (unsigned int i = 0; i < 4; i++) { - y = gr_branchless_quad_0deg_slicer(x[i]); + y = gr::branchless_quad_0deg_slicer(x[i]); //printf("in: %.4f+j%.4f out: %d desired: %d\n", x[i].real(), x[i].imag(), y, z[i]); CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9); @@ -77,7 +77,7 @@ qa_gr_math::test_quad_0deg_slicer1 () } void -qa_gr_math::test_quad_45deg_slicer1 () +qa_math::test_quad_45deg_slicer1() { gr_complex x[4] = {gr_complex(0.707, 0.707), gr_complex(-0.707, 0.707), @@ -89,7 +89,7 @@ qa_gr_math::test_quad_45deg_slicer1 () //printf("\nQuad45\n"); for (unsigned int i = 0; i < 4; i++) { - y = gr_quad_45deg_slicer(x[i]); + y = gr::quad_45deg_slicer(x[i]); //printf("in: %.4f+j%.4f out: %d desired: %d\n", x[i].real(), x[i].imag(), y, z[i]); CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9); @@ -97,7 +97,7 @@ qa_gr_math::test_quad_45deg_slicer1 () //printf("\nBranchless Quad45\n"); for (unsigned int i = 0; i < 4; i++) { - y = gr_branchless_quad_45deg_slicer(x[i]); + y = gr::branchless_quad_45deg_slicer(x[i]); //printf("in: %.4f+j%.4f out: %d desired: %d\n", x[i].real(), x[i].imag(), y, z[i]); CPPUNIT_ASSERT_DOUBLES_EQUAL(y, z[i], 1e-9); diff --git a/gnuradio-runtime/lib/qa_gr_math.h b/gnuradio-runtime/lib/math/qa_math.h index 86858c03d5..3621283b37 100644 --- a/gnuradio-runtime/lib/qa_gr_math.h +++ b/gnuradio-runtime/lib/math/qa_math.h @@ -25,9 +25,9 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/TestCase.h> -class qa_gr_math : public CppUnit::TestCase { - - CPPUNIT_TEST_SUITE(qa_gr_math); +class qa_math : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(qa_math); CPPUNIT_TEST(test_binary_slicer1); CPPUNIT_TEST(test_quad_0deg_slicer1); CPPUNIT_TEST(test_quad_45deg_slicer1); diff --git a/gnuradio-runtime/lib/qa_sincos.cc b/gnuradio-runtime/lib/math/qa_sincos.cc index be163117de..7def8a9bb8 100644 --- a/gnuradio-runtime/lib/qa_sincos.cc +++ b/gnuradio-runtime/lib/math/qa_sincos.cc @@ -25,8 +25,7 @@ #endif #include <qa_sincos.h> -#include <gr_sincos.h> -#include <attributes.h> +#include <gnuradio/sincos.h> #include <cppunit/TestAssert.h> #include <cmath> @@ -42,7 +41,7 @@ qa_sincos::t1() c_sin = sin(x); c_cos = cos(x); - gr_sincos(x, &gr_sin, &gr_cos); + gr::sincos(x, &gr_sin, &gr_cos); CPPUNIT_ASSERT_DOUBLES_EQUAL(c_sin, gr_sin, 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL(c_cos, gr_cos, 0.0001); @@ -61,7 +60,7 @@ qa_sincos::t2() c_sin = sinf(x); c_cos = cosf(x); - gr_sincosf(x, &gr_sin, &gr_cos); + gr::sincosf(x, &gr_sin, &gr_cos); CPPUNIT_ASSERT_DOUBLES_EQUAL(c_sin, gr_sin, 0.0001); CPPUNIT_ASSERT_DOUBLES_EQUAL(c_cos, gr_cos, 0.0001); diff --git a/gnuradio-runtime/lib/qa_sincos.h b/gnuradio-runtime/lib/math/qa_sincos.h index c54b75f97f..c54b75f97f 100644 --- a/gnuradio-runtime/lib/qa_sincos.h +++ b/gnuradio-runtime/lib/math/qa_sincos.h diff --git a/gnuradio-runtime/lib/math/random.cc b/gnuradio-runtime/lib/math/random.cc new file mode 100644 index 0000000000..7170f27edf --- /dev/null +++ b/gnuradio-runtime/lib/math/random.cc @@ -0,0 +1,188 @@ +/* -*- c++ -*- */ +/* + * Copyright 2002 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. + */ + +/* + * Copyright 1997 Massachusetts Institute of Technology + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation, and that the name of M.I.T. not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. M.I.T. makes no representations about the + * suitability of this software for any purpose. It is provided "as is" + * without express or implied warranty. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <math.h> +#include <gnuradio/random.h> + +namespace gr { + +#define IA 16807 +#define IM 2147483647 +#define AM (1.0/IM) +#define IQ 127773 +#define IR 2836 +#define NDIV (1+(IM-1)/NTAB) +#define EPS 1.2e-7 +#define RNMX (1.0-EPS) + + random::random(long seed) + { + reseed(seed); + } + + void + random::reseed(long seed) + { + d_seed = seed; + d_iy = 0; + for(int i = 0; i < NTAB; i++) + d_iv[i] = 0; + d_iset = 0; + d_gset = 0; + } + + /* + * This looks like it returns a uniform random deviate between 0.0 and 1.0 + * It looks similar to code from "Numerical Recipes in C". + */ + float + random::ran1() + { + int j; + long k; + float temp; + + if(d_seed <= 0 || !d_iy) { + if(-d_seed < 1) + d_seed=1; + else + d_seed = -d_seed; + for(j=NTAB+7;j>=0;j--) { + k=d_seed/IQ; + d_seed=IA*(d_seed-k*IQ)-IR*k; + if(d_seed < 0) + d_seed += IM; + if(j < NTAB) + d_iv[j] = d_seed; + } + d_iy=d_iv[0]; + } + k=(d_seed)/IQ; + d_seed=IA*(d_seed-k*IQ)-IR*k; + if(d_seed < 0) + d_seed += IM; + j=d_iy/NDIV; + d_iy=d_iv[j]; + d_iv[j] = d_seed; + temp=AM * d_iy; + if(temp > RNMX) + temp = RNMX; + return temp; + } + + /* + * Returns a normally distributed deviate with zero mean and variance 1. + * Also looks like it's from "Numerical Recipes in C". + */ + float + random::gasdev() + { + float fac,rsq,v1,v2; + d_iset = 1 - d_iset; + if(d_iset) { + do { + v1=2.0*ran1()-1.0; + v2=2.0*ran1()-1.0; + rsq=v1*v1+v2*v2; + } while(rsq >= 1.0 || rsq == 0.0); + fac= sqrt(-2.0*log(rsq)/rsq); + d_gset=v1*fac; + return v2*fac; + } + return d_gset; + } + + /* + * Copied from The KC7WW / OH2BNS Channel Simulator + * FIXME Need to check how good this is at some point + */ + float + random::laplacian() + { + float z = ran1(); + if(z < 0.5) + return log(2.0 * z) / M_SQRT2; + else + return -log(2.0 * (1.0 - z)) / M_SQRT2; + } + + /* + * Copied from The KC7WW / OH2BNS Channel Simulator + * FIXME Need to check how good this is at some point + */ + // 5 => scratchy, 8 => Geiger + float + random::impulse(float factor = 5) + { + float z = -M_SQRT2 * log(ran1()); + if(fabsf(z) <= factor) + return 0.0; + else + return z; + } + + /* + * Complex rayleigh is really gaussian I and gaussian Q + * It can also be generated by real rayleigh magnitude and + * uniform random angle + * Adapted from The KC7WW / OH2BNS Channel Simulator + * FIXME Need to check how good this is at some point + */ + gr_complex + random::rayleigh_complex() + { + return gr_complex(gasdev(),gasdev()); + } + + /* Other option + mag = rayleigh(); + ang = 2.0 * M_PI * RNG(); + *Rx = rxx * cos(z); + *Iy = rxx * sin(z); + */ + + float + random::rayleigh() + { + return sqrt(-2.0 * log(ran1())); + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gr_sincos.c b/gnuradio-runtime/lib/math/sincos.cc index a8d01b0da4..49a90d2128 100644 --- a/gnuradio-runtime/lib/gr_sincos.c +++ b/gnuradio-runtime/lib/math/sincos.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004,2010 Free Software Foundation, Inc. + * Copyright 2004,2010,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -28,56 +28,58 @@ #define _GNU_SOURCE // ask for GNU extensions if available #endif -#include <gr_sincos.h> +#include <gnuradio/sincos.h> #include <math.h> -// ---------------------------------------------------------------- +namespace gr { #if defined (HAVE_SINCOS) -void -gr_sincos (double x, double *sinx, double *cosx) -{ - sincos (x, sinx, cosx); -} + void + sincos(double x, double *sinx, double *cosx) + { + ::sincos(x, sinx, cosx); + } #else -void -gr_sincos (double x, double *sinx, double *cosx) -{ - *sinx = sin (x); - *cosx = cos (x); -} + void + sincos(double x, double *sinx, double *cosx) + { + *sinx = ::sin(x); + *cosx = ::cos(x); + } #endif -// ---------------------------------------------------------------- + // ---------------------------------------------------------------- #if defined (HAVE_SINCOSF) -void -gr_sincosf (float x, float *sinx, float *cosx) -{ - sincosf (x, sinx, cosx); -} + void + sincosf(float x, float *sinx, float *cosx) + { + ::sincosf(x, sinx, cosx); + } #elif defined (HAVE_SINF) && defined (HAVE_COSF) -void -gr_sincosf (float x, float *sinx, float *cosx) -{ - *sinx = sinf (x); - *cosx = cosf (x); -} + void + sincosf(float x, float *sinx, float *cosx) + { + *sinx = ::sinf(x); + *cosx = ::cosf(x); + } #else -void -gr_sincosf (float x, float *sinx, float *cosx) -{ - *sinx = sin (x); - *cosx = cos (x); -} + void + sincosf(float x, float *sinx, float *cosx) + { + *sinx = ::sin(x); + *cosx = ::cos(x); + } #endif + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/sine_table.h b/gnuradio-runtime/lib/math/sine_table.h index 69834943bc..69834943bc 100644 --- a/gnuradio-runtime/lib/sine_table.h +++ b/gnuradio-runtime/lib/math/sine_table.h diff --git a/gnuradio-runtime/lib/math/vco.h b/gnuradio-runtime/lib/math/vco.h new file mode 100644 index 0000000000..fa11732c1f --- /dev/null +++ b/gnuradio-runtime/lib/math/vco.h @@ -0,0 +1,99 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2013 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 _GR_VCO_H_ +#define _GR_VCO_H_ + +#include <gnuradio/sincos.h> +#include <gnuradio/gr_complex.h> +#include <vector> +#include <cmath> + +namespace gr { + + /*! + * \brief base class template for Voltage Controlled Oscillator (VCO) + * \ingroup misc + */ + template<class o_type, class i_type> + class vco + { + public: + vco() : d_phase(0) {} + + virtual ~vco() {} + + // radians + void set_phase(double angle) { + d_phase = angle; + } + + void adjust_phase(double delta_phase) { + d_phase += delta_phase; + if(fabs (d_phase) > M_PI){ + + while(d_phase > M_PI) + d_phase -= 2*M_PI; + + while(d_phase < -M_PI) + d_phase += 2*M_PI; + } + } + + double get_phase() const { return d_phase; } + + // compute sin and cos for current phase angle + void sincos(float *sinx, float *cosx) const; + + // compute cos or sin for current phase angle + float cos() const { return std::cos(d_phase); } + float sin() const { return std::sin(d_phase); } + + // compute a block at a time + void cos(float *output, const float *input, + int noutput_items, double k, double ampl = 1.0); + + protected: + double d_phase; + }; + + template<class o_type, class i_type> + void + vco<o_type,i_type>::sincos(float *sinx, float *cosx) const + { + gr::sincosf(d_phase, sinx, cosx); + } + + template<class o_type, class i_type> + void + vco<o_type,i_type>::cos(float *output, const float *input, + int noutput_items, double k, double ampl) + { + for(int i = 0; i < noutput_items; i++) { + output[i] = cos() * ampl; + adjust_phase(input[i] * k); + } + } + +} /* namespace gr */ + +#endif /* _GR_VCO_H_ */ diff --git a/gnuradio-runtime/lib/message.cc b/gnuradio-runtime/lib/message.cc new file mode 100644 index 0000000000..ac066d668e --- /dev/null +++ b/gnuradio-runtime/lib/message.cc @@ -0,0 +1,82 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 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 <gnuradio/message.h> +#include <assert.h> +#include <string.h> + +namespace gr { + + static long s_ncurrently_allocated = 0; + + message::sptr + message::make(long type, double arg1, double arg2, size_t length) + { + return message::sptr(new message(type, arg1, arg2, length)); + } + + message::sptr + message::make_from_string(const std::string s, long type, double arg1, double arg2) + { + message::sptr m = message::make(type, arg1, arg2, s.size()); + memcpy(m->msg(), s.data(), s.size()); + return m; + } + + message::message(long type, double arg1, double arg2, size_t length) + : d_type(type), d_arg1(arg1), d_arg2(arg2) + { + if(length == 0) + d_buf_start = d_msg_start = d_msg_end = d_buf_end = 0; + else { + d_buf_start = new unsigned char[length]; + d_msg_start = d_buf_start; + d_msg_end = d_buf_end = d_buf_start + length; + } + s_ncurrently_allocated++; + } + + message::~message() + { + assert (d_next == 0); + delete [] d_buf_start; + d_msg_start = d_msg_end = d_buf_end = 0; + s_ncurrently_allocated--; + } + + std::string + message::to_string() const + { + return std::string((char *)d_msg_start, length()); + } + + long + message_ncurrently_allocated() + { + return s_ncurrently_allocated; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/messages/msg_accepter.cc b/gnuradio-runtime/lib/messages/msg_accepter.cc index a0d2d840c6..cc86a6ff8a 100644 --- a/gnuradio-runtime/lib/messages/msg_accepter.cc +++ b/gnuradio-runtime/lib/messages/msg_accepter.cc @@ -24,7 +24,7 @@ #include "config.h" #endif -#include <messages/msg_accepter.h> +#include <gnuradio/messages/msg_accepter.h> namespace gr { namespace messages { diff --git a/gnuradio-runtime/lib/messages/msg_accepter_msgq.cc b/gnuradio-runtime/lib/messages/msg_accepter_msgq.cc index adbea5ebc6..7ee6ea02c1 100644 --- a/gnuradio-runtime/lib/messages/msg_accepter_msgq.cc +++ b/gnuradio-runtime/lib/messages/msg_accepter_msgq.cc @@ -23,9 +23,7 @@ #include <config.h> #endif -#include <messages/msg_accepter_msgq.h> - -using namespace pmt; +#include <gnuradio/messages/msg_accepter_msgq.h> namespace gr { namespace messages { @@ -41,7 +39,7 @@ namespace gr { } void - msg_accepter_msgq::post(pmt_t msg) + msg_accepter_msgq::post(pmt::pmt_t msg) { d_msg_queue->insert_tail(msg); } diff --git a/gnuradio-runtime/lib/messages/msg_producer.cc b/gnuradio-runtime/lib/messages/msg_producer.cc index c354422aa6..3f56bc6637 100644 --- a/gnuradio-runtime/lib/messages/msg_producer.cc +++ b/gnuradio-runtime/lib/messages/msg_producer.cc @@ -24,7 +24,7 @@ #include "config.h" #endif -#include <messages/msg_producer.h> +#include <gnuradio/messages/msg_producer.h> namespace gr { namespace messages { diff --git a/gnuradio-runtime/lib/messages/msg_queue.cc b/gnuradio-runtime/lib/messages/msg_queue.cc index 0d460dc05c..6db2d2daa2 100644 --- a/gnuradio-runtime/lib/messages/msg_queue.cc +++ b/gnuradio-runtime/lib/messages/msg_queue.cc @@ -24,11 +24,9 @@ #include "config.h" #endif -#include <messages/msg_queue.h> +#include <gnuradio/messages/msg_queue.h> #include <stdexcept> -using namespace pmt; - namespace gr { namespace messages { @@ -49,7 +47,7 @@ namespace gr { } void - msg_queue::insert_tail(pmt_t msg) + msg_queue::insert_tail(pmt::pmt_t msg) { gr::thread::scoped_lock guard(d_mutex); @@ -60,7 +58,7 @@ namespace gr { d_not_empty.notify_one(); } - pmt_t + pmt::pmt_t msg_queue::delete_head() { gr::thread::scoped_lock guard(d_mutex); @@ -68,7 +66,7 @@ namespace gr { while(empty_p()) d_not_empty.wait(guard); - pmt_t m(d_msgs.front()); + pmt::pmt_t m(d_msgs.front()); d_msgs.pop_front(); if(d_limit > 0) // Unlimited length queues never block on write @@ -77,15 +75,15 @@ namespace gr { return m; } - pmt_t + pmt::pmt_t msg_queue::delete_head_nowait() { gr::thread::scoped_lock guard(d_mutex); if(empty_p()) - return pmt_t(); + return pmt::pmt_t(); - pmt_t m(d_msgs.front()); + pmt::pmt_t m(d_msgs.front()); d_msgs.pop_front(); if(d_limit > 0) // Unlimited length queues never block on write @@ -97,7 +95,7 @@ namespace gr { void msg_queue::flush() { - while(delete_head_nowait() != pmt_t()) + while(delete_head_nowait() != pmt::pmt_t()) ; } diff --git a/gnuradio-runtime/lib/gr_reverse.cc b/gnuradio-runtime/lib/misc.cc index 08c588cb55..f9ad6ca89c 100644 --- a/gnuradio-runtime/lib/gr_reverse.cc +++ b/gnuradio-runtime/lib/misc.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2005 Free Software Foundation, Inc. + * Copyright 2005,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,37 +24,47 @@ #include "config.h" #endif -#include <gr_reverse.h> +#include "misc.h" +namespace gr { -std::vector<float> -gr_reverse (const std::vector<float> &taps) -{ - int size = taps.size (); - std::vector<float> new_taps(size); + unsigned int + rounduppow2(unsigned int n) + { + int i; + for(i=0;((n-1)>>i) != 0;i++) + ; + return 1<<i; + } - if (size == 0) - return new_taps; + // ---------------------------------------------------------------- - for (int i = 0; i < size; i++) - new_taps[i] = taps[size - i - 1]; + void + zero_vector(std::vector<float> &v) + { + for(unsigned int i=0; i < v.size(); i++) + v[i] = 0; + } - return new_taps; -} + void + zero_vector(std::vector<double> &v) + { + for(unsigned int i=0; i < v.size(); i++) + v[i] = 0; + } + void + zero_vector(std::vector<int> &v) + { + for(unsigned int i=0; i < v.size(); i++) + v[i] = 0; + } -std::vector<gr_complex> -gr_reverse (const std::vector<gr_complex> &taps) -{ - int size = taps.size (); - std::vector<gr_complex> new_taps(size); - - if (size == 0) - return new_taps; - - for (int i = 0; i < size; i++) - new_taps[i] = taps[size - i - 1]; - - return new_taps; -} + void + zero_vector(std::vector<gr_complex> &v) + { + for(unsigned int i=0; i < v.size(); i++) + v[i] = 0; + } +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gr_misc.h b/gnuradio-runtime/lib/misc.h index 182ae87de6..833b6470a5 100644 --- a/gnuradio-runtime/lib/gr_misc.h +++ b/gnuradio-runtime/lib/misc.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2005 Free Software Foundation, Inc. + * Copyright 2005,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,17 +23,20 @@ #ifndef INCLUDED_GR_MISC_H #define INCLUDED_GR_MISC_H -#include <gr_runtime_api.h> -#include <gr_types.h> +#include <gnuradio/api.h> +#include <gnuradio/types.h> -GR_RUNTIME_API unsigned int -gr_rounduppow2(unsigned int n); +namespace gr { -// FIXME should be template -GR_RUNTIME_API void gr_zero_vector(std::vector<float> &v); -GR_RUNTIME_API void gr_zero_vector(std::vector<double> &v); -GR_RUNTIME_API void gr_zero_vector(std::vector<int> &v); -GR_RUNTIME_API void gr_zero_vector(std::vector<gr_complex> &v); + GR_RUNTIME_API unsigned int + rounduppow2(unsigned int n); + // FIXME should be template + GR_RUNTIME_API void zero_vector(std::vector<float> &v); + GR_RUNTIME_API void zero_vector(std::vector<double> &v); + GR_RUNTIME_API void zero_vector(std::vector<int> &v); + GR_RUNTIME_API void zero_vector(std::vector<gr_complex> &v); + +} /* namespace gr */ #endif /* INCLUDED_GR_MISC_H */ diff --git a/gnuradio-runtime/lib/gr_msg_accepter.cc b/gnuradio-runtime/lib/msg_accepter.cc index 93d5fb20e8..354fce0c3d 100644 --- a/gnuradio-runtime/lib/gr_msg_accepter.cc +++ b/gnuradio-runtime/lib/msg_accepter.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2009 Free Software Foundation, Inc. + * Copyright 2009,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,37 +23,40 @@ #include <config.h> #endif -#include <gr_msg_accepter.h> -#include <gr_block.h> -#include <gr_block_detail.h> -#include <gr_hier_block2.h> +#include <gnuradio/msg_accepter.h> +#include <gnuradio/block.h> +#include <gnuradio/block_detail.h> +#include <gnuradio/hier_block2.h> #include <stdexcept> -using namespace pmt; - -gr_msg_accepter::gr_msg_accepter() -{ -} - -gr_msg_accepter::~gr_msg_accepter() -{ - // NOP, required as virtual destructor -} - -void -gr_msg_accepter::post(pmt_t which_port, pmt_t msg) -{ - // Notify derived class, handled case by case - gr_block *p = dynamic_cast<gr_block *>(this); - if (p) { - p->_post(which_port,msg); - return; +namespace gr { + + msg_accepter::msg_accepter() + { + } + + msg_accepter::~msg_accepter() + { + // NOP, required as virtual destructor } - gr_hier_block2 *p2 = dynamic_cast<gr_hier_block2 *>(this); - if (p2){ - // FIXME do the right thing - return; + + void + msg_accepter::post(pmt::pmt_t which_port, pmt::pmt_t msg) + { + // Notify derived class, handled case by case + block *p = dynamic_cast<block *>(this); + if(p) { + p->_post(which_port, msg); + return; + } + + hier_block2 *p2 = dynamic_cast<hier_block2 *>(this); + if(p2) { + // FIXME do the right thing + return; + } + + throw std::runtime_error("unknown derived class"); } - throw std::runtime_error("unknown derived class"); -} +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gr_msg_handler.cc b/gnuradio-runtime/lib/msg_handler.cc index 0f93497088..32d14eb715 100644 --- a/gnuradio-runtime/lib/gr_msg_handler.cc +++ b/gnuradio-runtime/lib/msg_handler.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2005 Free Software Foundation, Inc. + * Copyright 2005,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,8 +23,13 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include <gr_msg_handler.h> -gr_msg_handler::~gr_msg_handler () -{ -} +#include <gnuradio/msg_handler.h> + +namespace gr { + + msg_handler::~msg_handler() + { + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/msg_queue.cc b/gnuradio-runtime/lib/msg_queue.cc new file mode 100644 index 0000000000..9961f76296 --- /dev/null +++ b/gnuradio-runtime/lib/msg_queue.cc @@ -0,0 +1,130 @@ +/* -*- c++ -*- */ +/* + * Copyright 2005,2009,2013 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 <gnuradio/msg_queue.h> +#include <stdexcept> + +namespace gr { + + msg_queue::sptr + msg_queue::make(unsigned int limit) + { + return msg_queue::sptr(new msg_queue(limit)); + } + + msg_queue::msg_queue(unsigned int limit) + : d_not_empty(), d_not_full(), + /*d_head(0), d_tail(0),*/ d_count(0), d_limit(limit) + { + } + + msg_queue::~msg_queue() + { + flush (); + } + + void + msg_queue::insert_tail(message::sptr msg) + { + if(msg->d_next) + throw std::invalid_argument("gr::msg_queue::insert_tail: msg already in queue"); + + gr::thread::scoped_lock guard(d_mutex); + + while(full_p()) + d_not_full.wait(guard); + + if(d_tail == 0) { + d_tail = d_head = msg; + //msg->d_next = 0; + msg->d_next.reset(); + } + else { + d_tail->d_next = msg; + d_tail = msg; + //msg->d_next = 0; + msg->d_next.reset(); + } + d_count++; + d_not_empty.notify_one(); + } + + message::sptr + msg_queue::delete_head() + { + gr::thread::scoped_lock guard(d_mutex); + message::sptr m; + + while((m = d_head) == 0) + d_not_empty.wait(guard); + + d_head = m->d_next; + if(d_head == 0){ + //d_tail = 0; + d_tail.reset(); + } + + d_count--; + // m->d_next = 0; + m->d_next.reset(); + d_not_full.notify_one(); + return m; + } + + message::sptr + msg_queue::delete_head_nowait() + { + gr::thread::scoped_lock guard(d_mutex); + message::sptr m; + + if((m = d_head) == 0) { + //return 0; + return message::sptr(); + } + + d_head = m->d_next; + if(d_head == 0) { + //d_tail = 0; + d_tail.reset(); + } + + d_count--; + //m->d_next = 0; + m->d_next.reset(); + d_not_full.notify_one(); + return m; + } + + void + msg_queue::flush() + { + message::sptr m; + + while((m = delete_head_nowait ()) != 0) + ; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gr_pagesize.cc b/gnuradio-runtime/lib/pagesize.cc index e31e05ca70..373c0b6654 100644 --- a/gnuradio-runtime/lib/gr_pagesize.cc +++ b/gnuradio-runtime/lib/pagesize.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003 Free Software Foundation, Inc. + * Copyright 2003,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,33 +24,36 @@ #include "config.h" #endif -#include <gr_pagesize.h> +#include "pagesize.h" #include <unistd.h> #include <stdio.h> +namespace gr { + #if defined(_WIN32) && defined(HAVE_GETPAGESIZE) -extern "C" size_t getpagesize(void); + extern "C" size_t getpagesize(void); #endif -int -gr_pagesize () -{ - static int s_pagesize = -1; + int + pagesize() + { + static int s_pagesize = -1; - if (s_pagesize == -1){ + if(s_pagesize == -1) { #if defined(HAVE_GETPAGESIZE) - s_pagesize = getpagesize (); + s_pagesize = getpagesize(); #elif defined (HAVE_SYSCONF) - s_pagesize = sysconf (_SC_PAGESIZE); - if (s_pagesize == -1){ - perror ("_SC_PAGESIZE"); - s_pagesize = 4096; - } + s_pagesize = sysconf(_SC_PAGESIZE); + if(s_pagesize == -1) { + perror("_SC_PAGESIZE"); + s_pagesize = 4096; + } #else - fprintf (stderr, "gr_pagesize: no info; setting pagesize = 4096\n"); - s_pagesize = 4096; + fprintf(stderr, "gr::pagesize: no info; setting pagesize = 4096\n"); + s_pagesize = 4096; #endif + } + return s_pagesize; } - return s_pagesize; -} +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gr_pagesize.h b/gnuradio-runtime/lib/pagesize.h index d14cb22b1b..6a16882002 100644 --- a/gnuradio-runtime/lib/gr_pagesize.h +++ b/gnuradio-runtime/lib/pagesize.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2003 Free Software Foundation, Inc. + * Copyright 2003,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -19,16 +19,19 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ -#ifndef _GR_PAGESIZE_H_ -#define _GR_PAGESIZE_H_ -#include <gr_runtime_api.h> +#ifndef GR_PAGESIZE_H_ +#define GR_PAGESIZE_H_ -/*! - * \brief return the page size in bytes - */ +#include <gnuradio/api.h> + +namespace gr { -GR_RUNTIME_API int gr_pagesize (); + /*! + * \brief return the page size in bytes + */ + GR_RUNTIME_API int pagesize(); +} /* namespace gr */ -#endif /* _GR_PAGESIZE_H_ */
\ No newline at end of file +#endif /* GR_PAGESIZE_H_ */ diff --git a/gnuradio-runtime/lib/pmt/pmt.cc b/gnuradio-runtime/lib/pmt/pmt.cc index b6b3004331..f3f7783839 100644 --- a/gnuradio-runtime/lib/pmt/pmt.cc +++ b/gnuradio-runtime/lib/pmt/pmt.cc @@ -27,7 +27,7 @@ #include <vector> #include <pmt/pmt.h> #include "pmt_int.h" -#include <messages/msg_accepter.h> +#include <gnuradio/messages/msg_accepter.h> #include <pmt/pmt_pool.h> #include <stdio.h> #include <string.h> diff --git a/gnuradio-runtime/lib/pmt/qa_pmt.h b/gnuradio-runtime/lib/pmt/qa_pmt.h index 3e0c91abac..9293a076a6 100644 --- a/gnuradio-runtime/lib/pmt/qa_pmt.h +++ b/gnuradio-runtime/lib/pmt/qa_pmt.h @@ -23,7 +23,7 @@ #ifndef INCLUDED_QA_PMT_H #define INCLUDED_QA_PMT_H -#include <attributes.h> +#include <gnuradio/attributes.h> #include <cppunit/TestSuite.h> //! collect all the tests for pmt diff --git a/gnuradio-runtime/lib/pmt/qa_pmt_prims.cc b/gnuradio-runtime/lib/pmt/qa_pmt_prims.cc index e9a897deac..bfe71fbe5a 100644 --- a/gnuradio-runtime/lib/pmt/qa_pmt_prims.cc +++ b/gnuradio-runtime/lib/pmt/qa_pmt_prims.cc @@ -22,7 +22,7 @@ #include <qa_pmt_prims.h> #include <cppunit/TestAssert.h> -#include <messages/msg_passing.h> +#include <gnuradio/messages/msg_passing.h> #include <boost/format.hpp> #include <cstdio> #include <cstring> diff --git a/gnuradio-runtime/lib/pmt/qa_pmt_prims.h b/gnuradio-runtime/lib/pmt/qa_pmt_prims.h index 8c3f5c6220..f2f3dd77f7 100644 --- a/gnuradio-runtime/lib/pmt/qa_pmt_prims.h +++ b/gnuradio-runtime/lib/pmt/qa_pmt_prims.h @@ -22,13 +22,13 @@ #ifndef INCLUDED_QA_PMT_PRIMS_H #define INCLUDED_QA_PMT_PRIMS_H -#include <attributes.h> +#include <gnuradio/attributes.h> #include <pmt/api.h> //reason: suppress warnings #include <cppunit/extensions/HelperMacros.h> #include <cppunit/TestCase.h> -class __GR_ATTR_EXPORT qa_pmt_prims : public CppUnit::TestCase { - +class __GR_ATTR_EXPORT qa_pmt_prims : public CppUnit::TestCase +{ CPPUNIT_TEST_SUITE(qa_pmt_prims); CPPUNIT_TEST(test_symbols); CPPUNIT_TEST(test_booleans); diff --git a/gnuradio-runtime/lib/pmt/unv_qa_template.cc.t b/gnuradio-runtime/lib/pmt/unv_qa_template.cc.t index a04d532b4e..ea675cee16 100644 --- a/gnuradio-runtime/lib/pmt/unv_qa_template.cc.t +++ b/gnuradio-runtime/lib/pmt/unv_qa_template.cc.t @@ -2,7 +2,7 @@ void qa_pmt_unv::test_@TAG@vector() { static const size_t N = 3; - pmt_t v1 = pmt::make_@TAG@vector(N, 0); + pmt::pmt_t v1 = pmt::make_@TAG@vector(N, 0); CPPUNIT_ASSERT_EQUAL(N, pmt::length(v1)); @TYPE@ s0 = @TYPE@(10); @TYPE@ s1 = @TYPE@(20); diff --git a/gnuradio-runtime/lib/posix_memalign.cc b/gnuradio-runtime/lib/posix_memalign.cc index aaeff78042..a08e9e127a 100644 --- a/gnuradio-runtime/lib/posix_memalign.cc +++ b/gnuradio-runtime/lib/posix_memalign.cc @@ -36,7 +36,7 @@ /* emulate posix_memalign functionality, to some degree */ #include <errno.h> -#include "gr_pagesize.h" +#include "pagesize.h" int posix_memalign (void **memptr, size_t alignment, size_t size) @@ -86,7 +86,7 @@ int posix_memalign /* try valloc if it exists */ /* cheap and easy way to make sure alignment is met, so long as it * is <= pagesize () */ - if (alignment <= (size_t) gr_pagesize ()) { + if (alignment <= (size_t) gr::pagesize ()) { *memptr = valloc (size); } } diff --git a/gnuradio-runtime/lib/prefs.cc b/gnuradio-runtime/lib/prefs.cc new file mode 100644 index 0000000000..468532f33b --- /dev/null +++ b/gnuradio-runtime/lib/prefs.cc @@ -0,0 +1,401 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2013 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 <gnuradio/prefs.h> +#include <gnuradio/sys_paths.h> +#include <gnuradio/constants.h> +#include <algorithm> + +#include <boost/filesystem/operations.hpp> +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/fstream.hpp> +namespace fs = boost::filesystem; + +namespace gr { + + /* + * Stub implementations + */ + static prefs s_default_singleton; + static prefs *s_singleton = &s_default_singleton; + + prefs * + prefs::singleton() + { + return s_singleton; + } + + void + prefs::set_singleton(prefs *p) + { + s_singleton = p; + } + + prefs::prefs() + { + _read_files(); + } + + prefs::~prefs() + { + // nop + } + + std::vector<std::string> + prefs::_sys_prefs_filenames() + { + std::vector<std::string> fnames; + + fs::path dir = prefsdir(); + if(!fs::is_directory(dir)) + return fnames; + + fs::directory_iterator diritr(dir); + while(diritr != fs::directory_iterator()) { + fs::path p = *diritr++; + if(p.extension() != ".swp") + fnames.push_back(p.string()); + } + std::sort(fnames.begin(), fnames.end()); + + // Find if there is a ~/.gnuradio/config.conf file and add this to + // the end of the file list to override any preferences in the + // installed path config files. + fs::path homedir = fs::path(gr::appdata_path()); + homedir = homedir/".gnuradio/config.conf"; + if(fs::exists(homedir)) { + fnames.push_back(homedir.string()); + } + + return fnames; + } + + void + prefs::_read_files() + { + std::string config; + + std::vector<std::string> filenames = _sys_prefs_filenames(); + std::vector<std::string>::iterator sitr; + char tmp[1024]; + for(sitr = filenames.begin(); sitr != filenames.end(); sitr++) { + fs::ifstream fin(*sitr); + while(!fin.eof()) { + fin.getline(tmp, 1024); + std::string t(tmp); + // ignore empty lines or lines of just comments + if((t.size() > 0) && (t[0] != '#')) { + // remove any comments in the line + size_t hash = t.find("#"); + + // Use hash marks at the end of each segment as a delimiter + config += t.substr(0, hash) + '#'; + } + } + fin.close(); + } + + // Remove all whitespace. + config.erase(std::remove_if(config.begin(), config.end(), + ::isspace), config.end()); + + // Convert the string into a map + _convert_to_map(config); + } + + void + prefs::_convert_to_map(const std::string &conf) + { + // Convert the string into an map of maps + // Map is structured as {section name: map of options} + // And options map is simply: {option name: option value} + std::string sub = conf; + size_t sec_start = sub.find("["); + while(sec_start != std::string::npos) { + sub = sub.substr(sec_start); + + size_t sec_end = sub.find("]"); + if(sec_end == std::string::npos) + throw std::runtime_error("Config file error: Mismatched section label.\n"); + + std::string sec = sub.substr(1, sec_end-1); + size_t next_sec_start = sub.find("[", sec_end); + std::string subsec = sub.substr(sec_end+1, next_sec_start-sec_end-2); + + std::transform(sec.begin(), sec.end(), sec.begin(), ::tolower); + + std::map<std::string, std::string> options_map = d_config_map[sec]; + size_t next_opt = 0; + size_t next_val = 0; + next_opt = subsec.find("#"); + while(next_opt < subsec.size()-1) { + next_val = subsec.find("=", next_opt); + std::string option = subsec.substr(next_opt+1, next_val-next_opt-1); + + next_opt = subsec.find("#", next_val); + std::string value = subsec.substr(next_val+1, next_opt-next_val-1); + + std::transform(option.begin(), option.end(), option.begin(), ::tolower); + options_map[option] = value; + } + + d_config_map[sec] = options_map; + + sec_start = sub.find("[", sec_end); + } + } + + std::string + prefs::to_string() + { + config_map_itr sections; + config_map_elem_itr options; + std::stringstream s; + + for(sections = d_config_map.begin(); sections != d_config_map.end(); sections++) { + s << "[" << sections->first << "]" << std::endl; + for(options = sections->second.begin(); options != sections->second.end(); options++) { + s << options->first << " = " << options->second << std::endl; + } + s << std::endl; + } + + return s.str(); + } + + void + prefs::save() + { + std::string conf = to_string(); + + fs::path homedir = fs::path(gr::appdata_path()); + homedir = homedir/".gnuradio/config.conf"; + fs::ofstream fout(homedir); + fout << conf; + fout.close(); + } + + char * + prefs::option_to_env(std::string section, std::string option) + { + std::stringstream envname; + std::string secname=section, optname=option; + + std::transform(section.begin(), section.end(), secname.begin(), ::toupper); + std::transform(option.begin(), option.end(), optname.begin(), ::toupper); + envname << "GR_CONF_" << secname << "_" << optname; + + return getenv(envname.str().c_str()); + } + + bool + prefs::has_section(const std::string §ion) + { + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + return d_config_map.count(s) > 0; + } + + bool + prefs::has_option(const std::string §ion, const std::string &option) + { + if(option_to_env(section, option)) + return true; + + if(has_section(section)) { + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + + std::string o = option; + std::transform(option.begin(), option.end(), o.begin(), ::tolower); + + config_map_itr sec = d_config_map.find(s); + return sec->second.count(o) > 0; + } + else { + return false; + } + } + + const std::string + prefs::get_string(const std::string §ion, const std::string &option, + const std::string &default_val) + { + char *env = option_to_env(section, option); + if(env) + return std::string(env); + + if(has_option(section, option)) { + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + + std::string o = option; + std::transform(option.begin(), option.end(), o.begin(), ::tolower); + + config_map_itr sec = d_config_map.find(s); + config_map_elem_itr opt = sec->second.find(o); + return opt->second; + } + else { + return default_val; + } + } + + void + prefs::set_string(const std::string §ion, const std::string &option, + const std::string &val) + { + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + + std::string o = option; + std::transform(option.begin(), option.end(), o.begin(), ::tolower); + + std::map<std::string, std::string> opt_map = d_config_map[s]; + + opt_map[o] = val; + + d_config_map[s] = opt_map; + } + + bool + prefs::get_bool(const std::string §ion, const std::string &option, + bool default_val) + { + if(has_option(section, option)) { + std::string str = get_string(section, option, ""); + if(str == "") { + return default_val; + } + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + if((str == "true") || (str == "on") || (str == "1")) + return true; + else if((str == "false") || (str == "off") || (str == "0")) + return false; + else + return default_val; + } + else { + return default_val; + } + } + + void + prefs::set_bool(const std::string §ion, const std::string &option, + bool val) + { + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + + std::string o = option; + std::transform(option.begin(), option.end(), o.begin(), ::tolower); + + std::map<std::string, std::string> opt_map = d_config_map[s]; + + std::stringstream sstr; + sstr << (val == true); + opt_map[o] = sstr.str(); + + d_config_map[s] = opt_map; + } + + long + prefs::get_long(const std::string §ion, const std::string &option, + long default_val) + { + if(has_option(section, option)) { + std::string str = get_string(section, option, ""); + if(str == "") { + return default_val; + } + std::stringstream sstr(str); + long n; + sstr >> n; + return n; + } + else { + return default_val; + } + } + + void + prefs::set_long(const std::string §ion, const std::string &option, + long val) + { + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + + std::string o = option; + std::transform(option.begin(), option.end(), o.begin(), ::tolower); + + std::map<std::string, std::string> opt_map = d_config_map[s]; + + std::stringstream sstr; + sstr << val; + opt_map[o] = sstr.str(); + + d_config_map[s] = opt_map; + } + + double + prefs::get_double(const std::string §ion, const std::string &option, + double default_val) + { + if(has_option(section, option)) { + std::string str = get_string(section, option, ""); + if(str == "") { + return default_val; + } + std::stringstream sstr(str); + double n; + sstr >> n; + return n; + } + else { + return default_val; + } + } + + void + prefs::set_double(const std::string §ion, const std::string &option, + double val) + { + std::string s = section; + std::transform(section.begin(), section.end(), s.begin(), ::tolower); + + std::string o = option; + std::transform(option.begin(), option.end(), o.begin(), ::tolower); + + std::map<std::string, std::string> opt_map = d_config_map[s]; + + std::stringstream sstr; + sstr << val; + opt_map[o] = sstr.str(); + + d_config_map[s] = opt_map; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/qa_buffer.cc b/gnuradio-runtime/lib/qa_buffer.cc new file mode 100644 index 0000000000..5f1dece0ad --- /dev/null +++ b/gnuradio-runtime/lib/qa_buffer.cc @@ -0,0 +1,304 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 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_buffer.h> +#include <gnuradio/buffer.h> +#include <cppunit/TestAssert.h> +#include <stdlib.h> +#include <gnuradio/random.h> + +static void +leak_check(void f()) +{ + long buffer_count = gr::buffer_ncurrently_allocated(); + long buffer_reader_count = gr::buffer_reader_ncurrently_allocated(); + + f(); + + CPPUNIT_ASSERT_EQUAL(buffer_reader_count, gr::buffer_reader_ncurrently_allocated()); + CPPUNIT_ASSERT_EQUAL(buffer_count, gr::buffer_ncurrently_allocated()); +} + + +// ---------------------------------------------------------------------------- +// test single writer, no readers... +// + +static void +t0_body() +{ + int nitems = 4000 / sizeof(int); + int counter = 0; + + gr::buffer_sptr buf(gr::make_buffer(nitems, sizeof(int), gr::block_sptr())); + + int last_sa; + int sa; + + sa = buf->space_available(); + CPPUNIT_ASSERT(sa > 0); + last_sa = sa; + + for(int i = 0; i < 5; i++) { + sa = buf->space_available(); + CPPUNIT_ASSERT_EQUAL(last_sa, sa); + last_sa = sa; + + int *p = (int*)buf->write_pointer(); + CPPUNIT_ASSERT(p != 0); + + for(int j = 0; j < sa; j++) + *p++ = counter++; + + buf->update_write_pointer(sa); + } +} + +// ---------------------------------------------------------------------------- +// test single writer, single reader +// + +static void +t1_body() +{ + int nitems = 4000 / sizeof(int); + int write_counter = 0; + int read_counter = 0; + + gr::buffer_sptr buf(gr::make_buffer(nitems, sizeof(int), gr::block_sptr())); + gr::buffer_reader_sptr r1(gr::buffer_add_reader(buf, 0, gr::block_sptr())); + + int sa; + + // write 1/3 of buffer + + sa = buf->space_available(); + CPPUNIT_ASSERT(sa > 0); + + int *p = (int*)buf->write_pointer(); + CPPUNIT_ASSERT(p != 0); + + for(int j = 0; j < sa/3; j++) { + *p++ = write_counter++; + } + buf->update_write_pointer(sa/3); + + // write the next 1/3 (1/2 of what's left) + + sa = buf->space_available(); + CPPUNIT_ASSERT(sa > 0); + + p = (int*)buf->write_pointer(); + CPPUNIT_ASSERT(p != 0); + + for(int j = 0; j < sa/2; j++) { + *p++ = write_counter++; + } + buf->update_write_pointer(sa/2); + + // check that we can read it OK + + int ia = r1->items_available(); + CPPUNIT_ASSERT_EQUAL(write_counter, ia); + + int *rp = (int*)r1->read_pointer(); + CPPUNIT_ASSERT(rp != 0); + + for(int i = 0; i < ia/2; i++) { + CPPUNIT_ASSERT_EQUAL(read_counter, *rp); + read_counter++; + rp++; + } + r1->update_read_pointer(ia/2); + + // read the rest + + ia = r1->items_available(); + rp = (int *) r1->read_pointer(); + CPPUNIT_ASSERT(rp != 0); + + for(int i = 0; i < ia; i++) { + CPPUNIT_ASSERT_EQUAL(read_counter, *rp); + read_counter++; + rp++; + } + r1->update_read_pointer(ia); +} + +// ---------------------------------------------------------------------------- +// single writer, single reader: check wrap-around +// + +static void +t2_body() +{ + // 64K is the largest granularity we've seen so far (MS windows file mapping). + // This allows a bit of "white box testing" + + int nitems = (64 * (1L << 10)) / sizeof(int); // 64K worth of ints + + gr::buffer_sptr buf(gr::make_buffer(nitems, sizeof(int), gr::block_sptr())); + gr::buffer_reader_sptr r1(gr::buffer_add_reader(buf, 0, gr::block_sptr())); + + int read_counter = 0; + int write_counter = 0; + int n; + int *wp = 0; + int *rp = 0; + + // Write 3/4 of buffer + + n = (int)(buf->space_available() * 0.75); + wp = (int*)buf->write_pointer(); + + for(int i = 0; i < n; i++) + *wp++ = write_counter++; + buf->update_write_pointer(n); + + // Now read it all + + int m = r1->items_available(); + CPPUNIT_ASSERT_EQUAL(n, m); + rp = (int*)r1->read_pointer(); + + for(int i = 0; i < m; i++) { + CPPUNIT_ASSERT_EQUAL(read_counter, *rp); + read_counter++; + rp++; + } + r1->update_read_pointer(m); + + // Now write as much as we can. + // This will wrap around the buffer + + n = buf->space_available(); + CPPUNIT_ASSERT_EQUAL(nitems - 1, n); // white box test + wp = (int*)buf->write_pointer(); + + for(int i = 0; i < n; i++) + *wp++ = write_counter++; + buf->update_write_pointer(n); + + // now read it all + + m = r1->items_available(); + CPPUNIT_ASSERT_EQUAL(n, m); + rp = (int*)r1->read_pointer(); + + for(int i = 0; i < m; i++) { + CPPUNIT_ASSERT_EQUAL(read_counter, *rp); + read_counter++; + rp++; + } + r1->update_read_pointer(m); +} + +// ---------------------------------------------------------------------------- +// single writer, N readers, randomized order and lengths +// ---------------------------------------------------------------------------- + +static void +t3_body() +{ + int nitems = (64 * (1L << 10)) / sizeof(int); + + static const int N = 5; + gr::buffer_sptr buf(gr::make_buffer(nitems, sizeof(int), gr::block_sptr())); + gr::buffer_reader_sptr reader[N]; + int read_counter[N]; + int write_counter = 0; + gr::random random; + + for(int i = 0; i < N; i++) { + read_counter[i] = 0; + reader[i] = buffer_add_reader(buf, 0, gr::block_sptr()); + } + + for(int lc = 0; lc < 1000; lc++) { + + // write some + + int n = (int)(buf->space_available() * random.ran1()); + int *wp = (int*)buf->write_pointer(); + + for(int i = 0; i < n; i++) + *wp++ = write_counter++; + + buf->update_write_pointer(n); + + // pick a random reader and read some + + int r = (int)(N * random.ran1()); + CPPUNIT_ASSERT(0 <= r && r < N); + + int m = reader[r]->items_available(); + int *rp = (int*)reader[r]->read_pointer(); + + for(int i = 0; i < m; i++) { + CPPUNIT_ASSERT_EQUAL(read_counter[r], *rp); + read_counter[r]++; + rp++; + } + reader[r]->update_read_pointer (m); + } +} + + +// ---------------------------------------------------------------------------- + +void +qa_buffer::t0() +{ + leak_check(t0_body); +} + +void +qa_buffer::t1() +{ + leak_check(t1_body); +} + +void +qa_buffer::t2() +{ + leak_check(t2_body); +} + +void +qa_buffer::t3() +{ + leak_check(t3_body); +} + +void +qa_buffer::t4() +{ +} + +void +qa_buffer::t5() +{ +} diff --git a/gnuradio-runtime/lib/qa_gr_buffer.h b/gnuradio-runtime/lib/qa_buffer.h index 2937c24b68..a41e69dd48 100644 --- a/gnuradio-runtime/lib/qa_gr_buffer.h +++ b/gnuradio-runtime/lib/qa_buffer.h @@ -26,28 +26,24 @@ #include <cppunit/extensions/HelperMacros.h> #include <cppunit/TestCase.h> -class qa_gr_buffer : public CppUnit::TestCase { - - CPPUNIT_TEST_SUITE (qa_gr_buffer); - CPPUNIT_TEST (t0); - CPPUNIT_TEST (t1); - CPPUNIT_TEST (t2); - CPPUNIT_TEST (t3); - CPPUNIT_TEST (t4); - CPPUNIT_TEST (t5); - CPPUNIT_TEST_SUITE_END (); - +class qa_buffer : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(qa_buffer); + CPPUNIT_TEST(t0); + CPPUNIT_TEST(t1); + CPPUNIT_TEST(t2); + CPPUNIT_TEST(t3); + CPPUNIT_TEST(t4); + CPPUNIT_TEST(t5); + CPPUNIT_TEST_SUITE_END(); private: - - void t0 (); - void t1 (); - void t2 (); - void t3 (); - void t4 (); - void t5 (); + void t0(); + void t1(); + void t2(); + void t3(); + void t4(); + void t5(); }; - - #endif /* INCLUDED_QA_GR_BUFFER_H */ diff --git a/gnuradio-runtime/lib/qa_gr_circular_file.cc b/gnuradio-runtime/lib/qa_circular_file.cc index 243e44784b..d80831b4b9 100644 --- a/gnuradio-runtime/lib/qa_gr_circular_file.cc +++ b/gnuradio-runtime/lib/qa_circular_file.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2002 Free Software Foundation, Inc. + * Copyright 2002,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -23,8 +23,9 @@ #ifdef HAVE_CONFIG_H #include "config.h" #endif -#include <qa_gr_circular_file.h> -#include <gr_circular_file.h> + +#include "qa_circular_file.h" +#include "circular_file.h" #include <cppunit/TestAssert.h> #include <iostream> #include <stdio.h> @@ -35,38 +36,37 @@ static const int BUFFER_SIZE = 8192; static const int NWRITE = 8192 * 9 / 8; void -qa_gr_circular_file::t1 () +qa_circular_file::t1() { #ifdef HAVE_MMAP - gr_circular_file *cf_writer; - gr_circular_file *cf_reader; + gr::circular_file *cf_writer; + gr::circular_file *cf_reader; // write the data... - - cf_writer = new gr_circular_file (test_file, true, BUFFER_SIZE * sizeof (short)); + cf_writer = new gr::circular_file(test_file, true, + BUFFER_SIZE * sizeof(short)); short sd; - for (int i = 0; i < NWRITE; i++){ + for(int i = 0; i < NWRITE; i++) { sd = i; - cf_writer->write (&sd, sizeof (sd)); + cf_writer->write(&sd, sizeof (sd)); } delete cf_writer; // now read it back... - - cf_reader = new gr_circular_file (test_file); - for (int i = 0; i < BUFFER_SIZE; i++){ - int n = cf_reader->read (&sd, sizeof (sd)); - CPPUNIT_ASSERT_EQUAL ((int) sizeof (sd), n); - CPPUNIT_ASSERT_EQUAL (NWRITE - BUFFER_SIZE + i, (int) sd); + cf_reader = new gr::circular_file(test_file); + for(int i = 0; i < BUFFER_SIZE; i++) { + int n = cf_reader->read (&sd, sizeof(sd)); + CPPUNIT_ASSERT_EQUAL((int) sizeof (sd), n); + CPPUNIT_ASSERT_EQUAL(NWRITE - BUFFER_SIZE + i, (int)sd); } - int n = cf_reader->read (&sd, sizeof (sd)); - CPPUNIT_ASSERT_EQUAL (0, n); + int n = cf_reader->read(&sd, sizeof(sd)); + CPPUNIT_ASSERT_EQUAL(0, n); delete cf_reader; - unlink (test_file); + unlink(test_file); #endif // HAVE_MMAP } diff --git a/gnuradio-runtime/lib/qa_gr_vmcircbuf.h b/gnuradio-runtime/lib/qa_circular_file.h index 3576660d5a..fd5c156b56 100644 --- a/gnuradio-runtime/lib/qa_gr_vmcircbuf.h +++ b/gnuradio-runtime/lib/qa_circular_file.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2002,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -19,21 +19,21 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ -#ifndef _QA_GR_VMCIRCBUF_H_ -#define _QA_GR_VMCIRCBUF_H_ + +#ifndef QA_GR_CIRCULAR_FILE_H +#define QA_GR_CIRCULAR_FILE_H #include <cppunit/extensions/HelperMacros.h> #include <cppunit/TestCase.h> -class qa_gr_vmcircbuf : public CppUnit::TestCase { - - CPPUNIT_TEST_SUITE (qa_gr_vmcircbuf); - CPPUNIT_TEST (test_all); - CPPUNIT_TEST_SUITE_END (); +class qa_circular_file : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(qa_circular_file); + CPPUNIT_TEST(t1); + CPPUNIT_TEST_SUITE_END(); - private: - void test_all (); +private: + void t1(); }; - -#endif /* _QA_GR_VMCIRCBUF_H_ */ +#endif /* QA_GR_CIRCULAR_FILE_H */ diff --git a/gnuradio-runtime/lib/qa_gr_buffer.cc b/gnuradio-runtime/lib/qa_gr_buffer.cc deleted file mode 100644 index c74baf398e..0000000000 --- a/gnuradio-runtime/lib/qa_gr_buffer.cc +++ /dev/null @@ -1,307 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_buffer.h> -#include <gr_buffer.h> -#include <cppunit/TestAssert.h> -#include <stdlib.h> -#include <gr_random.h> - -static void -leak_check (void f ()) -{ - long buffer_count = gr_buffer_ncurrently_allocated (); - long buffer_reader_count = gr_buffer_reader_ncurrently_allocated (); - - f (); - - CPPUNIT_ASSERT_EQUAL (buffer_reader_count, gr_buffer_reader_ncurrently_allocated ()); - CPPUNIT_ASSERT_EQUAL (buffer_count, gr_buffer_ncurrently_allocated ()); -} - - -// ---------------------------------------------------------------------------- -// test single writer, no readers... -// - -static void -t0_body () -{ - int nitems = 4000 / sizeof (int); - int counter = 0; - - gr_buffer_sptr buf(gr_make_buffer(nitems, sizeof (int), gr_block_sptr())); - - int last_sa; - int sa; - - sa = buf->space_available (); - CPPUNIT_ASSERT (sa > 0); - last_sa = sa; - - for (int i = 0; i < 5; i++){ - sa = buf->space_available (); - CPPUNIT_ASSERT_EQUAL (last_sa, sa); - last_sa = sa; - - int *p = (int *) buf->write_pointer (); - CPPUNIT_ASSERT (p != 0); - - for (int j = 0; j < sa; j++) - *p++ = counter++; - - buf->update_write_pointer (sa); - } -} - -// ---------------------------------------------------------------------------- -// test single writer, single reader -// - -static void -t1_body () - { - int nitems = 4000 / sizeof (int); - int write_counter = 0; - int read_counter = 0; - - gr_buffer_sptr buf(gr_make_buffer(nitems, sizeof (int), gr_block_sptr())); - gr_buffer_reader_sptr r1 (gr_buffer_add_reader (buf, 0, gr_block_sptr())); - - - int sa; - - // write 1/3 of buffer - - sa = buf->space_available (); - CPPUNIT_ASSERT (sa > 0); - - int *p = (int *) buf->write_pointer (); - CPPUNIT_ASSERT (p != 0); - - for (int j = 0; j < sa/3; j++){ - *p++ = write_counter++; - } - buf->update_write_pointer (sa/3); - - - // write the next 1/3 (1/2 of what's left) - - sa = buf->space_available (); - CPPUNIT_ASSERT (sa > 0); - - p = (int *) buf->write_pointer (); - CPPUNIT_ASSERT (p != 0); - - for (int j = 0; j < sa/2; j++){ - *p++ = write_counter++; - } - buf->update_write_pointer (sa/2); - - - // check that we can read it OK - - int ia = r1->items_available (); - CPPUNIT_ASSERT_EQUAL (write_counter, ia); - - int *rp = (int *) r1->read_pointer (); - CPPUNIT_ASSERT (rp != 0); - - for (int i = 0; i < ia/2; i++){ - CPPUNIT_ASSERT_EQUAL (read_counter, *rp); - read_counter++; - rp++; - } - r1->update_read_pointer (ia/2); - - // read the rest - - ia = r1->items_available (); - rp = (int *) r1->read_pointer (); - CPPUNIT_ASSERT (rp != 0); - - for (int i = 0; i < ia; i++){ - CPPUNIT_ASSERT_EQUAL (read_counter, *rp); - read_counter++; - rp++; - } - r1->update_read_pointer (ia); -} - -// ---------------------------------------------------------------------------- -// single writer, single reader: check wrap-around -// - -static void -t2_body () -{ - // 64K is the largest granularity we've seen so far (MS windows file mapping). - // This allows a bit of "white box testing" - - int nitems = (64 * (1L << 10)) / sizeof (int); // 64K worth of ints - - gr_buffer_sptr buf(gr_make_buffer (nitems, sizeof (int), gr_block_sptr())); - gr_buffer_reader_sptr r1 (gr_buffer_add_reader (buf, 0, gr_block_sptr())); - - int read_counter = 0; - int write_counter = 0; - int n; - int *wp = 0; - int *rp = 0; - - // Write 3/4 of buffer - - n = (int) (buf->space_available () * 0.75); - wp = (int *) buf->write_pointer (); - - for (int i = 0; i < n; i++) - *wp++ = write_counter++; - buf->update_write_pointer (n); - - // Now read it all - - int m = r1->items_available (); - CPPUNIT_ASSERT_EQUAL (n, m); - rp = (int *) r1->read_pointer (); - - for (int i = 0; i < m; i++){ - CPPUNIT_ASSERT_EQUAL (read_counter, *rp); - read_counter++; - rp++; - } - r1->update_read_pointer (m); - - // Now write as much as we can. - // This will wrap around the buffer - - n = buf->space_available (); - CPPUNIT_ASSERT_EQUAL (nitems - 1, n); // white box test - wp = (int *) buf->write_pointer (); - - for (int i = 0; i < n; i++) - *wp++ = write_counter++; - buf->update_write_pointer (n); - - // now read it all - - m = r1->items_available (); - CPPUNIT_ASSERT_EQUAL (n, m); - rp = (int *) r1->read_pointer (); - - for (int i = 0; i < m; i++){ - CPPUNIT_ASSERT_EQUAL (read_counter, *rp); - read_counter++; - rp++; - } - r1->update_read_pointer (m); - -} - -// ---------------------------------------------------------------------------- -// single writer, N readers, randomized order and lengths -// ---------------------------------------------------------------------------- - -static void -t3_body () -{ - int nitems = (64 * (1L << 10)) / sizeof (int); - - static const int N = 5; - gr_buffer_sptr buf(gr_make_buffer(nitems, sizeof (int), gr_block_sptr())); - gr_buffer_reader_sptr reader[N]; - int read_counter[N]; - int write_counter = 0; - gr_random random; - - for (int i = 0; i < N; i++){ - read_counter[i] = 0; - reader[i] = gr_buffer_add_reader (buf, 0, gr_block_sptr()); - } - - for (int lc = 0; lc < 1000; lc++){ - - // write some - - int n = (int) (buf->space_available () * random.ran1 ()); - int *wp = (int *) buf->write_pointer (); - - for (int i = 0; i < n; i++) - *wp++ = write_counter++; - - buf->update_write_pointer (n); - - // pick a random reader and read some - - int r = (int) (N * random.ran1 ()); - CPPUNIT_ASSERT (0 <= r && r < N); - - int m = reader[r]->items_available (); - int *rp = (int *) reader[r]->read_pointer (); - - for (int i = 0; i < m; i++){ - CPPUNIT_ASSERT_EQUAL (read_counter[r], *rp); - read_counter[r]++; - rp++; - } - reader[r]->update_read_pointer (m); - } -} - - -// ---------------------------------------------------------------------------- - -void -qa_gr_buffer::t0 () -{ - leak_check (t0_body); -} - -void -qa_gr_buffer::t1 () -{ - leak_check (t1_body); -} - -void -qa_gr_buffer::t2 () -{ - leak_check (t2_body); -} - -void -qa_gr_buffer::t3 () -{ - leak_check (t3_body); -} - -void -qa_gr_buffer::t4 () -{ -} - -void -qa_gr_buffer::t5 () -{ -} diff --git a/gnuradio-runtime/lib/qa_gr_fxpt.cc b/gnuradio-runtime/lib/qa_gr_fxpt.cc deleted file mode 100644 index 7eac0d8964..0000000000 --- a/gnuradio-runtime/lib/qa_gr_fxpt.cc +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_fxpt.h> -#include <gr_fxpt.h> -#include <cppunit/TestAssert.h> -#include <iostream> -#include <stdio.h> -#include <unistd.h> -#include <math.h> - -static const float SIN_COS_TOLERANCE = 1e-5; - -void -qa_gr_fxpt::t0 () -{ - CPPUNIT_ASSERT_DOUBLES_EQUAL (M_PI/2, gr_fxpt::fixed_to_float (0x40000000), SIN_COS_TOLERANCE); - CPPUNIT_ASSERT_DOUBLES_EQUAL (0.0, gr_fxpt::fixed_to_float (0x00000000), SIN_COS_TOLERANCE); - CPPUNIT_ASSERT_DOUBLES_EQUAL (-M_PI, gr_fxpt::fixed_to_float (0x80000000), SIN_COS_TOLERANCE); - - if (0){ - /* - * These are disabled because of some precision issues. - * - * Different compilers seem to have different opinions on whether - * the calulations are done single or double (or extended) - * precision. Any of the answers are fine for our real purpose, but - * sometimes the answer is off by a few bits at the bottom. - * Hence, the disabled check. - */ - CPPUNIT_ASSERT_EQUAL ((gr_int32) 0x40000000, gr_fxpt::float_to_fixed (M_PI/2)); - CPPUNIT_ASSERT_EQUAL ((gr_int32) 0, gr_fxpt::float_to_fixed (0)); - CPPUNIT_ASSERT_EQUAL ((gr_int32) 0x80000000, gr_fxpt::float_to_fixed (-M_PI)); - } -} - -void -qa_gr_fxpt::t1 () -{ - - CPPUNIT_ASSERT_DOUBLES_EQUAL ( 0, gr_fxpt::sin (0x00000000), SIN_COS_TOLERANCE); - CPPUNIT_ASSERT_DOUBLES_EQUAL ( 0.707106781, gr_fxpt::sin (0x20000000), SIN_COS_TOLERANCE); - CPPUNIT_ASSERT_DOUBLES_EQUAL ( 1, gr_fxpt::sin (0x40000000), SIN_COS_TOLERANCE); - CPPUNIT_ASSERT_DOUBLES_EQUAL ( 0.707106781, gr_fxpt::sin (0x60000000), SIN_COS_TOLERANCE); - CPPUNIT_ASSERT_DOUBLES_EQUAL ( 0, gr_fxpt::sin (0x7fffffff), SIN_COS_TOLERANCE); - CPPUNIT_ASSERT_DOUBLES_EQUAL ( 0, gr_fxpt::sin (0x80000000), SIN_COS_TOLERANCE); - CPPUNIT_ASSERT_DOUBLES_EQUAL ( 0, gr_fxpt::sin (0x80000001), SIN_COS_TOLERANCE); - CPPUNIT_ASSERT_DOUBLES_EQUAL (-1, gr_fxpt::sin (-0x40000000), SIN_COS_TOLERANCE); - CPPUNIT_ASSERT_DOUBLES_EQUAL (-0.707106781, gr_fxpt::sin (-0x20000000), SIN_COS_TOLERANCE); - - - for (float p = -M_PI; p < M_PI; p += 2 * M_PI / 3600){ - float expected = sin (p); - float actual = gr_fxpt::sin (gr_fxpt::float_to_fixed (p)); - CPPUNIT_ASSERT_DOUBLES_EQUAL (expected, actual, SIN_COS_TOLERANCE); - } -} - -void -qa_gr_fxpt::t2 () -{ - for (float p = -M_PI; p < M_PI; p += 2 * M_PI / 3600){ - float expected = cos (p); - float actual = gr_fxpt::cos (gr_fxpt::float_to_fixed (p)); - CPPUNIT_ASSERT_DOUBLES_EQUAL (expected, actual, SIN_COS_TOLERANCE); - } -} - -void -qa_gr_fxpt::t3 () -{ - for (float p = -M_PI; p < M_PI; p += 2 * M_PI / 3600){ - float expected_sin = sin (p); - float expected_cos = cos (p); - float actual_sin; - float actual_cos; - gr_fxpt::sincos (gr_fxpt::float_to_fixed (p), &actual_sin, &actual_cos); - CPPUNIT_ASSERT_DOUBLES_EQUAL (expected_sin, actual_sin, SIN_COS_TOLERANCE); - CPPUNIT_ASSERT_DOUBLES_EQUAL (expected_cos, actual_cos, SIN_COS_TOLERANCE); - } -} diff --git a/gnuradio-runtime/lib/qa_gr_io_signature.cc b/gnuradio-runtime/lib/qa_gr_io_signature.cc deleted file mode 100644 index c1737ffb8e..0000000000 --- a/gnuradio-runtime/lib/qa_gr_io_signature.cc +++ /dev/null @@ -1,64 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2004 Free Software Foundation, Inc. - * - * This file is part of GNU Radio - * - * GNU Radio is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 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_io_signature.h> -#include <gr_io_signature.h> - -void -qa_gr_io_signature::t0 () -{ - gr_make_io_signature (1, 1, sizeof (int)); -} - -void -qa_gr_io_signature::t1 () -{ - gr_make_io_signature (3, 1, sizeof (int)); // throws std::invalid_argument -} - -void -qa_gr_io_signature::t2 () -{ - gr_io_signature_sptr p = - gr_make_io_signature (3, gr_io_signature::IO_INFINITE, sizeof (int)); - - CPPUNIT_ASSERT_EQUAL (p->min_streams (), 3); - CPPUNIT_ASSERT_EQUAL (p->sizeof_stream_item (0), (int) sizeof (int)); -} - -void -qa_gr_io_signature::t3 () -{ - gr_io_signature_sptr p = - gr_make_io_signature3 (0, 5, 1, 2, 3); - - CPPUNIT_ASSERT_EQUAL (p->min_streams (), 0); - CPPUNIT_ASSERT_EQUAL (p->max_streams (), 5); - CPPUNIT_ASSERT_EQUAL (p->sizeof_stream_item(0), 1); - CPPUNIT_ASSERT_EQUAL (p->sizeof_stream_item(1), 2); - CPPUNIT_ASSERT_EQUAL (p->sizeof_stream_item(2), 3); - CPPUNIT_ASSERT_EQUAL (p->sizeof_stream_item(3), 3); - CPPUNIT_ASSERT_EQUAL (p->sizeof_stream_item(4), 3); -} diff --git a/gnuradio-runtime/lib/qa_io_signature.cc b/gnuradio-runtime/lib/qa_io_signature.cc new file mode 100644 index 0000000000..bc3509a260 --- /dev/null +++ b/gnuradio-runtime/lib/qa_io_signature.cc @@ -0,0 +1,65 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2013 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_io_signature.h> +#include <gnuradio/io_signature.h> + +void +qa_io_signature::t0() +{ + gr::io_signature::make(1, 1, sizeof(int)); +} + +void +qa_io_signature::t1() +{ + gr::io_signature::make(3, 1, sizeof(int)); // throws std::invalid_argument +} + +void +qa_io_signature::t2() +{ + gr::io_signature::sptr p = + gr::io_signature::make(3, gr::io_signature::IO_INFINITE, sizeof(int)); + + CPPUNIT_ASSERT_EQUAL(p->min_streams(), 3); + CPPUNIT_ASSERT_EQUAL(p->sizeof_stream_item(0), (int)sizeof(int)); +} + +void +qa_io_signature::t3() +{ + gr::io_signature::sptr p = + gr::io_signature::make3(0, 5, 1, 2, 3); + + CPPUNIT_ASSERT_EQUAL(p->min_streams(), 0); + CPPUNIT_ASSERT_EQUAL(p->max_streams(), 5); + CPPUNIT_ASSERT_EQUAL(p->sizeof_stream_item(0), 1); + CPPUNIT_ASSERT_EQUAL(p->sizeof_stream_item(1), 2); + CPPUNIT_ASSERT_EQUAL(p->sizeof_stream_item(2), 3); + CPPUNIT_ASSERT_EQUAL(p->sizeof_stream_item(3), 3); + CPPUNIT_ASSERT_EQUAL(p->sizeof_stream_item(4), 3); +} diff --git a/gnuradio-runtime/lib/qa_gr_io_signature.h b/gnuradio-runtime/lib/qa_io_signature.h index 9cd6bb5247..981ad03b59 100644 --- a/gnuradio-runtime/lib/qa_gr_io_signature.h +++ b/gnuradio-runtime/lib/qa_io_signature.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2004,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -27,20 +27,20 @@ #include <cppunit/TestCase.h> #include <stdexcept> -class qa_gr_io_signature : public CppUnit::TestCase { - - CPPUNIT_TEST_SUITE (qa_gr_io_signature); - CPPUNIT_TEST (t0); - CPPUNIT_TEST_EXCEPTION (t1, std::invalid_argument); - CPPUNIT_TEST (t2); - CPPUNIT_TEST (t3); - CPPUNIT_TEST_SUITE_END (); +class qa_io_signature : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(qa_io_signature); + CPPUNIT_TEST(t0); + CPPUNIT_TEST_EXCEPTION(t1, std::invalid_argument); + CPPUNIT_TEST(t2); + CPPUNIT_TEST(t3); + CPPUNIT_TEST_SUITE_END(); private: - void t0 (); - void t1 (); - void t2 (); - void t3 (); + void t0(); + void t1(); + void t2(); + void t3(); }; #endif /* INCLUDED_QA_GR_IO_SIGNATURE_H */ diff --git a/gnuradio-runtime/lib/qa_gr_logger.cc b/gnuradio-runtime/lib/qa_logger.cc index a8e4a1d766..b147b36da1 100644 --- a/gnuradio-runtime/lib/qa_gr_logger.cc +++ b/gnuradio-runtime/lib/qa_logger.cc @@ -29,11 +29,11 @@ #include <config.h> #endif -#include <qa_gr_logger.h> -#include <gr_logger.h> +#include <qa_logger.h> +#include <gnuradio/logger.h> void -qa_gr_logger::t1() +qa_logger::t1() { #ifdef ENABLE_GR_LOG // This doesn't really test anything, more just diff --git a/gnuradio-runtime/lib/qa_gr_logger.h b/gnuradio-runtime/lib/qa_logger.h index b0d3711523..35f7f1f6c4 100644 --- a/gnuradio-runtime/lib/qa_gr_logger.h +++ b/gnuradio-runtime/lib/qa_logger.h @@ -28,15 +28,15 @@ //! collect all the tests for the example directory -class qa_gr_logger : public CppUnit::TestCase { - public: - CPPUNIT_TEST_SUITE(qa_gr_logger); +class qa_logger : public CppUnit::TestCase +{ +public: + CPPUNIT_TEST_SUITE(qa_logger); CPPUNIT_TEST(t1); CPPUNIT_TEST_SUITE_END(); private: void t1(); - }; #endif /* INCLUDED_QA_GR_LOG_H */ diff --git a/gnuradio-runtime/lib/qa_runtime.cc b/gnuradio-runtime/lib/qa_runtime.cc index b15051c2ad..dbf7e5bb9a 100644 --- a/gnuradio-runtime/lib/qa_runtime.cc +++ b/gnuradio-runtime/lib/qa_runtime.cc @@ -30,32 +30,32 @@ #endif #include <qa_runtime.h> -#include <qa_gr_buffer.h> -#include <qa_gr_circular_file.h> -#include <qa_gr_fxpt.h> -#include <qa_gr_fxpt_nco.h> -#include <qa_gr_fxpt_vco.h> -#include <qa_gr_io_signature.h> -#include <qa_gr_logger.h> -#include <qa_gr_math.h> -#include <qa_gr_vmcircbuf.h> +#include <qa_buffer.h> +#include <qa_io_signature.h> +#include <qa_circular_file.h> +#include <qa_fxpt.h> +#include <qa_fxpt_nco.h> +#include <qa_fxpt_vco.h> +#include <qa_logger.h> +#include <qa_math.h> +#include <qa_vmcircbuf.h> #include <qa_sincos.h> CppUnit::TestSuite * -qa_runtime::suite () +qa_runtime::suite() { - CppUnit::TestSuite *s = new CppUnit::TestSuite ("runtime"); + CppUnit::TestSuite *s = new CppUnit::TestSuite("runtime"); - s->addTest (qa_gr_buffer::suite ()); - s->addTest (qa_gr_circular_file::suite ()); - s->addTest (qa_gr_fxpt::suite ()); - s->addTest (qa_gr_fxpt_nco::suite ()); - s->addTest (qa_gr_fxpt_vco::suite ()); - s->addTest (qa_gr_io_signature::suite ()); - s->addTest (qa_gr_logger::suite ()); - s->addTest (qa_gr_math::suite ()); - s->addTest (qa_gr_vmcircbuf::suite ()); - s->addTest (qa_sincos::suite ()); + s->addTest(qa_buffer::suite()); + s->addTest(qa_io_signature::suite()); + s->addTest(qa_circular_file::suite()); + s->addTest(qa_fxpt::suite()); + s->addTest(qa_fxpt_nco::suite()); + s->addTest(qa_fxpt_vco::suite()); + s->addTest(qa_logger::suite()); + s->addTest(qa_math::suite()); + s->addTest(qa_vmcircbuf::suite()); + s->addTest(qa_sincos::suite()); return s; } diff --git a/gnuradio-runtime/lib/qa_runtime.h b/gnuradio-runtime/lib/qa_runtime.h index b03e3db721..a1e58190d6 100644 --- a/gnuradio-runtime/lib/qa_runtime.h +++ b/gnuradio-runtime/lib/qa_runtime.h @@ -23,7 +23,7 @@ #ifndef _QA_RUNTIME_H_ #define _QA_RUNTIME_H_ -#include <attributes.h> +#include <gnuradio/attributes.h> #include <cppunit/TestSuite.h> //! collect all the tests for the runtime directory diff --git a/gnuradio-runtime/lib/qa_gr_vmcircbuf.cc b/gnuradio-runtime/lib/qa_vmcircbuf.cc index e3b36d8829..7301b4cf17 100644 --- a/gnuradio-runtime/lib/qa_gr_vmcircbuf.cc +++ b/gnuradio-runtime/lib/qa_vmcircbuf.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2002 Free Software Foundation, Inc. + * Copyright 2002,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,17 +24,17 @@ #include <config.h> #endif -#include <qa_gr_vmcircbuf.h> +#include <qa_vmcircbuf.h> #include <cppunit/TestAssert.h> -#include <gr_vmcircbuf.h> +#include "vmcircbuf.h" #include <stdio.h> void -qa_gr_vmcircbuf::test_all () +qa_vmcircbuf::test_all() { - int verbose = 1; // summary + int verbose = 1; // summary - bool ok = gr_vmcircbuf_sysconfig::test_all_factories (verbose); + bool ok = gr::vmcircbuf_sysconfig::test_all_factories(verbose); - CPPUNIT_ASSERT_EQUAL (true, ok); + CPPUNIT_ASSERT_EQUAL(true, ok); } diff --git a/gnuradio-runtime/lib/qa_gr_circular_file.h b/gnuradio-runtime/lib/qa_vmcircbuf.h index df35ab077b..93f46cf4a8 100644 --- a/gnuradio-runtime/lib/qa_gr_circular_file.h +++ b/gnuradio-runtime/lib/qa_vmcircbuf.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2002 Free Software Foundation, Inc. + * Copyright 2004,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -19,22 +19,21 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ -#ifndef _QA_GR_CIRCULAR_FILE_H_ -#define _QA_GR_CIRCULAR_FILE_H_ + +#ifndef QA_GR_VMCIRCBUF_H +#define QA_GR_VMCIRCBUF_H #include <cppunit/extensions/HelperMacros.h> #include <cppunit/TestCase.h> -class qa_gr_circular_file : public CppUnit::TestCase { - - CPPUNIT_TEST_SUITE (qa_gr_circular_file); - CPPUNIT_TEST (t1); - CPPUNIT_TEST_SUITE_END (); - - private: - void t1 (); +class qa_vmcircbuf : public CppUnit::TestCase +{ + CPPUNIT_TEST_SUITE(qa_vmcircbuf); + CPPUNIT_TEST(test_all); + CPPUNIT_TEST_SUITE_END(); +private: + void test_all(); }; - -#endif /* _QA_GR_CIRCULAR_FILE_H_ */ +#endif /* QA_GR_VMCIRCBUF_H */ diff --git a/gnuradio-runtime/lib/random.h b/gnuradio-runtime/lib/random.h deleted file mode 100644 index c643c3e422..0000000000 --- a/gnuradio-runtime/lib/random.h +++ /dev/null @@ -1,38 +0,0 @@ -/* -*- c++ -*- */ -/* - * Copyright 2003, 2008 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 _RANDOM_H_ -#define _RANDOM_H_ - -// While rand(3) specifies RAND_MAX, random(3) says that the output -// ranges from 0 to 2^31-1 but does not specify a macro to denote -// this. We define RANDOM_MAX for cleanliness. We must omit the -// definition for systems that have made the same choice. (Note that -// random(3) is from 4.2BSD, and not specified by POSIX.) - -#ifndef RANDOM_MAX -static const int RANDOM_MAX = 2147483647; // 2^31-1 -#endif /* RANDOM_MAX */ - -#include <stdlib.h> - -#endif // _RANDOM_H_ diff --git a/gnuradio-runtime/lib/realtime.cc b/gnuradio-runtime/lib/realtime.cc index 5dadc26bbd..81f92ae488 100644 --- a/gnuradio-runtime/lib/realtime.cc +++ b/gnuradio-runtime/lib/realtime.cc @@ -24,155 +24,14 @@ #include <config.h> #endif -#include <realtime.h> - -#ifdef HAVE_SCHED_H -#include <sched.h> -#endif - -#include <algorithm> -#include <math.h> -#include <string.h> -#include <errno.h> -#include <stdio.h> - -#if defined(HAVE_PTHREAD_SETSCHEDPARAM) || defined(HAVE_SCHED_SETSCHEDULER) -#include <pthread.h> - -namespace gr { - - /*! - * Rescale our virtual priority so that it maps to the middle 1/2 of - * the priorities given by min_real_pri and max_real_pri. - */ - static int - rescale_virtual_pri(int virtual_pri, int min_real_pri, int max_real_pri) - { - float rmin = min_real_pri + (0.25 * (max_real_pri - min_real_pri)); - float rmax = min_real_pri + (0.75 * (max_real_pri - min_real_pri)); - float m = (rmax - rmin) / (rt_priority_max() - rt_priority_min()); - float y = m * (virtual_pri - rt_priority_min()) + rmin; - int y_int = static_cast<int>(rint(y)); - return std::max(min_real_pri, std::min(max_real_pri, y_int)); - } - -} // namespace gr - -#endif - - -#if defined(HAVE_PTHREAD_SETSCHEDPARAM) - -namespace gr { - - rt_status_t - enable_realtime_scheduling(rt_sched_param p) - { - int policy = p.policy == RT_SCHED_FIFO ? SCHED_FIFO : SCHED_RR; - int min_real_pri = sched_get_priority_min(policy); - int max_real_pri = sched_get_priority_max(policy); - int pri = rescale_virtual_pri(p.priority, min_real_pri, max_real_pri); - - // FIXME check hard and soft limits with getrlimit, and limit the value we ask for. - // fprintf(stderr, "pthread_setschedparam: policy = %d, pri = %d\n", policy, pri); - - struct sched_param param; - memset (¶m, 0, sizeof (param)); - param.sched_priority = pri; - int result = pthread_setschedparam (pthread_self(), policy, ¶m); - if (result != 0) { - if (result == EPERM) // N.B., return value, not errno - return RT_NO_PRIVS; - else { - fprintf(stderr, - "pthread_setschedparam: failed to set real time priority: %s\n", - strerror(result)); - return RT_OTHER_ERROR; - } - } - - //printf("SCHED_FIFO enabled with priority = %d\n", pri); - return RT_OK; - } -} // namespace gr - - -#elif defined(HAVE_SCHED_SETSCHEDULER) - -namespace gr { - - rt_status_t - enable_realtime_scheduling(rt_sched_param p) - { - int policy = p.policy == RT_SCHED_FIFO ? SCHED_FIFO : SCHED_RR; - int min_real_pri = sched_get_priority_min(policy); - int max_real_pri = sched_get_priority_max(policy); - int pri = rescale_virtual_pri(p.priority, min_real_pri, max_real_pri); - - // FIXME check hard and soft limits with getrlimit, and limit the value we ask for. - // fprintf(stderr, "sched_setscheduler: policy = %d, pri = %d\n", policy, pri); - - int pid = 0; // this process - struct sched_param param; - memset(¶m, 0, sizeof(param)); - param.sched_priority = pri; - int result = sched_setscheduler(pid, policy, ¶m); - if (result != 0){ - if (errno == EPERM) - return RT_NO_PRIVS; - else { - perror ("sched_setscheduler: failed to set real time priority"); - return RT_OTHER_ERROR; - } - } - - //printf("SCHED_FIFO enabled with priority = %d\n", pri); - return RT_OK; - } - -} // namespace gr - -#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) - -#include <windows.h> - -namespace gr { - - rt_status_t enable_realtime_scheduling(rt_sched_param p){ - - //set the priority class on the process - int pri_class = (true)? REALTIME_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS; - if (SetPriorityClass(GetCurrentProcess(), pri_class) == 0) - return RT_OTHER_ERROR; - - //scale the priority value to the constants - int priorities[] = { - THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, - THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL - }; - const double priority = double(p.priority)/(rt_priority_max() - rt_priority_min()); - size_t pri_index = size_t((priority+1.0)*6/2.0); // -1 -> 0, +1 -> 6 - pri_index %= sizeof(priorities)/sizeof(*priorities); //range check - - //set the thread priority on the thread - if (SetThreadPriority(GetCurrentThread(), priorities[pri_index]) == 0) - return RT_OTHER_ERROR; - - //printf("SetPriorityClass + SetThreadPriority\n"); - return RT_OK; - } - -} // namespace gr - -#else +#include <gnuradio/realtime.h> namespace gr { - + rt_status_t - enable_realtime_scheduling(rt_sched_param p) + enable_realtime_scheduling() { - return RT_NOT_IMPLEMENTED; + return enable_realtime_scheduling(); } -} // namespace gr -#endif +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/realtime_impl.cc b/gnuradio-runtime/lib/realtime_impl.cc new file mode 100644 index 0000000000..5dadc26bbd --- /dev/null +++ b/gnuradio-runtime/lib/realtime_impl.cc @@ -0,0 +1,178 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2007,2008 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 <realtime.h> + +#ifdef HAVE_SCHED_H +#include <sched.h> +#endif + +#include <algorithm> +#include <math.h> +#include <string.h> +#include <errno.h> +#include <stdio.h> + +#if defined(HAVE_PTHREAD_SETSCHEDPARAM) || defined(HAVE_SCHED_SETSCHEDULER) +#include <pthread.h> + +namespace gr { + + /*! + * Rescale our virtual priority so that it maps to the middle 1/2 of + * the priorities given by min_real_pri and max_real_pri. + */ + static int + rescale_virtual_pri(int virtual_pri, int min_real_pri, int max_real_pri) + { + float rmin = min_real_pri + (0.25 * (max_real_pri - min_real_pri)); + float rmax = min_real_pri + (0.75 * (max_real_pri - min_real_pri)); + float m = (rmax - rmin) / (rt_priority_max() - rt_priority_min()); + float y = m * (virtual_pri - rt_priority_min()) + rmin; + int y_int = static_cast<int>(rint(y)); + return std::max(min_real_pri, std::min(max_real_pri, y_int)); + } + +} // namespace gr + +#endif + + +#if defined(HAVE_PTHREAD_SETSCHEDPARAM) + +namespace gr { + + rt_status_t + enable_realtime_scheduling(rt_sched_param p) + { + int policy = p.policy == RT_SCHED_FIFO ? SCHED_FIFO : SCHED_RR; + int min_real_pri = sched_get_priority_min(policy); + int max_real_pri = sched_get_priority_max(policy); + int pri = rescale_virtual_pri(p.priority, min_real_pri, max_real_pri); + + // FIXME check hard and soft limits with getrlimit, and limit the value we ask for. + // fprintf(stderr, "pthread_setschedparam: policy = %d, pri = %d\n", policy, pri); + + struct sched_param param; + memset (¶m, 0, sizeof (param)); + param.sched_priority = pri; + int result = pthread_setschedparam (pthread_self(), policy, ¶m); + if (result != 0) { + if (result == EPERM) // N.B., return value, not errno + return RT_NO_PRIVS; + else { + fprintf(stderr, + "pthread_setschedparam: failed to set real time priority: %s\n", + strerror(result)); + return RT_OTHER_ERROR; + } + } + + //printf("SCHED_FIFO enabled with priority = %d\n", pri); + return RT_OK; + } +} // namespace gr + + +#elif defined(HAVE_SCHED_SETSCHEDULER) + +namespace gr { + + rt_status_t + enable_realtime_scheduling(rt_sched_param p) + { + int policy = p.policy == RT_SCHED_FIFO ? SCHED_FIFO : SCHED_RR; + int min_real_pri = sched_get_priority_min(policy); + int max_real_pri = sched_get_priority_max(policy); + int pri = rescale_virtual_pri(p.priority, min_real_pri, max_real_pri); + + // FIXME check hard and soft limits with getrlimit, and limit the value we ask for. + // fprintf(stderr, "sched_setscheduler: policy = %d, pri = %d\n", policy, pri); + + int pid = 0; // this process + struct sched_param param; + memset(¶m, 0, sizeof(param)); + param.sched_priority = pri; + int result = sched_setscheduler(pid, policy, ¶m); + if (result != 0){ + if (errno == EPERM) + return RT_NO_PRIVS; + else { + perror ("sched_setscheduler: failed to set real time priority"); + return RT_OTHER_ERROR; + } + } + + //printf("SCHED_FIFO enabled with priority = %d\n", pri); + return RT_OK; + } + +} // namespace gr + +#elif defined(_WIN32) || defined(__WIN32__) || defined(WIN32) + +#include <windows.h> + +namespace gr { + + rt_status_t enable_realtime_scheduling(rt_sched_param p){ + + //set the priority class on the process + int pri_class = (true)? REALTIME_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS; + if (SetPriorityClass(GetCurrentProcess(), pri_class) == 0) + return RT_OTHER_ERROR; + + //scale the priority value to the constants + int priorities[] = { + THREAD_PRIORITY_IDLE, THREAD_PRIORITY_LOWEST, THREAD_PRIORITY_BELOW_NORMAL, THREAD_PRIORITY_NORMAL, + THREAD_PRIORITY_ABOVE_NORMAL, THREAD_PRIORITY_HIGHEST, THREAD_PRIORITY_TIME_CRITICAL + }; + const double priority = double(p.priority)/(rt_priority_max() - rt_priority_min()); + size_t pri_index = size_t((priority+1.0)*6/2.0); // -1 -> 0, +1 -> 6 + pri_index %= sizeof(priorities)/sizeof(*priorities); //range check + + //set the thread priority on the thread + if (SetThreadPriority(GetCurrentThread(), priorities[pri_index]) == 0) + return RT_OTHER_ERROR; + + //printf("SetPriorityClass + SetThreadPriority\n"); + return RT_OK; + } + +} // namespace gr + +#else + +namespace gr { + + rt_status_t + enable_realtime_scheduling(rt_sched_param p) + { + return RT_NOT_IMPLEMENTED; + } +} // namespace gr + +#endif diff --git a/gnuradio-runtime/lib/runtime_block_gateway.cc b/gnuradio-runtime/lib/runtime_block_gateway.cc deleted file mode 100644 index 11d16af41e..0000000000 --- a/gnuradio-runtime/lib/runtime_block_gateway.cc +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright 2011-2012 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 <runtime_block_gateway.h> -#include <gr_io_signature.h> -#include <iostream> -#include <boost/bind.hpp> - -/*********************************************************************** - * Helper routines - **********************************************************************/ -template <typename OutType, typename InType> -void copy_pointers(OutType &out, const InType &in){ - out.resize(in.size()); - for (size_t i = 0; i < in.size(); i++){ - out[i] = (void *)(in[i]); - } -} - -/*********************************************************************** - * The gr_block gateway implementation class - **********************************************************************/ -class runtime_block_gateway_impl : public runtime_block_gateway{ -public: - runtime_block_gateway_impl( - gr_feval_ll *handler, - const std::string &name, - gr_io_signature_sptr in_sig, - gr_io_signature_sptr out_sig, - const gr_block_gw_work_type work_type, - const unsigned factor - ): - gr_block(name, in_sig, out_sig), - _handler(handler), - _work_type(work_type) - { - switch(_work_type){ - case GR_BLOCK_GW_WORK_GENERAL: - _decim = 1; //not relevant, but set anyway - _interp = 1; //not relevant, but set anyway - break; - - case GR_BLOCK_GW_WORK_SYNC: - _decim = 1; - _interp = 1; - this->set_fixed_rate(true); - break; - - case GR_BLOCK_GW_WORK_DECIM: - _decim = factor; - _interp = 1; - break; - - case GR_BLOCK_GW_WORK_INTERP: - _decim = 1; - _interp = factor; - this->set_output_multiple(_interp); - break; - } - } - - /******************************************************************* - * Overloads for various scheduler-called functions - ******************************************************************/ - void forecast( - int noutput_items, - gr_vector_int &ninput_items_required - ){ - switch(_work_type){ - case GR_BLOCK_GW_WORK_GENERAL: - _message.action = gr_block_gw_message_type::ACTION_FORECAST; - _message.forecast_args_noutput_items = noutput_items; - _message.forecast_args_ninput_items_required = ninput_items_required; - _handler->calleval(0); - ninput_items_required = _message.forecast_args_ninput_items_required; - return; - - default: - unsigned ninputs = ninput_items_required.size(); - for (unsigned i = 0; i < ninputs; i++) - ninput_items_required[i] = fixed_rate_noutput_to_ninput(noutput_items); - return; - } - } - - int general_work( - int noutput_items, - gr_vector_int &ninput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items - ){ - switch(_work_type){ - case GR_BLOCK_GW_WORK_GENERAL: - _message.action = gr_block_gw_message_type::ACTION_GENERAL_WORK; - _message.general_work_args_noutput_items = noutput_items; - _message.general_work_args_ninput_items = ninput_items; - copy_pointers(_message.general_work_args_input_items, input_items); - _message.general_work_args_output_items = output_items; - _handler->calleval(0); - return _message.general_work_args_return_value; - - default: - int r = work (noutput_items, input_items, output_items); - if (r > 0) consume_each(r*_decim/_interp); - return r; - } - } - - int work( - int noutput_items, - gr_vector_const_void_star &input_items, - gr_vector_void_star &output_items - ){ - _message.action = gr_block_gw_message_type::ACTION_WORK; - _message.work_args_ninput_items = fixed_rate_noutput_to_ninput(noutput_items); - if (_message.work_args_ninput_items == 0) return -1; - _message.work_args_noutput_items = noutput_items; - copy_pointers(_message.work_args_input_items, input_items); - _message.work_args_output_items = output_items; - _handler->calleval(0); - return _message.work_args_return_value; - } - - int fixed_rate_noutput_to_ninput(int noutput_items){ - return (noutput_items*_decim/_interp) + history() - 1; - } - - int fixed_rate_ninput_to_noutput(int ninput_items){ - return std::max(0, ninput_items - (int)history() + 1)*_interp/_decim; - } - - bool start(void){ - _message.action = gr_block_gw_message_type::ACTION_START; - _handler->calleval(0); - return _message.start_args_return_value; - } - - bool stop(void){ - _message.action = gr_block_gw_message_type::ACTION_STOP; - _handler->calleval(0); - return _message.stop_args_return_value; - } - - gr_block_gw_message_type &gr_block_message(void){ - return _message; - } - -private: - gr_feval_ll *_handler; - gr_block_gw_message_type _message; - const gr_block_gw_work_type _work_type; - unsigned _decim, _interp; -}; - -boost::shared_ptr<runtime_block_gateway> runtime_make_block_gateway( - gr_feval_ll *handler, - const std::string &name, - gr_io_signature_sptr in_sig, - gr_io_signature_sptr out_sig, - const gr_block_gw_work_type work_type, - const unsigned factor -){ - return boost::shared_ptr<runtime_block_gateway>( - new runtime_block_gateway_impl(handler, name, in_sig, out_sig, - work_type, factor) - ); -} diff --git a/gnuradio-runtime/lib/gr_scheduler.cc b/gnuradio-runtime/lib/scheduler.cc index c691f5d99f..38d95e6fb2 100644 --- a/gnuradio-runtime/lib/gr_scheduler.cc +++ b/gnuradio-runtime/lib/scheduler.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2008 Free Software Foundation, Inc. + * Copyright 2008,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -22,12 +22,18 @@ #ifdef HAVE_CONFIG_H #include <config.h> #endif -#include <gr_scheduler.h> -gr_scheduler::gr_scheduler(gr_flat_flowgraph_sptr ffg, int max_noutput_items) -{ -} +#include "scheduler.h" -gr_scheduler::~gr_scheduler() -{ -} +namespace gr { + + scheduler::scheduler(flat_flowgraph_sptr ffg, + int max_noutput_items) + { + } + + scheduler::~scheduler() + { + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/scheduler.h b/gnuradio-runtime/lib/scheduler.h new file mode 100644 index 0000000000..575862b27d --- /dev/null +++ b/gnuradio-runtime/lib/scheduler.h @@ -0,0 +1,68 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2013 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_GR_SCHEDULER_H +#define INCLUDED_GR_SCHEDULER_H + +#include <gnuradio/api.h> +#include <boost/utility.hpp> +#include <gnuradio/block.h> +#include "flat_flowgraph.h" + +namespace gr { + + class scheduler; + typedef boost::shared_ptr<scheduler> scheduler_sptr; + + /*! + * \brief Abstract scheduler that takes a flattened flow graph and + * runs it. + * + * Preconditions: details, buffers and buffer readers have been + * assigned. + */ + class GR_RUNTIME_API scheduler : boost::noncopyable + { + public: + /*! + * \brief Construct a scheduler and begin evaluating the graph. + * + * The scheduler will continue running until all blocks until they + * report that they are done or the stop method is called. + */ + scheduler(flat_flowgraph_sptr ffg, int max_noutput_items); + + virtual ~scheduler(); + + /*! + * \brief Tell the scheduler to stop executing. + */ + virtual void stop() = 0; + + /*! + * \brief Block until the graph is done. + */ + virtual void wait() = 0; + }; + +} /* namespace gr */ + +#endif /* INCLUDED_GR_SCHEDULER_H */ diff --git a/gnuradio-runtime/lib/scheduler_sts.cc b/gnuradio-runtime/lib/scheduler_sts.cc new file mode 100644 index 0000000000..cc60b55f02 --- /dev/null +++ b/gnuradio-runtime/lib/scheduler_sts.cc @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2013 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "scheduler_sts.h" +#include <gnuradio/single_threaded_scheduler.h> +#include <gnuradio/thread/thread_body_wrapper.h> + +namespace gr { + + class sts_container + { + block_vector_t d_blocks; + + public: + sts_container(block_vector_t blocks) + : d_blocks(blocks) {} + + void operator()() + { + make_single_threaded_scheduler(d_blocks)->run(); + } + }; + + scheduler_sptr + scheduler_sts::make(flat_flowgraph_sptr ffg, int max_noutput_items) + { + return scheduler_sptr(new scheduler_sts(ffg, max_noutput_items)); + } + + scheduler_sts::scheduler_sts(flat_flowgraph_sptr ffg, int max_noutput_items) + : scheduler(ffg, max_noutput_items) + { + // Split the flattened flow graph into discrete partitions, each + // of which is topologically sorted. + + std::vector<basic_block_vector_t> graphs = ffg->partition(); + + // For each partition, create a thread to evaluate it using + // an instance of the gr_single_threaded_scheduler + + for(std::vector<basic_block_vector_t>::iterator p = graphs.begin(); + p != graphs.end(); p++) { + + block_vector_t blocks = flat_flowgraph::make_block_vector(*p); + d_threads.create_thread( + gr::thread::thread_body_wrapper<sts_container>(sts_container(blocks), + "single-threaded-scheduler")); + } + } + + scheduler_sts::~scheduler_sts() + { + stop(); + } + + void + scheduler_sts::stop() + { + d_threads.interrupt_all(); + } + + void + scheduler_sts::wait() + { + d_threads.join_all(); + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/scheduler_sts.h b/gnuradio-runtime/lib/scheduler_sts.h new file mode 100644 index 0000000000..b4cddb4614 --- /dev/null +++ b/gnuradio-runtime/lib/scheduler_sts.h @@ -0,0 +1,66 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2013 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_GR_SCHEDULER_STS_H +#define INCLUDED_GR_SCHEDULER_STS_H + +#include <gnuradio/api.h> +#include <gnuradio/thread/thread_group.h> +#include "scheduler.h" + +namespace gr { + + /*! + * \brief Concrete scheduler that uses the single_threaded_scheduler + */ + class GR_RUNTIME_API scheduler_sts : public scheduler + { + gr::thread::thread_group d_threads; + + protected: + /*! + * \brief Construct a scheduler and begin evaluating the graph. + * + * The scheduler will continue running until all blocks until they + * report that they are done or the stop method is called. + */ + scheduler_sts(flat_flowgraph_sptr ffg, int max_noutput_items); + + public: + static scheduler_sptr make(flat_flowgraph_sptr ffg, + int max_noutput_items); + + ~scheduler_sts(); + + /*! + * \brief Tell the scheduler to stop executing. + */ + void stop(); + + /*! + * \brief Block until the graph is done. + */ + void wait(); + }; + +} /* namespace gr */ + +#endif /* INCLUDED_GR_SCHEDULER_STS_H */ diff --git a/gnuradio-runtime/lib/scheduler_tpb.cc b/gnuradio-runtime/lib/scheduler_tpb.cc new file mode 100644 index 0000000000..d35c37fb34 --- /dev/null +++ b/gnuradio-runtime/lib/scheduler_tpb.cc @@ -0,0 +1,106 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2013 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "scheduler_tpb.h" +#include "tpb_thread_body.h" +#include <gnuradio/thread/thread_body_wrapper.h> +#include <sstream> + +namespace gr { + + class tpb_container + { + block_sptr d_block; + int d_max_noutput_items; + + public: + tpb_container(block_sptr block, int max_noutput_items) + : d_block(block), d_max_noutput_items(max_noutput_items) {} + + void operator()() + { + tpb_thread_body body(d_block, d_max_noutput_items); + } + }; + + scheduler_sptr + scheduler_tpb::make(flat_flowgraph_sptr ffg, int max_noutput_items) + { + return scheduler_sptr(new scheduler_tpb(ffg, max_noutput_items)); + } + + scheduler_tpb::scheduler_tpb(flat_flowgraph_sptr ffg, + int max_noutput_items) + : scheduler(ffg, max_noutput_items) + { + // Get a topologically sorted vector of all the blocks in use. + // Being topologically sorted probably isn't going to matter, but + // there's a non-zero chance it might help... + + basic_block_vector_t used_blocks = ffg->calc_used_blocks(); + used_blocks = ffg->topological_sort(used_blocks); + block_vector_t blocks = flat_flowgraph::make_block_vector(used_blocks); + + // Ensure that the done flag is clear on all blocks + + for(size_t i = 0; i < blocks.size(); i++) { + blocks[i]->detail()->set_done(false); + } + + // Fire off a thead for each block + + for(size_t i = 0; i < blocks.size(); i++) { + std::stringstream name; + name << "thread-per-block[" << i << "]: " << blocks[i]; + + // If set, use internal value instead of global value + if(blocks[i]->is_set_max_noutput_items()) + max_noutput_items = blocks[i]->max_noutput_items(); + + d_threads.create_thread( + gr::thread::thread_body_wrapper<tpb_container> + (tpb_container(blocks[i], max_noutput_items), + name.str())); + } + } + + scheduler_tpb::~scheduler_tpb() + { + stop(); + } + + void + scheduler_tpb::stop() + { + d_threads.interrupt_all(); + } + + void + scheduler_tpb::wait() + { + d_threads.join_all(); + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/scheduler_tpb.h b/gnuradio-runtime/lib/scheduler_tpb.h new file mode 100644 index 0000000000..f5ab21f269 --- /dev/null +++ b/gnuradio-runtime/lib/scheduler_tpb.h @@ -0,0 +1,66 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2013 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef INCLUDED_GR_SCHEDULER_TPB_H +#define INCLUDED_GR_SCHEDULER_TPB_H + +#include <gnuradio/api.h> +#include <gnuradio/thread/thread_group.h> +#include "scheduler.h" + +namespace gr { + + /*! + * \brief Concrete scheduler that uses a kernel thread-per-block + */ + class GR_RUNTIME_API scheduler_tpb : public scheduler + { + gr::thread::thread_group d_threads; + + protected: + /*! + * \brief Construct a scheduler and begin evaluating the graph. + * + * The scheduler will continue running until all blocks until they + * report that they are done or the stop method is called. + */ + scheduler_tpb(flat_flowgraph_sptr ffg, int max_noutput_items); + + public: + static scheduler_sptr make(flat_flowgraph_sptr ffg, + int max_noutput_items=100000); + + ~scheduler_tpb(); + + /*! + * \brief Tell the scheduler to stop executing. + */ + void stop(); + + /*! + * \brief Block until the graph is done. + */ + void wait(); + }; + +} /* namespace gr */ + +#endif /* INCLUDED_GR_SCHEDULER_TPB_H */ diff --git a/gnuradio-runtime/lib/gr_select_handler.cc b/gnuradio-runtime/lib/select_handler.cc index 0fc86354a6..ca99ce6ce8 100644 --- a/gnuradio-runtime/lib/gr_select_handler.cc +++ b/gnuradio-runtime/lib/select_handler.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2005 Free Software Foundation, Inc. + * Copyright 2005,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -24,13 +24,17 @@ #include "config.h" #endif -#include <gr_select_handler.h> +#include <gnuradio/select_handler.h> -gr_select_handler::gr_select_handler(int fd) - : d_fd(fd) -{ -} +namespace gr { -gr_select_handler::~gr_select_handler() -{ -} + select_handler::select_handler(int fd) + : d_fd(fd) + { + } + + select_handler::~select_handler() + { + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/single_threaded_scheduler.cc b/gnuradio-runtime/lib/single_threaded_scheduler.cc new file mode 100644 index 0000000000..0d7f91670b --- /dev/null +++ b/gnuradio-runtime/lib/single_threaded_scheduler.cc @@ -0,0 +1,363 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 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 <gnuradio/single_threaded_scheduler.h> +#include <gnuradio/block.h> +#include <gnuradio/block_detail.h> +#include <gnuradio/buffer.h> +#include <boost/thread.hpp> +#include <boost/format.hpp> +#include <iostream> +#include <limits> +#include <assert.h> +#include <stdio.h> + +namespace gr { + + // must be defined to either 0 or 1 +#define ENABLE_LOGGING 0 + +#if (ENABLE_LOGGING) +#define LOG(x) do { x; } while(0) +#else +#define LOG(x) do {;} while(0) +#endif + + static int which_scheduler = 0; + + single_threaded_scheduler_sptr + make_single_threaded_scheduler(const std::vector<block_sptr> &blocks) + { + return single_threaded_scheduler_sptr + (new single_threaded_scheduler(blocks)); + } + + single_threaded_scheduler::single_threaded_scheduler(const std::vector<block_sptr> &blocks) + : d_blocks(blocks), d_enabled(true), d_log(0) + { + if(ENABLE_LOGGING) { + std::string name = str(boost::format("sst-%d.log") % which_scheduler++); + d_log = new std::ofstream(name.c_str()); + *d_log << "single_threaded_scheduler: " + << d_blocks.size () + << " blocks\n"; + } + } + + single_threaded_scheduler::~single_threaded_scheduler() + { + if(ENABLE_LOGGING) + delete d_log; + } + + void + single_threaded_scheduler::run() + { + // d_enabled = true; // KLUDGE + main_loop (); + } + + void + single_threaded_scheduler::stop() + { + if(0) + std::cout << "gr_singled_threaded_scheduler::stop() " + << this << std::endl; + d_enabled = false; + } + + inline static unsigned int + round_up(unsigned int n, unsigned int multiple) + { + return ((n + multiple - 1) / multiple) * multiple; + } + + inline static unsigned int + round_down(unsigned int n, unsigned int multiple) + { + return (n / multiple) * multiple; + } + + // + // Return minimum available write space in all our downstream + // buffers or -1 if we're output blocked and the output we're + // blocked on is done. + // + static int + min_available_space(block_detail *d, int output_multiple) + { + int min_space = std::numeric_limits<int>::max(); + + for(int i = 0; i < d->noutputs (); i++) { + int n = round_down (d->output(i)->space_available (), output_multiple); + if(n == 0) { // We're blocked on output. + if(d->output(i)->done()) { // Downstream is done, therefore we're done. + return -1; + } + return 0; + } + min_space = std::min (min_space, n); + } + return min_space; + } + + void + single_threaded_scheduler::main_loop() + { + static const int DEFAULT_CAPACITY = 16; + + int noutput_items; + gr_vector_int ninput_items_required(DEFAULT_CAPACITY); + gr_vector_int ninput_items(DEFAULT_CAPACITY); + gr_vector_const_void_star input_items(DEFAULT_CAPACITY); + gr_vector_void_star output_items(DEFAULT_CAPACITY); + unsigned int bi; + unsigned int nalive; + int max_items_avail; + bool made_progress_last_pass; + bool making_progress; + + for(unsigned i = 0; i < d_blocks.size (); i++) + d_blocks[i]->detail()->set_done (false); // reset any done flags + + for(unsigned i = 0; i < d_blocks.size (); i++) // enable any drivers, etc. + d_blocks[i]->start(); + + bi = 0; + made_progress_last_pass = true; + making_progress = false; + + // Loop while there are still blocks alive + + nalive = d_blocks.size (); + while(d_enabled && nalive > 0) { + if(boost::this_thread::interruption_requested()) + break; + + block *m = d_blocks[bi].get (); + block_detail *d = m->detail().get (); + + LOG(*d_log << std::endl << m); + + if(d->done ()) + goto next_block; + + if(d->source_p ()) { + // Invoke sources as a last resort. As long as the previous + // pass made progress, don't call a source. + if(made_progress_last_pass) { + LOG(*d_log << " Skipping source\n"); + goto next_block; + } + + ninput_items_required.resize (0); + ninput_items.resize (0); + input_items.resize (0); + output_items.resize (d->noutputs ()); + + // determine the minimum available output space + noutput_items = min_available_space (d, m->output_multiple ()); + LOG(*d_log << " source\n noutput_items = " << noutput_items << std::endl); + if(noutput_items == -1) // we're done + goto were_done; + + if(noutput_items == 0) { // we're output blocked + LOG(*d_log << " BLKD_OUT\n"); + goto next_block; + } + + goto setup_call_to_work; // jump to common code + } + + else if(d->sink_p ()) { + ninput_items_required.resize (d->ninputs ()); + ninput_items.resize (d->ninputs ()); + input_items.resize (d->ninputs ()); + output_items.resize (0); + LOG(*d_log << " sink\n"); + + max_items_avail = 0; + for(int i = 0; i < d->ninputs (); i++) { + ninput_items[i] = d->input(i)->items_available(); + //if (ninput_items[i] == 0 && d->input(i)->done()) + if(ninput_items[i] < m->output_multiple() && d->input(i)->done()) + goto were_done; + + max_items_avail = std::max (max_items_avail, ninput_items[i]); + } + + // take a swag at how much output we can sink + noutput_items = (int) (max_items_avail * m->relative_rate ()); + noutput_items = round_down (noutput_items, m->output_multiple ()); + LOG(*d_log << " max_items_avail = " << max_items_avail << std::endl); + LOG(*d_log << " noutput_items = " << noutput_items << std::endl); + + if(noutput_items == 0) { // we're blocked on input + LOG(*d_log << " BLKD_IN\n"); + goto next_block; + } + + goto try_again; // Jump to code shared with regular case. + } + + else { + // do the regular thing + ninput_items_required.resize(d->ninputs ()); + ninput_items.resize(d->ninputs ()); + input_items.resize(d->ninputs ()); + output_items.resize(d->noutputs ()); + + max_items_avail = 0; + for(int i = 0; i < d->ninputs (); i++) { + ninput_items[i] = d->input(i)->items_available (); + max_items_avail = std::max(max_items_avail, ninput_items[i]); + } + + // determine the minimum available output space + noutput_items = min_available_space(d, m->output_multiple ()); + if(ENABLE_LOGGING){ + *d_log << " regular "; + if(m->relative_rate() >= 1.0) + *d_log << "1:" << m->relative_rate() << std::endl; + else + *d_log << 1.0/m->relative_rate() << ":1\n"; + *d_log << " max_items_avail = " << max_items_avail << std::endl; + *d_log << " noutput_items = " << noutput_items << std::endl; + } + if(noutput_items == -1) // we're done + goto were_done; + + if(noutput_items == 0) { // we're output blocked + LOG(*d_log << " BLKD_OUT\n"); + goto next_block; + } + +#if 0 + // Compute best estimate of noutput_items that we can really use. + noutput_items = + std::min((unsigned)noutput_items, + std::max((unsigned)m->output_multiple(), + round_up((unsigned)(max_items_avail * m->relative_rate()), + m->output_multiple()))); + + LOG(*d_log << " revised noutput_items = " << noutput_items << std::endl); +#endif + + try_again: + if(m->fixed_rate()) { + // try to work it forward starting with max_items_avail. + // We want to try to consume all the input we've got. + int reqd_noutput_items = m->fixed_rate_ninput_to_noutput(max_items_avail); + reqd_noutput_items = round_up(reqd_noutput_items, m->output_multiple()); + if(reqd_noutput_items > 0 && reqd_noutput_items <= noutput_items) + noutput_items = reqd_noutput_items; + } + + // ask the block how much input they need to produce noutput_items + m->forecast(noutput_items, ninput_items_required); + + // See if we've got sufficient input available + int i; + for(i = 0; i < d->ninputs (); i++) + if(ninput_items_required[i] > ninput_items[i]) // not enough + break; + + if(i < d->ninputs()) { // not enough input on input[i] + // if we can, try reducing the size of our output request + if(noutput_items > m->output_multiple ()){ + noutput_items /= 2; + noutput_items = round_up (noutput_items, m->output_multiple ()); + goto try_again; + } + + // We're blocked on input + LOG(*d_log << " BLKD_IN\n"); + if(d->input(i)->done()) // If the upstream block is done, we're done + goto were_done; + + // Is it possible to ever fulfill this request? + if(ninput_items_required[i] > d->input(i)->max_possible_items_available ()) { + // Nope, never going to happen... + std::cerr << "\nsched: <block " << m->name() + << " (" << m->unique_id() << ")>" + << " is requesting more input data\n" + << " than we can provide.\n" + << " ninput_items_required = " + << ninput_items_required[i] << "\n" + << " max_possible_items_available = " + << d->input(i)->max_possible_items_available() << "\n" + << " If this is a filter, consider reducing the number of taps.\n"; + goto were_done; + } + + goto next_block; + } + + // We've got enough data on each input to produce noutput_items. + // Finish setting up the call to work. + for(int i = 0; i < d->ninputs (); i++) + input_items[i] = d->input(i)->read_pointer(); + + setup_call_to_work: + + for(int i = 0; i < d->noutputs (); i++) + output_items[i] = d->output(i)->write_pointer(); + + // Do the actual work of the block + int n = m->general_work(noutput_items, ninput_items, + input_items, output_items); + LOG(*d_log << " general_work: noutput_items = " << noutput_items + << " result = " << n << std::endl); + + if(n == -1) // block is done + goto were_done; + + d->produce_each(n); // advance write pointers + if(n > 0) + making_progress = true; + + goto next_block; + } + assert(0); + + were_done: + LOG(*d_log << " were_done\n"); + d->set_done (true); + nalive--; + + next_block: + if(++bi >= d_blocks.size ()) { + bi = 0; + made_progress_last_pass = making_progress; + making_progress = false; + } + } + + for(unsigned i = 0; i < d_blocks.size(); i++) // disable any drivers, etc. + d_blocks[i]->stop(); + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gr_sptr_magic.cc b/gnuradio-runtime/lib/sptr_magic.cc index 2073701422..70596abb05 100644 --- a/gnuradio-runtime/lib/gr_sptr_magic.cc +++ b/gnuradio-runtime/lib/sptr_magic.cc @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2008,2009 Free Software Foundation, Inc. + * Copyright 2008,2009,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -18,54 +18,54 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ + #ifdef HAVE_CONFIG_H #include <config.h> #endif -#include <gr_sptr_magic.h> -#include <gr_hier_block2.h> + +#include <gnuradio/sptr_magic.h> +#include <gnuradio/hier_block2.h> #include <map> #include <stdexcept> - -#include <thread/thread.h> +#include <gnuradio/thread/thread.h> namespace gnuradio { - static gr::thread::mutex s_mutex; - typedef std::map<gr_basic_block*, gr_basic_block_sptr> sptr_map; - static sptr_map s_map; + static gr::thread::mutex s_mutex; + typedef std::map<gr::basic_block*, gr::basic_block_sptr> sptr_map; + static sptr_map s_map; void - detail::sptr_magic::create_and_stash_initial_sptr(gr_hier_block2 *p) + detail::sptr_magic::create_and_stash_initial_sptr(gr::hier_block2 *p) { - gr_basic_block_sptr sptr(p); + gr::basic_block_sptr sptr(p); gr::thread::scoped_lock guard(s_mutex); - s_map.insert(sptr_map::value_type(static_cast<gr_basic_block *>(p), sptr)); + s_map.insert(sptr_map::value_type(static_cast<gr::basic_block *>(p), sptr)); } - - gr_basic_block_sptr - detail::sptr_magic::fetch_initial_sptr(gr_basic_block *p) + gr::basic_block_sptr + detail::sptr_magic::fetch_initial_sptr(gr::basic_block *p) { /* - * If p isn't a subclass of gr_hier_block2, just create the + * If p isn't a subclass of gr::hier_block2, just create the * shared ptr and return it. */ - gr_hier_block2 *hb2 = dynamic_cast<gr_hier_block2 *>(p); - if (!hb2){ - return gr_basic_block_sptr(p); + gr::hier_block2 *hb2 = dynamic_cast<gr::hier_block2 *>(p); + if(!hb2) { + return gr::basic_block_sptr(p); } /* - * p is a subclass of gr_hier_block2, thus we've already created the shared pointer + * p is a subclass of gr::hier_block2, thus we've already created the shared pointer * and stashed it away. Fish it out and return it. */ gr::thread::scoped_lock guard(s_mutex); - sptr_map::iterator pos = s_map.find(static_cast<gr_basic_block *>(p)); - if (pos == s_map.end()) - throw std::invalid_argument("gr_sptr_magic: invalid pointer!"); + sptr_map::iterator pos = s_map.find(static_cast<gr::basic_block *>(p)); + if(pos == s_map.end()) + throw std::invalid_argument("sptr_magic: invalid pointer!"); - gr_basic_block_sptr sptr = pos->second; + gr::basic_block_sptr sptr = pos->second; s_map.erase(pos); return sptr; } diff --git a/gnuradio-runtime/lib/sync_block.cc b/gnuradio-runtime/lib/sync_block.cc new file mode 100644 index 0000000000..e00b80c79e --- /dev/null +++ b/gnuradio-runtime/lib/sync_block.cc @@ -0,0 +1,72 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2013 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 <gnuradio/sync_block.h> + +namespace gr { + + sync_block::sync_block(const std::string &name, + io_signature::sptr input_signature, + io_signature::sptr output_signature) + : block(name, input_signature, output_signature) + { + set_fixed_rate(true); + } + + void + sync_block::forecast(int noutput_items, + gr_vector_int &ninput_items_required) + { + unsigned ninputs = ninput_items_required.size(); + for(unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = fixed_rate_noutput_to_ninput(noutput_items); + } + + int + sync_block::fixed_rate_noutput_to_ninput(int noutput_items) + { + return noutput_items + history() - 1; + } + + int + sync_block::fixed_rate_ninput_to_noutput(int ninput_items) + { + return std::max(0, ninput_items - (int)history() + 1); + } + + int + sync_block::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + int r = work(noutput_items, input_items, output_items); + if(r > 0) + consume_each(r); + return r; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/sync_decimator.cc b/gnuradio-runtime/lib/sync_decimator.cc new file mode 100644 index 0000000000..a9c2d1eeff --- /dev/null +++ b/gnuradio-runtime/lib/sync_decimator.cc @@ -0,0 +1,72 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2013 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 <gnuradio/sync_decimator.h> + +namespace gr { + + sync_decimator::sync_decimator(const std::string &name, + io_signature::sptr input_signature, + io_signature::sptr output_signature, + unsigned decimation) + : sync_block(name, input_signature, output_signature) + { + set_decimation(decimation); + } + + void + sync_decimator::forecast(int noutput_items, gr_vector_int &ninput_items_required) + { + unsigned ninputs = ninput_items_required.size(); + for(unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = fixed_rate_noutput_to_ninput(noutput_items); + } + + int + sync_decimator::fixed_rate_noutput_to_ninput(int noutput_items) + { + return noutput_items * decimation() + history() - 1; + } + + int + sync_decimator::fixed_rate_ninput_to_noutput(int ninput_items) + { + return std::max(0, ninput_items - (int)history() + 1) / decimation(); + } + + int + sync_decimator::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + int r = work(noutput_items, input_items, output_items); + if(r > 0) + consume_each(r * decimation ()); + return r; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/sync_interpolator.cc b/gnuradio-runtime/lib/sync_interpolator.cc new file mode 100644 index 0000000000..5721f24f0f --- /dev/null +++ b/gnuradio-runtime/lib/sync_interpolator.cc @@ -0,0 +1,73 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004,2008,2013 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 <gnuradio/sync_interpolator.h> + +namespace gr { + + sync_interpolator::sync_interpolator(const std::string &name, + io_signature::sptr input_signature, + io_signature::sptr output_signature, + unsigned interpolation) + : sync_block(name, input_signature, output_signature) + { + set_interpolation(interpolation); + } + + void + sync_interpolator::forecast(int noutput_items, + gr_vector_int &ninput_items_required) + { + unsigned ninputs = ninput_items_required.size(); + for(unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = fixed_rate_noutput_to_ninput(noutput_items); + } + + int + sync_interpolator::fixed_rate_noutput_to_ninput(int noutput_items) + { + return noutput_items / interpolation() + history() - 1; + } + + int + sync_interpolator::fixed_rate_ninput_to_noutput(int ninput_items) + { + return std::max(0, ninput_items - (int)history() + 1) * interpolation(); + } + + int + sync_interpolator::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + int r = work(noutput_items, input_items, output_items); + if(r > 0) + consume_each(r / interpolation()); + return r; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gr_sys_paths.cc b/gnuradio-runtime/lib/sys_paths.cc index b4918af33d..64853c68b2 100644 --- a/gnuradio-runtime/lib/gr_sys_paths.cc +++ b/gnuradio-runtime/lib/sys_paths.cc @@ -1,5 +1,5 @@ /* - * Copyright 2011 Free Software Foundation, Inc. + * Copyright 2011,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -19,37 +19,47 @@ * Boston, MA 02110-1301, USA. */ -#include <gr_sys_paths.h> +#include <gnuradio/sys_paths.h> #include <cstdlib> //getenv #include <cstdio> //P_tmpdir (maybe) -const char *gr_tmp_path(){ +namespace gr { + + const char *tmp_path() + { const char *path; //first case, try TMP environment variable path = getenv("TMP"); - if (path) return path; + if(path) + return path; //second case, try P_tmpdir when its defined #ifdef P_tmpdir - if (P_tmpdir) return P_tmpdir; + if(P_tmpdir) + return P_tmpdir; #endif /*P_tmpdir*/ //fall-through case, nothing worked return "/tmp"; -} + } -const char *gr_appdata_path(){ + const char *appdata_path() + { const char *path; //first case, try HOME environment variable (unix) path = getenv("HOME"); - if (path) return path; + if(path) + return path; //second case, try APPDATA environment variable (windows) path = getenv("APPDATA"); - if (path) return path; + if(path) + return path; //fall-through case, nothing worked - return gr_tmp_path(); -} + return tmp_path(); + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/tagged_stream_block.cc b/gnuradio-runtime/lib/tagged_stream_block.cc new file mode 100644 index 0000000000..40febfdeca --- /dev/null +++ b/gnuradio-runtime/lib/tagged_stream_block.cc @@ -0,0 +1,144 @@ +/* -*- c++ -*- */ +/* + * Copyright 2013 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 <boost/format.hpp> +#include <gnuradio/tagged_stream_block.h> + +namespace gr { + + tagged_stream_block::tagged_stream_block(const std::string &name, + io_signature::sptr input_signature, + io_signature::sptr output_signature, + const std::string &length_tag_key) + : block(name, input_signature, output_signature), + d_length_tag_key(pmt::string_to_symbol(length_tag_key)), + d_n_input_items_reqd(input_signature->min_streams(), 0), + d_length_tag_key_str(length_tag_key) + { + } + + // This is evil hackery: We trick the scheduler into creating the right number of input items + void + tagged_stream_block::forecast(int noutput_items, + gr_vector_int &ninput_items_required) + { + unsigned ninputs = ninput_items_required.size(); + for(unsigned i = 0; i < ninputs; i++) { + if (i < d_n_input_items_reqd.size() && d_n_input_items_reqd[i] != 0) { + ninput_items_required[i] = d_n_input_items_reqd[i]; + } + else { + // If there's no item, there's no tag--so there must at least be one! + ninput_items_required[i] = std::max(1, (int)std::floor((double) noutput_items / relative_rate() + 0.5)); + } + } + } + + void + tagged_stream_block::parse_length_tags(const std::vector<std::vector<tag_t> > &tags, + gr_vector_int &n_input_items_reqd) + { + for(unsigned i = 0; i < tags.size(); i++) { + for(unsigned k = 0; k < tags[i].size(); k++) { + if(tags[i][k].key == d_length_tag_key) { + n_input_items_reqd[i] = pmt::to_long(tags[i][k].value); + remove_item_tag(i, tags[i][k]); + } + } + } + } + + int + tagged_stream_block::calculate_output_stream_length(const gr_vector_int &ninput_items) + { + int noutput_items = *std::max_element(ninput_items.begin(), ninput_items.end()); + return (int)std::floor(relative_rate() * noutput_items + 0.5); + } + + void + tagged_stream_block::update_length_tags(int n_produced, int n_ports) + { + for(int i = 0; i < n_ports; i++) { + add_item_tag(i, nitems_written(i), + d_length_tag_key, + pmt::from_long(n_produced)); + } + return; + } + + int + tagged_stream_block::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + if(d_length_tag_key_str.empty()) { + return work(noutput_items, ninput_items, input_items, output_items); + } + + if(d_n_input_items_reqd[0] == 0) { // Otherwise, it's already set from a previous call + std::vector<std::vector<tag_t> > tags(input_items.size(), std::vector<tag_t>()); + for(unsigned i = 0; i < input_items.size(); i++) { + get_tags_in_range(tags[i], i, nitems_read(i), nitems_read(i)+1); + } + d_n_input_items_reqd.assign(input_items.size(), -1); + parse_length_tags(tags, d_n_input_items_reqd); + } + for(unsigned i = 0; i < input_items.size(); i++) { + if(d_n_input_items_reqd[i] == -1) { + GR_LOG_FATAL(d_logger, boost::format("Missing a required length tag on port %1% at item #%2%") % i % nitems_read(i)); + throw std::runtime_error("Missing length tag."); + } + if(d_n_input_items_reqd[i] > ninput_items[i]) { + return 0; + } + } + + int min_output_size = calculate_output_stream_length(d_n_input_items_reqd); + if(noutput_items < min_output_size) { + set_min_noutput_items(min_output_size); + return 0; + } + set_min_noutput_items(1); + + // WORK CALLED HERE // + int n_produced = work(noutput_items, d_n_input_items_reqd, input_items, output_items); + ////////////////////// + + if(n_produced == WORK_DONE) { + return n_produced; + } + for(int i = 0; i < (int) d_n_input_items_reqd.size(); i++) { + consume(i, d_n_input_items_reqd[i]); + } + update_length_tags(n_produced, output_items.size()); + + d_n_input_items_reqd.assign(input_items.size(), 0); + + return n_produced; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/test.cc b/gnuradio-runtime/lib/test.cc new file mode 100644 index 0000000000..775dc2bde4 --- /dev/null +++ b/gnuradio-runtime/lib/test.cc @@ -0,0 +1,181 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2008,2010,2013 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 "test.h" +#include <gnuradio/io_signature.h> +#include <stdexcept> +#include <iostream> +#include <string.h> + +namespace gr { + + test_sptr + make_test(const std::string &name, + int min_inputs, int max_inputs, unsigned int sizeof_input_item, + int min_outputs, int max_outputs, unsigned int sizeof_output_item, + unsigned int history, unsigned int output_multiple, double relative_rate, + bool fixed_rate, consume_type_t cons_type, produce_type_t prod_type) + { + return gnuradio::get_initial_sptr + (new test(name, min_inputs, max_inputs, sizeof_input_item, + min_outputs, max_outputs, sizeof_output_item, + history, output_multiple, relative_rate, + fixed_rate,cons_type, prod_type)); + } + + test::test(const std::string &name, + int min_inputs, int max_inputs, + unsigned int sizeof_input_item, + int min_outputs, int max_outputs, + unsigned int sizeof_output_item, + unsigned int history, + unsigned int output_multiple, + double relative_rate, + bool fixed_rate, + consume_type_t cons_type, produce_type_t prod_type) + : block (name, + io_signature::make(min_inputs, max_inputs, sizeof_input_item), + io_signature::make(min_outputs, max_outputs, sizeof_output_item)), + d_sizeof_input_item(sizeof_input_item), + d_sizeof_output_item(sizeof_output_item), + d_check_topology(true), + d_consume_type(cons_type), + d_min_consume(0), + d_max_consume(0), + d_produce_type(prod_type), + d_min_produce(0), + d_max_produce(0) + { + set_history(history); + set_output_multiple(output_multiple); + set_relative_rate(relative_rate); + set_fixed_rate(fixed_rate); + } + + int + test::general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items) + { + //touch all inputs and outputs to detect segfaults + unsigned ninputs = input_items.size (); + unsigned noutputs= output_items.size(); + for(unsigned i = 0; i < ninputs; i++) { + char * in=(char *)input_items[i]; + if(ninput_items[i]< (int)(noutput_items+history())) { + std::cerr << "ERROR: ninput_items[" << i << "] < noutput_items+history()" << std::endl; + std::cerr << "ninput_items[" << i << "] = " << ninput_items[i] << std::endl; + std::cerr << "noutput_items+history() = " << noutput_items+history() << std::endl; + std::cerr << "noutput_items = " << noutput_items << std::endl; + std::cerr << "history() = " << history() << std::endl; + throw std::runtime_error ("test"); + } + else { + for (int j = 0; j < ninput_items[i]; j++) { + //Touch every available input_item + //We use a class variable to avoid the compiler to optimize this away + for(unsigned int k = 0; k < d_sizeof_input_item; k++) + d_temp= in[j*d_sizeof_input_item+k]; + } + switch(d_consume_type){ + case CONSUME_NOUTPUT_ITEMS: + consume(i,noutput_items); + break; + case CONSUME_NOUTPUT_ITEMS_LIMIT_MAX: + consume(i,std::min(noutput_items,d_max_consume)); + break; + case CONSUME_NOUTPUT_ITEMS_LIMIT_MIN: + consume(i,std::min(std::max(noutput_items,d_min_consume),ninput_items[i])); + break; + case CONSUME_ALL_AVAILABLE: + consume(i,ninput_items[i]); + break; + case CONSUME_ALL_AVAILABLE_LIMIT_MAX: + consume(i,std::min(ninput_items[i],d_max_consume)); + break; +/* //This could result in segfault, uncomment if you want to test this + case CONSUME_ALL_AVAILABLE_LIMIT_MIN: + consume(i,std::max(ninput_items[i],d_max_consume)); + break;*/ + case CONSUME_ZERO: + consume(i,0); + break; + case CONSUME_ONE: + consume(i,1); + break; + case CONSUME_MINUS_ONE: + consume(i,-1); + break; + default: + consume(i,noutput_items); + } + } + } + for(unsigned i = 0; i < noutputs; i++) { + char * out=(char *)output_items[i]; + { + for(int j=0;j<noutput_items;j++) { + //Touch every available output_item + for(unsigned int k=0;k<d_sizeof_output_item;k++) + out[j*d_sizeof_input_item+k]=0; + } + } + } + //Now copy input to output until max ninputs or max noutputs is reached + int common_nports=std::min(ninputs,noutputs); + if(d_sizeof_output_item==d_sizeof_input_item) + for(int i = 0; i < common_nports; i++) { + memcpy(output_items[i],input_items[i],noutput_items*d_sizeof_input_item); + } + int noutput_items_produced=0; + switch(d_produce_type) { + case PRODUCE_NOUTPUT_ITEMS: + noutput_items_produced=noutput_items; + break; + case PRODUCE_NOUTPUT_ITEMS_LIMIT_MAX: + noutput_items_produced=std::min(noutput_items,d_max_produce); + break; +/* //This could result in segfault, uncomment if you want to test this + case PRODUCE_NOUTPUT_ITEMS_LIMIT_MIN: + noutput_items_produced=std::max(noutput_items,d_min_produce); + break;*/ + case PRODUCE_ZERO: + noutput_items_produced=0; + break; + case PRODUCE_ONE: + noutput_items_produced=1; + break; + case PRODUCE_MINUS_ONE: + noutput_items_produced=-1; + break; + default: + noutput_items_produced=noutput_items; + } + return noutput_items_produced; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/test.h b/gnuradio-runtime/lib/test.h new file mode 100644 index 0000000000..cbe42f94e8 --- /dev/null +++ b/gnuradio-runtime/lib/test.h @@ -0,0 +1,225 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2013 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_TEST_H +#define INCLUDED_GR_TEST_H + +#include <gnuradio/api.h> +#include <gnuradio/block.h> +#include <string> +#include "test_types.h" + +namespace gr { + + class test; + typedef boost::shared_ptr<test> test_sptr; + + // public constructor + GR_RUNTIME_API test_sptr + make_test(const std::string &name=std::string("test"), + int min_inputs=1, int max_inputs=1, unsigned int sizeof_input_item=1, + int min_outputs=1, int max_outputs=1, unsigned int sizeof_output_item=1, + unsigned int history=1,unsigned int output_multiple=1,double relative_rate=1.0, + bool fixed_rate=true,consume_type_t cons_type=CONSUME_NOUTPUT_ITEMS, + produce_type_t prod_type=PRODUCE_NOUTPUT_ITEMS); + + /*! + * \brief Test class for testing runtime system (setting up buffers and such.) + * \ingroup misc + * + * This block does not do any usefull actual data processing. It + * just exposes setting all standard block parameters using the + * contructor or public methods. + * + * This block can be usefull when testing the runtime system. + * You can force this block to have a large history, decimation + * factor and/or large output_multiple. + * The runtime system should detect this and create large enough buffers + * all through the signal chain. + */ + class GR_RUNTIME_API test : public block + { + public: + ~test() {} + + int general_work(int noutput_items, + gr_vector_int &ninput_items, + gr_vector_const_void_star &input_items, + gr_vector_void_star &output_items); + + // ---------------------------------------------------------------- + // override these to define your behavior + // ---------------------------------------------------------------- + + /*! + * \brief Estimate input requirements given output request + * + * \param noutput_items number of output items to produce + * \param ninput_items_required number of input items required on each input stream + * + * Given a request to product \p noutput_items, estimate the + * number of data items required on each input stream. The + * estimate doesn't have to be exact, but should be close. + */ + void forecast(int noutput_items, + gr_vector_int &ninput_items_required) + { + unsigned ninputs = ninput_items_required.size(); + for(unsigned i = 0; i < ninputs; i++) + ninput_items_required[i] = (int)((double)noutput_items / relative_rate()) + (int)history(); + } + + /*! + * \brief Force check topology to return true or false. + * + * \param check_topology value to return when check_topology is + * called (true or false) default check_topology returns true + */ + void set_check_topology(bool check_topology) { + d_check_topology=check_topology; + } + + /*! + * \brief Confirm that ninputs and noutputs is an acceptable combination. + * + * \param ninputs number of input streams connected + * \param noutputs number of output streams connected + * + * \returns true if this is a valid configuration for this block. + * + * This function is called by the runtime system whenever the + * topology changes. Most classes do not need to override this. + * This check is in addition to the constraints specified by the + * input and output gr::io_signatures. + */ + bool check_topology(int ninputs, int noutputs) { + return d_check_topology; + } + + // ---------------------------------------------------------------- + /* + * The following two methods provide special case info to the + * scheduler in the event that a block has a fixed input to output + * ratio. gr::sync_block, gr::sync_decimator and + * gr::sync_interpolator override these. If you're fixed rate, + * subclass one of those. + */ + /*! + * \brief Given ninput samples, return number of output samples + * that will be produced. N.B. this is only defined if fixed_rate + * returns true. Generally speaking, you don't need to override + * this. + */ + int fixed_rate_ninput_to_noutput(int ninput) { + return (int)((double)ninput/relative_rate()); + } + + /*! + * \brief Given noutput samples, return number of input samples + * required to produce noutput. N.B. this is only defined if + * fixed_rate returns true. + */ + int fixed_rate_noutput_to_ninput(int noutput) { + return (int)((double)noutput*relative_rate()); + } + + /*! + * \brief Set if fixed rate should return true. + * N.B. This is normally a private method but we make it available here as public. + */ + void set_fixed_rate_public(bool fixed_rate) { + set_fixed_rate(fixed_rate); + } + + /*! + * \brief Set the consume pattern. + * + * \param cons_type which consume pattern to use + */ + void set_consume_type(consume_type_t cons_type) { + d_consume_type=cons_type; + } + + /*! + * \brief Set the consume limit. + * + * \param limit min or maximum items to consume (depending on + * consume_type) + */ + void set_consume_limit(unsigned int limit) { + d_min_consume=limit; d_max_consume=limit; + } + + /*! + * \brief Set the produce pattern. + * + * \param prod_type which produce pattern to use + */ + void set_produce_type(produce_type_t prod_type) { + d_produce_type=prod_type; + } + + /*! + * \brief Set the produce limit. + * + * \param limit min or maximum items to produce (depending on + * produce_type) + */ + void set_produce_limit(unsigned int limit) { + d_min_produce=limit; d_max_produce=limit; + } + + // ---------------------------------------------------------------------------- + + protected: + unsigned int d_sizeof_input_item; + unsigned int d_sizeof_output_item; + bool d_check_topology; + char d_temp; + consume_type_t d_consume_type; + int d_min_consume; + int d_max_consume; + produce_type_t d_produce_type; + int d_min_produce; + int d_max_produce; + test(const std::string &name,int min_inputs, int max_inputs, + unsigned int sizeof_input_item, + int min_outputs, int max_outputs, unsigned int sizeof_output_item, + unsigned int history, unsigned int output_multiple, double relative_rate, + bool fixed_rate, consume_type_t cons_type, produce_type_t prod_type); + + friend GR_RUNTIME_API test_sptr make_test(const std::string &name, + int min_inputs, int max_inputs, + unsigned int sizeof_input_item, + int min_outputs, int max_outputs, + unsigned int sizeof_output_item, + unsigned int history, + unsigned int output_multiple, + double relative_rate, + bool fixed_rate, + consume_type_t cons_type, + produce_type_t prod_type); + }; + +} /* namespace gr */ + +#endif /* INCLUDED_TEST_H */ diff --git a/gnuradio-runtime/lib/test_runtime.cc b/gnuradio-runtime/lib/test_runtime.cc index 7dc7b17ea0..c85d325174 100644 --- a/gnuradio-runtime/lib/test_runtime.cc +++ b/gnuradio-runtime/lib/test_runtime.cc @@ -27,7 +27,7 @@ #include <cppunit/TextTestRunner.h> #include <cppunit/XmlOutputter.h> -#include <gr_unittests.h> +#include <gnuradio/unittests.h> #include <qa_runtime.h> #include <pmt/qa_pmt.h> diff --git a/gnuradio-runtime/lib/gr_test_types.h b/gnuradio-runtime/lib/test_types.h index 04f38f7b26..868a9e62a3 100644 --- a/gnuradio-runtime/lib/gr_test_types.h +++ b/gnuradio-runtime/lib/test_types.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2006 Free Software Foundation, Inc. + * Copyright 2006,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -19,28 +19,33 @@ * the Free Software Foundation, Inc., 51 Franklin Street, * Boston, MA 02110-1301, USA. */ + #ifndef INCLUDED_GR_TEST_TYPES_H #define INCLUDED_GR_TEST_TYPES_H -typedef enum { - CONSUME_NOUTPUT_ITEMS=0, - CONSUME_NOUTPUT_ITEMS_LIMIT_MAX=1, - CONSUME_NOUTPUT_ITEMS_LIMIT_MIN=2, - CONSUME_ALL_AVAILABLE=3, - CONSUME_ALL_AVAILABLE_LIMIT_MAX=4, - /*CONSUME_ALL_AVAILABLE_LIMIT_MIN=5,*/ - CONSUME_ZERO=6, - CONSUME_ONE=7, - CONSUME_MINUS_ONE=8 - } gr_consume_type_t; +namespace gr { + + typedef enum { + CONSUME_NOUTPUT_ITEMS=0, + CONSUME_NOUTPUT_ITEMS_LIMIT_MAX=1, + CONSUME_NOUTPUT_ITEMS_LIMIT_MIN=2, + CONSUME_ALL_AVAILABLE=3, + CONSUME_ALL_AVAILABLE_LIMIT_MAX=4, + /*CONSUME_ALL_AVAILABLE_LIMIT_MIN=5,*/ + CONSUME_ZERO=6, + CONSUME_ONE=7, + CONSUME_MINUS_ONE=8 + } consume_type_t; + + typedef enum { + PRODUCE_NOUTPUT_ITEMS=0, + PRODUCE_NOUTPUT_ITEMS_LIMIT_MAX=1, + /*PRODUCE_NOUTPUT_ITEMS_LIMIT_MIN=2,*/ + PRODUCE_ZERO=6, + PRODUCE_ONE=7, + PRODUCE_MINUS_ONE=8 + } produce_type_t; -typedef enum { - PRODUCE_NOUTPUT_ITEMS=0, - PRODUCE_NOUTPUT_ITEMS_LIMIT_MAX=1, - /*PRODUCE_NOUTPUT_ITEMS_LIMIT_MIN=2,*/ - PRODUCE_ZERO=6, - PRODUCE_ONE=7, - PRODUCE_MINUS_ONE=8 - } gr_produce_type_t; +} /* namespace gr */ #endif /* INCLUDED_GR_TEST_TYPES_H */ diff --git a/gnuradio-runtime/lib/thread/thread.cc b/gnuradio-runtime/lib/thread/thread.cc index af0822445d..1727dc6621 100644 --- a/gnuradio-runtime/lib/thread/thread.cc +++ b/gnuradio-runtime/lib/thread/thread.cc @@ -23,7 +23,7 @@ #include <config.h> #endif -#include <thread/thread.h> +#include <gnuradio/thread/thread.h> #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) diff --git a/gnuradio-runtime/lib/thread/thread_body_wrapper.cc b/gnuradio-runtime/lib/thread/thread_body_wrapper.cc index 47feafdd42..e23b7d15d0 100644 --- a/gnuradio-runtime/lib/thread/thread_body_wrapper.cc +++ b/gnuradio-runtime/lib/thread/thread_body_wrapper.cc @@ -23,7 +23,7 @@ #include <config.h> #endif -#include <thread/thread_body_wrapper.h> +#include <gnuradio/thread/thread_body_wrapper.h> #ifdef HAVE_SIGNAL_H #include <signal.h> diff --git a/gnuradio-runtime/lib/thread/thread_group.cc b/gnuradio-runtime/lib/thread/thread_group.cc index 034fe82e75..e467dfda5a 100644 --- a/gnuradio-runtime/lib/thread/thread_group.cc +++ b/gnuradio-runtime/lib/thread/thread_group.cc @@ -12,7 +12,7 @@ * This was extracted from Boost 1.35.0 and fixed. */ -#include <thread/thread_group.h> +#include <gnuradio/thread/thread_group.h> namespace gr { namespace thread { diff --git a/gnuradio-runtime/lib/top_block.cc b/gnuradio-runtime/lib/top_block.cc new file mode 100644 index 0000000000..8d2e42bb12 --- /dev/null +++ b/gnuradio-runtime/lib/top_block.cc @@ -0,0 +1,167 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2013 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 "top_block_impl.h" +#include <gnuradio/top_block.h> +#include <gnuradio/io_signature.h> +#include <gnuradio/prefs.h> +#include <unistd.h> +#include <iostream> + +namespace gr { + top_block_sptr + make_top_block(const std::string &name) + { + return gnuradio::get_initial_sptr + (new top_block(name)); + } + + top_block::top_block(const std::string &name) + : hier_block2(name, + io_signature::make(0,0,0), + io_signature::make(0,0,0)) + { + d_impl = new top_block_impl(this); + } + + top_block::~top_block() + { + stop(); + wait(); + + delete d_impl; + } + + void + top_block::start(int max_noutput_items) + { + d_impl->start(max_noutput_items); + + if(prefs::singleton()->get_bool("ControlPort", "on", false)) { + setup_rpc(); + } + } + + void + top_block::stop() + { + d_impl->stop(); + } + + void + top_block::wait() + { + d_impl->wait(); + } + + void + top_block::run(int max_noutput_items) + { + start(max_noutput_items); + wait(); + } + + void + top_block::lock() + { + d_impl->lock(); + } + + void + top_block::unlock() + { + d_impl->unlock(); + } + + std::string + top_block::edge_list() + { + return d_impl->edge_list(); + } + + void + top_block::dump() + { + d_impl->dump(); + } + + int + top_block::max_noutput_items() + { + return d_impl->max_noutput_items(); + } + + void + top_block::set_max_noutput_items(int nmax) + { + d_impl->set_max_noutput_items(nmax); + } + + top_block_sptr + top_block::to_top_block() + { + return cast_to_top_block_sptr(shared_from_this()); + } + + void + top_block::setup_rpc() + { +#ifdef GR_CTRLPORT + if(is_rpc_set()) + return; + + // Getters + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<top_block, int>( + alias(), "max noutput_items", + &top_block::max_noutput_items, + pmt::mp(0), pmt::mp(8192), pmt::mp(8192), + "items", "Max number of output items", + RPC_PRIVLVL_MIN, DISPNULL))); + + if(prefs::singleton()->get_bool("ControlPort", "edges_list", false)) { + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_get<top_block, std::string>( + alias(), "edge list", + &top_block::edge_list, + pmt::mp(""), pmt::mp(""), pmt::mp(""), + "edges", "List of edges in the graph", + RPC_PRIVLVL_MIN, DISPNULL))); + } + + // Setters + add_rpc_variable( + rpcbasic_sptr(new rpcbasic_register_set<top_block, int>( + alias(), "max noutput_items", + &top_block::set_max_noutput_items, + pmt::mp(0), pmt::mp(8192), pmt::mp(8192), + "items", "Max number of output items", + RPC_PRIVLVL_MIN, DISPNULL))); + rpc_set(); +#endif /* GR_CTRLPORT */ + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/top_block_impl.cc b/gnuradio-runtime/lib/top_block_impl.cc new file mode 100644 index 0000000000..9d377f469f --- /dev/null +++ b/gnuradio-runtime/lib/top_block_impl.cc @@ -0,0 +1,212 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008,2013 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 "top_block_impl.h" +#include "flat_flowgraph.h" +#include "scheduler_sts.h" +#include "scheduler_tpb.h" +#include <gnuradio/top_block.h> +#include <gnuradio/prefs.h> + +#include <stdexcept> +#include <iostream> +#include <string.h> +#include <unistd.h> +#include <stdlib.h> + +namespace gr { + +#define GR_TOP_BLOCK_IMPL_DEBUG 0 + + typedef scheduler_sptr(*scheduler_maker)(flat_flowgraph_sptr ffg, + int max_noutput_items); + + static struct scheduler_table { + const char *name; + scheduler_maker f; + } scheduler_table[] = { + { "TPB", scheduler_tpb::make }, // first entry is default + { "STS", scheduler_sts::make } + }; + + static scheduler_sptr + make_scheduler(flat_flowgraph_sptr ffg, int max_noutput_items) + { + static scheduler_maker factory = 0; + + if(factory == 0) { + char *v = getenv("GR_SCHEDULER"); + if(!v) + factory = scheduler_table[0].f; // use default + else { + for(size_t i = 0; i < sizeof(scheduler_table)/sizeof(scheduler_table[0]); i++) { + if(strcmp(v, scheduler_table[i].name) == 0) { + factory = scheduler_table[i].f; + break; + } + } + if(factory == 0) { + std::cerr << "warning: Invalid GR_SCHEDULER environment variable value \"" + << v << "\". Using \"" << scheduler_table[0].name << "\"\n"; + factory = scheduler_table[0].f; + } + } + } + return factory(ffg, max_noutput_items); + } + + top_block_impl::top_block_impl(top_block *owner) + : d_owner(owner), d_ffg(), + d_state(IDLE), d_lock_count(0) + { + } + + top_block_impl::~top_block_impl() + { + d_owner = 0; + } + + void + top_block_impl::start(int max_noutput_items) + { + gr::thread::scoped_lock l(d_mutex); + + d_max_noutput_items = max_noutput_items; + + if(d_state != IDLE) + throw std::runtime_error("top_block::start: top block already running or wait() not called after previous stop()"); + + if(d_lock_count > 0) + throw std::runtime_error("top_block::start: can't start with flow graph locked"); + + // Create new flat flow graph by flattening hierarchy + d_ffg = d_owner->flatten(); + + // Validate new simple flow graph and wire it up + d_ffg->validate(); + d_ffg->setup_connections(); + + // Only export perf. counters if ControlPort config param is + // enabled and if the PerfCounter option 'export' is turned on. + prefs *p = prefs::singleton(); + if(p->get_bool("ControlPort", "on", false) && p->get_bool("PerfCounters", "export", false)) + d_ffg->enable_pc_rpc(); + + d_scheduler = make_scheduler(d_ffg, d_max_noutput_items); + d_state = RUNNING; + } + + void + top_block_impl::stop() + { + if(d_scheduler) + d_scheduler->stop(); + } + + void + top_block_impl::wait() + { + if(d_scheduler) + d_scheduler->wait(); + + d_state = IDLE; + } + + // N.B. lock() and unlock() cannot be called from a flow graph + // thread or deadlock will occur when reconfiguration happens + void + top_block_impl::lock() + { + gr::thread::scoped_lock lock(d_mutex); + d_lock_count++; + } + + void + top_block_impl::unlock() + { + gr::thread::scoped_lock lock(d_mutex); + + if(d_lock_count <= 0) { + d_lock_count = 0; // fix it, then complain + throw std::runtime_error("unpaired unlock() call"); + } + + d_lock_count--; + if(d_lock_count > 0 || d_state == IDLE) // nothing to do + return; + + restart(); + } + + /* + * restart is called with d_mutex held + */ + void + top_block_impl::restart() + { + stop(); // Stop scheduler and wait for completion + wait(); + + // Create new simple flow graph + flat_flowgraph_sptr new_ffg = d_owner->flatten(); + new_ffg->validate(); // check consistency, sanity, etc + new_ffg->merge_connections(d_ffg); // reuse buffers, etc + d_ffg = new_ffg; + + // Create a new scheduler to execute it + d_scheduler = make_scheduler(d_ffg, d_max_noutput_items); + d_state = RUNNING; + } + + std::string + top_block_impl::edge_list() + { + if(d_ffg) + return d_ffg->edge_list(); + else + return ""; + } + + void + top_block_impl::dump() + { + if(d_ffg) + d_ffg->dump(); + } + + int + top_block_impl::max_noutput_items() + { + return d_max_noutput_items; + } + + void + top_block_impl::set_max_noutput_items(int nmax) + { + d_max_noutput_items = nmax; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/top_block_impl.h b/gnuradio-runtime/lib/top_block_impl.h new file mode 100644 index 0000000000..9e0e661a02 --- /dev/null +++ b/gnuradio-runtime/lib/top_block_impl.h @@ -0,0 +1,90 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2008,2013 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 <gnuradio/api.h> +#include "scheduler.h" +#include <gnuradio/thread/thread.h> + +namespace gr { + + /*! + *\brief Abstract implementation details of top_block + * \ingroup internal + * + * The actual implementation of top_block. Separate class allows + * decoupling of changes from dependent classes. + */ + class GR_RUNTIME_API top_block_impl + { + public: + top_block_impl(top_block *owner); + ~top_block_impl(); + + // Create and start scheduler threads + void start(int max_noutput_items=100000000); + + // 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(); + + // Return a string list of edges + std::string edge_list(); + + // Dump the flowgraph to stdout + void dump(); + + // Get the number of max noutput_items in the flowgraph + int max_noutput_items(); + + // Set the maximum number of noutput_items in the flowgraph + void set_max_noutput_items(int nmax); + + protected: + enum tb_state { IDLE, RUNNING }; + + top_block *d_owner; + flat_flowgraph_sptr d_ffg; + scheduler_sptr d_scheduler; + + gr::thread::mutex d_mutex; // protects d_state and d_lock_count + tb_state d_state; + int d_lock_count; + int d_max_noutput_items; + + private: + void restart(); + }; + +} /* namespace gr */ + +#endif /* INCLUDED_GR_TOP_BLOCK_IMPL_H */ diff --git a/gnuradio-runtime/lib/tpb_detail.cc b/gnuradio-runtime/lib/tpb_detail.cc new file mode 100644 index 0000000000..cf05c2b102 --- /dev/null +++ b/gnuradio-runtime/lib/tpb_detail.cc @@ -0,0 +1,71 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2013 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <gnuradio/tpb_detail.h> +#include <gnuradio/block.h> +#include <gnuradio/block_detail.h> +#include <gnuradio/buffer.h> + +namespace gr { + + /* + * We assume that no worker threads are ever running when the graph + * structure is being manipulated, thus it's safe for us to poke + * around in our neighbors w/o holding any locks. + */ + void + tpb_detail::notify_upstream(block_detail *d) + { + // For each of our inputs, tell the guy upstream that we've + // consumed some input, and that he most likely has more output + // buffer space available. + + for(size_t i = 0; i < d->d_input.size(); i++) { + // Can you say, "pointer chasing?" + d->d_input[i]->buffer()->link()->detail()->d_tpb.set_output_changed(); + } + } + + void + tpb_detail::notify_downstream(block_detail *d) + { + // For each of our outputs, tell the guys downstream that they + // have new input available. + + for(size_t i = 0; i < d->d_output.size(); i++) { + buffer_sptr buf = d->d_output[i]; + for(size_t j = 0, k = buf->nreaders(); j < k; j++) + buf->reader(j)->link()->detail()->d_tpb.set_input_changed(); + } + } + + void + tpb_detail::notify_neighbors(block_detail *d) + { + notify_downstream(d); + notify_upstream(d); + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/tpb_thread_body.cc b/gnuradio-runtime/lib/tpb_thread_body.cc new file mode 100644 index 0000000000..ceb94fbb2a --- /dev/null +++ b/gnuradio-runtime/lib/tpb_thread_body.cc @@ -0,0 +1,151 @@ +/* -*- c++ -*- */ +/* + * Copyright 2008,2009,2011,2013 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 this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "tpb_thread_body.h" +#include <gnuradio/prefs.h> +#include <boost/thread.hpp> +#include <boost/foreach.hpp> +#include <pmt/pmt.h> +#include <iostream> + +namespace gr { + + tpb_thread_body::tpb_thread_body(block_sptr block, int max_noutput_items) + : d_exec(block, max_noutput_items) + { + //std::cerr << "tpb_thread_body: " << block << std::endl; + + block_detail *d = block->detail().get(); + block_executor::state s; + pmt::pmt_t msg; + + d->threaded = true; + d->thread = gr::thread::get_current_thread_id(); + + prefs *p = prefs::singleton(); + size_t max_nmsgs = static_cast<size_t>(p->get_long("DEFAULT", "max_messages", 100)); + + // Set thread affinity if it was set before fg was started. + if(block->processor_affinity().size() > 0) { + gr::thread::thread_bind_to_processor(d->thread, block->processor_affinity()); + } + + while(1) { + boost::this_thread::interruption_point(); + + // handle any queued up messages + //BOOST_FOREACH( pmt::pmt_t port, block->msg_queue.keys() ) + + BOOST_FOREACH(basic_block::msg_queue_map_t::value_type &i, block->msg_queue) { + // Check if we have a message handler attached before getting + // any messages. This is mostly a protection for the unknown + // startup sequence of the threads. + if(block->has_msg_handler(i.first)) { + while((msg = block->delete_head_nowait(i.first))) { + block->dispatch_msg(i.first,msg); + } + } + else { + // If we don't have a handler but are building up messages, + // prune the queue from the front to keep memory in check. + if(block->nmsgs(i.first) > max_nmsgs) + msg = block->delete_head_nowait(i.first); + } + } + + d->d_tpb.clear_changed(); + // run one iteration if we are a connected stream block + if(d->noutputs() >0 || d->ninputs()>0){ + s = d_exec.run_one_iteration(); + } + else { + s = block_executor::BLKD_IN; + } + + switch(s){ + case block_executor::READY: // Tell neighbors we made progress. + d->d_tpb.notify_neighbors(d); + break; + + case block_executor::READY_NO_OUTPUT: // Notify upstream only + d->d_tpb.notify_upstream(d); + break; + + case block_executor::DONE: // Game over. + d->d_tpb.notify_neighbors(d); + return; + + case block_executor::BLKD_IN: // Wait for input. + { + gr::thread::scoped_lock guard(d->d_tpb.mutex); + while(!d->d_tpb.input_changed) { + + // wait for input or message + while(!d->d_tpb.input_changed && block->empty_p()) + d->d_tpb.input_cond.wait(guard); + + // handle all pending messages + BOOST_FOREACH(basic_block::msg_queue_map_t::value_type &i, block->msg_queue) { + while((msg = block->delete_head_nowait(i.first))) { + guard.unlock(); // release lock while processing msg + block->dispatch_msg(i.first, msg); + guard.lock(); + } + } + } + } + break; + + case block_executor::BLKD_OUT: // Wait for output buffer space. + { + gr::thread::scoped_lock guard(d->d_tpb.mutex); + while(!d->d_tpb.output_changed) { + // wait for output room or message + while(!d->d_tpb.output_changed && block->empty_p()) + d->d_tpb.output_cond.wait(guard); + + // handle all pending messages + BOOST_FOREACH(basic_block::msg_queue_map_t::value_type &i, block->msg_queue) { + while((msg = block->delete_head_nowait(i.first))) { + guard.unlock(); // release lock while processing msg + block->dispatch_msg(i.first,msg); + guard.lock(); + } + } + } + } + break; + + default: + assert(0); + } + } + } + + tpb_thread_body::~tpb_thread_body() + { + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gr_tpb_thread_body.h b/gnuradio-runtime/lib/tpb_thread_body.h index 6ecb022f69..9859b125dd 100644 --- a/gnuradio-runtime/lib/gr_tpb_thread_body.h +++ b/gnuradio-runtime/lib/tpb_thread_body.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2008 Free Software Foundation, Inc. + * Copyright 2008,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -21,26 +21,29 @@ #ifndef INCLUDED_GR_TPB_THREAD_BODY_H #define INCLUDED_GR_TPB_THREAD_BODY_H -#include <gr_runtime_api.h> -#include <gr_block_executor.h> -#include <gr_block.h> -#include <gr_block_detail.h> +#include <gnuradio/api.h> +#include <gnuradio/block.h> +#include <gnuradio/block_detail.h> +#include "block_executor.h" -/*! - * \brief The body of each thread-per-block thread. - * - * One of these is instantiated in its own thread for each block. The - * constructor turns into the main loop which returns when the block is - * done or is interrupted. - */ +namespace gr { -class GR_RUNTIME_API gr_tpb_thread_body { - gr_block_executor d_exec; + /*! + * \brief The body of each thread-per-block thread. + * + * One of these is instantiated in its own thread for each block. + * The constructor turns into the main loop which returns when the + * block is done or is interrupted. + */ + class GR_RUNTIME_API tpb_thread_body + { + block_executor d_exec; -public: - gr_tpb_thread_body(gr_block_sptr block, int max_noutput_items=100000); - ~gr_tpb_thread_body(); -}; + public: + tpb_thread_body(block_sptr block, int max_noutput_items=100000); + ~tpb_thread_body(); + }; +} /* namespace gr */ #endif /* INCLUDED_GR_TPB_THREAD_BODY_H */ diff --git a/gnuradio-runtime/lib/vmcircbuf.cc b/gnuradio-runtime/lib/vmcircbuf.cc new file mode 100644 index 0000000000..0fccb3d914 --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf.cc @@ -0,0 +1,299 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2013 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 <assert.h> +#include <stdexcept> +#include <stdio.h> +#include <string.h> +#include <vector> +#include <boost/format.hpp> +#include "vmcircbuf.h" +#include "vmcircbuf_prefs.h" +#include "local_sighandler.h" + +// all the factories we know about +#include "vmcircbuf_createfilemapping.h" +#include "vmcircbuf_sysv_shm.h" +#include "vmcircbuf_mmap_shm_open.h" +#include "vmcircbuf_mmap_tmpfile.h" + +namespace gr { + + static const char *FACTORY_PREF_KEY = "vmcircbuf_default_factory"; + + vmcircbuf::~vmcircbuf() + { + } + + vmcircbuf_factory::~vmcircbuf_factory() + { + } + + // ---------------------------------------------------------------- + + static vmcircbuf_factory *s_default_factory = 0; + + vmcircbuf_factory * + vmcircbuf_sysconfig::get_default_factory() + { + if(s_default_factory) + return s_default_factory; + + bool verbose = false; + + std::vector<gr::vmcircbuf_factory *> all = all_factories (); + + const char *name = gr::vmcircbuf_prefs::get(FACTORY_PREF_KEY); + + if(name) { + for(unsigned int i = 0; i < all.size (); i++) { + if(strcmp(name, all[i]->name ()) == 0) { + s_default_factory = all[i]; + if(verbose) + fprintf(stderr, "gr::vmcircbuf_sysconfig: using %s\n", + s_default_factory->name()); + return s_default_factory; + } + } + } + + // either we don't have a default, or the default named is not in our + // list of factories. Find the first factory that works. + + if(verbose) + fprintf(stderr, "gr::vmcircbuf_sysconfig: finding a working factory...\n"); + + for(unsigned int i = 0; i < all.size (); i++) { + if(test_factory(all[i], verbose)) { + set_default_factory(all[i]); + return s_default_factory; + } + } + + // We're screwed! + fprintf(stderr, "gr::vmcircbuf_sysconfig: unable to find a working factory!\n"); + throw std::runtime_error("gr::vmcircbuf_sysconfig"); + } + + std::vector<vmcircbuf_factory *> + vmcircbuf_sysconfig::all_factories() + { + std::vector<vmcircbuf_factory*> result; + + result.push_back(gr::vmcircbuf_createfilemapping_factory::singleton()); +#ifdef TRY_SHM_VMCIRCBUF + result.push_back(gr::vmcircbuf_sysv_shm_factory::singleton()); + result.push_back(gr::vmcircbuf_mmap_shm_open_factory::singleton()); +#endif + result.push_back (gr::vmcircbuf_mmap_tmpfile_factory::singleton()); + + return result; + } + + void + vmcircbuf_sysconfig::set_default_factory(vmcircbuf_factory *f) + { + gr::vmcircbuf_prefs::set(FACTORY_PREF_KEY, f->name()); + s_default_factory = f; + } + + + // ------------------------------------------------------------------------ + // test code for vmcircbuf factories + // ------------------------------------------------------------------------ + + static void + init_buffer(vmcircbuf *c, int counter, int size) + { + unsigned int *p = (unsigned int*)c->pointer_to_first_copy(); + for(unsigned int i = 0; i < size / sizeof(int); i++) + p[i] = counter + i; + } + + static bool + check_mapping(vmcircbuf *c, int counter, int size, const char *msg, bool verbose) + { + bool ok = true; + + if(verbose) + fprintf(stderr, "... %s", msg); + + unsigned int *p1 = (unsigned int *)c->pointer_to_first_copy(); + unsigned int *p2 = (unsigned int *)c->pointer_to_second_copy(); + + // fprintf(stderr, "p1 = %p, p2 = %p\n", p1, p2); + + for(unsigned int i = 0; i < size / sizeof (int); i++) { + if(p1[i] != counter + i) { + ok = false; + if(verbose) + fprintf(stderr, " p1[%d] == %u, expected %u\n", i, p1[i], counter + i); + break; + } + if(p2[i] != counter + i) { + if(verbose) + fprintf(stderr, " p2[%d] == %u, expected %u\n", i, p2[i], counter + i); + ok = false; + break; + } + } + + if(ok && verbose) { + fprintf(stderr, " OK\n"); + } + return ok; + } + + static const char * + memsize(int size) + { + static std::string buf; + if(size >= (1 << 20)) { + buf = str(boost::format("%dMB") % (size / (1 << 20))); + } + else if(size >= (1 << 10)){ + buf = str(boost::format("%dKB") % (size / (1 << 10))); + } + else { + buf = str(boost::format("%d") % size); + } + return buf.c_str(); + } + + static bool + test_a_bunch(vmcircbuf_factory *factory, int n, int size, int *start_ptr, bool verbose) + { + bool ok = true; + std::vector<int> counter(n); + std::vector<vmcircbuf*> c(n); + int cum_size = 0; + + for(int i = 0; i < n; i++) { + counter[i] = *start_ptr; + *start_ptr += size; + if((c[i] = factory->make (size)) == 0) { + if(verbose) + fprintf(stderr, + "Failed to allocate gr::vmcircbuf number %d of size %d (cum = %s)\n", + i + 1, size, memsize(cum_size)); + return false; + } + init_buffer(c[i], counter[i], size); + cum_size += size; + } + + for(int i = 0; i < n; i++) { + std::string msg = str(boost::format("test_a_bunch_%dx%s[%d]") % n % memsize(size) % i); + ok &= check_mapping(c[i], counter[i], size, msg.c_str(), verbose); + } + + for(int i = 0; i < n; i++) { + delete c[i]; + c[i] = 0; + } + + return ok; + } + + static bool + standard_tests(vmcircbuf_factory *f, int verbose) + { + if(verbose >= 1) + fprintf(stderr, "Testing %s...\n", f->name()); + + bool v = verbose >= 2; + int granularity = f->granularity(); + int start = 0; + bool ok = true; + + ok &= test_a_bunch(f, 1, 1 * granularity, &start, v); // 1 x 4KB = 4KB + + if(ok) { + ok &= test_a_bunch(f, 64, 4 * granularity, &start, v); // 64 x 16KB = 1MB + ok &= test_a_bunch(f, 4, 4 * (1L << 20), &start, v); // 4 x 4MB = 16MB + // ok &= test_a_bunch(f, 256, 256 * (1L << 10), &start, v); // 256 x 256KB = 64MB + } + + if(verbose >= 1) + fprintf(stderr, "....... %s: %s", f->name(), ok ? "OK\n" : "Doesn't work\n"); + + return ok; + } + + bool + vmcircbuf_sysconfig::test_factory(vmcircbuf_factory *f, int verbose) + { + // Install local signal handlers for SIGSEGV and SIGBUS. + // If something goes wrong, these signals may be invoked. + +#ifdef SIGSEGV + gr::local_sighandler sigsegv (SIGSEGV, gr::local_sighandler::throw_signal); +#endif +#ifdef SIGBUS + gr::local_sighandler sigbus (SIGBUS, gr::local_sighandler::throw_signal); +#endif +#ifdef SIGSYS + gr::local_sighandler sigsys (SIGSYS, gr::local_sighandler::throw_signal); +#endif + + try { + return standard_tests (f, verbose); + } + catch(gr::signal &sig) { + if(verbose) { + fprintf(stderr, "....... %s: %s", f->name(), "Doesn't work\n"); + fprintf(stderr, + "gr::vmcircbuf_factory::test_factory (%s): caught %s\n", + f->name(), sig.name().c_str()); + return false; + } + } + catch (...) { + if(verbose) { + fprintf(stderr, "....... %s: %s", f->name(), "Doesn't work\n"); + fprintf(stderr, + "gr::vmcircbuf_factory::test_factory (%s): some kind of uncaught exception\n", + f->name()); + } + return false; + } + return false; // never gets here. shut compiler up. + } + + bool + vmcircbuf_sysconfig::test_all_factories(int verbose) + { + bool ok = false; + + std::vector<vmcircbuf_factory *> all = all_factories(); + + for(unsigned int i = 0; i < all.size (); i++) + ok |= test_factory(all[i], verbose); + + return ok; + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/vmcircbuf.h b/gnuradio-runtime/lib/vmcircbuf.h new file mode 100644 index 0000000000..c3ddfe0043 --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf.h @@ -0,0 +1,125 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2013 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 GR_VMCIRCBUF_H +#define GR_VMCIRCBUF_H + +#include <gnuradio/api.h> +#include <vector> + +namespace gr { + + /*! + * \brief abstract class to implement doubly mapped virtual memory circular buffers + * \ingroup internal + */ + class GR_RUNTIME_API vmcircbuf + { + protected: + int d_size; + char *d_base; + + // CREATORS + vmcircbuf(int size) : d_size(size), d_base(0) {}; + + public: + virtual ~vmcircbuf(); + + // ACCESSORS + void *pointer_to_first_copy() const{ return d_base; } + void *pointer_to_second_copy() const{ return d_base + d_size; } + }; + + /*! + * \brief abstract factory for creating circular buffers + */ + class GR_RUNTIME_API vmcircbuf_factory + { + protected: + vmcircbuf_factory() {}; + virtual ~vmcircbuf_factory(); + + public: + + /*! + * \brief return name of this factory + */ + virtual const char *name() const = 0; + + /*! + * \brief return granularity of mapping, typically equal to page size + */ + virtual int granularity() = 0; + + /*! + * \brief return a gr::vmcircbuf, or 0 if unable. + * + * Call this to create a doubly mapped circular buffer. + */ + virtual vmcircbuf *make(int size) = 0; + }; + + /* + * \brief pulls together all implementations of gr::vmcircbuf + */ + class GR_RUNTIME_API vmcircbuf_sysconfig + { + public: + /* + * \brief return the single instance of the default factory. + * + * returns the default factory to use if it's already defined, + * else find the first working factory and use it. + */ + static vmcircbuf_factory *get_default_factory(); + + static int granularity() { return get_default_factory()->granularity(); } + static vmcircbuf *make(int size) { return get_default_factory()->make(size); } + + // N.B. not all factories are guaranteed to work. + // It's too hard to check everything at config time, so we check at runtime + static std::vector<vmcircbuf_factory*> all_factories(); + + // make this factory the default + static void set_default_factory(vmcircbuf_factory *f); + + /*! + * \brief Does this factory really work? + * + * verbose = 0: silent + * verbose = 1: names of factories tested and results + * verbose = 2: all intermediate results + */ + static bool test_factory(vmcircbuf_factory *f, int verbose); + + /*! + * \brief Test all factories, return true if at least one of them works + * verbose = 0: silent + * verbose = 1: names of factories tested and results + * verbose = 2: all intermediate results + */ + static bool test_all_factories(int verbose); + }; + +} /* namespace gr */ + +#endif /* GR_VMCIRCBUF_H */ diff --git a/gnuradio-runtime/lib/vmcircbuf_createfilemapping.cc b/gnuradio-runtime/lib/vmcircbuf_createfilemapping.cc new file mode 100644 index 0000000000..2d345a29b1 --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf_createfilemapping.cc @@ -0,0 +1,204 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2005,2011,2013 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 <stdexcept> +#include <assert.h> +#include <unistd.h> +#include <fcntl.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <errno.h> +#include <stdio.h> +#include "pagesize.h" +#include "vmcircbuf_createfilemapping.h" +#include <boost/format.hpp> + +namespace gr { + +#ifdef HAVE_CREATEFILEMAPPING + // Print Windows error (could/should be global?) + static void + werror(char *where, DWORD last_error) + { + char buf[1024]; + + FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + last_error, + 0, // default language + buf, + sizeof(buf)/sizeof(TCHAR), // buffer size + NULL); + fprintf(stderr, "%s: Error %d: %s", where, last_error, buf); + return; + } +#endif + + + vmcircbuf_createfilemapping::vmcircbuf_createfilemapping(int size) + : gr::vmcircbuf(size) + { +#if !defined(HAVE_CREATEFILEMAPPING) + fprintf(stderr, "%s: createfilemapping is not available\n", __FUNCTION__); + throw std::runtime_error("gr::vmcircbuf_createfilemapping"); +#else + static int s_seg_counter = 0; + + if(size <= 0 || (size % gr::pagesize ()) != 0) { + fprintf(stderr, "gr::vmcircbuf_createfilemapping: invalid size = %d\n", size); + throw std::runtime_error ("gr::vmcircbuf_createfilemapping"); + } + + std::string seg_name = str(boost::format("/gnuradio-%d-%d") % getpid() % s_seg_counter); + + d_handle = CreateFileMapping(INVALID_HANDLE_VALUE, // use paging file + NULL, // default security + PAGE_READWRITE, // read/write access + 0, // max. object size + size, // buffer size + seg_name.c_str()); // name of mapping object + + s_seg_counter++; + if(d_handle == NULL || d_handle == INVALID_HANDLE_VALUE) { + std::string msg = str(boost::format( + "gr::vmcircbuf_mmap_createfilemapping: CreateFileMapping [%s]") % + seg_name); + werror((char*)msg.c_str(), GetLastError()); + throw std::runtime_error("gr::vmcircbuf_mmap_createfilemapping"); + } + + // Allocate virtual memory of the needed size, then free it so we can use it + LPVOID first_tmp; + first_tmp = VirtualAlloc( NULL, 2*size, MEM_RESERVE, PAGE_NOACCESS ); + if(first_tmp == NULL) { + werror("gr::vmcircbuf_mmap_createfilemapping: VirtualAlloc", GetLastError()); + CloseHandle(d_handle); // cleanup + throw std::runtime_error("gr::vmcircbuf_mmap_createfilemapping"); + } + + if(VirtualFree(first_tmp, 0, MEM_RELEASE) == 0) { + werror("gr::vmcircbuf_mmap_createfilemapping: VirtualFree", GetLastError()); + CloseHandle(d_handle); // cleanup + throw std::runtime_error("gr::vmcircbuf_mmap_createfilemapping"); + } + + d_first_copy = MapViewOfFileEx((HANDLE)d_handle, // handle to map object + FILE_MAP_WRITE, // read/write permission + 0, + 0, + size, + first_tmp); + if(d_first_copy != first_tmp) { + werror( "gr::vmcircbuf_mmap_createfilemapping: MapViewOfFileEx(1)", GetLastError()); + CloseHandle(d_handle); // cleanup + throw std::runtime_error ("gr::vmcircbuf_mmap_createfilemapping"); + } + + d_second_copy = MapViewOfFileEx((HANDLE)d_handle, // handle to map object + FILE_MAP_WRITE, // read/write permission + 0, + 0, + size, + (char*)first_tmp + size);//(LPVOID) ((char *)d_first_copy + size)); + + if(d_second_copy != (char *)first_tmp + size) { + werror( "gr::vmcircbuf_mmap_createfilemapping: MapViewOfFileEx(2)", GetLastError()); + UnmapViewOfFile(d_first_copy); + CloseHandle(d_handle); // cleanup + throw std::runtime_error ("gr::vmcircbuf_mmap_createfilemapping"); + } + +#ifdef DEBUG + fprintf(stderr,"gr::vmcircbuf_mmap_createfilemapping: contiguous? mmap %p %p %p %p\n", + (char*)d_first_copy, (char*)d_second_copy, size, (char*)d_first_copy + size); +#endif + + // Now remember the important stuff + d_base = (char*)d_first_copy; + d_size = size; +#endif /*HAVE_CREATEFILEMAPPING*/ + } + + vmcircbuf_createfilemapping::~vmcircbuf_createfilemapping() + { +#ifdef HAVE_CREATEFILEMAPPING + if(UnmapViewOfFile(d_first_copy) == 0) { + werror("gr::vmcircbuf_createfilemapping: UnmapViewOfFile(d_first_copy)", GetLastError()); + } + d_base=NULL; + if(UnmapViewOfFile(d_second_copy) == 0) { + werror("gr::vmcircbuf_createfilemapping: UnmapViewOfFile(d_second_copy)", GetLastError()); + } + //d_second=NULL; + CloseHandle(d_handle); +#endif + } + + // ---------------------------------------------------------------- + // The factory interface + // ---------------------------------------------------------------- + + gr::vmcircbuf_factory *vmcircbuf_createfilemapping_factory::s_the_factory = 0; + + gr::vmcircbuf_factory * + vmcircbuf_createfilemapping_factory::singleton() + { + if(s_the_factory) + return s_the_factory; + s_the_factory = new vmcircbuf_createfilemapping_factory(); + return s_the_factory; + } + + int + vmcircbuf_createfilemapping_factory::granularity() + { +#ifdef HAVE_CREATEFILEMAPPING + // return 65536;//TODO, check, is this needed or can we just use gr::pagesize() + SYSTEM_INFO system_info; + GetSystemInfo(&system_info); + //fprintf(stderr,"win32 AllocationGranularity %p\n",(int)system_info.dwAllocationGranularity); + return (int)system_info.dwAllocationGranularity; +#else + return gr::pagesize(); +#endif + } + + gr::vmcircbuf * + vmcircbuf_createfilemapping_factory::make(int size) + { + try { + return new vmcircbuf_createfilemapping(size); + } + catch(...) { + return 0; + } + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/vmcircbuf_createfilemapping.h b/gnuradio-runtime/lib/vmcircbuf_createfilemapping.h new file mode 100644 index 0000000000..0513112f23 --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf_createfilemapping.h @@ -0,0 +1,81 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2005,2013 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 GR_VMCIRCBUF_CREATEFILEMAPPING_H +#define GR_VMCIRCBUF_CREATEFILEMAPPING_H + +#include <gnuradio/api.h> +#include "vmcircbuf.h" + +#ifdef HAVE_CREATEFILEMAPPING +#include <windows.h> +#endif + +namespace gr { + + /*! + * \brief concrete class to implement circular buffers with mmap and shm_open + * \ingroup internal + */ + class GR_RUNTIME_API vmcircbuf_createfilemapping : public gr::vmcircbuf + { + public: + // CREATORS + vmcircbuf_createfilemapping(int size); + virtual ~vmcircbuf_createfilemapping(); +#ifdef HAVE_CREATEFILEMAPPING + private: + HANDLE d_handle; + LPVOID d_first_copy; + LPVOID d_second_copy; +#endif + }; + + /*! + * \brief concrete factory for circular buffers built using mmap and shm_open + */ + class GR_RUNTIME_API vmcircbuf_createfilemapping_factory : public gr::vmcircbuf_factory + { + private: + static gr::vmcircbuf_factory *s_the_factory; + + public: + static gr::vmcircbuf_factory *singleton(); + + virtual const char *name() const { return "gr::vmcircbuf_createfilemapping_factory"; } + + /*! + * \brief return granularity of mapping, typically equal to page size + */ + virtual int granularity(); + + /*! + * \brief return a gr::vmcircbuf, or 0 if unable. + * + * Call this to create a doubly mapped circular buffer. + */ + virtual gr::vmcircbuf *make(int size); + }; + +} /* namespace gr */ + +#endif /* GR_VMCIRCBUF_CREATEFILEMAPPING_H */ diff --git a/gnuradio-runtime/lib/vmcircbuf_mmap_shm_open.cc b/gnuradio-runtime/lib/vmcircbuf_mmap_shm_open.cc new file mode 100644 index 0000000000..7b461bc26b --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf_mmap_shm_open.cc @@ -0,0 +1,204 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2011,2013 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 "vmcircbuf_mmap_shm_open.h" +#include <stdexcept> +#include <assert.h> +#include <unistd.h> +#include <fcntl.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <errno.h> +#include <stdio.h> +#include "pagesize.h" +#include <gnuradio/sys_paths.h> + +namespace gr { + + vmcircbuf_mmap_shm_open::vmcircbuf_mmap_shm_open(int size) + : gr::vmcircbuf(size) + { +#if !defined(HAVE_MMAP) || !defined(HAVE_SHM_OPEN) + fprintf(stderr, "gr::vmcircbuf_mmap_shm_open: mmap or shm_open is not available\n"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); +#else + static int s_seg_counter = 0; + + if(size <= 0 || (size % gr::pagesize ()) != 0) { + fprintf(stderr, "gr::vmcircbuf_mmap_shm_open: invalid size = %d\n", size); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + + int shm_fd = -1; + char seg_name[1024]; + static bool portable_format = true; + + // open a new named shared memory segment + while(1) { + if(portable_format) { + + // This is the POSIX recommended "portable format". + // Of course the "portable format" doesn't work on some systems... + + snprintf(seg_name, sizeof(seg_name), + "/gnuradio-%d-%d", getpid(), s_seg_counter); + } + else { + + // Where the "portable format" doesn't work, we try building + // a full filesystem pathname pointing into a suitable temporary directory. + + snprintf(seg_name, sizeof(seg_name), + "%s/gnuradio-%d-%d", gr::tmp_path(), getpid(), s_seg_counter); + } + + shm_fd = shm_open(seg_name, O_RDWR | O_CREAT | O_EXCL, 0600); + if(shm_fd == -1 && errno == EACCES && portable_format) { + portable_format = false; + continue; // try again using "non-portable format" + } + + s_seg_counter++; + + if(shm_fd == -1) { + if(errno == EEXIST) // Named segment already exists (shouldn't happen). Try again + continue; + + char msg[1024]; + snprintf(msg, sizeof(msg), "gr::vmcircbuf_mmap_shm_open: shm_open [%s]", seg_name); + perror(msg); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + break; + } + + // We've got a new shared memory segment fd open. + // Now set it's length to 2x what we really want and mmap it in. + if(ftruncate(shm_fd, (off_t)2 * size) == -1) { + close(shm_fd); // cleanup + perror("gr::vmcircbuf_mmap_shm_open: ftruncate (1)"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + + void *first_copy = mmap(0, 2 * size, + PROT_READ | PROT_WRITE, MAP_SHARED, + shm_fd, (off_t) 0); + + if(first_copy == MAP_FAILED) { + close(shm_fd); // cleanup + perror("gr::vmcircbuf_mmap_shm_open: mmap (1)"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + + // unmap the 2nd half + if(munmap ((char *) first_copy + size, size) == -1) { + close(shm_fd); // cleanup + perror("gr::vmcircbuf_mmap_shm_open: munmap (1)"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + + // map the first half into the now available hole where the + // second half used to be. + void *second_copy = mmap((char*)first_copy + size, size, + PROT_READ | PROT_WRITE, MAP_SHARED, + shm_fd, (off_t)0); + + if(second_copy == MAP_FAILED) { + close(shm_fd); // cleanup + perror("gr::vmcircbuf_mmap_shm_open: mmap (2)"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + +#if 0 // OS/X doesn't allow you to resize the segment + + // cut the shared memory segment down to size + if(ftruncate(shm_fd, (off_t)size) == -1) { + close(shm_fd); // cleanup + perror("gr::vmcircbuf_mmap_shm_open: ftruncate (2)"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } +#endif + + close(shm_fd); // fd no longer needed. The mapping is retained. + + if(shm_unlink(seg_name) == -1) { // unlink the seg_name. + perror("gr::vmcircbuf_mmap_shm_open: shm_unlink"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + + // Now remember the important stuff + d_base = (char*)first_copy; + d_size = size; +#endif + } + + vmcircbuf_mmap_shm_open::~vmcircbuf_mmap_shm_open() + { +#if defined(HAVE_MMAP) + if(munmap (d_base, 2 * d_size) == -1) { + perror("gr::vmcircbuf_mmap_shm_open: munmap (2)"); + } +#endif + } + + // ---------------------------------------------------------------- + // The factory interface + // ---------------------------------------------------------------- + + gr::vmcircbuf_factory *vmcircbuf_mmap_shm_open_factory::s_the_factory = 0; + + gr::vmcircbuf_factory * + vmcircbuf_mmap_shm_open_factory::singleton() + { + if(s_the_factory) + return s_the_factory; + + s_the_factory = new gr::vmcircbuf_mmap_shm_open_factory(); + return s_the_factory; + } + + int + vmcircbuf_mmap_shm_open_factory::granularity() + { + return gr::pagesize(); + } + + gr::vmcircbuf * + vmcircbuf_mmap_shm_open_factory::make(int size) + { + try { + return new vmcircbuf_mmap_shm_open(size); + } + catch (...) { + return 0; + } + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/vmcircbuf_mmap_shm_open.h b/gnuradio-runtime/lib/vmcircbuf_mmap_shm_open.h new file mode 100644 index 0000000000..60654ee46e --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf_mmap_shm_open.h @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2013 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 GR_VMCIRCBUF_MMAP_SHM_OPEN_H +#define GR_VMCIRCBUF_MMAP_SHM_OPEN_H + +#include <gnuradio/api.h> +#include "vmcircbuf.h" + +namespace gr { + + /*! + * \brief concrete class to implement circular buffers with mmap and shm_open + * \ingroup internal + */ + class GR_RUNTIME_API vmcircbuf_mmap_shm_open : public gr::vmcircbuf + { + public: + vmcircbuf_mmap_shm_open(int size); + virtual ~vmcircbuf_mmap_shm_open(); + }; + + /*! + * \brief concrete factory for circular buffers built using mmap and shm_open + */ + class GR_RUNTIME_API vmcircbuf_mmap_shm_open_factory : public gr::vmcircbuf_factory + { + private: + static gr::vmcircbuf_factory *s_the_factory; + + public: + static gr::vmcircbuf_factory *singleton(); + + virtual const char *name() const { return "gr::vmcircbuf_mmap_shm_open_factory"; } + + /*! + * \brief return granularity of mapping, typically equal to page size + */ + virtual int granularity(); + + /*! + * \brief return a gr::vmcircbuf, or 0 if unable. + * + * Call this to create a doubly mapped circular buffer. + */ + virtual gr::vmcircbuf *make(int size); + }; + +} /* namespace gr */ + +#endif /* GR_VMCIRCBUF_MMAP_SHM_OPEN_H */ diff --git a/gnuradio-runtime/lib/vmcircbuf_mmap_tmpfile.cc b/gnuradio-runtime/lib/vmcircbuf_mmap_tmpfile.cc new file mode 100644 index 0000000000..ffe2a3d2c2 --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf_mmap_tmpfile.cc @@ -0,0 +1,197 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2011,2013 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 "vmcircbuf_mmap_tmpfile.h" +#include <stdexcept> +#include <assert.h> +#include <unistd.h> +#include <stdlib.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <fcntl.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include "pagesize.h" +#include <gnuradio/sys_paths.h> + +namespace gr { + + vmcircbuf_mmap_tmpfile::vmcircbuf_mmap_tmpfile (int size) + : gr::vmcircbuf (size) + { +#if !defined(HAVE_MMAP) + fprintf(stderr, "gr::vmcircbuf_mmap_tmpfile: mmap or mkstemp is not available\n"); + throw std::runtime_error("gr::vmcircbuf_mmap_tmpfile"); +#else + + if(size <= 0 || (size % gr::pagesize ()) != 0) { + fprintf(stderr, "gr::vmcircbuf_mmap_tmpfile: invalid size = %d\n", size); + throw std::runtime_error("gr::vmcircbuf_mmap_tmpfile"); + } + + int seg_fd = -1; + char seg_name[1024]; + + static int s_seg_counter = 0; + + // open a temporary file that we'll map in a bit later + while(1) { + snprintf(seg_name, sizeof(seg_name), + "%s/gnuradio-%d-%d-XXXXXX", gr::tmp_path(), getpid(), s_seg_counter); + s_seg_counter++; + + seg_fd = open(seg_name, O_RDWR | O_CREAT | O_EXCL, 0600); + if(seg_fd == -1) { + if(errno == EEXIST) // File already exists (shouldn't happen). Try again + continue; + + char msg[1024]; + snprintf(msg, sizeof (msg), + "gr::vmcircbuf_mmap_tmpfile: open [%s]", seg_name); + perror(msg); + throw std::runtime_error("gr::vmcircbuf_mmap_tmpfile"); + } + break; + } + + if(unlink (seg_name) == -1) { + perror("gr::vmcircbuf_mmap_tmpfile: unlink"); + throw std::runtime_error ("gr::vmcircbuf_mmap_tmpfile"); + } + + // We've got a valid file descriptor to a tmp file. + // Now set it's length to 2x what we really want and mmap it in. + if(ftruncate (seg_fd, (off_t) 2 * size) == -1) { + close(seg_fd); // cleanup + perror("gr::vmcircbuf_mmap_tmpfile: ftruncate (1)"); + throw std::runtime_error("gr::vmcircbuf_mmap_tmpfile"); + } + + void *first_copy = mmap(0, 2 * size, + PROT_READ | PROT_WRITE, MAP_SHARED, + seg_fd, (off_t)0); + + if(first_copy == MAP_FAILED) { + close(seg_fd); // cleanup + perror("gr::vmcircbuf_mmap_tmpfile: mmap (1)"); + throw std::runtime_error ("gr::vmcircbuf_mmap_tmpfile"); + } + + // unmap the 2nd half + if(munmap ((char *) first_copy + size, size) == -1) { + close(seg_fd); // cleanup + perror("gr::vmcircbuf_mmap_tmpfile: munmap (1)"); + throw std::runtime_error("gr::vmcircbuf_mmap_tmpfile"); + } + + // map the first half into the now available hole where the + // second half used to be. + void *second_copy = mmap((char*)first_copy + size, size, + PROT_READ | PROT_WRITE, MAP_SHARED, + seg_fd, (off_t)0); + + if(second_copy == MAP_FAILED) { + munmap(first_copy, size); // cleanup + close(seg_fd); + perror("gr::vmcircbuf_mmap_tmpfile: mmap(2)"); + throw std::runtime_error("gr::vmcircbuf_mmap_tmpfile"); + } + + // check for contiguity + if((char*)second_copy != (char*)first_copy + size) { + munmap(first_copy, size); // cleanup + munmap(second_copy, size); + close(seg_fd); + perror("gr::vmcircbuf_mmap_tmpfile: non-contiguous second copy"); + throw std::runtime_error("gr::vmcircbuf_mmap_tmpfile"); + } + + // cut the tmp file down to size + if(ftruncate (seg_fd, (off_t) size) == -1) { + munmap(first_copy, size); // cleanup + munmap(second_copy, size); + close(seg_fd); + perror("gr::vmcircbuf_mmap_tmpfile: ftruncate (2)"); + throw std::runtime_error("gr::vmcircbuf_mmap_tmpfile"); + } + + close(seg_fd); // fd no longer needed. The mapping is retained. + + // Now remember the important stuff + + d_base = (char*)first_copy; + d_size = size; +#endif + } + + vmcircbuf_mmap_tmpfile::~vmcircbuf_mmap_tmpfile() + { +#if defined(HAVE_MMAP) + if(munmap(d_base, 2 * d_size) == -1) { + perror("gr::vmcircbuf_mmap_tmpfile: munmap(2)"); + } +#endif + } + + // ---------------------------------------------------------------- + // The factory interface + // ---------------------------------------------------------------- + + gr::vmcircbuf_factory *vmcircbuf_mmap_tmpfile_factory::s_the_factory = 0; + + gr::vmcircbuf_factory * + vmcircbuf_mmap_tmpfile_factory::singleton() + { + if(s_the_factory) + return s_the_factory; + + s_the_factory = new gr::vmcircbuf_mmap_tmpfile_factory(); + return s_the_factory; + } + + int + vmcircbuf_mmap_tmpfile_factory::granularity() + { + return gr::pagesize(); + } + + gr::vmcircbuf * + vmcircbuf_mmap_tmpfile_factory::make(int size) + { + try { + return new vmcircbuf_mmap_tmpfile(size); + } + catch (...) { + return 0; + } + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/vmcircbuf_mmap_tmpfile.h b/gnuradio-runtime/lib/vmcircbuf_mmap_tmpfile.h new file mode 100644 index 0000000000..f8959c5736 --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf_mmap_tmpfile.h @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2013 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 GR_VMCIRCBUF_MMAP_TMPFILE_H +#define GR_VMCIRCBUF_MMAP_TMPFILE_H + +#include <gnuradio/api.h> +#include "vmcircbuf.h" + +namespace gr { + + /*! + * \brief concrete class to implement circular buffers with mmap and shm_open + * \ingroup internal + */ + class GR_RUNTIME_API vmcircbuf_mmap_tmpfile : public gr::vmcircbuf + { + public: + vmcircbuf_mmap_tmpfile(int size); + virtual ~vmcircbuf_mmap_tmpfile(); + }; + + /*! + * \brief concrete factory for circular buffers built using mmap and shm_open + */ + class GR_RUNTIME_API vmcircbuf_mmap_tmpfile_factory : public gr::vmcircbuf_factory + { + private: + static gr::vmcircbuf_factory *s_the_factory; + + public: + static gr::vmcircbuf_factory *singleton(); + + virtual const char *name() const { return "gr::vmcircbuf_mmap_tmpfile_factory"; } + + /*! + * \brief return granularity of mapping, typically equal to page size + */ + virtual int granularity(); + + /*! + * \brief return a gr::vmcircbuf, or 0 if unable. + * + * Call this to create a doubly mapped circular buffer. + */ + virtual gr::vmcircbuf *make(int size); + }; + +} /* namespace gr */ + +#endif /* GR_VMCIRCBUF_MMAP_TMPFILE_H */ diff --git a/gnuradio-runtime/lib/vmcircbuf_prefs.cc b/gnuradio-runtime/lib/vmcircbuf_prefs.cc new file mode 100644 index 0000000000..1fa6350385 --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf_prefs.cc @@ -0,0 +1,113 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2010,2011,2013 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 "vmcircbuf_prefs.h" +#include <gnuradio/sys_paths.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <string.h> + +#include <boost/filesystem/operations.hpp> +#include <boost/filesystem/path.hpp> +namespace fs = boost::filesystem; + +namespace gr { + + /* + * The simplest thing that could possibly work: + * the key is the filename; the value is the file contents. + */ + static const char * + pathname(const char *key) + { + static fs::path path; + path = fs::path(gr::appdata_path()) / ".gnuradio" / "prefs" / key; + return path.string().c_str(); + } + + static void + ensure_dir_path() + { + fs::path path = fs::path(gr::appdata_path()) / ".gnuradio"; + if(!fs::is_directory(path)) + fs::create_directory(path); + + path = path / "prefs"; + if(!fs::is_directory(path)) + fs::create_directory(path); + } + + const char * + vmcircbuf_prefs::get(const char *key) + { + static char buf[1024]; + + FILE *fp = fopen(pathname (key), "r"); + if(fp == 0) { + perror(pathname (key)); + return 0; + } + + memset(buf, 0, sizeof (buf)); + size_t ret = fread(buf, 1, sizeof(buf) - 1, fp); + if(ret == 0) { + if(ferror(fp) != 0) { + perror(pathname (key)); + fclose(fp); + return 0; + } + } + fclose(fp); + return buf; + } + + void + vmcircbuf_prefs::set(const char *key, const char *value) + { + ensure_dir_path(); + + FILE *fp = fopen(pathname(key), "w"); + if(fp == 0) { + perror(pathname (key)); + return; + } + + size_t ret = fwrite(value, 1, strlen(value), fp); + if(ret == 0) { + if(ferror(fp) != 0) { + perror(pathname (key)); + fclose(fp); + return; + } + } + fclose(fp); + }; + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/gri_debugger_hook.h b/gnuradio-runtime/lib/vmcircbuf_prefs.h index 6d31ed1b2c..709b8ff459 100644 --- a/gnuradio-runtime/lib/gri_debugger_hook.h +++ b/gnuradio-runtime/lib/vmcircbuf_prefs.h @@ -1,6 +1,6 @@ /* -*- c++ -*- */ /* - * Copyright 2004 Free Software Foundation, Inc. + * Copyright 2003,2013 Free Software Foundation, Inc. * * This file is part of GNU Radio * @@ -20,11 +20,20 @@ * Boston, MA 02110-1301, USA. */ -#ifndef INCLUDED_GRI_DEBUGGER_HOOK_H -#define INCLUDED_GRI_DEBUGGER_HOOK_H +#ifndef GR_PREFERENCES_H +#define GR_PREFERENCES_H -#include <gr_runtime_api.h> +#include <gnuradio/api.h> -GR_RUNTIME_API void gri_debugger_hook (); +namespace gr { -#endif /* INCLUDED_GRI_DEBUGGER_HOOK_H */
\ No newline at end of file + class GR_RUNTIME_API vmcircbuf_prefs + { + public: + static const char *get(const char *key); + static void set(const char *key, const char *value); + }; + +} /* namespace gr */ + +#endif /* GR_PREFERENCES_H */ diff --git a/gnuradio-runtime/lib/vmcircbuf_sysv_shm.cc b/gnuradio-runtime/lib/vmcircbuf_sysv_shm.cc new file mode 100644 index 0000000000..0d7e9b7d34 --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf_sysv_shm.cc @@ -0,0 +1,196 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2013 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 "vmcircbuf_sysv_shm.h" +#include <stdexcept> +#include <assert.h> +#include <unistd.h> +#include <stdlib.h> +#include <fcntl.h> +#ifdef HAVE_SYS_IPC_H +#include <sys/ipc.h> +#endif +#ifdef HAVE_SYS_SHM_H +#include <sys/shm.h> +#endif +#include <errno.h> +#include <stdio.h> +#include "pagesize.h" + + +namespace gr { + + vmcircbuf_sysv_shm::vmcircbuf_sysv_shm(int size) + : gr::vmcircbuf(size) + { +#if !defined(HAVE_SYS_SHM_H) + fprintf(stderr, "gr::vmcircbuf_sysv_shm: sysv shared memory is not available\n"); + throw std::runtime_error("gr::vmcircbuf_sysv_shm"); +#else + + int pagesize = gr::pagesize(); + + if(size <= 0 || (size % pagesize) != 0) { + fprintf(stderr, "gr::vmcircbuf_sysv_shm: invalid size = %d\n", size); + throw std::runtime_error("gr::vmcircbuf_sysv_shm"); + } + + int shmid_guard = -1; + int shmid1 = -1; + int shmid2 = -1; + + // We use this as a guard page. We'll map it read-only on both ends of the buffer. + // Ideally we'd map it no access, but I don't think that's possible with SysV + if((shmid_guard = shmget(IPC_PRIVATE, pagesize, IPC_CREAT | 0400)) == -1) { + perror("gr::vmcircbuf_sysv_shm: shmget (0)"); + throw std::runtime_error("gr::vmcircbuf_sysv_shm"); + } + + if((shmid2 = shmget(IPC_PRIVATE, 2 * size + 2 * pagesize, IPC_CREAT | 0700)) == -1) { + perror("gr::vmcircbuf_sysv_shm: shmget(1)"); + shmctl(shmid_guard, IPC_RMID, 0); + throw std::runtime_error ("gr::vmcircbuf_sysv_shm"); + } + + if((shmid1 = shmget(IPC_PRIVATE, size, IPC_CREAT | 0700)) == -1) { + perror("gr::vmcircbuf_sysv_shm: shmget (2)"); + shmctl(shmid_guard, IPC_RMID, 0); + shmctl(shmid2, IPC_RMID, 0); + throw std::runtime_error("gr::vmcircbuf_sysv_shm"); + } + + void *first_copy = shmat (shmid2, 0, 0); + if(first_copy == (void *) -1) { + perror("gr::vmcircbuf_sysv_shm: shmat(1)"); + shmctl(shmid_guard, IPC_RMID, 0); + shmctl(shmid2, IPC_RMID, 0); + shmctl(shmid1, IPC_RMID, 0); + throw std::runtime_error("gr::vmcircbuf_sysv_shm"); + } + + shmctl(shmid2, IPC_RMID, 0); + + // There may be a race between our detach and attach. + // + // If the system allocates all shared memory segments at the same + // virtual addresses in all processes and if the system allocates + // some other segment to first_copy or first_copoy + size between + // our detach and attach, the attaches below could fail [I've never + // seen it fail for this reason]. + shmdt(first_copy); + + // first read-only guard page + if(shmat(shmid_guard, first_copy, SHM_RDONLY) == (void *) -1) { + perror("gr::vmcircbuf_sysv_shm: shmat(2)"); + shmctl(shmid_guard, IPC_RMID, 0); + shmctl(shmid1, IPC_RMID, 0); + throw std::runtime_error("gr::vmcircbuf_sysv_shm"); + } + + // first copy + if(shmat (shmid1, (char*)first_copy + pagesize, 0) == (void *) -1) { + perror("gr::vmcircbuf_sysv_shm: shmat (3)"); + shmctl(shmid_guard, IPC_RMID, 0); + shmctl(shmid1, IPC_RMID, 0); + shmdt(first_copy); + throw std::runtime_error("gr::vmcircbuf_sysv_shm"); + } + + // second copy + if(shmat (shmid1, (char*)first_copy + pagesize + size, 0) == (void *) -1) { + perror("gr::vmcircbuf_sysv_shm: shmat (4)"); + shmctl(shmid_guard, IPC_RMID, 0); + shmctl(shmid1, IPC_RMID, 0); + shmdt((char *)first_copy + pagesize); + throw std::runtime_error("gr::vmcircbuf_sysv_shm"); + } + + // second read-only guard page + if(shmat(shmid_guard, (char*)first_copy + pagesize + 2 * size, SHM_RDONLY) == (void *) -1) { + perror("gr::vmcircbuf_sysv_shm: shmat(5)"); + shmctl(shmid_guard, IPC_RMID, 0); + shmctl(shmid1, IPC_RMID, 0); + shmdt(first_copy); + shmdt((char *)first_copy + pagesize); + shmdt((char *)first_copy + pagesize + size); + throw std::runtime_error ("gr::vmcircbuf_sysv_shm"); + } + + shmctl(shmid1, IPC_RMID, 0); + shmctl(shmid_guard, IPC_RMID, 0); + + // Now remember the important stuff + d_base = (char*)first_copy + pagesize; + d_size = size; +#endif + } + + vmcircbuf_sysv_shm::~vmcircbuf_sysv_shm() + { +#if defined(HAVE_SYS_SHM_H) + if(shmdt(d_base - gr::pagesize()) == -1 + || shmdt(d_base) == -1 + || shmdt(d_base + d_size) == -1 + || shmdt(d_base + 2 * d_size) == -1){ + perror("gr::vmcircbuf_sysv_shm: shmdt(2)"); + } +#endif + } + + // ---------------------------------------------------------------- + // The factory interface + // ---------------------------------------------------------------- + + gr::vmcircbuf_factory *vmcircbuf_sysv_shm_factory::s_the_factory = 0; + + gr::vmcircbuf_factory * + vmcircbuf_sysv_shm_factory::singleton() + { + if(s_the_factory) + return s_the_factory; + + s_the_factory = new gr::vmcircbuf_sysv_shm_factory(); + return s_the_factory; + } + + int + vmcircbuf_sysv_shm_factory::granularity() + { + return gr::pagesize(); + } + + gr::vmcircbuf * + vmcircbuf_sysv_shm_factory::make(int size) + { + try { + return new vmcircbuf_sysv_shm(size); + } + catch (...) { + return 0; + } + } + +} /* namespace gr */ diff --git a/gnuradio-runtime/lib/vmcircbuf_sysv_shm.h b/gnuradio-runtime/lib/vmcircbuf_sysv_shm.h new file mode 100644 index 0000000000..08e0040bf1 --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf_sysv_shm.h @@ -0,0 +1,70 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003 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 GR_VMCIRCBUF_SYSV_SHM_H +#define GR_VMCIRCBUF_SYSV_SHM_H + +#include <gnuradio/api.h> +#include "vmcircbuf.h" + +namespace gr { + + /*! + * \brief concrete class to implement circular buffers with mmap and shm_open + * \ingroup internal + */ + class GR_RUNTIME_API vmcircbuf_sysv_shm : public gr::vmcircbuf + { + public: + vmcircbuf_sysv_shm(int size); + virtual ~vmcircbuf_sysv_shm(); + }; + + /*! + * \brief concrete factory for circular buffers built using mmap and shm_open + */ + class GR_RUNTIME_API vmcircbuf_sysv_shm_factory : public gr::vmcircbuf_factory + { + private: + static gr::vmcircbuf_factory *s_the_factory; + + public: + static gr::vmcircbuf_factory *singleton(); + + virtual const char *name() const { return "gr::vmcircbuf_sysv_shm_factory"; } + + /*! + * \brief return granularity of mapping, typically equal to page size + */ + virtual int granularity(); + + /*! + * \brief return a gr::vmcircbuf, or 0 if unable. + * + * Call this to create a doubly mapped circular buffer. + */ + virtual gr::vmcircbuf *make(int size); + }; + +} /* namespace gr */ + +#endif /* GR_VMCIRCBUF_SYSV_SHM_H */ |