aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--host/cmake/Modules/UHDVersion.cmake24
-rw-r--r--host/examples/network_relay.cpp4
-rw-r--r--host/examples/tx_samples_c.c7
-rw-r--r--host/lib/rfnoc/nocscript/expression.hpp2
-rw-r--r--host/lib/transport/nirio_zero_copy.cpp39
-rw-r--r--host/lib/transport/super_send_packet_handler.hpp211
-rw-r--r--host/lib/utils/tasks.cpp4
7 files changed, 104 insertions, 187 deletions
diff --git a/host/cmake/Modules/UHDVersion.cmake b/host/cmake/Modules/UHDVersion.cmake
index 0e8064ff3..d557fdd29 100644
--- a/host/cmake/Modules/UHDVersion.cmake
+++ b/host/cmake/Modules/UHDVersion.cmake
@@ -87,26 +87,30 @@ EXECUTE_PROCESS(
#only set the build info on success
IF(_git_describe_result EQUAL 0)
- EXECUTE_PROCESS(
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- COMMAND ${PYTHON_EXECUTABLE} -c "
+ IF(NOT UHD_GIT_COUNT)
+ EXECUTE_PROCESS(
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ COMMAND ${PYTHON_EXECUTABLE} -c "
try:
print('${_git_describe}'.split('-')[-2])
except IndexError:
print('0')
"
- OUTPUT_VARIABLE UHD_GIT_COUNT OUTPUT_STRIP_TRAILING_WHITESPACE
- )
- EXECUTE_PROCESS(
- WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
- COMMAND ${PYTHON_EXECUTABLE} -c "
+ OUTPUT_VARIABLE UHD_GIT_COUNT OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ ENDIF()
+ IF(NOT UHD_GIT_HASH)
+ EXECUTE_PROCESS(
+ WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
+ COMMAND ${PYTHON_EXECUTABLE} -c "
try:
print('${_git_describe}'.split('-')[-1])
except IndexError:
print('unknown')
"
- OUTPUT_VARIABLE UHD_GIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE
- )
+ OUTPUT_VARIABLE UHD_GIT_HASH OUTPUT_STRIP_TRAILING_WHITESPACE
+ )
+ ENDIF()
ENDIF()
## Set default values if all fails. Make sure they're identical to the ones above.
diff --git a/host/examples/network_relay.cpp b/host/examples/network_relay.cpp
index b16bcaaa5..7e354934a 100644
--- a/host/examples/network_relay.cpp
+++ b/host/examples/network_relay.cpp
@@ -100,9 +100,9 @@ public:
std::cout << "spawning relay threads... " << _port << std::endl;
boost::unique_lock<boost::mutex> lock(spawn_mutex); // lock in preparation to wait for threads to spawn
- _thread_group.create_thread(boost::bind(&udp_relay_type::server_thread, this));
+ (void)_thread_group.create_thread(boost::bind(&udp_relay_type::server_thread, this));
wait_for_thread.wait(lock); // wait for thread to spin up
- _thread_group.create_thread(boost::bind(&udp_relay_type::client_thread, this));
+ (void)_thread_group.create_thread(boost::bind(&udp_relay_type::client_thread, this));
wait_for_thread.wait(lock); // wait for thread to spin up
std::cout << " done!" << std::endl << std::endl;
}
diff --git a/host/examples/tx_samples_c.c b/host/examples/tx_samples_c.c
index f04d4b26c..333c7e820 100644
--- a/host/examples/tx_samples_c.c
+++ b/host/examples/tx_samples_c.c
@@ -57,7 +57,7 @@ int main(int argc, char* argv[]){
double freq = 2e9;
double rate = 1e6;
double gain = 0;
- char* device_args = "";
+ char* device_args;
size_t channel = 0;
uint64_t total_num_samps = 0;
bool verbose = false;
@@ -106,6 +106,9 @@ int main(int argc, char* argv[]){
fprintf(stderr, "Unable to set thread priority. Continuing anyway.\n");
}
+ if (device_args == NULL){
+ device_args = "";
+ }
// Create USRP
uhd_usrp_handle usrp;
fprintf(stderr, "Creating USRP with args \"%s\"...\n", device_args);
@@ -246,7 +249,7 @@ int main(int argc, char* argv[]){
uhd_usrp_free(&usrp);
free_option_strings:
- if(strcmp(device_args,"")){
+ if(device_args != NULL){
free(device_args);
}
diff --git a/host/lib/rfnoc/nocscript/expression.hpp b/host/lib/rfnoc/nocscript/expression.hpp
index 83fc5bcbc..1acd02009 100644
--- a/host/lib/rfnoc/nocscript/expression.hpp
+++ b/host/lib/rfnoc/nocscript/expression.hpp
@@ -215,6 +215,7 @@ class expression_container : public expression
//! Create an empty container
expression_container() : _combiner(COMBINE_NOTSET) {};
+ virtual ~expression_container(){};
/*! Type-deduction rules for containers are:
* - If the combination type is COMBINE_ALL or COMBINE_AND,
@@ -299,6 +300,7 @@ class expression_function : public expression_container
const std::string &name,
const boost::shared_ptr<function_table> func_table
);
+ ~expression_function(){};
//! Add an argument expression
virtual void add(expression::sptr new_expr);
diff --git a/host/lib/transport/nirio_zero_copy.cpp b/host/lib/transport/nirio_zero_copy.cpp
index 14118d393..0635e01cf 100644
--- a/host/lib/transport/nirio_zero_copy.cpp
+++ b/host/lib/transport/nirio_zero_copy.cpp
@@ -32,6 +32,23 @@
//@TODO: Move the register defs required by the class to a common location
#include "../usrp/x300/x300_regs.hpp"
+#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32)
+#include <windows.h>
+static UHD_INLINE size_t get_page_size()
+{
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ return si.dwPageSize;
+}
+#else
+#include <unistd.h>
+static UHD_INLINE size_t get_page_size()
+{
+ return size_t(sysconf(_SC_PAGESIZE));
+}
+#endif
+static const size_t page_size = get_page_size();
+
using namespace uhd;
using namespace uhd::transport;
using namespace uhd::niusrprio;
@@ -351,7 +368,6 @@ nirio_zero_copy::sptr nirio_zero_copy::make(
){
//Initialize xport_params
zero_copy_xport_params xport_params = default_buff_args;
- size_t page_size = boost::interprocess::mapped_region::get_page_size();
//The kernel buffer for this transport must be (num_frames * frame_size) big. Unlike ethernet,
//where the kernel buffer size is independent of the circular buffer size for the transport,
@@ -366,6 +382,22 @@ nirio_zero_copy::sptr nirio_zero_copy::make(
size_t usr_recv_buff_size = static_cast<size_t>(
hints.cast<double>("recv_buff_size", default_buff_args.num_recv_frames));
+ if (hints.has_key("recv_buff_size"))
+ {
+ if (usr_recv_buff_size % page_size != 0)
+ {
+ throw uhd::value_error((boost::format("recv_buff_size must be multiple of %d") % page_size).str());
+ }
+ }
+
+ if (hints.has_key("recv_frame_size") and hints.has_key("num_recv_frames"))
+ {
+ if (usr_num_recv_frames * xport_params.recv_frame_size % page_size != 0)
+ {
+ throw uhd::value_error((boost::format("num_recv_frames * recv_frame_size must be an even multiple of %d") % page_size).str());
+ }
+ }
+
if (hints.has_key("num_recv_frames") and hints.has_key("recv_buff_size")) {
if (usr_recv_buff_size < xport_params.recv_frame_size)
throw uhd::value_error("recv_buff_size must be equal to or greater than (num_recv_frames * recv_frame_size)");
@@ -380,6 +412,11 @@ nirio_zero_copy::sptr nirio_zero_copy::make(
xport_params.num_recv_frames = usr_num_recv_frames;
}
+ if (xport_params.num_recv_frames * xport_params.recv_frame_size % page_size != 0)
+ {
+ throw uhd::value_error((boost::format("num_recv_frames * recv_frame_size must be an even multiple of %d") % page_size).str());
+ }
+
//TX
xport_params.send_frame_size = size_t(hints.cast<double>("send_frame_size", default_buff_args.send_frame_size));
diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp
index 003689a78..12c053efb 100644
--- a/host/lib/transport/super_send_packet_handler.hpp
+++ b/host/lib/transport/super_send_packet_handler.hpp
@@ -29,12 +29,9 @@
#include <uhd/types/metadata.hpp>
#include <uhd/transport/vrt_if_packet.hpp>
#include <uhd/transport/zero_copy.hpp>
-#include <uhd/utils/safe_call.hpp>
#include <boost/thread/thread.hpp>
#include <boost/thread/thread_time.hpp>
#include <boost/function.hpp>
-#include <boost/atomic.hpp>
-#include <boost/make_shared.hpp>
#include <iostream>
#include <vector>
@@ -51,9 +48,6 @@ namespace uhd {
namespace transport {
namespace sph {
-static const size_t MAX_INTERLEAVE = 4;
-static const double GET_BUFF_TIMEOUT = 0.1;
-
/***********************************************************************
* Super send packet handler
*
@@ -73,39 +67,19 @@ public:
* \param size the number of transport channels
*/
send_packet_handler(const size_t size = 1):
- _next_packet_seq(0), _cached_metadata(false)
+ _next_packet_seq(0), _cached_metadata(false)
{
this->set_enable_trailer(true);
this->resize(size);
}
~send_packet_handler(void){
- UHD_SAFE_CALL(
- for (size_t i = 0; i < _worker_data.size(); i++)
- {
- _worker_data[i]->stop = true;
- }
- _worker_thread_group.join_all();
- );
+ /* NOP */
}
//! Resize the number of transport channels
void resize(const size_t size){
if (this->size() == size) return;
-
- // Stop all worker threads
- for (size_t i = 0; i < _worker_data.size(); i++)
- {
- _worker_data[i]->stop = true;
- }
- _worker_thread_group.join_all();
- _worker_threads.resize(size);
- _worker_data.resize(size);
- for (size_t i = 0; i < size; i++)
- {
- _worker_data[i] = boost::make_shared<worker_thread_data_t>();
- }
-
_props.resize(size);
static const uint64_t zero = 0;
_zero_buffs.resize(size, &zero);
@@ -170,15 +144,7 @@ public:
* \param get_buff the getter function
*/
void set_xport_chan_get_buff(const size_t xport_chan, const get_buff_type &get_buff){
- if (_worker_threads[xport_chan])
- {
- _worker_thread_group.remove_thread(_worker_threads[xport_chan]);
- _worker_data[xport_chan]->stop = true;
- _worker_threads[xport_chan]->join();
- _worker_data[xport_chan]->stop = false;
- }
_props.at(xport_chan).get_buff = get_buff;
- _worker_threads[xport_chan] = _worker_thread_group.create_thread(boost::bind(&send_packet_handler::worker, this, xport_chan));
}
//! Set the conversion routine for all channels
@@ -414,147 +380,63 @@ private:
if_packet_info.num_payload_words32 = (if_packet_info.num_payload_bytes + 3/*round up*/)/sizeof(uint32_t);
if_packet_info.packet_count = _next_packet_seq;
- // wait for all worker threads to be ready or timeout
- boost::system_time expiration = boost::get_system_time() + boost::posix_time::milliseconds(long(timeout * 1000));
- for (size_t i = 0; i < this->size(); i++)
- {
- while (not _worker_data[i]->ready)
- {
- if (boost::get_system_time() > expiration)
- {
- return 0;
- }
- }
- _worker_data[i]->ready = false;
+ //get a buffer for each channel or timeout
+ BOOST_FOREACH(xport_chan_props_type &props, _props){
+ if (not props.buff) props.buff = props.get_buff(timeout);
+ if (not props.buff) return 0; //timeout
}
- //setup the data to share with worker threads
+ //setup the data to share with converter threads
_convert_nsamps = nsamps_per_buff;
_convert_buffs = &buffs;
_convert_buffer_offset_bytes = buffer_offset_bytes;
_convert_if_packet_info = &if_packet_info;
- //start N channels of conversion
- for (size_t i = 0; i < this->size(); i++)
- {
- _worker_data[i]->go = true;
- }
-
- //make sure any sleeping worker threads are woken up
- for (size_t i = 0; i < this->size(); i++)
- {
- // Acquiring the lock used by the condition variable
- // takes too long, so do a spin wait. If the go flag
- // is not cleared by this point, it will be cleared
- // immediately by the worker thread when it wakes up.
- while (_worker_data[i]->go)
- {
- _worker_data[i]->data_ready.notify_one();
- }
- }
-
- //wait for all worker threads to be done
- for (size_t i = 0; i < this->size(); i++)
- {
- //TODO: Implement a better wait strategy
- //busy loop give fastest response, but these are just wasted cycles
- while (not _worker_data[i]->done) {}
- _worker_data[i]->done = false;
+ //perform N channels of conversion
+ for (size_t i = 0; i < this->size(); i++) {
+ convert_to_in_buff(i);
}
_next_packet_seq++; //increment sequence after commits
return nsamps_per_buff;
}
- /*! Worker thread routine.
+ /*! Run the conversion from the internal buffers to the user's input
+ * buffer.
*
- * - Gets an internal data buffer
* - Calls the converter
* - Releases internal data buffers
+ * - Updates read/write pointers
*/
- void worker(const size_t index)
+ UHD_INLINE void convert_to_in_buff(const size_t index)
{
- //maximum number of cycles to spin before waiting on condition variable
- //the value of 30000000 was derived from 15ms on a 10 GHz CPU divided by 5 cycles per loop
- //the assumption is that anything held up for 15ms can wait
- static const size_t MAX_SPIN_CYCLES = 30000000;
-
- //maximum amount of time to wait before checking the stop flag
- static const double MAX_WAIT = 0.1;
-
- managed_send_buffer::sptr buff;
- vrt::if_packet_info_t if_packet_info;
- std::vector<const void *> in_buffs(MAX_INTERLEAVE);
- boost::shared_ptr<worker_thread_data_t> worker_data = _worker_data[index];
- boost::unique_lock<boost::mutex> lock(worker_data->data_ready_lock);
- size_t spins = 0;
-
- while (not worker_data->stop)
- {
- if (not buff)
- {
- buff = _props[index].get_buff(MAX_WAIT);
- if (not buff)
- {
- continue;
- }
- worker_data->ready = true;
- }
-
- //make sure done flag is cleared by controlling thread before waiting on go signal
- if (worker_data->done)
- {
- continue;
- }
-
- //partial spin lock before wait
- while (not worker_data->go and spins < MAX_SPIN_CYCLES)
- {
- spins++;
- }
- if (not worker_data->go and
- not worker_data->data_ready.timed_wait(lock, boost::posix_time::milliseconds(long(MAX_WAIT*1000))))
- {
- continue;
- }
- // Clear the go flag immediately to let the
- // controlling thread know we are not sleeping.
- worker_data->go = false;
-
- //reset the spin count
- spins = 0;
-
- //pack metadata into a vrt header
- uint32_t *otw_mem = buff->cast<uint32_t *>() + _header_offset_words32;
- if_packet_info = *_convert_if_packet_info;
- if_packet_info.has_sid = _props[index].has_sid;
- if_packet_info.sid = _props[index].sid;
- _vrt_packer(otw_mem, if_packet_info);
- otw_mem += if_packet_info.num_header_words32;
-
- //prepare the input buffers
- for (size_t i = 0; i < _num_inputs; i++)
- {
- in_buffs[i] =
- (reinterpret_cast<const char *>((*_convert_buffs)[index*_num_inputs + i]))
- + _convert_buffer_offset_bytes;
- }
-
- //perform the conversion operation
- _converter->conv(in_buffs, otw_mem, _convert_nsamps);
-
- //let the master know that new data can be prepared
- _worker_data[index]->done = true;
-
- //commit the samples to the zero-copy interface
- buff->commit(
- (_header_offset_words32 + if_packet_info.num_packet_words32)
- * sizeof(uint32_t)
- );
-
- //release the buffer
- buff.reset();
+ //shortcut references to local data structures
+ managed_send_buffer::sptr &buff = _props[index].buff;
+ vrt::if_packet_info_t if_packet_info = *_convert_if_packet_info;
+ const tx_streamer::buffs_type &buffs = *_convert_buffs;
+
+ //fill IO buffs with pointers into the output buffer
+ const void *io_buffs[4/*max interleave*/];
+ for (size_t i = 0; i < _num_inputs; i++){
+ const char *b = reinterpret_cast<const char *>(buffs[index*_num_inputs + i]);
+ io_buffs[i] = b + _convert_buffer_offset_bytes;
}
+ const ref_vector<const void *> in_buffs(io_buffs, _num_inputs);
+
+ //pack metadata into a vrt header
+ uint32_t *otw_mem = buff->cast<uint32_t *>() + _header_offset_words32;
+ if_packet_info.has_sid = _props[index].has_sid;
+ if_packet_info.sid = _props[index].sid;
+ _vrt_packer(otw_mem, if_packet_info);
+ otw_mem += if_packet_info.num_header_words32;
+
+ //perform the conversion operation
+ _converter->conv(in_buffs, otw_mem, _convert_nsamps);
+
+ //commit the samples to the zero-copy interface
+ const size_t num_vita_words32 = _header_offset_words32+if_packet_info.num_packet_words32;
+ buff->commit(num_vita_words32*sizeof(uint32_t));
+ buff.reset(); //effectively a release
}
//! Shared variables for the worker threads
@@ -562,18 +444,7 @@ private:
const tx_streamer::buffs_type *_convert_buffs;
size_t _convert_buffer_offset_bytes;
vrt::if_packet_info_t *_convert_if_packet_info;
- struct worker_thread_data_t {
- worker_thread_data_t() : ready(false), go(false), done(false), stop(false) {}
- boost::atomic_bool ready;
- boost::atomic_bool go;
- boost::atomic_bool done;
- boost::atomic_bool stop;
- boost::mutex data_ready_lock;
- boost::condition_variable data_ready;
- };
- std::vector< boost::shared_ptr<worker_thread_data_t> > _worker_data;
- boost::thread_group _worker_thread_group;
- std::vector<boost::thread *> _worker_threads;
+
};
class send_packet_streamer : public send_packet_handler, public tx_streamer{
diff --git a/host/lib/utils/tasks.cpp b/host/lib/utils/tasks.cpp
index 4cc28e48b..5dac729c8 100644
--- a/host/lib/utils/tasks.cpp
+++ b/host/lib/utils/tasks.cpp
@@ -32,7 +32,7 @@ public:
task_impl(const task_fcn_type &task_fcn):
_spawn_barrier(2)
{
- _thread_group.create_thread(boost::bind(&task_impl::task_loop, this, task_fcn));
+ (void)_thread_group.create_thread(boost::bind(&task_impl::task_loop, this, task_fcn));
_spawn_barrier.wait();
}
@@ -99,7 +99,7 @@ public:
msg_task_impl(const task_fcn_type &task_fcn):
_spawn_barrier(2)
{
- _thread_group.create_thread(boost::bind(&msg_task_impl::task_loop, this, task_fcn));
+ (void)_thread_group.create_thread(boost::bind(&msg_task_impl::task_loop, this, task_fcn));
_spawn_barrier.wait();
}