diff options
Diffstat (limited to 'host/lib/transport')
25 files changed, 2745 insertions, 2326 deletions
diff --git a/host/lib/transport/buffer_pool.cpp b/host/lib/transport/buffer_pool.cpp index 5d1ce37ab..c481b9d02 100644 --- a/host/lib/transport/buffer_pool.cpp +++ b/host/lib/transport/buffer_pool.cpp @@ -22,31 +22,35 @@ boost::detail::atomic_count managed_buffer::s_buffer_count(0); #endif // UHD_TXRX_DEBUG_PRINTS //! pad the byte count to a multiple of alignment -static size_t pad_to_boundary(const size_t bytes, const size_t alignment){ - return bytes + (alignment - bytes)%alignment; +static size_t pad_to_boundary(const size_t bytes, const size_t alignment) +{ + return bytes + (alignment - bytes) % alignment; } -buffer_pool::~buffer_pool(void){ +buffer_pool::~buffer_pool(void) +{ /* NOP */ } /*********************************************************************** * Buffer pool implementation **********************************************************************/ -class buffer_pool_impl : public buffer_pool{ +class buffer_pool_impl : public buffer_pool +{ public: - buffer_pool_impl( - const std::vector<ptr_type> &ptrs, - boost::shared_array<char> mem - ): _ptrs(ptrs), _mem(mem){ + buffer_pool_impl(const std::vector<ptr_type>& ptrs, boost::shared_array<char> mem) + : _ptrs(ptrs), _mem(mem) + { /* NOP */ } - ptr_type at(const size_t index) const{ + ptr_type at(const size_t index) const + { return _ptrs.at(index); } - size_t size(void) const{ + size_t size(void) const + { return _ptrs.size(); } @@ -59,26 +63,23 @@ private: * Buffer pool factor function **********************************************************************/ buffer_pool::sptr buffer_pool::make( - const size_t num_buffs, - const size_t buff_size, - const size_t alignment -){ - //1) pad the buffer size to be a multiple of alignment - //2) pad the overall memory size for room after alignment - //3) allocate the memory in one block of sufficient size + const size_t num_buffs, const size_t buff_size, const size_t alignment) +{ + // 1) pad the buffer size to be a multiple of alignment + // 2) pad the overall memory size for room after alignment + // 3) allocate the memory in one block of sufficient size const size_t padded_buff_size = pad_to_boundary(buff_size, alignment); - boost::shared_array<char> mem(new char[padded_buff_size*num_buffs + alignment-1]); + boost::shared_array<char> mem(new char[padded_buff_size * num_buffs + alignment - 1]); - //Fill a vector with boundary-aligned points in the memory + // Fill a vector with boundary-aligned points in the memory const size_t mem_start = pad_to_boundary(size_t(mem.get()), alignment); std::vector<ptr_type> ptrs(num_buffs); - for (size_t i = 0; i < num_buffs; i++){ - ptrs[i] = ptr_type(mem_start + padded_buff_size*i); + for (size_t i = 0; i < num_buffs; i++) { + ptrs[i] = ptr_type(mem_start + padded_buff_size * i); } - //Create a new buffer pool implementation with: + // Create a new buffer pool implementation with: // - the pre-computed pointers, and // - the reference to allocated memory. return sptr(new buffer_pool_impl(ptrs, mem)); } - diff --git a/host/lib/transport/chdr.cpp b/host/lib/transport/chdr.cpp index 36f380d62..ff3b6475a 100644 --- a/host/lib/transport/chdr.cpp +++ b/host/lib/transport/chdr.cpp @@ -5,23 +5,23 @@ // SPDX-License-Identifier: GPL-3.0-or-later // +#include <uhd/exception.hpp> #include <uhd/transport/chdr.hpp> #include <uhd/utils/byteswap.hpp> -#include <uhd/exception.hpp> -//define the endian macros to convert integers +// define the endian macros to convert integers #ifdef BOOST_BIG_ENDIAN - #define BE_MACRO(x) (x) - #define LE_MACRO(x) uhd::byteswap(x) +# define BE_MACRO(x) (x) +# define LE_MACRO(x) uhd::byteswap(x) #else - #define BE_MACRO(x) uhd::byteswap(x) - #define LE_MACRO(x) (x) +# define BE_MACRO(x) uhd::byteswap(x) +# define LE_MACRO(x) (x) #endif using namespace uhd::transport::vrt; -static const uint32_t HDR_FLAG_TSF = (1 << 29); -static const uint32_t HDR_FLAG_EOB = (1 << 28); +static const uint32_t HDR_FLAG_TSF = (1 << 29); +static const uint32_t HDR_FLAG_EOB = (1 << 28); static const uint32_t HDR_FLAG_ERROR = (1 << 28); static const uint32_t HDR_FLAG_FCACK = (1 << 28); @@ -30,24 +30,25 @@ static const uint32_t HDR_FLAG_FCACK = (1 << 28); /***************************************************************************/ /*! Translate the contents of \p if_packet_info into a 32-Bit word and return it. */ -UHD_INLINE uint32_t _hdr_pack_chdr( - if_packet_info_t &if_packet_info -) { +UHD_INLINE uint32_t _hdr_pack_chdr(if_packet_info_t& if_packet_info) +{ // Set fields in if_packet_info if_packet_info.num_header_words32 = 2 + (if_packet_info.has_tsf ? 2 : 0); if_packet_info.num_packet_words32 = - if_packet_info.num_header_words32 + - if_packet_info.num_payload_words32; + if_packet_info.num_header_words32 + if_packet_info.num_payload_words32; uint16_t pkt_length = if_packet_info.num_payload_bytes + (4 * if_packet_info.num_header_words32); - uint32_t chdr = 0 + uint32_t chdr = + 0 // 2 Bits: Packet type | (if_packet_info.packet_type << 30) // 1 Bit: Has time | (if_packet_info.has_tsf ? HDR_FLAG_TSF : 0) // 1 Bit: EOB or Error or FC ACK - | ((if_packet_info.eob or if_packet_info.error or if_packet_info.fc_ack) ? HDR_FLAG_EOB : 0) + | ((if_packet_info.eob or if_packet_info.error or if_packet_info.fc_ack) + ? HDR_FLAG_EOB + : 0) // 12 Bits: Sequence number | ((if_packet_info.packet_count & 0xFFF) << 16) // 16 Bits: Total packet length @@ -55,10 +56,8 @@ UHD_INLINE uint32_t _hdr_pack_chdr( return chdr; } -void chdr::if_hdr_pack_be( - uint32_t *packet_buff, - if_packet_info_t &if_packet_info -) { +void chdr::if_hdr_pack_be(uint32_t* packet_buff, if_packet_info_t& if_packet_info) +{ // Write header and update if_packet_info packet_buff[0] = BE_MACRO(_hdr_pack_chdr(if_packet_info)); @@ -72,10 +71,8 @@ void chdr::if_hdr_pack_be( } } -void chdr::if_hdr_pack_le( - uint32_t *packet_buff, - if_packet_info_t &if_packet_info -) { +void chdr::if_hdr_pack_le(uint32_t* packet_buff, if_packet_info_t& if_packet_info) +{ // Write header and update if_packet_info packet_buff[0] = LE_MACRO(_hdr_pack_chdr(if_packet_info)); @@ -93,27 +90,28 @@ void chdr::if_hdr_pack_le( /***************************************************************************/ /* Unpacking */ /***************************************************************************/ -UHD_INLINE void _hdr_unpack_chdr( - const uint32_t chdr, - if_packet_info_t &if_packet_info -) { +UHD_INLINE void _hdr_unpack_chdr(const uint32_t chdr, if_packet_info_t& if_packet_info) +{ // Set constant members if_packet_info.link_type = if_packet_info_t::LINK_TYPE_CHDR; - if_packet_info.has_cid = false; - if_packet_info.has_sid = true; - if_packet_info.has_tsi = false; - if_packet_info.has_tlr = false; - if_packet_info.sob = false; + if_packet_info.has_cid = false; + if_packet_info.has_sid = true; + if_packet_info.has_tsi = false; + if_packet_info.has_tlr = false; + if_packet_info.sob = false; // Set configurable members - if_packet_info.has_tsf = (chdr & HDR_FLAG_TSF) > 0; + if_packet_info.has_tsf = (chdr & HDR_FLAG_TSF) > 0; if_packet_info.packet_type = if_packet_info_t::packet_type_t((chdr >> 30) & 0x3); - if_packet_info.eob = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_DATA) - && ((chdr & HDR_FLAG_EOB) > 0); - if_packet_info.error = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_RESP) - && ((chdr & HDR_FLAG_ERROR) > 0); - if_packet_info.fc_ack = (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_FC) - && ((chdr & HDR_FLAG_FCACK) > 0); + if_packet_info.eob = + (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_DATA) + && ((chdr & HDR_FLAG_EOB) > 0); + if_packet_info.error = + (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_RESP) + && ((chdr & HDR_FLAG_ERROR) > 0); + if_packet_info.fc_ack = + (if_packet_info.packet_type == if_packet_info_t::PACKET_TYPE_FC) + && ((chdr & HDR_FLAG_FCACK) > 0); if_packet_info.packet_count = (chdr >> 16) & 0xFFF; // Set packet length variables @@ -122,7 +120,7 @@ UHD_INLINE void _hdr_unpack_chdr( } else { if_packet_info.num_header_words32 = 2; } - size_t pkt_size_bytes = (chdr & 0xFFFF); + size_t pkt_size_bytes = (chdr & 0xFFFF); size_t pkt_size_word32 = (pkt_size_bytes / 4) + ((pkt_size_bytes % 4) ? 1 : 0); // Check lengths match: if (pkt_size_word32 < if_packet_info.num_header_words32) { @@ -131,14 +129,14 @@ UHD_INLINE void _hdr_unpack_chdr( if (if_packet_info.num_packet_words32 < pkt_size_word32) { throw uhd::value_error("Bad CHDR or packet fragment"); } - if_packet_info.num_payload_bytes = pkt_size_bytes - (4 * if_packet_info.num_header_words32); - if_packet_info.num_payload_words32 = pkt_size_word32 - if_packet_info.num_header_words32; + if_packet_info.num_payload_bytes = + pkt_size_bytes - (4 * if_packet_info.num_header_words32); + if_packet_info.num_payload_words32 = + pkt_size_word32 - if_packet_info.num_header_words32; } -void chdr::if_hdr_unpack_be( - const uint32_t *packet_buff, - if_packet_info_t &if_packet_info -) { +void chdr::if_hdr_unpack_be(const uint32_t* packet_buff, if_packet_info_t& if_packet_info) +{ // Read header and update if_packet_info uint32_t chdr = BE_MACRO(packet_buff[0]); _hdr_unpack_chdr(chdr, if_packet_info); @@ -148,16 +146,13 @@ void chdr::if_hdr_unpack_be( // Read time (has_tsf was updated earlier) if (if_packet_info.has_tsf) { - if_packet_info.tsf = 0 - | uint64_t(BE_MACRO(packet_buff[2])) << 32 - | BE_MACRO(packet_buff[3]); + if_packet_info.tsf = 0 | uint64_t(BE_MACRO(packet_buff[2])) << 32 + | BE_MACRO(packet_buff[3]); } } -void chdr::if_hdr_unpack_le( - const uint32_t *packet_buff, - if_packet_info_t &if_packet_info -) { +void chdr::if_hdr_unpack_le(const uint32_t* packet_buff, if_packet_info_t& if_packet_info) +{ // Read header and update if_packet_info uint32_t chdr = LE_MACRO(packet_buff[0]); _hdr_unpack_chdr(chdr, if_packet_info); @@ -167,9 +162,7 @@ void chdr::if_hdr_unpack_le( // Read time (has_tsf was updated earlier) if (if_packet_info.has_tsf) { - if_packet_info.tsf = 0 - | uint64_t(LE_MACRO(packet_buff[2])) << 32 - | LE_MACRO(packet_buff[3]); + if_packet_info.tsf = 0 | uint64_t(LE_MACRO(packet_buff[2])) << 32 + | LE_MACRO(packet_buff[3]); } } - diff --git a/host/lib/transport/dpdk_zero_copy.cpp b/host/lib/transport/dpdk_zero_copy.cpp index 2e95efd81..51c9b9dba 100644 --- a/host/lib/transport/dpdk_zero_copy.cpp +++ b/host/lib/transport/dpdk_zero_copy.cpp @@ -6,106 +6,104 @@ #include "dpdk_zero_copy.hpp" #include <uhd/config.hpp> -#include <uhd/utils/static.hpp> #include <uhd/utils/log.hpp> +#include <uhd/utils/static.hpp> #include <uhdlib/transport/uhd-dpdk.h> -#include <boost/make_shared.hpp> +#include <arpa/inet.h> #include <sys/syslog.h> +#include <boost/make_shared.hpp> #include <stack> -#include <arpa/inet.h> namespace uhd { namespace transport { namespace { - static constexpr uint64_t USEC = 1000000; - // FIXME: Make configurable and have uhd-dpdk library track buffer sizes - static constexpr size_t DEFAULT_FRAME_SIZE = 8000; +static constexpr uint64_t USEC = 1000000; +// FIXME: Make configurable and have uhd-dpdk library track buffer sizes +static constexpr size_t DEFAULT_FRAME_SIZE = 8000; - inline char * eal_add_opt(std::vector<const char*>& argv, size_t n, - char *dst, const char *opt, const char *arg) - { - char *ptr = dst; - strncpy(ptr, opt, n); - argv.push_back(ptr); - ptr += strlen(opt) + 1; - n -= ptr - dst; - strncpy(ptr, arg, n); - argv.push_back(ptr); - ptr += strlen(arg) + 1; - return ptr; - } +inline char* eal_add_opt( + std::vector<const char*>& argv, size_t n, char* dst, const char* opt, const char* arg) +{ + char* ptr = dst; + strncpy(ptr, opt, n); + argv.push_back(ptr); + ptr += strlen(opt) + 1; + n -= ptr - dst; + strncpy(ptr, arg, n); + argv.push_back(ptr); + ptr += strlen(arg) + 1; + return ptr; } +} // namespace uhd_dpdk_ctx::uhd_dpdk_ctx(void) : _init_done(false) {} uhd_dpdk_ctx::~uhd_dpdk_ctx(void) {} /* Initialize uhd-dpdk (and do only once) */ -void uhd_dpdk_ctx::init(const dict<std::string, std::string> &eal_args, - unsigned int num_ports, int *port_thread_mapping, - int num_mbufs, int mbuf_cache_size, size_t mtu) +void uhd_dpdk_ctx::init(const dict<std::string, std::string>& eal_args, + unsigned int num_ports, + int* port_thread_mapping, + int num_mbufs, + int mbuf_cache_size, + size_t mtu) { std::lock_guard<std::mutex> lock(_init_mutex); if (!_init_done) { _mtu = mtu; /* Build up argc and argv */ - std::vector<const char *> argv; + std::vector<const char*> argv; argv.push_back("uhd-dpdk"); - char *args = new char[4096]; - char *opt = args; - char *end = args + sizeof(args); - for (std::string &key : eal_args.keys()) { + char* args = new char[4096]; + char* opt = args; + char* end = args + sizeof(args); + for (std::string& key : eal_args.keys()) { std::string val = eal_args[key]; if (key == "coremask") { - opt = eal_add_opt(argv, end - opt, opt, "-c", - val.c_str()); + opt = eal_add_opt(argv, end - opt, opt, "-c", val.c_str()); } else if (key == "corelist") { /* NOTE: This arg may have commas, so limited to config file */ - opt = eal_add_opt(argv, end - opt, opt, "-l", - val.c_str()); + opt = eal_add_opt(argv, end - opt, opt, "-l", val.c_str()); } else if (key == "coremap") { - opt = eal_add_opt(argv, end - opt, opt, "--lcores", - val.c_str()); + opt = eal_add_opt(argv, end - opt, opt, "--lcores", val.c_str()); } else if (key == "master-lcore") { - opt = eal_add_opt(argv, end - opt, opt, "--master-lcore", - val.c_str()); + opt = eal_add_opt(argv, end - opt, opt, "--master-lcore", val.c_str()); } else if (key == "pci-blacklist") { - opt = eal_add_opt(argv, end - opt, opt, "-b", - val.c_str()); + opt = eal_add_opt(argv, end - opt, opt, "-b", val.c_str()); } else if (key == "pci-whitelist") { - opt = eal_add_opt(argv, end - opt, opt, "-w", - val.c_str()); + opt = eal_add_opt(argv, end - opt, opt, "-w", val.c_str()); } else if (key == "log-level") { - opt = eal_add_opt(argv, end - opt, opt, "--log-level", - val.c_str()); + opt = eal_add_opt(argv, end - opt, opt, "--log-level", val.c_str()); } else if (key == "huge-dir") { - opt = eal_add_opt(argv, end - opt, opt, "--huge-dir", - val.c_str()); + opt = eal_add_opt(argv, end - opt, opt, "--huge-dir", val.c_str()); } else if (key == "file-prefix") { - opt = eal_add_opt(argv, end - opt, opt, "--file-prefix", - val.c_str()); + opt = eal_add_opt(argv, end - opt, opt, "--file-prefix", val.c_str()); } } - uhd_dpdk_init(argv.size(), argv.data(), num_ports, port_thread_mapping, num_mbufs, - mbuf_cache_size, _mtu); + uhd_dpdk_init(argv.size(), + argv.data(), + num_ports, + port_thread_mapping, + num_mbufs, + mbuf_cache_size, + _mtu); delete args; _init_done = true; } } -int uhd_dpdk_ctx::get_port_id(std::array<uint8_t, 6> mac_addr, - unsigned int &port_id) +int uhd_dpdk_ctx::get_port_id(std::array<uint8_t, 6> mac_addr, unsigned int& port_id) { UHD_ASSERT_THROW(is_init_done()); int num_ports = uhd_dpdk_port_count(); for (int i = 0; i < num_ports; i++) { - struct eth_addr port_mac_addr = uhd_dpdk_get_eth_addr((unsigned int) i); + struct eth_addr port_mac_addr = uhd_dpdk_get_eth_addr((unsigned int)i); for (int j = 0; j < 6; j++) { if (mac_addr[j] != port_mac_addr.addr[j]) { break; } if (j == 5) { - port_id = (unsigned int) i; + port_id = (unsigned int)i; return 0; } } @@ -113,23 +111,23 @@ int uhd_dpdk_ctx::get_port_id(std::array<uint8_t, 6> mac_addr, return -1; } -int uhd_dpdk_ctx::get_route(const std::string &addr) const +int uhd_dpdk_ctx::get_route(const std::string& addr) const { - const uint32_t dst_ipv4 = (uint32_t) inet_addr(addr.c_str()); + const uint32_t dst_ipv4 = (uint32_t)inet_addr(addr.c_str()); const unsigned int num_ports = uhd_dpdk_port_count(); for (unsigned int port = 0; port < num_ports; port++) { uint32_t src_ipv4; uint32_t netmask; uhd_dpdk_get_ipv4_addr(port, &src_ipv4, &netmask); if ((src_ipv4 & netmask) == (dst_ipv4 & netmask)) { - return (int) port; - } + return (int)port; + } } return -ENODEV; } -int uhd_dpdk_ctx::set_ipv4_addr(unsigned int port_id, uint32_t ipv4_addr, - uint32_t netmask) +int uhd_dpdk_ctx::set_ipv4_addr( + unsigned int port_id, uint32_t ipv4_addr, uint32_t netmask) { return uhd_dpdk_set_ipv4_addr(port_id, ipv4_addr, netmask); } @@ -140,23 +138,25 @@ bool uhd_dpdk_ctx::is_init_done(void) } -class dpdk_zero_copy_msb : public managed_send_buffer { +class dpdk_zero_copy_msb : public managed_send_buffer +{ public: - dpdk_zero_copy_msb(struct uhd_dpdk_socket *sock, - std::stack<dpdk_zero_copy_msb *, std::vector<dpdk_zero_copy_msb *>> &free_bufs) - : _sock(sock), _buf(nullptr), _free_bufs(free_bufs) {}; + dpdk_zero_copy_msb(struct uhd_dpdk_socket* sock, + std::stack<dpdk_zero_copy_msb*, std::vector<dpdk_zero_copy_msb*>>& free_bufs) + : _sock(sock), _buf(nullptr), _free_bufs(free_bufs){}; ~dpdk_zero_copy_msb(void) {} void release(void) { if (_buf) { - _buf->pkt_len = _length; + _buf->pkt_len = _length; _buf->data_len = _length; - int num_tx = uhd_dpdk_send(_sock, &_buf, 1); + int num_tx = uhd_dpdk_send(_sock, &_buf, 1); if (num_tx == 0) { /* Drop packet and free buffer (do not share sockets!) */ - UHD_LOG_ERROR("DPDK", "Invalid shared socket usage detected. Dropping packet..."); + UHD_LOG_ERROR( + "DPDK", "Invalid shared socket usage detected. Dropping packet..."); uhd_dpdk_free_buf(_buf); } // Push back into pool @@ -170,21 +170,21 @@ public: if (bufs != 1 || !_buf) return sptr(); - return make(this, uhd_dpdk_buf_to_data(_sock, _buf), - DEFAULT_FRAME_SIZE); + return make(this, uhd_dpdk_buf_to_data(_sock, _buf), DEFAULT_FRAME_SIZE); } private: - struct uhd_dpdk_socket *_sock; - struct rte_mbuf *_buf; - std::stack<dpdk_zero_copy_msb *, std::vector<dpdk_zero_copy_msb *>> &_free_bufs; + struct uhd_dpdk_socket* _sock; + struct rte_mbuf* _buf; + std::stack<dpdk_zero_copy_msb*, std::vector<dpdk_zero_copy_msb*>>& _free_bufs; }; -class dpdk_zero_copy_mrb : public managed_recv_buffer { +class dpdk_zero_copy_mrb : public managed_recv_buffer +{ public: - dpdk_zero_copy_mrb(struct uhd_dpdk_socket *sock, - std::stack<dpdk_zero_copy_mrb *, std::vector<dpdk_zero_copy_mrb *>> &free_bufs) - : _sock(sock), _buf(nullptr), _free_bufs(free_bufs) {}; + dpdk_zero_copy_mrb(struct uhd_dpdk_socket* sock, + std::stack<dpdk_zero_copy_mrb*, std::vector<dpdk_zero_copy_mrb*>>& free_bufs) + : _sock(sock), _buf(nullptr), _free_bufs(free_bufs){}; ~dpdk_zero_copy_mrb(void) {} void release(void) @@ -197,7 +197,7 @@ public: sptr get_new(double timeout) { - int bufs = uhd_dpdk_recv(_sock, &_buf, 1, (int) (timeout*USEC)); + int bufs = uhd_dpdk_recv(_sock, &_buf, 1, (int)(timeout * USEC)); if (bufs != 1 || _buf == nullptr) { // Push back into pool if we didn't get a real buffer _free_bufs.push(this); @@ -210,32 +210,32 @@ public: return sptr(); } - return make(this, uhd_dpdk_buf_to_data(_sock, _buf), - uhd_dpdk_get_len(_sock, _buf)); + return make( + this, uhd_dpdk_buf_to_data(_sock, _buf), uhd_dpdk_get_len(_sock, _buf)); } private: - struct uhd_dpdk_socket *_sock; - struct rte_mbuf *_buf; - std::stack<dpdk_zero_copy_mrb *, std::vector<dpdk_zero_copy_mrb *>> &_free_bufs; + struct uhd_dpdk_socket* _sock; + struct rte_mbuf* _buf; + std::stack<dpdk_zero_copy_mrb*, std::vector<dpdk_zero_copy_mrb*>>& _free_bufs; }; -class dpdk_zero_copy_impl : public dpdk_zero_copy { +class dpdk_zero_copy_impl : public dpdk_zero_copy +{ public: - - dpdk_zero_copy_impl(struct uhd_dpdk_ctx &ctx, - const unsigned int dpdk_port_id, - const std::string &addr, - const std::string &remote_port, - const std::string &local_port, - const zero_copy_xport_params& xport_params) - : _num_send_frames(xport_params.num_send_frames), - _send_frame_size(xport_params.send_frame_size), - _num_recv_frames(xport_params.num_recv_frames), - _recv_frame_size(xport_params.recv_frame_size), - _port_id(dpdk_port_id), - _rx_empty_count(0), - _tx_empty_count(0) + dpdk_zero_copy_impl(struct uhd_dpdk_ctx& ctx, + const unsigned int dpdk_port_id, + const std::string& addr, + const std::string& remote_port, + const std::string& local_port, + const zero_copy_xport_params& xport_params) + : _num_send_frames(xport_params.num_send_frames) + , _send_frame_size(xport_params.send_frame_size) + , _num_recv_frames(xport_params.num_recv_frames) + , _recv_frame_size(xport_params.recv_frame_size) + , _port_id(dpdk_port_id) + , _rx_empty_count(0) + , _tx_empty_count(0) { // TODO: Handle xport_params UHD_ASSERT_THROW(xport_params.recv_frame_size > 0); @@ -247,30 +247,28 @@ public: const int num_ports = uhd_dpdk_port_count(); UHD_ASSERT_THROW(num_ports > 0); - UHD_ASSERT_THROW(dpdk_port_id < (unsigned int) num_ports); + UHD_ASSERT_THROW(dpdk_port_id < (unsigned int)num_ports); // Convert ipv4 addr from string to uint32_t, network format - uint32_t dst_ipv4 = (uint32_t) inet_addr(addr.c_str()); + uint32_t dst_ipv4 = (uint32_t)inet_addr(addr.c_str()); // Convert port from string to uint16_t, network format uint16_t dst_port = htons(std::stoi(remote_port, NULL, 0)); uint16_t src_port = htons(std::stoi(local_port, NULL, 0)); // Create RX socket first - struct uhd_dpdk_sockarg_udp sockarg = { - .is_tx = false, - .local_port = src_port, - .remote_port = dst_port, - .dst_addr = dst_ipv4 - }; + struct uhd_dpdk_sockarg_udp sockarg = {.is_tx = false, + .local_port = src_port, + .remote_port = dst_port, + .dst_addr = dst_ipv4}; _rx_sock = uhd_dpdk_sock_open(dpdk_port_id, UHD_DPDK_SOCK_UDP, &sockarg); UHD_ASSERT_THROW(_rx_sock != nullptr); // Backfill the local port, in case it was auto-assigned uhd_dpdk_udp_get_info(_rx_sock, &sockarg); - sockarg.is_tx = true; + sockarg.is_tx = true; sockarg.remote_port = dst_port; - sockarg.dst_addr = dst_ipv4; + sockarg.dst_addr = dst_ipv4; _tx_sock = uhd_dpdk_sock_open(dpdk_port_id, UHD_DPDK_SOCK_UDP, &sockarg); UHD_ASSERT_THROW(_tx_sock != nullptr); @@ -282,9 +280,10 @@ public: _msb_pool.push(new dpdk_zero_copy_msb(_tx_sock, _msb_pool)); } - UHD_LOG_TRACE("DPDK", "Created transports between " << addr << ":" - << remote_port << " and NIC(" << dpdk_port_id - << "):" << ntohs(sockarg.local_port)); + UHD_LOG_TRACE("DPDK", + "Created transports between " << addr << ":" << remote_port << " and NIC(" + << dpdk_port_id + << "):" << ntohs(sockarg.local_port)); } ~dpdk_zero_copy_impl(void) @@ -293,18 +292,23 @@ public: size_t count; uhd_dpdk_udp_get_info(_rx_sock, &sockarg); uhd_dpdk_get_drop_count(_rx_sock, &count); - UHD_LOG_TRACE("DPDK", "Closing transports between " << sockarg.dst_addr << ":" - << ntohs(sockarg.remote_port) << " and local:" - << ntohs(sockarg.local_port)); - UHD_LOG_TRACE("DPDK", "(" << ntohs(sockarg.remote_port) << "," << ntohs(sockarg.local_port) << ") " - << " Dropped "<< count << " packets"); + UHD_LOG_TRACE("DPDK", + "Closing transports between " << sockarg.dst_addr << ":" + << ntohs(sockarg.remote_port) + << " and local:" << ntohs(sockarg.local_port)); + UHD_LOG_TRACE("DPDK", + "(" << ntohs(sockarg.remote_port) << "," << ntohs(sockarg.local_port) << ") " + << " Dropped " << count << " packets"); uhd_dpdk_get_xfer_count(_rx_sock, &count); - UHD_LOG_TRACE("DPDK", "(" << ntohs(sockarg.remote_port) << "," << ntohs(sockarg.local_port) << ") " - << " Received "<< count << " packets"); - UHD_LOG_TRACE("DPDK", "(" << ntohs(sockarg.remote_port) << "," << ntohs(sockarg.local_port) << ") " - << "RX empty count is " << _rx_empty_count); - UHD_LOG_TRACE("DPDK", "(" << ntohs(sockarg.remote_port) << "," << ntohs(sockarg.local_port) << ") " - << "TX empty count is " << _tx_empty_count); + UHD_LOG_TRACE("DPDK", + "(" << ntohs(sockarg.remote_port) << "," << ntohs(sockarg.local_port) << ") " + << " Received " << count << " packets"); + UHD_LOG_TRACE("DPDK", + "(" << ntohs(sockarg.remote_port) << "," << ntohs(sockarg.local_port) << ") " + << "RX empty count is " << _rx_empty_count); + UHD_LOG_TRACE("DPDK", + "(" << ntohs(sockarg.remote_port) << "," << ntohs(sockarg.local_port) << ") " + << "TX empty count is " << _tx_empty_count); uhd_dpdk_sock_close(_rx_sock); uhd_dpdk_sock_close(_tx_sock); } @@ -316,7 +320,7 @@ public: return managed_recv_buffer::sptr(); } - dpdk_zero_copy_mrb *mrb = _mrb_pool.top(); + dpdk_zero_copy_mrb* mrb = _mrb_pool.top(); _mrb_pool.pop(); managed_recv_buffer::sptr buff = mrb->get_new(timeout); if (!buff) @@ -341,7 +345,7 @@ public: return managed_send_buffer::sptr(); } - dpdk_zero_copy_msb *msb = _msb_pool.top(); + dpdk_zero_copy_msb* msb = _msb_pool.top(); _msb_pool.pop(); managed_send_buffer::sptr buff = msb->get_new(timeout); if (!buff) @@ -369,14 +373,11 @@ public: std::string get_local_addr(void) const { uint32_t ipv4_addr; - int status = uhd_dpdk_get_ipv4_addr(_port_id, &ipv4_addr, NULL); - auto retval = std::to_string(ipv4_addr >> 0 & 0xff) + - "." + - std::to_string(ipv4_addr >> 8 & 0xff) + - "." + - std::to_string(ipv4_addr >> 16 & 0xff) + - "." + - std::to_string(ipv4_addr >> 24 & 0xff); + int status = uhd_dpdk_get_ipv4_addr(_port_id, &ipv4_addr, NULL); + auto retval = std::to_string(ipv4_addr >> 0 & 0xff) + "." + + std::to_string(ipv4_addr >> 8 & 0xff) + "." + + std::to_string(ipv4_addr >> 16 & 0xff) + "." + + std::to_string(ipv4_addr >> 24 & 0xff); return retval; } @@ -386,9 +387,10 @@ public: uhd_dpdk_get_drop_count(_rx_sock, &drop_count); return drop_count; } + private: - struct uhd_dpdk_socket *_rx_sock; - struct uhd_dpdk_socket *_tx_sock; + struct uhd_dpdk_socket* _rx_sock; + struct uhd_dpdk_socket* _tx_sock; const size_t _num_send_frames; const size_t _send_frame_size; const size_t _num_recv_frames; @@ -397,22 +399,20 @@ private: unsigned int _rx_empty_count; unsigned int _tx_empty_count; - std::stack<dpdk_zero_copy_mrb *, std::vector<dpdk_zero_copy_mrb *>> _mrb_pool; - std::stack<dpdk_zero_copy_msb *, std::vector<dpdk_zero_copy_msb *>> _msb_pool; + std::stack<dpdk_zero_copy_mrb*, std::vector<dpdk_zero_copy_mrb*>> _mrb_pool; + std::stack<dpdk_zero_copy_msb*, std::vector<dpdk_zero_copy_msb*>> _msb_pool; }; -dpdk_zero_copy::sptr dpdk_zero_copy::make( - struct uhd_dpdk_ctx &ctx, +dpdk_zero_copy::sptr dpdk_zero_copy::make(struct uhd_dpdk_ctx& ctx, const unsigned int dpdk_port_id, - const std::string &addr, - const std::string &remote_port, - const std::string &local_port, - const zero_copy_xport_params &default_buff_args, - const device_addr_t &hints) + const std::string& addr, + const std::string& remote_port, + const std::string& local_port, + const zero_copy_xport_params& default_buff_args, + const device_addr_t& hints) { - return dpdk_zero_copy::sptr( - new dpdk_zero_copy_impl(ctx, dpdk_port_id, addr, remote_port, local_port, default_buff_args) - ); + return dpdk_zero_copy::sptr(new dpdk_zero_copy_impl( + ctx, dpdk_port_id, addr, remote_port, local_port, default_buff_args)); } -}} +}} // namespace uhd::transport diff --git a/host/lib/transport/dpdk_zero_copy.hpp b/host/lib/transport/dpdk_zero_copy.hpp index a4b5b4879..f90e73d0e 100644 --- a/host/lib/transport/dpdk_zero_copy.hpp +++ b/host/lib/transport/dpdk_zero_copy.hpp @@ -8,19 +8,20 @@ #define DPDK_ZERO_COPY_HPP #include <uhd/config.hpp> +#include <uhd/transport/zero_copy.hpp> #include <uhd/types/device_addr.hpp> -#include <uhd/utils/static.hpp> #include <uhd/utils/log.hpp> -#include <uhd/transport/zero_copy.hpp> +#include <uhd/utils/static.hpp> #include <boost/shared_ptr.hpp> +#include <mutex> #include <string> #include <vector> -#include <mutex> namespace uhd { namespace transport { -class uhd_dpdk_ctx : boost::noncopyable { +class uhd_dpdk_ctx : boost::noncopyable +{ public: UHD_SINGLETON_FCN(uhd_dpdk_ctx, get); @@ -35,9 +36,12 @@ public: * \param mbuf_cache_size Size of per-core packet buffer cache from mempool * \param mtu MTU of NIC ports */ - void init(const dict<std::string, std::string> &eal_args, unsigned int num_ports, - int *port_thread_mapping, int num_mbufs, int mbuf_cache_size, - size_t mtu); + void init(const dict<std::string, std::string>& eal_args, + unsigned int num_ports, + int* port_thread_mapping, + int num_mbufs, + int mbuf_cache_size, + size_t mtu); /*! * Get port ID from provided MAC address @@ -45,14 +49,14 @@ public: * \param port_id Int to write ID of port corresponding to MAC address * \return 0 if match found, else no match */ - int get_port_id(std::array<uint8_t, 6> mac_addr, unsigned int &port_id); + int get_port_id(std::array<uint8_t, 6> mac_addr, unsigned int& port_id); /*! * Get port ID for routing packet destined for given address * \param addr Destination address * \return port ID from routing table */ - int get_route(const std::string &addr) const; + int get_route(const std::string& addr) const; /*! * Set IPv4 address and subnet mask of given NIC port @@ -80,19 +84,18 @@ private: /*! * A zero copy transport interface to the dpdk DMA library. */ -class dpdk_zero_copy : public virtual zero_copy_if { +class dpdk_zero_copy : public virtual zero_copy_if +{ public: typedef boost::shared_ptr<dpdk_zero_copy> sptr; - static sptr make( - struct uhd_dpdk_ctx &ctx, + static sptr make(struct uhd_dpdk_ctx& ctx, const unsigned int dpdk_port_id, - const std::string &addr, - const std::string &remote_port, - const std::string &local_port, /* 0 = auto-assign */ - const zero_copy_xport_params &default_buff_args, - const device_addr_t &hints - ); + const std::string& addr, + const std::string& remote_port, + const std::string& local_port, /* 0 = auto-assign */ + const zero_copy_xport_params& default_buff_args, + const device_addr_t& hints); virtual uint16_t get_local_port(void) const = 0; @@ -101,6 +104,6 @@ public: virtual uint32_t get_drop_count(void) const = 0; }; -}} +}} // namespace uhd::transport #endif /* DPDK_ZERO_COPY_HPP */ diff --git a/host/lib/transport/if_addrs.cpp b/host/lib/transport/if_addrs.cpp index 109619601..a1cb6909f 100644 --- a/host/lib/transport/if_addrs.cpp +++ b/host/lib/transport/if_addrs.cpp @@ -6,47 +6,54 @@ // #include <uhd/transport/if_addrs.hpp> -#include <boost/asio/ip/address_v4.hpp> #include <stdint.h> +#include <boost/asio/ip/address_v4.hpp> #include <iostream> /*********************************************************************** * Interface address discovery through ifaddrs api **********************************************************************/ #ifdef HAVE_GETIFADDRS -#include <ifaddrs.h> +# include <ifaddrs.h> -static boost::asio::ip::address_v4 sockaddr_to_ip_addr(sockaddr *addr){ - return boost::asio::ip::address_v4(ntohl( - reinterpret_cast<sockaddr_in*>(addr)->sin_addr.s_addr - )); +static boost::asio::ip::address_v4 sockaddr_to_ip_addr(sockaddr* addr) +{ + return boost::asio::ip::address_v4( + ntohl(reinterpret_cast<sockaddr_in*>(addr)->sin_addr.s_addr)); } -std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){ +std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void) +{ std::vector<if_addrs_t> if_addrs; - struct ifaddrs *ifap; - if (getifaddrs(&ifap) == 0){ - for (struct ifaddrs *iter = ifap; iter != nullptr; iter = iter->ifa_next){ - //ensure that the entries are valid - if (iter->ifa_addr == nullptr) continue; - if (iter->ifa_addr->sa_family != AF_INET) continue; - if (iter->ifa_netmask->sa_family != AF_INET) continue; - if (iter->ifa_broadaddr->sa_family != AF_INET) continue; - - //append a new set of interface addresses + struct ifaddrs* ifap; + if (getifaddrs(&ifap) == 0) { + for (struct ifaddrs* iter = ifap; iter != nullptr; iter = iter->ifa_next) { + // ensure that the entries are valid + if (iter->ifa_addr == nullptr) + continue; + if (iter->ifa_addr->sa_family != AF_INET) + continue; + if (iter->ifa_netmask->sa_family != AF_INET) + continue; + if (iter->ifa_broadaddr->sa_family != AF_INET) + continue; + + // append a new set of interface addresses if_addrs_t if_addr; - if_addr.inet = sockaddr_to_ip_addr(iter->ifa_addr).to_string(); - if_addr.mask = sockaddr_to_ip_addr(iter->ifa_netmask).to_string(); + if_addr.inet = sockaddr_to_ip_addr(iter->ifa_addr).to_string(); + if_addr.mask = sockaddr_to_ip_addr(iter->ifa_netmask).to_string(); if_addr.bcast = sockaddr_to_ip_addr(iter->ifa_broadaddr).to_string(); - //correct the bcast address when its same as the gateway - if (if_addr.inet == if_addr.bcast or sockaddr_to_ip_addr(iter->ifa_broadaddr) == boost::asio::ip::address_v4(0)){ - //manually calculate broadcast address - //https://svn.boost.org/trac/boost/ticket/5198 - const uint32_t addr = sockaddr_to_ip_addr(iter->ifa_addr).to_ulong(); - const uint32_t mask = sockaddr_to_ip_addr(iter->ifa_netmask).to_ulong(); + // correct the bcast address when its same as the gateway + if (if_addr.inet == if_addr.bcast + or sockaddr_to_ip_addr(iter->ifa_broadaddr) + == boost::asio::ip::address_v4(0)) { + // manually calculate broadcast address + // https://svn.boost.org/trac/boost/ticket/5198 + const uint32_t addr = sockaddr_to_ip_addr(iter->ifa_addr).to_ulong(); + const uint32_t mask = sockaddr_to_ip_addr(iter->ifa_netmask).to_ulong(); const uint32_t bcast = (addr & mask) | ~mask; - if_addr.bcast = boost::asio::ip::address_v4(bcast).to_string(); + if_addr.bcast = boost::asio::ip::address_v4(bcast).to_string(); } if_addrs.push_back(if_addr); @@ -62,34 +69,44 @@ std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){ * Interface address discovery through windows api **********************************************************************/ #ifdef HAVE_SIO_GET_INTERFACE_LIST -#include <winsock2.h> +# include <winsock2.h> -std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){ +std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void) +{ std::vector<if_addrs_t> if_addrs; SOCKET sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0); if (sd == SOCKET_ERROR) { - std::cerr << "Failed to get a socket. Error " << WSAGetLastError() << - std::endl; return if_addrs; + std::cerr << "Failed to get a socket. Error " << WSAGetLastError() << std::endl; + return if_addrs; } INTERFACE_INFO InterfaceList[20]; unsigned long nBytesReturned; - if (WSAIoctl(sd, SIO_GET_INTERFACE_LIST, 0, 0, &InterfaceList, - sizeof(InterfaceList), &nBytesReturned, 0, 0) == SOCKET_ERROR) { - std::cerr << "Failed calling WSAIoctl: error " << WSAGetLastError() << - std::endl; - return if_addrs; + if (WSAIoctl(sd, + SIO_GET_INTERFACE_LIST, + 0, + 0, + &InterfaceList, + sizeof(InterfaceList), + &nBytesReturned, + 0, + 0) + == SOCKET_ERROR) { + std::cerr << "Failed calling WSAIoctl: error " << WSAGetLastError() << std::endl; + return if_addrs; } int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO); for (int i = 0; i < nNumInterfaces; ++i) { - uint32_t iiAddress = ntohl(reinterpret_cast<sockaddr_in&>(InterfaceList[i].iiAddress).sin_addr.s_addr); - uint32_t iiNetmask = ntohl(reinterpret_cast<sockaddr_in&>(InterfaceList[i].iiNetmask).sin_addr.s_addr); + uint32_t iiAddress = ntohl( + reinterpret_cast<sockaddr_in&>(InterfaceList[i].iiAddress).sin_addr.s_addr); + uint32_t iiNetmask = ntohl( + reinterpret_cast<sockaddr_in&>(InterfaceList[i].iiNetmask).sin_addr.s_addr); uint32_t iiBroadcastAddress = (iiAddress & iiNetmask) | ~iiNetmask; if_addrs_t if_addr; - if_addr.inet = boost::asio::ip::address_v4(iiAddress).to_string(); - if_addr.mask = boost::asio::ip::address_v4(iiNetmask).to_string(); + if_addr.inet = boost::asio::ip::address_v4(iiAddress).to_string(); + if_addr.mask = boost::asio::ip::address_v4(iiNetmask).to_string(); if_addr.bcast = boost::asio::ip::address_v4(iiBroadcastAddress).to_string(); if_addrs.push_back(if_addr); } @@ -104,7 +121,8 @@ std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){ **********************************************************************/ #ifdef HAVE_IF_ADDRS_DUMMY -std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void){ +std::vector<uhd::transport::if_addrs_t> uhd::transport::get_if_addrs(void) +{ return std::vector<if_addrs_t>(); } diff --git a/host/lib/transport/liberio_zero_copy.cpp b/host/lib/transport/liberio_zero_copy.cpp index 0999d78cf..989480382 100644 --- a/host/lib/transport/liberio_zero_copy.cpp +++ b/host/lib/transport/liberio_zero_copy.cpp @@ -7,33 +7,34 @@ #include "liberio_zero_copy.hpp" #include <uhd/config.hpp> -#include <uhd/utils/static.hpp> #include <uhd/utils/log.hpp> +#include <uhd/utils/static.hpp> #include <liberio/liberio.h> -#include <boost/make_shared.hpp> #include <sys/syslog.h> +#include <boost/make_shared.hpp> #include <mutex> namespace uhd { namespace transport { static const uint64_t USEC = 1000000; -static void liberio_log_cb(int severity, const char *msg, void *) +static void liberio_log_cb(int severity, const char* msg, void*) { switch (severity) { - case LOG_WARNING: - UHD_LOG_WARNING("LIBERIO", msg); - return; - case LOG_NOTICE: - case LOG_INFO: - UHD_LOG_INFO("LIBERIO", msg); - return; - default: - UHD_LOG_INFO("LIBERIO", msg); + case LOG_WARNING: + UHD_LOG_WARNING("LIBERIO", msg); + return; + case LOG_NOTICE: + case LOG_INFO: + UHD_LOG_INFO("LIBERIO", msg); + return; + default: + UHD_LOG_INFO("LIBERIO", msg); }; } -class liberio_context_holder { +class liberio_context_holder +{ public: liberio_context_holder(void) { @@ -41,22 +42,27 @@ public: liberio_ctx_register_logger(_ctx, &liberio_log_cb, nullptr); } - ~liberio_context_holder(void) { liberio_ctx_put(_ctx); } + ~liberio_context_holder(void) + { + liberio_ctx_put(_ctx); + } liberio_ctx* get(void) { liberio_ctx_get(_ctx); return _ctx; } + private: - liberio_ctx *_ctx; + liberio_ctx* _ctx; }; UHD_SINGLETON_FCN(liberio_context_holder, get_liberio_context_holder); -class liberio_zero_copy_msb : public virtual managed_send_buffer { +class liberio_zero_copy_msb : public virtual managed_send_buffer +{ public: - liberio_zero_copy_msb(liberio_chan *chan) : _chan(chan), _buf(nullptr) {} + liberio_zero_copy_msb(liberio_chan* chan) : _chan(chan), _buf(nullptr) {} ~liberio_zero_copy_msb(void) { liberio_chan_put(_chan); @@ -70,7 +76,7 @@ public: } } - sptr get_new(double timeout, size_t &index) + sptr get_new(double timeout, size_t& index) { _buf = liberio_chan_buf_dequeue(_chan, timeout * USEC); if (!_buf) @@ -78,18 +84,18 @@ public: index++; - return make(this, liberio_buf_get_mem(_buf, 0), - liberio_buf_get_len(_buf, 0)); + return make(this, liberio_buf_get_mem(_buf, 0), liberio_buf_get_len(_buf, 0)); } private: - liberio_chan *_chan; - liberio_buf *_buf; + liberio_chan* _chan; + liberio_buf* _buf; }; -class liberio_zero_copy_mrb : public virtual managed_recv_buffer { +class liberio_zero_copy_mrb : public virtual managed_recv_buffer +{ public: - liberio_zero_copy_mrb(liberio_chan *chan) : _chan(chan), _buf(nullptr) {} + liberio_zero_copy_mrb(liberio_chan* chan) : _chan(chan), _buf(nullptr) {} ~liberio_zero_copy_mrb(void) { liberio_chan_put(_chan); @@ -101,7 +107,7 @@ public: liberio_chan_buf_enqueue(_chan, _buf); } - sptr get_new(double timeout, size_t &index) + sptr get_new(double timeout, size_t& index) { _buf = liberio_chan_buf_dequeue(_chan, timeout * USEC); if (!_buf) @@ -109,65 +115,55 @@ public: index++; - return make(this, liberio_buf_get_mem(_buf, 0), - liberio_buf_get_payload(_buf, 0)); + return make(this, liberio_buf_get_mem(_buf, 0), liberio_buf_get_payload(_buf, 0)); } private: - liberio_chan *_chan; - liberio_buf *_buf; + liberio_chan* _chan; + liberio_buf* _buf; }; -class liberio_zero_copy_impl : public liberio_zero_copy { +class liberio_zero_copy_impl : public liberio_zero_copy +{ public: - - liberio_zero_copy_impl(const std::string &tx_path, - const std::string &rx_path, - const zero_copy_xport_params& xport_params) - : _tx_buf_size(xport_params.send_frame_size), - _rx_buf_size(xport_params.recv_frame_size), - _next_recv_buff_index(0), - _next_send_buff_index(0) + liberio_zero_copy_impl(const std::string& tx_path, + const std::string& rx_path, + const zero_copy_xport_params& xport_params) + : _tx_buf_size(xport_params.send_frame_size) + , _rx_buf_size(xport_params.recv_frame_size) + , _next_recv_buff_index(0) + , _next_send_buff_index(0) { UHD_ASSERT_THROW(xport_params.recv_frame_size > 0); UHD_ASSERT_THROW(xport_params.send_frame_size > 0); UHD_ASSERT_THROW(xport_params.num_send_frames > 0); UHD_ASSERT_THROW(xport_params.num_recv_frames > 0); - liberio_ctx *ctx = get_liberio_context_holder().get(); + liberio_ctx* ctx = get_liberio_context_holder().get(); /* we hold a reference, that we'd drop immediately after, * so no requirement to get another one here ... */ - _tx_chan = liberio_ctx_alloc_chan(ctx, tx_path.c_str(), TX, - USRP_MEMORY_MMAP); + _tx_chan = liberio_ctx_alloc_chan(ctx, tx_path.c_str(), TX, USRP_MEMORY_MMAP); UHD_ASSERT_THROW(_tx_chan); liberio_chan_stop_streaming(_tx_chan); liberio_chan_request_buffers(_tx_chan, 0); UHD_ASSERT_THROW( - !liberio_chan_set_fixed_size(_tx_chan, 0, - xport_params.send_frame_size - ) - ); + !liberio_chan_set_fixed_size(_tx_chan, 0, xport_params.send_frame_size)); UHD_ASSERT_THROW( - !liberio_chan_request_buffers( - _tx_chan, xport_params.num_send_frames - ) - ); + !liberio_chan_request_buffers(_tx_chan, xport_params.num_send_frames)); _num_send_bufs = liberio_chan_get_num_bufs(_tx_chan); for (size_t i = 0; i < xport_params.num_send_frames; i++) { liberio_chan_get(_tx_chan); - _msb_pool.push_back( - boost::make_shared<liberio_zero_copy_msb>(_tx_chan)); + _msb_pool.push_back(boost::make_shared<liberio_zero_copy_msb>(_tx_chan)); } /* we hold a reference, that we'd drop immediately after, * so no requirement to get another one here ... */ - _rx_chan = liberio_ctx_alloc_chan(ctx, rx_path.c_str(), - RX, USRP_MEMORY_MMAP); + _rx_chan = liberio_ctx_alloc_chan(ctx, rx_path.c_str(), RX, USRP_MEMORY_MMAP); UHD_ASSERT_THROW(_rx_chan); /* done with the local reference, the channel keeps its own */ @@ -177,18 +173,14 @@ public: liberio_chan_stop_streaming(_rx_chan); liberio_chan_request_buffers(_rx_chan, 0); UHD_ASSERT_THROW( - !liberio_chan_set_fixed_size(_rx_chan, 0, - xport_params.recv_frame_size - ) - ); - UHD_ASSERT_THROW(!liberio_chan_request_buffers( - _rx_chan, xport_params.num_recv_frames)); + !liberio_chan_set_fixed_size(_rx_chan, 0, xport_params.recv_frame_size)); + UHD_ASSERT_THROW( + !liberio_chan_request_buffers(_rx_chan, xport_params.num_recv_frames)); _num_recv_bufs = liberio_chan_get_num_bufs(_rx_chan); for (size_t i = 0; i < xport_params.num_recv_frames; i++) { liberio_chan_get(_rx_chan); - _mrb_pool.push_back( - boost::make_shared<liberio_zero_copy_mrb>(_rx_chan)); + _mrb_pool.push_back(boost::make_shared<liberio_zero_copy_mrb>(_rx_chan)); } UHD_ASSERT_THROW(!liberio_chan_enqueue_all(_rx_chan)); @@ -208,8 +200,7 @@ public: std::lock_guard<std::mutex> lock(_rx_mutex); if (_next_recv_buff_index == _num_recv_bufs) _next_recv_buff_index = 0; - return _mrb_pool[_next_recv_buff_index]->get_new( - timeout, _next_recv_buff_index); + return _mrb_pool[_next_recv_buff_index]->get_new(timeout, _next_recv_buff_index); } size_t get_num_recv_frames(void) const @@ -223,12 +214,11 @@ public: } managed_send_buffer::sptr get_send_buff(double timeout = 0.1) - { + { std::lock_guard<std::mutex> lock(_tx_mutex); if (_next_send_buff_index == _num_send_bufs) _next_send_buff_index = 0; - return _msb_pool[_next_send_buff_index]->get_new( - timeout, _next_send_buff_index); + return _msb_pool[_next_send_buff_index]->get_new(timeout, _next_send_buff_index); } size_t get_num_send_frames(void) const @@ -242,29 +232,27 @@ public: } private: - liberio_chan *_tx_chan; + liberio_chan* _tx_chan; const size_t _tx_buf_size; size_t _num_send_bufs; - liberio_chan *_rx_chan; + liberio_chan* _rx_chan; const size_t _rx_buf_size; size_t _num_recv_bufs; - std::vector<boost::shared_ptr<liberio_zero_copy_mrb> > _mrb_pool; + std::vector<boost::shared_ptr<liberio_zero_copy_mrb>> _mrb_pool; size_t _next_recv_buff_index; - std::vector<boost::shared_ptr<liberio_zero_copy_msb> > _msb_pool; + std::vector<boost::shared_ptr<liberio_zero_copy_msb>> _msb_pool; size_t _next_send_buff_index; std::mutex _rx_mutex; std::mutex _tx_mutex; }; -liberio_zero_copy::sptr liberio_zero_copy::make( - const std::string &tx_path, - const std::string &rx_path, - const zero_copy_xport_params &default_buff_args) +liberio_zero_copy::sptr liberio_zero_copy::make(const std::string& tx_path, + const std::string& rx_path, + const zero_copy_xport_params& default_buff_args) { return liberio_zero_copy::sptr( - new liberio_zero_copy_impl(tx_path, rx_path, default_buff_args) - ); + new liberio_zero_copy_impl(tx_path, rx_path, default_buff_args)); } -}} +}} // namespace uhd::transport diff --git a/host/lib/transport/liberio_zero_copy.hpp b/host/lib/transport/liberio_zero_copy.hpp index 1dfa3af71..b41b6416c 100644 --- a/host/lib/transport/liberio_zero_copy.hpp +++ b/host/lib/transport/liberio_zero_copy.hpp @@ -8,30 +8,28 @@ #ifndef LIBERIO_HPP #define LIBERIO_HPP -#include <string> -#include <vector> - #include <uhd/config.hpp> #include <uhd/transport/zero_copy.hpp> #include <uhd/types/device_addr.hpp> #include <boost/shared_ptr.hpp> +#include <string> +#include <vector> namespace uhd { namespace transport { /*! * A zero copy transport interface to the liberio DMA library. */ -class liberio_zero_copy : public virtual zero_copy_if { +class liberio_zero_copy : public virtual zero_copy_if +{ public: typedef boost::shared_ptr<liberio_zero_copy> sptr; - static sptr make( - const std::string &tx_path, - const std::string &rx_path, - const zero_copy_xport_params &default_buff_args - ); + static sptr make(const std::string& tx_path, + const std::string& rx_path, + const zero_copy_xport_params& default_buff_args); }; -}} +}} // namespace uhd::transport #endif /* LIBERIO_HPP */ diff --git a/host/lib/transport/libusb1_base.cpp b/host/lib/transport/libusb1_base.cpp index 03d99aa47..83d9fe1df 100644 --- a/host/lib/transport/libusb1_base.cpp +++ b/host/lib/transport/libusb1_base.cpp @@ -7,14 +7,13 @@ #include "libusb1_base.hpp" #include <uhd/exception.hpp> - -#include <uhd/utils/log.hpp> -#include <uhd/utils/tasks.hpp> #include <uhd/types/dict.hpp> #include <uhd/types/serial.hpp> -#include <boost/weak_ptr.hpp> -#include <boost/thread/mutex.hpp> +#include <uhd/utils/log.hpp> +#include <uhd/utils/tasks.hpp> #include <boost/bind.hpp> +#include <boost/thread/mutex.hpp> +#include <boost/weak_ptr.hpp> #include <cstdlib> #include <iostream> @@ -24,75 +23,84 @@ using namespace uhd::transport; /*********************************************************************** * libusb session **********************************************************************/ -libusb::session::~session(void) { +libusb::session::~session(void) +{ /* NOP */ } -class libusb_session_impl : public libusb::session{ +class libusb_session_impl : public libusb::session +{ public: - libusb_session_impl(void){ + libusb_session_impl(void) + { UHD_ASSERT_THROW(libusb_init(&_context) == 0); libusb_set_debug(_context, debug_level); - task_handler = task::make(boost::bind(&libusb_session_impl::libusb_event_handler_task, this, _context)); + task_handler = task::make( + boost::bind(&libusb_session_impl::libusb_event_handler_task, this, _context)); } virtual ~libusb_session_impl(void); - libusb_context *get_context(void) const{ + libusb_context* get_context(void) const + { return _context; } private: - libusb_context *_context; + libusb_context* _context; task::sptr task_handler; /* - * Task to handle libusb events. There should only be one thread per libusb_context handling events. - * Using more than one thread can result in excessive CPU usage in kernel space (presumably from locking/waiting). - * The libusb documentation says it is safe, which it is, but it neglects to state the cost in CPU usage. - * Just don't do it! + * Task to handle libusb events. There should only be one thread per libusb_context + * handling events. Using more than one thread can result in excessive CPU usage in + * kernel space (presumably from locking/waiting). The libusb documentation says it is + * safe, which it is, but it neglects to state the cost in CPU usage. Just don't do + * it! */ - UHD_INLINE void libusb_event_handler_task(libusb_context *context) + UHD_INLINE void libusb_event_handler_task(libusb_context* context) { timeval tv; - tv.tv_sec = 0; + tv.tv_sec = 0; tv.tv_usec = 100000; - int ret = libusb_handle_events_timeout(context, &tv); - switch (ret) - { - case LIBUSB_SUCCESS: - case LIBUSB_ERROR_TIMEOUT: - break; - case LIBUSB_ERROR_NO_DEVICE: - throw uhd::io_error(libusb_strerror(LIBUSB_ERROR_NO_DEVICE)); - default: - UHD_LOGGER_ERROR("USB") << __FUNCTION__ << ": " << libusb_strerror((libusb_error)ret) ; - break; + int ret = libusb_handle_events_timeout(context, &tv); + switch (ret) { + case LIBUSB_SUCCESS: + case LIBUSB_ERROR_TIMEOUT: + break; + case LIBUSB_ERROR_NO_DEVICE: + throw uhd::io_error(libusb_strerror(LIBUSB_ERROR_NO_DEVICE)); + default: + UHD_LOGGER_ERROR("USB") + << __FUNCTION__ << ": " << libusb_strerror((libusb_error)ret); + break; } } }; -libusb_session_impl::~libusb_session_impl(void){ +libusb_session_impl::~libusb_session_impl(void) +{ task_handler.reset(); libusb_exit(_context); } -libusb::session::sptr libusb::session::get_global_session(void){ +libusb::session::sptr libusb::session::get_global_session(void) +{ static boost::weak_ptr<session> global_session; - //not expired -> get existing session - if (not global_session.expired()) return global_session.lock(); + // not expired -> get existing session + if (not global_session.expired()) + return global_session.lock(); - //create a new global session + // create a new global session sptr new_global_session(new libusb_session_impl()); global_session = new_global_session; - //set logging if envvar is set - const char *level_string = getenv("LIBUSB_DEBUG_LEVEL"); - if (level_string != NULL) - { - const int level = int(level_string[0] - '0'); //easy conversion to integer - if (level >= 0 and level <= 3) libusb_set_debug(new_global_session->get_context(), level); + // set logging if envvar is set + const char* level_string = getenv("LIBUSB_DEBUG_LEVEL"); + if (level_string != NULL) { + const int level = int(level_string[0] - '0'); // easy conversion to integer + if (level >= 0 and level <= 3) + libusb_set_debug(new_global_session->get_context(), level); } return new_global_session; @@ -101,65 +109,75 @@ libusb::session::sptr libusb::session::get_global_session(void){ /*********************************************************************** * libusb device **********************************************************************/ -libusb::device::~device(void) { +libusb::device::~device(void) +{ /* NOP */ } -class libusb_device_impl : public libusb::device{ +class libusb_device_impl : public libusb::device +{ public: - libusb_device_impl(libusb_device *dev){ + libusb_device_impl(libusb_device* dev) + { _session = libusb::session::get_global_session(); - _dev = dev; + _dev = dev; } virtual ~libusb_device_impl(void); - libusb_device *get(void) const{ + libusb_device* get(void) const + { return _dev; } private: - libusb::session::sptr _session; //always keep a reference to session - libusb_device *_dev; + libusb::session::sptr _session; // always keep a reference to session + libusb_device* _dev; }; -libusb_device_impl::~libusb_device_impl(void){ +libusb_device_impl::~libusb_device_impl(void) +{ libusb_unref_device(this->get()); } /*********************************************************************** * libusb device list **********************************************************************/ -libusb::device_list::~device_list(void){ +libusb::device_list::~device_list(void) +{ /* NOP */ } -class libusb_device_list_impl : public libusb::device_list{ +class libusb_device_list_impl : public libusb::device_list +{ public: - libusb_device_list_impl(void){ + libusb_device_list_impl(void) + { libusb::session::sptr sess = libusb::session::get_global_session(); - //allocate a new list of devices + // allocate a new list of devices libusb_device** dev_list; ssize_t ret = libusb_get_device_list(sess->get_context(), &dev_list); - if (ret < 0) throw uhd::os_error("cannot enumerate usb devices"); + if (ret < 0) + throw uhd::os_error("cannot enumerate usb devices"); - //fill the vector of device references - for (size_t i = 0; i < size_t(ret); i++) _devs.push_back( - libusb::device::sptr(new libusb_device_impl(dev_list[i])) - ); + // fill the vector of device references + for (size_t i = 0; i < size_t(ret); i++) + _devs.push_back(libusb::device::sptr(new libusb_device_impl(dev_list[i]))); - //free the device list but dont unref (done in ~device) - libusb_free_device_list(dev_list, false/*dont unref*/); + // free the device list but dont unref (done in ~device) + libusb_free_device_list(dev_list, false /*dont unref*/); } virtual ~libusb_device_list_impl(void); - size_t size(void) const{ + size_t size(void) const + { return _devs.size(); } - libusb::device::sptr at(size_t i) const{ + libusb::device::sptr at(size_t i) const + { return _devs.at(i); } @@ -167,96 +185,113 @@ private: std::vector<libusb::device::sptr> _devs; }; -libusb_device_list_impl::~libusb_device_list_impl(void){ +libusb_device_list_impl::~libusb_device_list_impl(void) +{ /* NOP */ } -libusb::device_list::sptr libusb::device_list::make(void){ +libusb::device_list::sptr libusb::device_list::make(void) +{ return sptr(new libusb_device_list_impl()); } /*********************************************************************** * libusb device descriptor **********************************************************************/ -libusb::device_descriptor::~device_descriptor(void){ +libusb::device_descriptor::~device_descriptor(void) +{ /* NOP */ } -class libusb_device_descriptor_impl : public libusb::device_descriptor{ +class libusb_device_descriptor_impl : public libusb::device_descriptor +{ public: - libusb_device_descriptor_impl(libusb::device::sptr dev){ + libusb_device_descriptor_impl(libusb::device::sptr dev) + { _dev = dev; UHD_ASSERT_THROW(libusb_get_device_descriptor(_dev->get(), &_desc) == 0); } virtual ~libusb_device_descriptor_impl(void); - const libusb_device_descriptor &get(void) const{ + const libusb_device_descriptor& get(void) const + { return _desc; } - std::string get_ascii_property(const std::string &what) const + std::string get_ascii_property(const std::string& what) const { uint8_t off = 0; - if (what == "serial") off = this->get().iSerialNumber; - if (what == "product") off = this->get().iProduct; - if (what == "manufacturer") off = this->get().iManufacturer; - if (off == 0) return ""; + if (what == "serial") + off = this->get().iSerialNumber; + if (what == "product") + off = this->get().iProduct; + if (what == "manufacturer") + off = this->get().iManufacturer; + if (off == 0) + return ""; libusb::device_handle::sptr handle( - libusb::device_handle::get_cached_handle(_dev) - ); + libusb::device_handle::get_cached_handle(_dev)); unsigned char buff[512]; int ret = libusb_get_string_descriptor_ascii( - handle->get(), off, buff, int(sizeof(buff)) - ); - if (ret < 0) return ""; //on error, just return empty string + handle->get(), off, buff, int(sizeof(buff))); + if (ret < 0) + return ""; // on error, just return empty string - std::string string_descriptor((char *)buff, size_t(ret)); + std::string string_descriptor((char*)buff, size_t(ret)); byte_vector_t string_vec(string_descriptor.begin(), string_descriptor.end()); std::string out; - for(uint8_t byte: string_vec){ - if (byte < 32 or byte > 127) return out; + for (uint8_t byte : string_vec) { + if (byte < 32 or byte > 127) + return out; out += byte; } return out; } private: - libusb::device::sptr _dev; //always keep a reference to device + libusb::device::sptr _dev; // always keep a reference to device libusb_device_descriptor _desc; }; -libusb_device_descriptor_impl::~libusb_device_descriptor_impl(void){ +libusb_device_descriptor_impl::~libusb_device_descriptor_impl(void) +{ /* NOP */ } -libusb::device_descriptor::sptr libusb::device_descriptor::make(device::sptr dev){ +libusb::device_descriptor::sptr libusb::device_descriptor::make(device::sptr dev) +{ return sptr(new libusb_device_descriptor_impl(dev)); } /*********************************************************************** * libusb device handle **********************************************************************/ -libusb::device_handle::~device_handle(void){ +libusb::device_handle::~device_handle(void) +{ /* NOP */ } -class libusb_device_handle_impl : public libusb::device_handle{ +class libusb_device_handle_impl : public libusb::device_handle +{ public: - libusb_device_handle_impl(libusb::device::sptr dev){ + libusb_device_handle_impl(libusb::device::sptr dev) + { _dev = dev; UHD_ASSERT_THROW(libusb_open(_dev->get(), &_handle) == 0); } virtual ~libusb_device_handle_impl(void); - libusb_device_handle *get(void) const{ + libusb_device_handle* get(void) const + { return _handle; } - void claim_interface(int interface){ + void claim_interface(int interface) + { UHD_ASSERT_THROW(libusb_claim_interface(this->get(), interface) == 0); _claimed.push_back(interface); } @@ -264,59 +299,61 @@ public: void clear_endpoints(unsigned char recv_endpoint, unsigned char send_endpoint) { int ret; - ret = libusb_clear_halt(this->get(), recv_endpoint | 0x80); - UHD_LOGGER_TRACE("USB") << "usb device handle: recv endpoint clear: " << libusb_error_name(ret) ; + ret = libusb_clear_halt(this->get(), recv_endpoint | 0x80); + UHD_LOGGER_TRACE("USB") + << "usb device handle: recv endpoint clear: " << libusb_error_name(ret); ret = libusb_clear_halt(this->get(), send_endpoint | 0x00); - UHD_LOGGER_TRACE("USB") << "usb device handle: send endpoint clear: " << libusb_error_name(ret) ; + UHD_LOGGER_TRACE("USB") + << "usb device handle: send endpoint clear: " << libusb_error_name(ret); } void reset_device(void) { int ret = libusb_reset_device(this->get()); - UHD_LOGGER_TRACE("USB") << "usb device handle: dev Reset: " << libusb_error_name(ret) ; + UHD_LOGGER_TRACE("USB") + << "usb device handle: dev Reset: " << libusb_error_name(ret); } private: - libusb::device::sptr _dev; //always keep a reference to device - libusb_device_handle *_handle; + libusb::device::sptr _dev; // always keep a reference to device + libusb_device_handle* _handle; std::vector<int> _claimed; }; -libusb_device_handle_impl::~libusb_device_handle_impl(void){ - //release all claimed interfaces - for (size_t i = 0; i < _claimed.size(); i++){ +libusb_device_handle_impl::~libusb_device_handle_impl(void) +{ + // release all claimed interfaces + for (size_t i = 0; i < _claimed.size(); i++) { libusb_release_interface(this->get(), _claimed[i]); } libusb_close(_handle); } -libusb::device_handle::sptr libusb::device_handle::get_cached_handle(device::sptr dev){ - static uhd::dict<libusb_device *, boost::weak_ptr<device_handle> > handles; +libusb::device_handle::sptr libusb::device_handle::get_cached_handle(device::sptr dev) +{ + static uhd::dict<libusb_device*, boost::weak_ptr<device_handle>> handles; - //lock for atomic access to static table above + // lock for atomic access to static table above static boost::mutex mutex; boost::mutex::scoped_lock lock(mutex); - //not expired -> get existing handle - if (handles.has_key(dev->get()) and not handles[dev->get()].expired()){ + // not expired -> get existing handle + if (handles.has_key(dev->get()) and not handles[dev->get()].expired()) { return handles[dev->get()].lock(); } - //create a new cached handle - try{ + // create a new cached handle + try { sptr new_handle(new libusb_device_handle_impl(dev)); handles[dev->get()] = new_handle; return new_handle; - } - catch(const uhd::exception &){ - #ifdef UHD_PLATFORM_LINUX - UHD_LOGGER_ERROR("USB") << - "USB open failed: insufficient permissions.\n" - "See the application notes for your device.\n" - ; - #else - UHD_LOGGER_DEBUG("USB") << "USB open failed: device already claimed." ; - #endif + } catch (const uhd::exception&) { +#ifdef UHD_PLATFORM_LINUX + UHD_LOGGER_ERROR("USB") << "USB open failed: insufficient permissions.\n" + "See the application notes for your device.\n"; +#else + UHD_LOGGER_DEBUG("USB") << "USB open failed: device already claimed."; +#endif throw; } } @@ -324,85 +361,105 @@ libusb::device_handle::sptr libusb::device_handle::get_cached_handle(device::spt /*********************************************************************** * libusb special handle **********************************************************************/ -libusb::special_handle::~special_handle(void){ +libusb::special_handle::~special_handle(void) +{ /* NOP */ } -class libusb_special_handle_impl : public libusb::special_handle{ +class libusb_special_handle_impl : public libusb::special_handle +{ public: - libusb_special_handle_impl(libusb::device::sptr dev){ + libusb_special_handle_impl(libusb::device::sptr dev) + { _dev = dev; } virtual ~libusb_special_handle_impl(void); - libusb::device::sptr get_device(void) const{ + libusb::device::sptr get_device(void) const + { return _dev; } - std::string get_serial(void) const{ - return libusb::device_descriptor::make(this->get_device())->get_ascii_property("serial"); + std::string get_serial(void) const + { + return libusb::device_descriptor::make(this->get_device()) + ->get_ascii_property("serial"); } - std::string get_manufacturer() const{ - return libusb::device_descriptor::make(this->get_device())->get_ascii_property("manufacturer"); + std::string get_manufacturer() const + { + return libusb::device_descriptor::make(this->get_device()) + ->get_ascii_property("manufacturer"); } - std::string get_product() const{ - return libusb::device_descriptor::make(this->get_device())->get_ascii_property("product"); + std::string get_product() const + { + return libusb::device_descriptor::make(this->get_device()) + ->get_ascii_property("product"); } - uint16_t get_vendor_id(void) const{ + uint16_t get_vendor_id(void) const + { return libusb::device_descriptor::make(this->get_device())->get().idVendor; } - uint16_t get_product_id(void) const{ + uint16_t get_product_id(void) const + { return libusb::device_descriptor::make(this->get_device())->get().idProduct; } - bool firmware_loaded() { - return (get_manufacturer() == "Ettus Research LLC") or - (get_manufacturer() == "National Instruments Corp.") or - (get_manufacturer() == "Free Software Folks"); + bool firmware_loaded() + { + return (get_manufacturer() == "Ettus Research LLC") + or (get_manufacturer() == "National Instruments Corp.") + or (get_manufacturer() == "Free Software Folks"); } private: - libusb::device::sptr _dev; //always keep a reference to device + libusb::device::sptr _dev; // always keep a reference to device }; -libusb_special_handle_impl::~libusb_special_handle_impl(void){ +libusb_special_handle_impl::~libusb_special_handle_impl(void) +{ /* NOP */ } -libusb::special_handle::sptr libusb::special_handle::make(device::sptr dev){ +libusb::special_handle::sptr libusb::special_handle::make(device::sptr dev) +{ return sptr(new libusb_special_handle_impl(dev)); } /*********************************************************************** * list device handles implementations **********************************************************************/ -usb_device_handle::~usb_device_handle(void) { +usb_device_handle::~usb_device_handle(void) +{ /* NOP */ } std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list( - uint16_t vid, uint16_t pid -){ - return usb_device_handle::get_device_list(std::vector<usb_device_handle::vid_pid_pair_t>(1,usb_device_handle::vid_pid_pair_t(vid,pid))); + uint16_t vid, uint16_t pid) +{ + return usb_device_handle::get_device_list( + std::vector<usb_device_handle::vid_pid_pair_t>( + 1, usb_device_handle::vid_pid_pair_t(vid, pid))); } -std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(const std::vector<usb_device_handle::vid_pid_pair_t>& vid_pid_pair_list) +std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list( + const std::vector<usb_device_handle::vid_pid_pair_t>& vid_pid_pair_list) { std::vector<usb_device_handle::sptr> handles; libusb::device_list::sptr dev_list = libusb::device_list::make(); - for(size_t iter = 0; iter < vid_pid_pair_list.size(); ++iter) - { - for (size_t i = 0; i < dev_list->size(); i++){ - usb_device_handle::sptr handle = libusb::special_handle::make(dev_list->at(i)); - if (handle->get_vendor_id() == vid_pid_pair_list[iter].first and handle->get_product_id() == vid_pid_pair_list[iter].second){ - handles.push_back(handle); - } - } + for (size_t iter = 0; iter < vid_pid_pair_list.size(); ++iter) { + for (size_t i = 0; i < dev_list->size(); i++) { + usb_device_handle::sptr handle = + libusb::special_handle::make(dev_list->at(i)); + if (handle->get_vendor_id() == vid_pid_pair_list[iter].first + and handle->get_product_id() == vid_pid_pair_list[iter].second) { + handles.push_back(handle); + } + } } return handles; } diff --git a/host/lib/transport/libusb1_base.hpp b/host/lib/transport/libusb1_base.hpp index 958248a5c..8ff1cf4cc 100644 --- a/host/lib/transport/libusb1_base.hpp +++ b/host/lib/transport/libusb1_base.hpp @@ -9,32 +9,30 @@ #define INCLUDED_LIBUHD_TRANSPORT_LIBUSB_HPP #include <uhd/config.hpp> -#include <boost/utility.hpp> -#include <boost/shared_ptr.hpp> #include <uhd/transport/usb_device_handle.hpp> #include <libusb.h> +#include <boost/shared_ptr.hpp> +#include <boost/utility.hpp> //! Define LIBUSB_CALL when its missing (non-windows) #ifndef LIBUSB_CALL - #define LIBUSB_CALL +# define LIBUSB_CALL #endif /*LIBUSB_CALL*/ //! libusb_handle_events_timeout_completed is only in newer API #ifndef HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED - #define libusb_handle_events_timeout_completed(ctx, tx, completed) \ +# define libusb_handle_events_timeout_completed(ctx, tx, completed) \ libusb_handle_events_timeout(ctx, tx) #endif /* HAVE_LIBUSB_HANDLE_EVENTS_TIMEOUT_COMPLETED */ //! libusb_error_name is only in newer API #ifndef HAVE_LIBUSB_ERROR_NAME - #define libusb_error_name(code) \ - str(boost::format("LIBUSB_ERROR_CODE %d") % code) +# define libusb_error_name(code) str(boost::format("LIBUSB_ERROR_CODE %d") % code) #endif /* HAVE_LIBUSB_ERROR_NAME */ //! libusb_strerror is only in newer API #ifndef HAVE_LIBUSB_STRERROR - #define libusb_strerror(code) \ - libusb_error_name(code) +# define libusb_strerror(code) libusb_error_name(code) #endif /* HAVE_LIBUSB_STRERROR */ /*********************************************************************** @@ -44,135 +42,138 @@ * also store tables of already allocated structures to avoid multiple * occurrences of opened handles (for example). **********************************************************************/ -namespace uhd { namespace transport { - -namespace libusb { - - /*! - * This session class holds a global libusb context for this process. - * The get global session call will create a new context if none exists. - * When all references to session are destroyed, the context will be freed. - */ - class session : boost::noncopyable { - public: - typedef boost::shared_ptr<session> sptr; - - virtual ~session(void); +namespace uhd { namespace transport { namespace libusb { - /*! - * Level 0: no messages ever printed by the library (default) - * Level 1: error messages are printed to stderr - * Level 2: warning and error messages are printed to stderr - * Level 3: informational messages are printed to stdout, warning - * and error messages are printed to stderr - */ - static const int debug_level = 0; +/*! + * This session class holds a global libusb context for this process. + * The get global session call will create a new context if none exists. + * When all references to session are destroyed, the context will be freed. + */ +class session : boost::noncopyable +{ +public: + typedef boost::shared_ptr<session> sptr; - //! get a shared pointer to the global session - static sptr get_global_session(void); - - //! get the underlying libusb context pointer - virtual libusb_context *get_context(void) const = 0; - }; + virtual ~session(void); /*! - * Holds a device pointer with a reference to the session. + * Level 0: no messages ever printed by the library (default) + * Level 1: error messages are printed to stderr + * Level 2: warning and error messages are printed to stderr + * Level 3: informational messages are printed to stdout, warning + * and error messages are printed to stderr */ - class device : boost::noncopyable { - public: - typedef boost::shared_ptr<device> sptr; + static const int debug_level = 0; - virtual ~device(void); + //! get a shared pointer to the global session + static sptr get_global_session(void); - //! get the underlying device pointer - virtual libusb_device *get(void) const = 0; - }; + //! get the underlying libusb context pointer + virtual libusb_context* get_context(void) const = 0; +}; - /*! - * This device list class holds a device list that will be - * automatically freed when the last reference is destroyed. - */ - class device_list : boost::noncopyable { - public: - typedef boost::shared_ptr<device_list> sptr; +/*! + * Holds a device pointer with a reference to the session. + */ +class device : boost::noncopyable +{ +public: + typedef boost::shared_ptr<device> sptr; - virtual ~device_list(void); + virtual ~device(void); - //! make a new device list - static sptr make(void); + //! get the underlying device pointer + virtual libusb_device* get(void) const = 0; +}; - //! the number of devices in this list - virtual size_t size() const = 0; +/*! + * This device list class holds a device list that will be + * automatically freed when the last reference is destroyed. + */ +class device_list : boost::noncopyable +{ +public: + typedef boost::shared_ptr<device_list> sptr; - //! get the device pointer at a particular index - virtual device::sptr at(size_t index) const = 0; - }; + virtual ~device_list(void); - /*! - * Holds a device descriptor and a reference to the device. - */ - class device_descriptor : boost::noncopyable { - public: - typedef boost::shared_ptr<device_descriptor> sptr; + //! make a new device list + static sptr make(void); - virtual ~device_descriptor(void); + //! the number of devices in this list + virtual size_t size() const = 0; - //! make a new descriptor from a device reference - static sptr make(device::sptr); + //! get the device pointer at a particular index + virtual device::sptr at(size_t index) const = 0; +}; - //! get the underlying device descriptor - virtual const libusb_device_descriptor &get(void) const = 0; +/*! + * Holds a device descriptor and a reference to the device. + */ +class device_descriptor : boost::noncopyable +{ +public: + typedef boost::shared_ptr<device_descriptor> sptr; - virtual std::string get_ascii_property(const std::string &what) const = 0; - }; + virtual ~device_descriptor(void); - /*! - * Holds a device handle and a reference to the device. - */ - class device_handle : boost::noncopyable { - public: - typedef boost::shared_ptr<device_handle> sptr; + //! make a new descriptor from a device reference + static sptr make(device::sptr); - virtual ~device_handle(void); + //! get the underlying device descriptor + virtual const libusb_device_descriptor& get(void) const = 0; - //! get a cached handle or make a new one given the device - static sptr get_cached_handle(device::sptr); + virtual std::string get_ascii_property(const std::string& what) const = 0; +}; - //! get the underlying device handle - virtual libusb_device_handle *get(void) const = 0; +/*! + * Holds a device handle and a reference to the device. + */ +class device_handle : boost::noncopyable +{ +public: + typedef boost::shared_ptr<device_handle> sptr; - /*! - * Open USB interfaces for control using magic value - * IN interface: 2 - * OUT interface: 1 - * Control interface: 0 - */ - virtual void claim_interface(int) = 0; + virtual ~device_handle(void); - virtual void clear_endpoints(unsigned char recv_endpoint, unsigned char send_endpoint) = 0; + //! get a cached handle or make a new one given the device + static sptr get_cached_handle(device::sptr); - virtual void reset_device(void) = 0; - }; + //! get the underlying device handle + virtual libusb_device_handle* get(void) const = 0; /*! - * The special handle is our internal implementation of the - * usb device handle which is used publicly to identify a device. + * Open USB interfaces for control using magic value + * IN interface: 2 + * OUT interface: 1 + * Control interface: 0 */ - class special_handle : public usb_device_handle { - public: - typedef boost::shared_ptr<special_handle> sptr; + virtual void claim_interface(int) = 0; + + virtual void clear_endpoints( + unsigned char recv_endpoint, unsigned char send_endpoint) = 0; + + virtual void reset_device(void) = 0; +}; - virtual ~special_handle(void); +/*! + * The special handle is our internal implementation of the + * usb device handle which is used publicly to identify a device. + */ +class special_handle : public usb_device_handle +{ +public: + typedef boost::shared_ptr<special_handle> sptr; - //! make a new special handle from device - static sptr make(device::sptr); + virtual ~special_handle(void); - //! get the underlying device reference - virtual device::sptr get_device(void) const = 0; - }; + //! make a new special handle from device + static sptr make(device::sptr); -} + //! get the underlying device reference + virtual device::sptr get_device(void) const = 0; +}; -}} //namespace +}}} // namespace uhd::transport::libusb #endif /* INCLUDED_LIBUHD_TRANSPORT_LIBUSB_HPP */ diff --git a/host/lib/transport/libusb1_control.cpp b/host/lib/transport/libusb1_control.cpp index 2a338bba1..10ab53553 100644 --- a/host/lib/transport/libusb1_control.cpp +++ b/host/lib/transport/libusb1_control.cpp @@ -11,17 +11,19 @@ using namespace uhd::transport; -usb_control::~usb_control(void){ +usb_control::~usb_control(void) +{ /* NOP */ } /*********************************************************************** * libusb-1.0 implementation of USB control transport **********************************************************************/ -class libusb_control_impl : public usb_control { +class libusb_control_impl : public usb_control +{ public: - libusb_control_impl(libusb::device_handle::sptr handle, const int interface): - _handle(handle) + libusb_control_impl(libusb::device_handle::sptr handle, const int interface) + : _handle(handle) { _handle->claim_interface(interface); } @@ -29,22 +31,22 @@ public: virtual ~libusb_control_impl(void); int submit(uint8_t request_type, - uint8_t request, - uint16_t value, - uint16_t index, - unsigned char *buff, - uint16_t length, - uint32_t libusb_timeout = 0 - ){ + uint8_t request, + uint16_t value, + uint16_t index, + unsigned char* buff, + uint16_t length, + uint32_t libusb_timeout = 0) + { boost::mutex::scoped_lock lock(_mutex); return libusb_control_transfer(_handle->get(), - request_type, - request, - value, - index, - buff, - length, - libusb_timeout); + request_type, + request, + value, + index, + buff, + length, + libusb_timeout); } private: @@ -52,15 +54,18 @@ private: boost::mutex _mutex; }; -libusb_control_impl::~libusb_control_impl(void) { - /* NOP */ +libusb_control_impl::~libusb_control_impl(void) +{ + /* NOP */ } /*********************************************************************** * USB control public make functions **********************************************************************/ -usb_control::sptr usb_control::make(usb_device_handle::sptr handle, const int interface){ - return sptr(new libusb_control_impl(libusb::device_handle::get_cached_handle( - boost::static_pointer_cast<libusb::special_handle>(handle)->get_device() - ), interface)); +usb_control::sptr usb_control::make(usb_device_handle::sptr handle, const int interface) +{ + return sptr(new libusb_control_impl( + libusb::device_handle::get_cached_handle( + boost::static_pointer_cast<libusb::special_handle>(handle)->get_device()), + interface)); } diff --git a/host/lib/transport/libusb1_zero_copy.cpp b/host/lib/transport/libusb1_zero_copy.cpp index 9e91ae2fc..5b03aa86f 100644 --- a/host/lib/transport/libusb1_zero_copy.cpp +++ b/host/lib/transport/libusb1_zero_copy.cpp @@ -6,35 +6,35 @@ // #include "libusb1_base.hpp" -#include <uhd/transport/usb_zero_copy.hpp> -#include <uhd/transport/buffer_pool.hpp> +#include <uhd/exception.hpp> #include <uhd/transport/bounded_buffer.hpp> +#include <uhd/transport/buffer_pool.hpp> +#include <uhd/transport/usb_zero_copy.hpp> #include <uhd/utils/log.hpp> -#include <uhd/exception.hpp> +#include <boost/bind.hpp> +#include <boost/circular_buffer.hpp> #include <boost/format.hpp> #include <boost/function.hpp> -#include <boost/bind.hpp> #include <boost/make_shared.hpp> -#include <boost/circular_buffer.hpp> -#include <boost/thread/mutex.hpp> #include <boost/thread/condition_variable.hpp> +#include <boost/thread/mutex.hpp> #include <list> #ifdef UHD_TXRX_DEBUG_PRINTS -#include <vector> -#include <fstream> -#include <boost/format.hpp> +# include <boost/format.hpp> +# include <fstream> +# include <vector> #endif using namespace uhd; using namespace uhd::transport; -static const size_t DEFAULT_NUM_XFERS = 16; //num xfers -static const size_t DEFAULT_XFER_SIZE = 32*512; //bytes +static const size_t DEFAULT_NUM_XFERS = 16; // num xfers +static const size_t DEFAULT_XFER_SIZE = 32 * 512; // bytes //! type for sharing the release queue with managed buffers class libusb_zero_copy_mb; -typedef boost::shared_ptr<bounded_buffer<libusb_zero_copy_mb *> > mb_queue_sptr; +typedef boost::shared_ptr<bounded_buffer<libusb_zero_copy_mb*>> mb_queue_sptr; /*! * The libusb docs state that status and actual length can only be read in the callback. @@ -44,12 +44,12 @@ struct lut_result_t { lut_result_t(void) { - completed = 0; - status = LIBUSB_TRANSFER_COMPLETED; + completed = 0; + status = LIBUSB_TRANSFER_COMPLETED; actual_length = 0; #ifdef UHD_TXRX_DEBUG_PRINTS start_time = 0; - buff_num = -1; + buff_num = -1; #endif } int completed; @@ -67,17 +67,22 @@ struct lut_result_t }; // Created to be used as an argument to boost::condition_variable::timed_wait() function -struct lut_result_completed { +struct lut_result_completed +{ const lut_result_t& _result; - lut_result_completed(const lut_result_t& result):_result(result) {} - bool operator()() const {return (_result.completed ? true : false);} + lut_result_completed(const lut_result_t& result) : _result(result) {} + bool operator()() const + { + return (_result.completed ? true : false); + } }; #ifdef UHD_TXRX_DEBUG_PRINTS static std::string dbg_prefix("libusb1_zero_copy,"); -static void libusb1_zerocopy_dbg_print_err(std::string msg){ - msg = dbg_prefix + msg; - fprintf(stderr, "%s\n", msg.c_str()); +static void libusb1_zerocopy_dbg_print_err(std::string msg) +{ + msg = dbg_prefix + msg; + fprintf(stderr, "%s\n", msg.c_str()); } #endif @@ -87,17 +92,21 @@ static void libusb1_zerocopy_dbg_print_err(std::string msg){ */ //! helper function: handles all async callbacks -static void LIBUSB_CALL libusb_async_cb(libusb_transfer *lut) +static void LIBUSB_CALL libusb_async_cb(libusb_transfer* lut) { - lut_result_t *r = (lut_result_t *)lut->user_data; + lut_result_t* r = (lut_result_t*)lut->user_data; boost::lock_guard<boost::mutex> lock(r->mut); - r->status = lut->status; + r->status = lut->status; r->actual_length = lut->actual_length; - r->completed = 1; - r->usb_transfer_complete.notify_one(); // wake up thread waiting in wait_for_completion() member function below + r->completed = 1; + r->usb_transfer_complete.notify_one(); // wake up thread waiting in + // wait_for_completion() member function below #ifdef UHD_TXRX_DEBUG_PRINTS long end_time = boost::get_system_time().time_of_day().total_microseconds(); - libusb1_zerocopy_dbg_print_err( (boost::format("libusb_async_cb,%s,%i,%i,%i,%ld,%ld") % (r->is_recv ? "rx":"tx") % r->buff_num % r->actual_length % r->status % end_time % r->start_time).str() ); + libusb1_zerocopy_dbg_print_err( + (boost::format("libusb_async_cb,%s,%i,%i,%i,%ld,%ld") % (r->is_recv ? "rx" : "tx") + % r->buff_num % r->actual_length % r->status % end_time % r->start_time) + .str()); #endif } @@ -109,41 +118,53 @@ static void LIBUSB_CALL libusb_async_cb(libusb_transfer *lut) class libusb_zero_copy_mb : public managed_buffer { public: - libusb_zero_copy_mb(libusb_transfer *lut, const size_t frame_size, boost::function<void(libusb_zero_copy_mb *)> release_cb, const bool is_recv, const std::string &name): - _release_cb(release_cb), _is_recv(is_recv), _name(name), - _ctx(libusb::session::get_global_session()->get_context()), - _lut(lut), _frame_size(frame_size) { /* NOP */ } + libusb_zero_copy_mb(libusb_transfer* lut, + const size_t frame_size, + boost::function<void(libusb_zero_copy_mb*)> release_cb, + const bool is_recv, + const std::string& name) + : _release_cb(release_cb) + , _is_recv(is_recv) + , _name(name) + , _ctx(libusb::session::get_global_session()->get_context()) + , _lut(lut) + , _frame_size(frame_size) + { /* NOP */ + } virtual ~libusb_zero_copy_mb(void); - void release(void){ - _release_cb(this); + void release(void) + { + _release_cb(this); } UHD_INLINE void submit(void) { - _lut->length = int((_is_recv)? _frame_size : size()); //always set length + _lut->length = int((_is_recv) ? _frame_size : size()); // always set length #ifdef UHD_TXRX_DEBUG_PRINTS result.start_time = boost::get_system_time().time_of_day().total_microseconds(); - result.buff_num = num(); - result.is_recv = _is_recv; + result.buff_num = num(); + result.is_recv = _is_recv; #endif - int ret = libusb_submit_transfer(_lut); + int ret = libusb_submit_transfer(_lut); if (ret != LIBUSB_SUCCESS) - throw uhd::usb_error(ret, str(boost::format( - "usb %s submit failed: %s") % _name % libusb_error_name(ret))); + throw uhd::usb_error(ret, + str(boost::format("usb %s submit failed: %s") % _name + % libusb_error_name(ret))); } template <typename buffer_type> UHD_INLINE typename buffer_type::sptr get_new(const double timeout) { - if (wait_for_completion(timeout)) - { + if (wait_for_completion(timeout)) { if (result.status != LIBUSB_TRANSFER_COMPLETED) throw uhd::io_error(str(boost::format("usb %s transfer status: %d") % _name % libusb_error_name(result.status))); result.completed = 0; - return make(reinterpret_cast<buffer_type *>(this), _lut->buffer, (_is_recv)? size_t(result.actual_length) : _frame_size); + return make(reinterpret_cast<buffer_type*>(this), + _lut->buffer, + (_is_recv) ? size_t(result.actual_length) : _frame_size); } return typename buffer_type::sptr(); } @@ -164,23 +185,27 @@ public: if (timeout < 0.0) { result.usb_transfer_complete.wait(lock); } else { - const boost::system_time timeout_time = boost::get_system_time() + boost::posix_time::microseconds(long(timeout*1000000)); - result.usb_transfer_complete.timed_wait(lock, timeout_time, lut_result_completed(result)); + const boost::system_time timeout_time = + boost::get_system_time() + + boost::posix_time::microseconds(long(timeout * 1000000)); + result.usb_transfer_complete.timed_wait( + lock, timeout_time, lut_result_completed(result)); } } return (result.completed > 0); } private: - boost::function<void(libusb_zero_copy_mb *)> _release_cb; + boost::function<void(libusb_zero_copy_mb*)> _release_cb; const bool _is_recv; const std::string _name; - libusb_context *_ctx; - libusb_transfer *_lut; + libusb_context* _ctx; + libusb_transfer* _lut; const size_t _frame_size; }; -libusb_zero_copy_mb::~libusb_zero_copy_mb(void) { +libusb_zero_copy_mb::~libusb_zero_copy_mb(void) +{ /* NOP */ } @@ -190,70 +215,71 @@ libusb_zero_copy_mb::~libusb_zero_copy_mb(void) { class libusb_zero_copy_single { public: - libusb_zero_copy_single( - libusb::device_handle::sptr handle, - const int interface, const unsigned char endpoint, - const size_t num_frames, const size_t frame_size - ): - _handle(handle), - _num_frames(num_frames), - _frame_size(frame_size), - _buffer_pool(buffer_pool::make(_num_frames, _frame_size)), - _enqueued(_num_frames), _released(_num_frames), - _status(STATUS_RUNNING) + libusb_zero_copy_single(libusb::device_handle::sptr handle, + const int interface, + const unsigned char endpoint, + const size_t num_frames, + const size_t frame_size) + : _handle(handle) + , _num_frames(num_frames) + , _frame_size(frame_size) + , _buffer_pool(buffer_pool::make(_num_frames, _frame_size)) + , _enqueued(_num_frames) + , _released(_num_frames) + , _status(STATUS_RUNNING) { const bool is_recv = (endpoint & 0x80) != 0; - const std::string name = str(boost::format("%s%d") % ((is_recv)? "rx" : "tx") % int(endpoint & 0x7f)); + const std::string name = + str(boost::format("%s%d") % ((is_recv) ? "rx" : "tx") % int(endpoint & 0x7f)); _handle->claim_interface(interface); - //flush the buffers out of the recv endpoint - //limit the flushing to at most one second - if (is_recv) for (size_t i = 0; i < 100; i++) - { - unsigned char buff[512]; - int transfered = 0; - const int status = libusb_bulk_transfer( - _handle->get(), // dev_handle - endpoint, // endpoint - static_cast<unsigned char *>(buff), - int(sizeof(buff)), - &transfered, //bytes xfered - 10 //timeout ms - ); - if (status == LIBUSB_ERROR_TIMEOUT) break; - } + // flush the buffers out of the recv endpoint + // limit the flushing to at most one second + if (is_recv) + for (size_t i = 0; i < 100; i++) { + unsigned char buff[512]; + int transfered = 0; + const int status = libusb_bulk_transfer(_handle->get(), // dev_handle + endpoint, // endpoint + static_cast<unsigned char*>(buff), + int(sizeof(buff)), + &transfered, // bytes xfered + 10 // timeout ms + ); + if (status == LIBUSB_ERROR_TIMEOUT) + break; + } - //allocate libusb transfer structs and managed buffers - for (size_t i = 0; i < get_num_frames(); i++) - { - libusb_transfer *lut = libusb_alloc_transfer(0); + // allocate libusb transfer structs and managed buffers + for (size_t i = 0; i < get_num_frames(); i++) { + libusb_transfer* lut = libusb_alloc_transfer(0); UHD_ASSERT_THROW(lut != NULL); - _mb_pool.push_back(boost::make_shared<libusb_zero_copy_mb>( - lut, this->get_frame_size(), boost::bind(&libusb_zero_copy_single::enqueue_buffer, this, _1), is_recv, name - )); - - libusb_fill_bulk_transfer( - lut, // transfer - _handle->get(), // dev_handle - endpoint, // endpoint - static_cast<unsigned char *>(_buffer_pool->at(i)), // buffer - int(this->get_frame_size()), // length - libusb_transfer_cb_fn(&libusb_async_cb), // callback - static_cast<void *>(&_mb_pool.back()->result), // user_data - 0 // timeout (ms) + _mb_pool.push_back(boost::make_shared<libusb_zero_copy_mb>(lut, + this->get_frame_size(), + boost::bind(&libusb_zero_copy_single::enqueue_buffer, this, _1), + is_recv, + name)); + + libusb_fill_bulk_transfer(lut, // transfer + _handle->get(), // dev_handle + endpoint, // endpoint + static_cast<unsigned char*>(_buffer_pool->at(i)), // buffer + int(this->get_frame_size()), // length + libusb_transfer_cb_fn(&libusb_async_cb), // callback + static_cast<void*>(&_mb_pool.back()->result), // user_data + 0 // timeout (ms) ); _all_luts.push_back(lut); } - //initial release for all buffers - for (size_t i = 0; i < get_num_frames(); i++) - { - libusb_zero_copy_mb &mb = *(_mb_pool[i]); - if (is_recv) mb.release(); - else - { + // initial release for all buffers + for (size_t i = 0; i < get_num_frames(); i++) { + libusb_zero_copy_mb& mb = *(_mb_pool[i]); + if (is_recv) + mb.release(); + else { mb.result.completed = 1; _enqueued.push_back(&mb); } @@ -262,21 +288,18 @@ public: ~libusb_zero_copy_single(void) { - //cancel all transfers - for(libusb_transfer *lut: _all_luts) - { + // cancel all transfers + for (libusb_transfer* lut : _all_luts) { libusb_cancel_transfer(lut); } - //process all transfers until timeout occurs - for(libusb_zero_copy_mb *mb: _enqueued) - { + // process all transfers until timeout occurs + for (libusb_zero_copy_mb* mb : _enqueued) { mb->wait_for_completion(0.01); } - //free all transfers - for(libusb_transfer *lut: _all_luts) - { + // free all transfers + for (libusb_transfer* lut : _all_luts) { libusb_free_transfer(lut); } } @@ -293,24 +316,32 @@ public: boost::mutex::scoped_lock get_buff_lock(_get_buff_mutex); boost::mutex::scoped_lock queue_lock(_queue_mutex); - if (_enqueued.empty()) - { - _buff_ready_cond.timed_wait(queue_lock, boost::posix_time::microseconds(long(timeout*1e6))); + if (_enqueued.empty()) { + _buff_ready_cond.timed_wait( + queue_lock, boost::posix_time::microseconds(long(timeout * 1e6))); } - if (_enqueued.empty()) return buff; - libusb_zero_copy_mb *front = _enqueued.front(); + if (_enqueued.empty()) + return buff; + libusb_zero_copy_mb* front = _enqueued.front(); queue_lock.unlock(); buff = front->get_new<buffer_type>(timeout); queue_lock.lock(); - if (buff) _enqueued.pop_front(); + if (buff) + _enqueued.pop_front(); this->submit_what_we_can(); return buff; } - UHD_INLINE size_t get_num_frames(void) const { return _num_frames; } - UHD_INLINE size_t get_frame_size(void) const { return _frame_size; } + UHD_INLINE size_t get_num_frames(void) const + { + return _num_frames; + } + UHD_INLINE size_t get_frame_size(void) const + { + return _frame_size; + } private: libusb::device_handle::sptr _handle; @@ -318,18 +349,18 @@ private: //! Storage for transfer related objects buffer_pool::sptr _buffer_pool; - std::vector<boost::shared_ptr<libusb_zero_copy_mb> > _mb_pool; + std::vector<boost::shared_ptr<libusb_zero_copy_mb>> _mb_pool; boost::mutex _queue_mutex; boost::condition_variable _buff_ready_cond; boost::mutex _get_buff_mutex; //! why 2 queues? there is room in the future to have > N buffers but only N in flight - boost::circular_buffer<libusb_zero_copy_mb *> _enqueued, _released; + boost::circular_buffer<libusb_zero_copy_mb*> _enqueued, _released; - enum {STATUS_RUNNING, STATUS_ERROR} _status; + enum { STATUS_RUNNING, STATUS_ERROR } _status; - void enqueue_buffer(libusb_zero_copy_mb *mb) + void enqueue_buffer(libusb_zero_copy_mb* mb) { boost::mutex::scoped_lock l(_queue_mutex); _released.push_back(mb); @@ -341,15 +372,12 @@ private: { if (_status == STATUS_ERROR) return; - while (not _released.empty() and not _enqueued.full()) - { + while (not _released.empty() and not _enqueued.full()) { try { _released.front()->submit(); _enqueued.push_back(_released.front()); _released.pop_front(); - } - catch (uhd::usb_error& e) - { + } catch (uhd::usb_error& e) { _status = STATUS_ERROR; throw e; } @@ -357,7 +385,7 @@ private: } //! a list of all transfer structs we allocated - std::list<libusb_transfer *> _all_luts; + std::list<libusb_transfer*> _all_luts; }; /*********************************************************************** @@ -365,20 +393,21 @@ private: **********************************************************************/ struct libusb_zero_copy_impl : usb_zero_copy { - libusb_zero_copy_impl( - libusb::device_handle::sptr handle, + libusb_zero_copy_impl(libusb::device_handle::sptr handle, const int recv_interface, const unsigned char recv_endpoint, const int send_interface, const unsigned char send_endpoint, - const device_addr_t &hints - ){ - _recv_impl.reset(new libusb_zero_copy_single( - handle, recv_interface, (recv_endpoint & 0x7f) | 0x80, + const device_addr_t& hints) + { + _recv_impl.reset(new libusb_zero_copy_single(handle, + recv_interface, + (recv_endpoint & 0x7f) | 0x80, size_t(hints.cast<double>("num_recv_frames", DEFAULT_NUM_XFERS)), size_t(hints.cast<double>("recv_frame_size", DEFAULT_XFER_SIZE)))); - _send_impl.reset(new libusb_zero_copy_single( - handle, send_interface, (send_endpoint & 0x7f) | 0x00, + _send_impl.reset(new libusb_zero_copy_single(handle, + send_interface, + (send_endpoint & 0x7f) | 0x00, size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_XFERS)), size_t(hints.cast<double>("send_frame_size", DEFAULT_XFER_SIZE)))); } @@ -397,42 +426,53 @@ struct libusb_zero_copy_impl : usb_zero_copy return _send_impl->get_buff<managed_send_buffer>(timeout); } - size_t get_num_recv_frames(void) const { return _recv_impl->get_num_frames(); } - size_t get_num_send_frames(void) const { return _send_impl->get_num_frames(); } + size_t get_num_recv_frames(void) const + { + return _recv_impl->get_num_frames(); + } + size_t get_num_send_frames(void) const + { + return _send_impl->get_num_frames(); + } - size_t get_recv_frame_size(void) const { return _recv_impl->get_frame_size(); } - size_t get_send_frame_size(void) const { return _send_impl->get_frame_size(); } + size_t get_recv_frame_size(void) const + { + return _recv_impl->get_frame_size(); + } + size_t get_send_frame_size(void) const + { + return _send_impl->get_frame_size(); + } boost::shared_ptr<libusb_zero_copy_single> _recv_impl, _send_impl; boost::mutex _recv_mutex, _send_mutex; }; -libusb_zero_copy_impl::~libusb_zero_copy_impl(void) { +libusb_zero_copy_impl::~libusb_zero_copy_impl(void) +{ /* NOP */ } /*********************************************************************** * USB zero_copy destructor **********************************************************************/ -usb_zero_copy::~usb_zero_copy(void) { +usb_zero_copy::~usb_zero_copy(void) +{ /* NOP */ } /*********************************************************************** * USB zero_copy make functions **********************************************************************/ -usb_zero_copy::sptr usb_zero_copy::make( - usb_device_handle::sptr handle, +usb_zero_copy::sptr usb_zero_copy::make(usb_device_handle::sptr handle, const int recv_interface, const unsigned char recv_endpoint, const int send_interface, const unsigned char send_endpoint, - const device_addr_t &hints -){ + const device_addr_t& hints) +{ libusb::device_handle::sptr dev_handle(libusb::device_handle::get_cached_handle( - boost::static_pointer_cast<libusb::special_handle>(handle)->get_device() - )); + boost::static_pointer_cast<libusb::special_handle>(handle)->get_device())); return sptr(new libusb_zero_copy_impl( - dev_handle, recv_interface, recv_endpoint, send_interface, send_endpoint, hints - )); + dev_handle, recv_interface, recv_endpoint, send_interface, send_endpoint, hints)); } diff --git a/host/lib/transport/muxed_zero_copy_if.cpp b/host/lib/transport/muxed_zero_copy_if.cpp index 2e7583276..b26d2097c 100644 --- a/host/lib/transport/muxed_zero_copy_if.cpp +++ b/host/lib/transport/muxed_zero_copy_if.cpp @@ -5,73 +5,75 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#include <uhd/transport/muxed_zero_copy_if.hpp> -#include <uhd/transport/bounded_buffer.hpp> #include <uhd/exception.hpp> +#include <uhd/transport/bounded_buffer.hpp> +#include <uhd/transport/muxed_zero_copy_if.hpp> #include <uhd/utils/safe_call.hpp> #include <boost/enable_shared_from_this.hpp> #include <boost/make_shared.hpp> #include <boost/thread.hpp> #include <boost/thread/locks.hpp> -#include <map> #include <chrono> +#include <map> #include <thread> using namespace uhd; using namespace uhd::transport; -class muxed_zero_copy_if_impl : public muxed_zero_copy_if, - public boost::enable_shared_from_this<muxed_zero_copy_if_impl> +class muxed_zero_copy_if_impl + : public muxed_zero_copy_if, + public boost::enable_shared_from_this<muxed_zero_copy_if_impl> { public: typedef boost::shared_ptr<muxed_zero_copy_if_impl> sptr; - muxed_zero_copy_if_impl( - zero_copy_if::sptr base_xport, + muxed_zero_copy_if_impl(zero_copy_if::sptr base_xport, stream_classifier_fn classify_fn, - size_t max_streams - ): - _base_xport(base_xport), _classify(classify_fn), - _max_num_streams(max_streams), _num_dropped_frames(0) + size_t max_streams) + : _base_xport(base_xport) + , _classify(classify_fn) + , _max_num_streams(max_streams) + , _num_dropped_frames(0) { - //Create the receive thread to poll the underlying transport - //and classify packets into queues - _recv_thread = boost::thread( - boost::bind(&muxed_zero_copy_if_impl::_update_queues, this)); + // Create the receive thread to poll the underlying transport + // and classify packets into queues + _recv_thread = + boost::thread(boost::bind(&muxed_zero_copy_if_impl::_update_queues, this)); } virtual ~muxed_zero_copy_if_impl() { UHD_SAFE_CALL( - //Interrupt buffer updater loop + // Interrupt buffer updater loop _recv_thread.interrupt(); - //Wait for loop to finish - //No timeout on join. The recv loop is guaranteed - //to terminate in a reasonable amount of time because - //there are no timed blocks on the underlying. + // Wait for loop to finish + // No timeout on join. The recv loop is guaranteed + // to terminate in a reasonable amount of time because + // there are no timed blocks on the underlying. _recv_thread.join(); - //Flush base transport + // Flush base transport while (_base_xport->get_recv_buff(0.0001)) /*NOP*/; - //Release child streams - //Note that this will not delete or flush the child streams - //until the owners of the streams have released the respective - //shared pointers. This ensures that packets are not dropped. - _streams.clear(); - ); + // Release child streams + // Note that this will not delete or flush the child streams + // until the owners of the streams have released the respective + // shared pointers. This ensures that packets are not dropped. + _streams.clear();); } virtual zero_copy_if::sptr make_stream(const uint32_t stream_num) { boost::lock_guard<boost::mutex> lock(_mutex); if (_streams.size() >= _max_num_streams) { - throw uhd::runtime_error("muxed_zero_copy_if: stream capacity exceeded. cannot create more streams."); + throw uhd::runtime_error("muxed_zero_copy_if: stream capacity exceeded. " + "cannot create more streams."); } // Only allocate a portion of the base transport's frames to each stream // to prevent all streams from attempting to use all the frames. - stream_impl::sptr stream = boost::make_shared<stream_impl>( - this->shared_from_this(), stream_num, - _base_xport->get_num_send_frames() / _max_num_streams, - _base_xport->get_num_recv_frames() / _max_num_streams); + stream_impl::sptr stream = + boost::make_shared<stream_impl>(this->shared_from_this(), + stream_num, + _base_xport->get_num_send_frames() / _max_num_streams, + _base_xport->get_num_recv_frames() / _max_num_streams); _streams[stream_num] = stream; return stream; } @@ -97,20 +99,21 @@ private: public: stream_mrb(size_t size) : _buff(new char[size]) {} - ~stream_mrb() { + ~stream_mrb() + { delete[] _buff; } void release() {} - UHD_INLINE sptr get_new(char *buff, size_t len) + UHD_INLINE sptr get_new(char* buff, size_t len) { memcpy(_buff, buff, len); return make(this, _buff, len); } private: - char *_buff; + char* _buff; }; class stream_impl : public zero_copy_if @@ -119,20 +122,19 @@ private: typedef boost::shared_ptr<stream_impl> sptr; typedef boost::weak_ptr<stream_impl> wptr; - stream_impl( - muxed_zero_copy_if_impl::sptr muxed_xport, + stream_impl(muxed_zero_copy_if_impl::sptr muxed_xport, const uint32_t stream_num, const size_t num_send_frames, - const size_t num_recv_frames - ) : - _stream_num(stream_num), _muxed_xport(muxed_xport), - _num_send_frames(num_send_frames), - _send_frame_size(_muxed_xport->base_xport()->get_send_frame_size()), - _num_recv_frames(num_recv_frames), - _recv_frame_size(_muxed_xport->base_xport()->get_recv_frame_size()), - _buff_queue(num_recv_frames), - _buffers(num_recv_frames), - _buffer_index(0) + const size_t num_recv_frames) + : _stream_num(stream_num) + , _muxed_xport(muxed_xport) + , _num_send_frames(num_send_frames) + , _send_frame_size(_muxed_xport->base_xport()->get_send_frame_size()) + , _num_recv_frames(num_recv_frames) + , _recv_frame_size(_muxed_xport->base_xport()->get_recv_frame_size()) + , _buff_queue(num_recv_frames) + , _buffers(num_recv_frames) + , _buffer_index(0) { for (size_t i = 0; i < num_recv_frames; i++) { _buffers[i] = boost::make_shared<stream_mrb>(_recv_frame_size); @@ -141,25 +143,28 @@ private: ~stream_impl(void) { - //First remove the stream from muxed transport - //so no more frames are pushed in + // First remove the stream from muxed transport + // so no more frames are pushed in _muxed_xport->remove_stream(_stream_num); - //Flush the transport + // Flush the transport managed_recv_buffer::sptr buff; while (_buff_queue.pop_with_haste(buff)) { - //NOP + // NOP } } - size_t get_num_recv_frames(void) const { + size_t get_num_recv_frames(void) const + { return _num_recv_frames; } - size_t get_recv_frame_size(void) const { + size_t get_recv_frame_size(void) const + { return _recv_frame_size; } - managed_recv_buffer::sptr get_recv_buff(double timeout) { + managed_recv_buffer::sptr get_recv_buff(double timeout) + { managed_recv_buffer::sptr buff; if (_buff_queue.pop_with_timed_wait(buff, timeout)) { return buff; @@ -168,16 +173,20 @@ private: } } - void push_recv_buff(managed_recv_buffer::sptr buff) { - _buff_queue.push_with_wait(_buffers.at(_buffer_index++)->get_new(buff->cast<char*>(), buff->size())); + void push_recv_buff(managed_recv_buffer::sptr buff) + { + _buff_queue.push_with_wait( + _buffers.at(_buffer_index++)->get_new(buff->cast<char*>(), buff->size())); _buffer_index %= _buffers.size(); } - size_t get_num_send_frames(void) const { + size_t get_num_send_frames(void) const + { return _num_send_frames; } - size_t get_send_frame_size(void) const { + size_t get_send_frame_size(void) const + { return _send_frame_size; } @@ -187,51 +196,55 @@ private: } private: - const uint32_t _stream_num; - muxed_zero_copy_if_impl::sptr _muxed_xport; - const size_t _num_send_frames; - const size_t _send_frame_size; - const size_t _num_recv_frames; - const size_t _recv_frame_size; - bounded_buffer<managed_recv_buffer::sptr> _buff_queue; - std::vector< boost::shared_ptr<stream_mrb> > _buffers; - size_t _buffer_index; + const uint32_t _stream_num; + muxed_zero_copy_if_impl::sptr _muxed_xport; + const size_t _num_send_frames; + const size_t _send_frame_size; + const size_t _num_recv_frames; + const size_t _recv_frame_size; + bounded_buffer<managed_recv_buffer::sptr> _buff_queue; + std::vector<boost::shared_ptr<stream_mrb>> _buffers; + size_t _buffer_index; }; - inline zero_copy_if::sptr& base_xport() { return _base_xport; } + inline zero_copy_if::sptr& base_xport() + { + return _base_xport; + } void _update_queues() { - //Run forever: + // Run forever: // - Pull packets from the base transport // - Classify them // - Push them to the appropriate receive queue while (true) { - { //Uninterruptable block of code + { // Uninterruptable block of code boost::this_thread::disable_interruption interrupt_disabler; if (not _process_next_buffer()) { - //Be a good citizen and yield if no packet is processed + // Be a good citizen and yield if no packet is processed static const size_t MIN_DUR = 1; std::this_thread::sleep_for(std::chrono::nanoseconds(MIN_DUR)); - //We call sleep(MIN_DUR) above instead of yield() to ensure that we - //relinquish the current scheduler time slot. - //yield() is a hint to the scheduler to end the time - //slice early and schedule in another thread that is ready to run. - //However in most situations, there will be no other thread and - //this thread will continue to run which will rail a CPU core. - //We call sleep(MIN_DUR=1) instead which will sleep for a minimum time. - //Ideally we would like to use boost::chrono::.*seconds::min() but that - //is bound to 0, which causes the sleep_for call to be a no-op and - //thus useless to actually force a sleep. + // We call sleep(MIN_DUR) above instead of yield() to ensure that we + // relinquish the current scheduler time slot. + // yield() is a hint to the scheduler to end the time + // slice early and schedule in another thread that is ready to run. + // However in most situations, there will be no other thread and + // this thread will continue to run which will rail a CPU core. + // We call sleep(MIN_DUR=1) instead which will sleep for a minimum + // time. Ideally we would like to use boost::chrono::.*seconds::min() + // but that is bound to 0, which causes the sleep_for call to be a + // no-op and thus useless to actually force a sleep. //**************************************************************** - //NOTE: This behavior makes this transport a poor choice for + // NOTE: This behavior makes this transport a poor choice for // low latency communication. //**************************************************************** } } - //Check if the master thread has requested a shutdown - if (boost::this_thread::interruption_requested()) break; + // Check if the master thread has requested a shutdown + if (boost::this_thread::interruption_requested()) + break; } } @@ -241,10 +254,11 @@ private: if (buff) { stream_impl::sptr stream; try { - const uint32_t stream_num = _classify(buff->cast<void*>(), _base_xport->get_recv_frame_size()); + const uint32_t stream_num = + _classify(buff->cast<void*>(), _base_xport->get_recv_frame_size()); { - //Hold the stream mutex long enough to pull a bounded buffer - //and lock it (increment its ref count). + // Hold the stream mutex long enough to pull a bounded buffer + // and lock it (increment its ref count). boost::lock_guard<boost::mutex> lock(_mutex); stream_map_t::iterator str_iter = _streams.find(stream_num); if (str_iter != _streams.end()) { @@ -252,41 +266,41 @@ private: } } } catch (std::exception&) { - //If _classify throws we simply drop the frame + // If _classify throws we simply drop the frame } - //Once a bounded buffer is acquired, we can rely on its - //thread safety to serialize with the consumer. + // Once a bounded buffer is acquired, we can rely on its + // thread safety to serialize with the consumer. if (stream.get()) { stream->push_recv_buff(buff); } else { boost::lock_guard<boost::mutex> lock(_mutex); _num_dropped_frames++; } - //We processed a packet, and there could be more coming - //Don't yield in the next iteration. + // We processed a packet, and there could be more coming + // Don't yield in the next iteration. return true; } else { - //The base transport is idle. Return false to let the - //thread yield. + // The base transport is idle. Return false to let the + // thread yield. return false; } } typedef std::map<uint32_t, stream_impl::wptr> stream_map_t; - zero_copy_if::sptr _base_xport; - stream_classifier_fn _classify; - stream_map_t _streams; - const size_t _max_num_streams; - size_t _num_dropped_frames; - boost::thread _recv_thread; - boost::mutex _mutex; + zero_copy_if::sptr _base_xport; + stream_classifier_fn _classify; + stream_map_t _streams; + const size_t _max_num_streams; + size_t _num_dropped_frames; + boost::thread _recv_thread; + boost::mutex _mutex; }; -muxed_zero_copy_if::sptr muxed_zero_copy_if::make( - zero_copy_if::sptr base_xport, +muxed_zero_copy_if::sptr muxed_zero_copy_if::make(zero_copy_if::sptr base_xport, muxed_zero_copy_if::stream_classifier_fn classify_fn, - size_t max_streams -) { - return boost::make_shared<muxed_zero_copy_if_impl>(base_xport, classify_fn, max_streams); + size_t max_streams) +{ + return boost::make_shared<muxed_zero_copy_if_impl>( + base_xport, classify_fn, max_streams); } diff --git a/host/lib/transport/nirio_zero_copy.cpp b/host/lib/transport/nirio_zero_copy.cpp index 993a2c593..e72064427 100644 --- a/host/lib/transport/nirio_zero_copy.cpp +++ b/host/lib/transport/nirio_zero_copy.cpp @@ -5,25 +5,25 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#include <uhd/transport/nirio_zero_copy.hpp> #include <uhd/transport/nirio/nirio_fifo.h> +#include <uhd/transport/nirio_zero_copy.hpp> #include <uhd/utils/log.hpp> #include <uhdlib/utils/atomic.hpp> +#include <stdio.h> +#include <boost/date_time/posix_time/posix_time.hpp> #include <boost/format.hpp> +#include <boost/interprocess/mapped_region.hpp> //get_page_size() #include <boost/make_shared.hpp> -#include <boost/date_time/posix_time/posix_time.hpp> -#include <boost/interprocess/mapped_region.hpp> //get_page_size() -#include <vector> -#include <algorithm> // std::max +#include <algorithm> // std::max #include <chrono> #include <thread> -#include <stdio.h> +#include <vector> //@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> +# include <windows.h> static UHD_INLINE size_t get_page_size() { SYSTEM_INFO si; @@ -31,7 +31,7 @@ static UHD_INLINE size_t get_page_size() return si.dwPageSize; } #else -#include <unistd.h> +# include <unistd.h> static UHD_INLINE size_t get_page_size() { return size_t(sysconf(_SC_PAGESIZE)); @@ -48,153 +48,172 @@ typedef uint64_t fifo_data_t; class nirio_zero_copy_mrb : public managed_recv_buffer { public: - nirio_zero_copy_mrb(nirio_fifo<fifo_data_t>& fifo, const size_t frame_size): - _fifo(fifo), _frame_size(frame_size) { } + nirio_zero_copy_mrb(nirio_fifo<fifo_data_t>& fifo, const size_t frame_size) + : _fifo(fifo), _frame_size(frame_size) + { + } void release(void) { _fifo.release(_frame_size / sizeof(fifo_data_t)); } - UHD_INLINE sptr get_new(const double timeout, size_t &index) + UHD_INLINE sptr get_new(const double timeout, size_t& index) { - nirio_status status = 0; - size_t elems_acquired = 0; + nirio_status status = 0; + size_t elems_acquired = 0; size_t elems_remaining = 0; - nirio_status_chain(_fifo.acquire( - _typed_buffer, _frame_size / sizeof(fifo_data_t), - static_cast<uint32_t>(timeout*1000), - elems_acquired, elems_remaining), status); + nirio_status_chain(_fifo.acquire(_typed_buffer, + _frame_size / sizeof(fifo_data_t), + static_cast<uint32_t>(timeout * 1000), + elems_acquired, + elems_remaining), + status); _length = elems_acquired * sizeof(fifo_data_t); _buffer = static_cast<void*>(_typed_buffer); if (nirio_status_not_fatal(status)) { - index++; //Advances the caller's buffer + index++; // Advances the caller's buffer return make(this, _buffer, _length); } else if (status == NiRio_Status_CommunicationTimeout) { nirio_status_to_exception(status, "NI-RIO PCIe data transfer failed."); return sptr(); } else { - return sptr(); //NULL for timeout or error. + return sptr(); // NULL for timeout or error. } } private: - nirio_fifo<fifo_data_t>& _fifo; - fifo_data_t* _typed_buffer; - const size_t _frame_size; + nirio_fifo<fifo_data_t>& _fifo; + fifo_data_t* _typed_buffer; + const size_t _frame_size; }; class nirio_zero_copy_msb : public managed_send_buffer { public: - nirio_zero_copy_msb(nirio_fifo<fifo_data_t>& fifo, const size_t frame_size): - _fifo(fifo), _frame_size(frame_size) { } + nirio_zero_copy_msb(nirio_fifo<fifo_data_t>& fifo, const size_t frame_size) + : _fifo(fifo), _frame_size(frame_size) + { + } void release(void) { _fifo.release(_frame_size / sizeof(fifo_data_t)); } - UHD_INLINE sptr get_new(const double timeout, size_t &index) + UHD_INLINE sptr get_new(const double timeout, size_t& index) { - nirio_status status = 0; - size_t elems_acquired = 0; + nirio_status status = 0; + size_t elems_acquired = 0; size_t elems_remaining = 0; - nirio_status_chain(_fifo.acquire( - _typed_buffer, _frame_size / sizeof(fifo_data_t), - static_cast<uint32_t>(timeout*1000), - elems_acquired, elems_remaining), status); + nirio_status_chain(_fifo.acquire(_typed_buffer, + _frame_size / sizeof(fifo_data_t), + static_cast<uint32_t>(timeout * 1000), + elems_acquired, + elems_remaining), + status); _length = elems_acquired * sizeof(fifo_data_t); _buffer = static_cast<void*>(_typed_buffer); if (nirio_status_not_fatal(status)) { - index++; //Advances the caller's buffer + index++; // Advances the caller's buffer return make(this, _buffer, _length); } else if (status == NiRio_Status_CommunicationTimeout) { nirio_status_to_exception(status, "NI-RIO PCIe data transfer failed."); return sptr(); } else { - return sptr(); //NULL for timeout or error. + return sptr(); // NULL for timeout or error. } } private: - nirio_fifo<fifo_data_t>& _fifo; - fifo_data_t* _typed_buffer; - const size_t _frame_size; + nirio_fifo<fifo_data_t>& _fifo; + fifo_data_t* _typed_buffer; + const size_t _frame_size; }; -class nirio_zero_copy_impl : public nirio_zero_copy { +class nirio_zero_copy_impl : public nirio_zero_copy +{ public: typedef boost::shared_ptr<nirio_zero_copy_impl> sptr; - nirio_zero_copy_impl( - uhd::niusrprio::niusrprio_session::sptr fpga_session, + nirio_zero_copy_impl(uhd::niusrprio::niusrprio_session::sptr fpga_session, uint32_t instance, - const zero_copy_xport_params& xport_params - ): - _fpga_session(fpga_session), - _fifo_instance(instance), - _xport_params(xport_params), - _next_recv_buff_index(0), _next_send_buff_index(0) + const zero_copy_xport_params& xport_params) + : _fpga_session(fpga_session) + , _fifo_instance(instance) + , _xport_params(xport_params) + , _next_recv_buff_index(0) + , _next_send_buff_index(0) { - UHD_LOGGER_TRACE("NIRIO") << boost::format("Creating PCIe transport for channel %d") % instance ; - UHD_LOGGER_TRACE("NIRIO") << boost::format("nirio zero-copy RX transport configured with frame size = %u, #frames = %u, buffer size = %u\n") - % _xport_params.recv_frame_size % _xport_params.num_recv_frames % - (_xport_params.recv_frame_size * _xport_params.num_recv_frames); - UHD_LOGGER_TRACE("NIRIO") << boost::format("nirio zero-copy TX transport configured with frame size = %u, #frames = %u, buffer size = %u\n") - % _xport_params.send_frame_size % _xport_params.num_send_frames % (_xport_params.send_frame_size * _xport_params.num_send_frames); + UHD_LOGGER_TRACE("NIRIO") + << boost::format("Creating PCIe transport for channel %d") % instance; + UHD_LOGGER_TRACE("NIRIO") + << boost::format("nirio zero-copy RX transport configured with frame size = " + "%u, #frames = %u, buffer size = %u\n") + % _xport_params.recv_frame_size % _xport_params.num_recv_frames + % (_xport_params.recv_frame_size * _xport_params.num_recv_frames); + UHD_LOGGER_TRACE("NIRIO") + << boost::format("nirio zero-copy TX transport configured with frame size = " + "%u, #frames = %u, buffer size = %u\n") + % _xport_params.send_frame_size % _xport_params.num_send_frames + % (_xport_params.send_frame_size * _xport_params.num_send_frames); nirio_status status = 0; size_t actual_depth = 0, actual_size = 0; - //Disable DMA streams in case last shutdown was unclean (cleanup, so don't status chain) - _proxy()->poke(PCIE_TX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), DMA_CTRL_DISABLED); - _proxy()->poke(PCIE_RX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), DMA_CTRL_DISABLED); + // Disable DMA streams in case last shutdown was unclean (cleanup, so don't status + // chain) + _proxy()->poke( + PCIE_TX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), DMA_CTRL_DISABLED); + _proxy()->poke( + PCIE_RX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), DMA_CTRL_DISABLED); _wait_until_stream_ready(); - //Configure frame width + // Configure frame width nirio_status_chain( _proxy()->poke(PCIE_TX_DMA_REG(DMA_FRAME_SIZE_REG, _fifo_instance), - static_cast<uint32_t>(_xport_params.send_frame_size/sizeof(fifo_data_t))), + static_cast<uint32_t>( + _xport_params.send_frame_size / sizeof(fifo_data_t))), status); nirio_status_chain( _proxy()->poke(PCIE_RX_DMA_REG(DMA_FRAME_SIZE_REG, _fifo_instance), - static_cast<uint32_t>(_xport_params.recv_frame_size/sizeof(fifo_data_t))), + static_cast<uint32_t>( + _xport_params.recv_frame_size / sizeof(fifo_data_t))), status); - //Config 32-bit word flipping and enable DMA streams + // Config 32-bit word flipping and enable DMA streams nirio_status_chain( _proxy()->poke(PCIE_TX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), - DMA_CTRL_SW_BUF_U32 | DMA_CTRL_ENABLED), + DMA_CTRL_SW_BUF_U32 | DMA_CTRL_ENABLED), status); nirio_status_chain( _proxy()->poke(PCIE_RX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), - DMA_CTRL_SW_BUF_U32 | DMA_CTRL_ENABLED), + DMA_CTRL_SW_BUF_U32 | DMA_CTRL_ENABLED), status); - //Create FIFOs + // Create FIFOs nirio_status_chain( - _fpga_session->create_rx_fifo(_fifo_instance, _recv_fifo), - status); + _fpga_session->create_rx_fifo(_fifo_instance, _recv_fifo), status); nirio_status_chain( - _fpga_session->create_tx_fifo(_fifo_instance, _send_fifo), - status); + _fpga_session->create_tx_fifo(_fifo_instance, _send_fifo), status); if ((_recv_fifo.get() != NULL) && (_send_fifo.get() != NULL)) { - //Initialize FIFOs - nirio_status_chain( - _recv_fifo->initialize( - (_xport_params.recv_frame_size*_xport_params.num_recv_frames)/sizeof(fifo_data_t), - _xport_params.recv_frame_size / sizeof(fifo_data_t), - actual_depth, actual_size), + // Initialize FIFOs + nirio_status_chain(_recv_fifo->initialize((_xport_params.recv_frame_size + * _xport_params.num_recv_frames) + / sizeof(fifo_data_t), + _xport_params.recv_frame_size / sizeof(fifo_data_t), + actual_depth, + actual_size), status); - nirio_status_chain( - _send_fifo->initialize( - (_xport_params.send_frame_size*_xport_params.num_send_frames)/sizeof(fifo_data_t), - _xport_params.send_frame_size / sizeof(fifo_data_t), - actual_depth, actual_size), + nirio_status_chain(_send_fifo->initialize((_xport_params.send_frame_size + * _xport_params.num_send_frames) + / sizeof(fifo_data_t), + _xport_params.send_frame_size / sizeof(fifo_data_t), + actual_depth, + actual_size), status); _proxy()->get_rio_quirks().add_tx_fifo(_fifo_instance); @@ -203,16 +222,16 @@ public: nirio_status_chain(_send_fifo->start(), status); if (nirio_status_not_fatal(status)) { - //allocate re-usable managed receive buffers - for (size_t i = 0; i < get_num_recv_frames(); i++){ - _mrb_pool.push_back(boost::shared_ptr<nirio_zero_copy_mrb>(new nirio_zero_copy_mrb( - *_recv_fifo, get_recv_frame_size()))); + // allocate re-usable managed receive buffers + for (size_t i = 0; i < get_num_recv_frames(); i++) { + _mrb_pool.push_back(boost::shared_ptr<nirio_zero_copy_mrb>( + new nirio_zero_copy_mrb(*_recv_fifo, get_recv_frame_size()))); } - //allocate re-usable managed send buffers - for (size_t i = 0; i < get_num_send_frames(); i++){ - _msb_pool.push_back(boost::shared_ptr<nirio_zero_copy_msb>(new nirio_zero_copy_msb( - *_send_fifo, get_send_frame_size()))); + // allocate re-usable managed send buffers + for (size_t i = 0; i < get_num_send_frames(); i++) { + _msb_pool.push_back(boost::shared_ptr<nirio_zero_copy_msb>( + new nirio_zero_copy_msb(*_send_fifo, get_send_frame_size()))); } } } else { @@ -226,14 +245,16 @@ public: { _proxy()->get_rio_quirks().remove_tx_fifo(_fifo_instance); - //Disable DMA streams (cleanup, so don't status chain) - _proxy()->poke(PCIE_TX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), DMA_CTRL_DISABLED); - _proxy()->poke(PCIE_RX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), DMA_CTRL_DISABLED); + // Disable DMA streams (cleanup, so don't status chain) + _proxy()->poke( + PCIE_TX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), DMA_CTRL_DISABLED); + _proxy()->poke( + PCIE_RX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), DMA_CTRL_DISABLED); _flush_rx_buff(); - //Stop DMA channels. Stop is called in the fifo dtor but - //it doesn't hurt to do it here. + // Stop DMA channels. Stop is called in the fifo dtor but + // it doesn't hurt to do it here. _send_fifo->stop(); _recv_fifo->stop(); } @@ -244,12 +265,19 @@ public: ******************************************************************/ managed_recv_buffer::sptr get_recv_buff(double timeout) { - if (_next_recv_buff_index == _xport_params.num_recv_frames) _next_recv_buff_index = 0; + if (_next_recv_buff_index == _xport_params.num_recv_frames) + _next_recv_buff_index = 0; return _mrb_pool[_next_recv_buff_index]->get_new(timeout, _next_recv_buff_index); } - size_t get_num_recv_frames(void) const {return _xport_params.num_recv_frames;} - size_t get_recv_frame_size(void) const {return _xport_params.recv_frame_size;} + size_t get_num_recv_frames(void) const + { + return _xport_params.num_recv_frames; + } + size_t get_recv_frame_size(void) const + { + return _xport_params.recv_frame_size; + } /******************************************************************* * Send implementation: @@ -257,16 +285,25 @@ public: ******************************************************************/ managed_send_buffer::sptr get_send_buff(double timeout) { - if (_next_send_buff_index == _xport_params.num_send_frames) _next_send_buff_index = 0; + if (_next_send_buff_index == _xport_params.num_send_frames) + _next_send_buff_index = 0; return _msb_pool[_next_send_buff_index]->get_new(timeout, _next_send_buff_index); } - size_t get_num_send_frames(void) const {return _xport_params.num_send_frames;} - size_t get_send_frame_size(void) const {return _xport_params.send_frame_size;} + size_t get_num_send_frames(void) const + { + return _xport_params.num_send_frames; + } + size_t get_send_frame_size(void) const + { + return _xport_params.send_frame_size; + } private: - - UHD_INLINE niriok_proxy::sptr _proxy() { return _fpga_session->get_kernel_proxy(); } + UHD_INLINE niriok_proxy::sptr _proxy() + { + return _fpga_session->get_kernel_proxy(); + } UHD_INLINE void _flush_rx_buff() { @@ -275,21 +312,19 @@ private: // repeatedly with the number of remaining elements // until the buffer is empty for (size_t num_elems_requested = 0, - num_elems_acquired = 0, - num_elems_remaining = 1; - num_elems_remaining; - num_elems_requested = num_elems_remaining) - { + num_elems_acquired = 0, + num_elems_remaining = 1; + num_elems_remaining; + num_elems_requested = num_elems_remaining) { fifo_data_t* elems_buffer = NULL; - nirio_status status = _recv_fifo->acquire( - elems_buffer, + nirio_status status = _recv_fifo->acquire(elems_buffer, num_elems_requested, - 0, // timeout + 0, // timeout num_elems_acquired, num_elems_remaining); // throw excetption if status is fatal - nirio_status_to_exception(status, - "NI-RIO PCIe data transfer failed during flush."); + nirio_status_to_exception( + status, "NI-RIO PCIe data transfer failed during flush."); _recv_fifo->release(num_elems_acquired); } } @@ -304,44 +339,52 @@ private: boost::posix_time::time_duration elapsed; nirio_status status = NiRio_Status_Success; - nirio_status_chain(_proxy()->peek( - PCIE_TX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), reg_data), status); + nirio_status_chain( + _proxy()->peek( + PCIE_TX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), reg_data), + status); tx_busy = (reg_data & DMA_STATUS_BUSY) > 0; - nirio_status_chain(_proxy()->peek( - PCIE_RX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), reg_data), status); + nirio_status_chain( + _proxy()->peek( + PCIE_RX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), reg_data), + status); rx_busy = (reg_data & DMA_STATUS_BUSY) > 0; if (nirio_status_not_fatal(status) && (tx_busy || rx_busy)) { start_time = boost::posix_time::microsec_clock::local_time(); do { - std::this_thread::sleep_for(std::chrono::microseconds(50)); //Avoid flooding the bus + std::this_thread::sleep_for( + std::chrono::microseconds(50)); // Avoid flooding the bus elapsed = boost::posix_time::microsec_clock::local_time() - start_time; - nirio_status_chain(_proxy()->peek( - PCIE_TX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), reg_data), status); + nirio_status_chain( + _proxy()->peek( + PCIE_TX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), reg_data), + status); tx_busy = (reg_data & DMA_STATUS_BUSY) > 0; - nirio_status_chain(_proxy()->peek( - PCIE_RX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), reg_data), status); + nirio_status_chain( + _proxy()->peek( + PCIE_RX_DMA_REG(DMA_CTRL_STATUS_REG, _fifo_instance), reg_data), + status); rx_busy = (reg_data & DMA_STATUS_BUSY) > 0; - } while ( - nirio_status_not_fatal(status) && - (tx_busy || rx_busy) && - elapsed.total_milliseconds() < TIMEOUT_IN_MS); + } while (nirio_status_not_fatal(status) && (tx_busy || rx_busy) + && elapsed.total_milliseconds() < TIMEOUT_IN_MS); if (tx_busy || rx_busy) { nirio_status_chain(NiRio_Status_FpgaBusy, status); } - nirio_status_to_exception(status, "Could not create nirio_zero_copy transport."); + nirio_status_to_exception( + status, "Could not create nirio_zero_copy transport."); } } - //memory management -> buffers and fifos + // memory management -> buffers and fifos niusrprio::niusrprio_session::sptr _fpga_session; uint32_t _fifo_instance; nirio_fifo<fifo_data_t>::sptr _recv_fifo, _send_fifo; const zero_copy_xport_params _xport_params; - std::vector<boost::shared_ptr<nirio_zero_copy_msb> > _msb_pool; - std::vector<boost::shared_ptr<nirio_zero_copy_mrb> > _mrb_pool; + std::vector<boost::shared_ptr<nirio_zero_copy_msb>> _msb_pool; + std::vector<boost::shared_ptr<nirio_zero_copy_mrb>> _mrb_pool; size_t _next_recv_buff_index, _next_send_buff_index; }; @@ -350,102 +393,121 @@ nirio_zero_copy::sptr nirio_zero_copy::make( uhd::niusrprio::niusrprio_session::sptr fpga_session, const uint32_t instance, const zero_copy_xport_params& default_buff_args, - const device_addr_t &hints -){ - //Initialize xport_params + const device_addr_t& hints) +{ + // Initialize xport_params zero_copy_xport_params xport_params = default_buff_args; - //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, - //it is possible for users to over constrain the system when they set the num_frames and the buff_size - //So we give buff_size priority over num_frames and throw an error if they conflict. + // 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, it is possible for users to over constrain the system when they + // set the num_frames and the buff_size So we give buff_size priority over num_frames + // and throw an error if they conflict. - //RX - xport_params.recv_frame_size = size_t(hints.cast<double>("recv_frame_size", default_buff_args.recv_frame_size)); + // RX + xport_params.recv_frame_size = + size_t(hints.cast<double>("recv_frame_size", default_buff_args.recv_frame_size)); size_t usr_num_recv_frames = static_cast<size_t>( hints.cast<double>("num_recv_frames", default_buff_args.num_recv_frames)); 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_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("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)"); + throw uhd::value_error("recv_buff_size must be equal to or greater than " + "(num_recv_frames * recv_frame_size)"); - if ((usr_recv_buff_size/xport_params.recv_frame_size) != usr_num_recv_frames) - throw uhd::value_error("Conflicting values for recv_buff_size and num_recv_frames"); + if ((usr_recv_buff_size / xport_params.recv_frame_size) != usr_num_recv_frames) + throw uhd::value_error( + "Conflicting values for recv_buff_size and num_recv_frames"); } if (hints.has_key("recv_buff_size")) { - xport_params.num_recv_frames = std::max<size_t>(1, usr_recv_buff_size/xport_params.recv_frame_size); //Round down + xport_params.num_recv_frames = std::max<size_t>( + 1, usr_recv_buff_size / xport_params.recv_frame_size); // Round down } else if (hints.has_key("num_recv_frames")) { 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()); + 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)); + // TX + xport_params.send_frame_size = + size_t(hints.cast<double>("send_frame_size", default_buff_args.send_frame_size)); size_t usr_num_send_frames = static_cast<size_t>( hints.cast<double>("num_send_frames", default_buff_args.num_send_frames)); size_t usr_send_buff_size = static_cast<size_t>( hints.cast<double>("send_buff_size", default_buff_args.num_send_frames)); - if (hints.has_key("send_buff_size")) - { - if (usr_send_buff_size % page_size != 0) - { - throw uhd::value_error((boost::format("send_buff_size must be multiple of %d") % page_size).str()); + if (hints.has_key("send_buff_size")) { + if (usr_send_buff_size % page_size != 0) { + throw uhd::value_error( + (boost::format("send_buff_size must be multiple of %d") % page_size) + .str()); } } - if (hints.has_key("send_frame_size") and hints.has_key("num_send_frames")) - { - if (usr_num_send_frames * xport_params.send_frame_size % page_size != 0) - { - throw uhd::value_error((boost::format("num_send_frames * send_frame_size must be an even multiple of %d") % page_size).str()); + if (hints.has_key("send_frame_size") and hints.has_key("num_send_frames")) { + if (usr_num_send_frames * xport_params.send_frame_size % page_size != 0) { + throw uhd::value_error( + (boost::format( + "num_send_frames * send_frame_size must be an even multiple of %d") + % page_size) + .str()); } } if (hints.has_key("num_send_frames") and hints.has_key("send_buff_size")) { if (usr_send_buff_size < xport_params.send_frame_size) - throw uhd::value_error("send_buff_size must be equal to or greater than (num_send_frames * send_frame_size)"); + throw uhd::value_error("send_buff_size must be equal to or greater than " + "(num_send_frames * send_frame_size)"); - if ((usr_send_buff_size/xport_params.send_frame_size) != usr_num_send_frames) - throw uhd::value_error("Conflicting values for send_buff_size and num_send_frames"); + if ((usr_send_buff_size / xport_params.send_frame_size) != usr_num_send_frames) + throw uhd::value_error( + "Conflicting values for send_buff_size and num_send_frames"); } if (hints.has_key("send_buff_size")) { - xport_params.num_send_frames = std::max<size_t>(1, usr_send_buff_size/xport_params.send_frame_size); //Round down + xport_params.num_send_frames = std::max<size_t>( + 1, usr_send_buff_size / xport_params.send_frame_size); // Round down } else if (hints.has_key("num_send_frames")) { xport_params.num_send_frames = usr_num_send_frames; } - if (xport_params.num_send_frames * xport_params.send_frame_size % page_size != 0) - { - throw uhd::value_error((boost::format("num_send_frames * send_frame_size must be an even multiple of %d") % page_size).str()); + if (xport_params.num_send_frames * xport_params.send_frame_size % page_size != 0) { + throw uhd::value_error( + (boost::format( + "num_send_frames * send_frame_size must be an even multiple of %d") + % page_size) + .str()); } - return nirio_zero_copy::sptr(new nirio_zero_copy_impl(fpga_session, instance, xport_params)); + return nirio_zero_copy::sptr( + new nirio_zero_copy_impl(fpga_session, instance, xport_params)); } - diff --git a/host/lib/transport/super_recv_packet_handler.hpp b/host/lib/transport/super_recv_packet_handler.hpp index 894287d6b..342d273a6 100644 --- a/host/lib/transport/super_recv_packet_handler.hpp +++ b/host/lib/transport/super_recv_packet_handler.hpp @@ -9,43 +9,43 @@ #define INCLUDED_LIBUHD_TRANSPORT_SUPER_RECV_PACKET_HANDLER_HPP #include <uhd/config.hpp> -#include <uhd/exception.hpp> #include <uhd/convert.hpp> +#include <uhd/exception.hpp> #include <uhd/stream.hpp> -#include <uhd/utils/tasks.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/log.hpp> -#include <uhd/types/metadata.hpp> #include <uhd/transport/vrt_if_packet.hpp> #include <uhd/transport/zero_copy.hpp> +#include <uhd/types/metadata.hpp> +#include <uhd/utils/byteswap.hpp> +#include <uhd/utils/log.hpp> +#include <uhd/utils/tasks.hpp> #include <uhdlib/rfnoc/rx_stream_terminator.hpp> #include <boost/dynamic_bitset.hpp> -#include <boost/function.hpp> #include <boost/format.hpp> +#include <boost/function.hpp> #include <boost/make_shared.hpp> #include <iostream> #include <vector> // Included for debugging #ifdef UHD_TXRX_DEBUG_PRINTS -#include <boost/format.hpp> -#include <boost/thread/thread.hpp> -#include "boost/date_time/posix_time/posix_time.hpp" +# include "boost/date_time/posix_time/posix_time.hpp" +# include <boost/format.hpp> +# include <boost/thread/thread.hpp> #endif -namespace uhd{ namespace transport{ namespace sph{ +namespace uhd { namespace transport { namespace sph { UHD_INLINE uint32_t get_context_code( - const uint32_t *vrt_hdr, const vrt::if_packet_info_t &if_packet_info -){ - //extract the context word (we dont know the endianness so mirror the bytes) - uint32_t word0 = vrt_hdr[if_packet_info.num_header_words32] | - uhd::byteswap(vrt_hdr[if_packet_info.num_header_words32]); + const uint32_t* vrt_hdr, const vrt::if_packet_info_t& if_packet_info) +{ + // extract the context word (we dont know the endianness so mirror the bytes) + uint32_t word0 = vrt_hdr[if_packet_info.num_header_words32] + | uhd::byteswap(vrt_hdr[if_packet_info.num_header_words32]); return word0 & 0xff; } typedef boost::function<void(void)> handle_overflow_type; -static inline void handle_overflow_nop(void){} +static inline void handle_overflow_nop(void) {} /*********************************************************************** * Super receive packet handler @@ -54,51 +54,58 @@ static inline void handle_overflow_nop(void){} * The channel group shares a common sample rate. * All channels are received in unison in recv(). **********************************************************************/ -class recv_packet_handler{ +class recv_packet_handler +{ public: typedef boost::function<managed_recv_buffer::sptr(double)> get_buff_type; typedef boost::function<void(const size_t)> handle_flowctrl_type; - typedef std::function<void(const uint32_t *)> handle_flowctrl_ack_type; + typedef std::function<void(const uint32_t*)> handle_flowctrl_ack_type; typedef boost::function<void(const stream_cmd_t&)> issue_stream_cmd_type; - typedef void(*vrt_unpacker_type)(const uint32_t *, vrt::if_packet_info_t &); - //typedef boost::function<void(const uint32_t *, vrt::if_packet_info_t &)> vrt_unpacker_type; + typedef void (*vrt_unpacker_type)(const uint32_t*, vrt::if_packet_info_t&); + // typedef boost::function<void(const uint32_t *, vrt::if_packet_info_t &)> + // vrt_unpacker_type; /*! * Make a new packet handler for receive * \param size the number of transport channels */ - recv_packet_handler(const size_t size = 1): - _queue_error_for_next_call(false), - _buffers_infos_index(0) + recv_packet_handler(const size_t size = 1) + : _queue_error_for_next_call(false), _buffers_infos_index(0) { - #ifdef ERROR_INJECT_DROPPED_PACKETS +#ifdef ERROR_INJECT_DROPPED_PACKETS recvd_packets = 0; - #endif +#endif this->resize(size); set_alignment_failure_threshold(1000); } - ~recv_packet_handler(void){ + ~recv_packet_handler(void) + { /* NOP */ } //! Resize the number of transport channels - void resize(const size_t size){ - if (this->size() == size) return; + void resize(const size_t size) + { + if (this->size() == size) + return; _props.resize(size); - //re-initialize all buffers infos by re-creating the vector + // re-initialize all buffers infos by re-creating the vector _buffers_infos = std::vector<buffers_info_type>(4, buffers_info_type(size)); } //! Get the channel width of this handler - size_t size(void) const{ + size_t size(void) const + { return _props.size(); } //! Setup the vrt unpacker function and offset - void set_vrt_unpacker(const vrt_unpacker_type &vrt_unpacker, const size_t header_offset_words32 = 0){ - _vrt_unpacker = vrt_unpacker; + void set_vrt_unpacker( + const vrt_unpacker_type& vrt_unpacker, const size_t header_offset_words32 = 0) + { + _vrt_unpacker = vrt_unpacker; _header_offset_words32 = header_offset_words32; } @@ -107,17 +114,20 @@ public: * How many packets throw out before giving up? * \param threshold number of packets per channel */ - void set_alignment_failure_threshold(const size_t threshold){ - _alignment_failure_threshold = threshold*this->size(); + void set_alignment_failure_threshold(const size_t threshold) + { + _alignment_failure_threshold = threshold * this->size(); } //! Set the rate of ticks per second - void set_tick_rate(const double rate){ + void set_tick_rate(const double rate) + { _tick_rate = rate; } //! Set the rate of samples per second - void set_samp_rate(const double rate){ + void set_samp_rate(const double rate) + { _samp_rate = rate; } @@ -126,9 +136,12 @@ public: * \param xport_chan which transport channel * \param get_buff the getter function */ - void set_xport_chan_get_buff(const size_t xport_chan, const get_buff_type &get_buff, const bool flush = false){ - if (flush){ - while (get_buff(0.0)) {}; + void set_xport_chan_get_buff( + const size_t xport_chan, const get_buff_type& get_buff, const bool flush = false) + { + if (flush) { + while (get_buff(0.0)) { + }; } _props.at(xport_chan).get_buff = get_buff; } @@ -148,58 +161,67 @@ public: * \param xport_chan which transport channel * \param handle_flowctrl the callback function */ - void set_xport_handle_flowctrl(const size_t xport_chan, const handle_flowctrl_type &handle_flowctrl, const size_t update_window, const bool do_init = false) + void set_xport_handle_flowctrl(const size_t xport_chan, + const handle_flowctrl_type& handle_flowctrl, + const size_t update_window, + const bool do_init = false) { _props.at(xport_chan).handle_flowctrl = handle_flowctrl; - //we need the window size to be within the 0xfff (max 12 bit seq) + // we need the window size to be within the 0xfff (max 12 bit seq) _props.at(xport_chan).fc_update_window = std::min<size_t>(update_window, 0xfff); - if (do_init) handle_flowctrl(0); + if (do_init) + handle_flowctrl(0); } void set_xport_handle_flowctrl_ack( - const size_t xport_chan, - const handle_flowctrl_ack_type &handle_flowctrl_ack - ) { + const size_t xport_chan, const handle_flowctrl_ack_type& handle_flowctrl_ack) + { _props.at(xport_chan).handle_flowctrl_ack = handle_flowctrl_ack; } //! Set the conversion routine for all channels - void set_converter(const uhd::convert::id_type &id){ + void set_converter(const uhd::convert::id_type& id) + { _num_outputs = id.num_outputs; - _converter = uhd::convert::get_converter(id)(); - this->set_scale_factor(1/32767.); //update after setting converter + _converter = uhd::convert::get_converter(id)(); + this->set_scale_factor(1 / 32767.); // update after setting converter _bytes_per_otw_item = uhd::convert::get_bytes_per_item(id.input_format); _bytes_per_cpu_item = uhd::convert::get_bytes_per_item(id.output_format); } //! Set the transport channel's overflow handler - void set_overflow_handler(const size_t xport_chan, const handle_overflow_type &handle_overflow){ + void set_overflow_handler( + const size_t xport_chan, const handle_overflow_type& handle_overflow) + { _props.at(xport_chan).handle_overflow = handle_overflow; } //! Set the scale factor used in float conversion - void set_scale_factor(const double scale_factor){ + void set_scale_factor(const double scale_factor) + { _converter->set_scalar(scale_factor); } //! Set the callback to issue stream commands - void set_issue_stream_cmd(const size_t xport_chan, const issue_stream_cmd_type &issue_stream_cmd) + void set_issue_stream_cmd( + const size_t xport_chan, const issue_stream_cmd_type& issue_stream_cmd) { _props.at(xport_chan).issue_stream_cmd = issue_stream_cmd; } //! Overload call to issue stream commands - void issue_stream_cmd(const stream_cmd_t &stream_cmd) + void issue_stream_cmd(const stream_cmd_t& stream_cmd) { - if (size() > 1 and stream_cmd.stream_now and - stream_cmd.stream_mode != stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS) - { - throw uhd::runtime_error("Invalid recv stream command - stream now on multiple channels in a single streamer will fail to time align."); + if (size() > 1 and stream_cmd.stream_now + and stream_cmd.stream_mode != stream_cmd_t::STREAM_MODE_STOP_CONTINUOUS) { + throw uhd::runtime_error( + "Invalid recv stream command - stream now on multiple channels in a " + "single streamer will fail to time align."); } - for (size_t i = 0; i < _props.size(); i++) - { - if (_props[i].issue_stream_cmd) _props[i].issue_stream_cmd(stream_cmd); + for (size_t i = 0; i < _props.size(); i++) { + if (_props[i].issue_stream_cmd) + _props[i].issue_stream_cmd(stream_cmd); } } @@ -208,56 +230,57 @@ public: * The entry point for the fast-path receive calls. * Dispatch into combinations of single packet receive calls. ******************************************************************/ - UHD_INLINE size_t recv( - const uhd::rx_streamer::buffs_type &buffs, + UHD_INLINE size_t recv(const uhd::rx_streamer::buffs_type& buffs, const size_t nsamps_per_buff, - uhd::rx_metadata_t &metadata, + uhd::rx_metadata_t& metadata, const double timeout, - const bool one_packet - ){ - //handle metadata queued from a previous receive - if (_queue_error_for_next_call){ + const bool one_packet) + { + // handle metadata queued from a previous receive + if (_queue_error_for_next_call) { _queue_error_for_next_call = false; - metadata = _queue_metadata; - //We want to allow a full buffer recv to be cut short by a timeout, - //but do not want to generate an inline timeout message packet. - if (_queue_metadata.error_code != rx_metadata_t::ERROR_CODE_TIMEOUT) return 0; + metadata = _queue_metadata; + // We want to allow a full buffer recv to be cut short by a timeout, + // but do not want to generate an inline timeout message packet. + if (_queue_metadata.error_code != rx_metadata_t::ERROR_CODE_TIMEOUT) + return 0; } - size_t accum_num_samps = recv_one_packet( - buffs, nsamps_per_buff, metadata, timeout - ); + size_t accum_num_samps = + recv_one_packet(buffs, nsamps_per_buff, metadata, timeout); - if (one_packet or metadata.end_of_burst){ + if (one_packet or metadata.end_of_burst) { #ifdef UHD_TXRX_DEBUG_PRINTS - dbg_gather_data(nsamps_per_buff, accum_num_samps, metadata, timeout, one_packet); + dbg_gather_data( + nsamps_per_buff, accum_num_samps, metadata, timeout, one_packet); #endif return accum_num_samps; } - //first recv had an error code set, return immediately + // first recv had an error code set, return immediately if (metadata.error_code != rx_metadata_t::ERROR_CODE_NONE) { return accum_num_samps; } - //loop until buffer is filled or error code - while(accum_num_samps < nsamps_per_buff){ - size_t num_samps = recv_one_packet( - buffs, nsamps_per_buff - accum_num_samps, _queue_metadata, - timeout, accum_num_samps*_bytes_per_cpu_item - ); + // loop until buffer is filled or error code + while (accum_num_samps < nsamps_per_buff) { + size_t num_samps = recv_one_packet(buffs, + nsamps_per_buff - accum_num_samps, + _queue_metadata, + timeout, + accum_num_samps * _bytes_per_cpu_item); metadata.end_of_burst = _queue_metadata.end_of_burst; - //metadata had an error code set, store for next call and return - if (_queue_metadata.error_code != rx_metadata_t::ERROR_CODE_NONE){ + // metadata had an error code set, store for next call and return + if (_queue_metadata.error_code != rx_metadata_t::ERROR_CODE_NONE) { _queue_error_for_next_call = true; break; } accum_num_samps += num_samps; - //return immediately if end of burst + // return immediately if end of burst if (_queue_metadata.end_of_burst) { break; } @@ -275,12 +298,12 @@ private: bool _queue_error_for_next_call; size_t _alignment_failure_threshold; rx_metadata_t _queue_metadata; - struct xport_chan_props_type{ - xport_chan_props_type(void): - packet_count(0), - handle_overflow(&handle_overflow_nop), - fc_update_window(0) - {} + struct xport_chan_props_type + { + xport_chan_props_type(void) + : packet_count(0), handle_overflow(&handle_overflow_nop), fc_update_window(0) + { + } get_buff_type get_buff; issue_stream_cmd_type issue_stream_cmd; size_t packet_count; @@ -291,65 +314,80 @@ private: }; std::vector<xport_chan_props_type> _props; size_t _num_outputs; - size_t _bytes_per_otw_item; //used in conversion - size_t _bytes_per_cpu_item; //used in conversion - uhd::convert::converter::sptr _converter; //used in conversion + size_t _bytes_per_otw_item; // used in conversion + size_t _bytes_per_cpu_item; // used in conversion + uhd::convert::converter::sptr _converter; // used in conversion //! information stored for a received buffer - struct per_buffer_info_type{ + struct per_buffer_info_type + { void reset() { buff.reset(); - vrt_hdr = nullptr; - time = 0; + vrt_hdr = nullptr; + time = 0; copy_buff = nullptr; } managed_recv_buffer::sptr buff; - const uint32_t *vrt_hdr; + const uint32_t* vrt_hdr; vrt::if_packet_info_t ifpi; uint64_t time; - const char *copy_buff; + const char* copy_buff; }; - //!information stored for a set of aligned buffers - struct buffers_info_type : std::vector<per_buffer_info_type> { - buffers_info_type(const size_t size): - std::vector<per_buffer_info_type>(size), - indexes_todo(size, true), - alignment_time(0), - alignment_time_valid(false), - data_bytes_to_copy(0), - fragment_offset_in_samps(0) - {/* NOP */} + //! information stored for a set of aligned buffers + struct buffers_info_type : std::vector<per_buffer_info_type> + { + buffers_info_type(const size_t size) + : std::vector<per_buffer_info_type>(size) + , indexes_todo(size, true) + , alignment_time(0) + , alignment_time_valid(false) + , data_bytes_to_copy(0) + , fragment_offset_in_samps(0) + { /* NOP */ + } void reset() { indexes_todo.set(); - alignment_time = 0; - alignment_time_valid = false; - data_bytes_to_copy = 0; + alignment_time = 0; + alignment_time_valid = false; + data_bytes_to_copy = 0; fragment_offset_in_samps = 0; metadata.reset(); for (size_t i = 0; i < size(); i++) at(i).reset(); } - boost::dynamic_bitset<> indexes_todo; //used in alignment logic - uint64_t alignment_time; //used in alignment logic - bool alignment_time_valid; //used in alignment logic - size_t data_bytes_to_copy; //keeps track of state - size_t fragment_offset_in_samps; //keeps track of state - rx_metadata_t metadata; //packet description + boost::dynamic_bitset<> indexes_todo; // used in alignment logic + uint64_t alignment_time; // used in alignment logic + bool alignment_time_valid; // used in alignment logic + size_t data_bytes_to_copy; // keeps track of state + size_t fragment_offset_in_samps; // keeps track of state + rx_metadata_t metadata; // packet description }; //! a circular queue of buffer infos std::vector<buffers_info_type> _buffers_infos; size_t _buffers_infos_index; - buffers_info_type &get_curr_buffer_info(void){return _buffers_infos[_buffers_infos_index];} - buffers_info_type &get_prev_buffer_info(void){return _buffers_infos[(_buffers_infos_index + 3)%4];} - buffers_info_type &get_next_buffer_info(void){return _buffers_infos[(_buffers_infos_index + 1)%4];} - void increment_buffer_info(void){_buffers_infos_index = (_buffers_infos_index + 1)%4;} + buffers_info_type& get_curr_buffer_info(void) + { + return _buffers_infos[_buffers_infos_index]; + } + buffers_info_type& get_prev_buffer_info(void) + { + return _buffers_infos[(_buffers_infos_index + 3) % 4]; + } + buffers_info_type& get_next_buffer_info(void) + { + return _buffers_infos[(_buffers_infos_index + 1) % 4]; + } + void increment_buffer_info(void) + { + _buffers_infos_index = (_buffers_infos_index + 1) % 4; + } //! possible return options for the packet receiver - enum packet_type{ + enum packet_type { PACKET_IF_DATA, PACKET_TIMESTAMP_ERROR, PACKET_INLINE_MESSAGE, @@ -357,9 +395,9 @@ private: PACKET_SEQUENCE_ERROR }; - #ifdef ERROR_INJECT_DROPPED_PACKETS +#ifdef ERROR_INJECT_DROPPED_PACKETS int recvd_packets; - #endif +#endif /******************************************************************* * Get and process a single packet from the transport: @@ -367,57 +405,56 @@ private: * Extract all the relevant info and store. * Check the info to determine the return code. ******************************************************************/ - UHD_INLINE packet_type get_and_process_single_packet( - const size_t index, - per_buffer_info_type &prev_buffer_info, - per_buffer_info_type &curr_buffer_info, - double timeout - ){ - managed_recv_buffer::sptr &buff = curr_buffer_info.buff; - per_buffer_info_type &info = curr_buffer_info; - while (1) - { - //get a single packet from the transport layer + UHD_INLINE packet_type get_and_process_single_packet(const size_t index, + per_buffer_info_type& prev_buffer_info, + per_buffer_info_type& curr_buffer_info, + double timeout) + { + managed_recv_buffer::sptr& buff = curr_buffer_info.buff; + per_buffer_info_type& info = curr_buffer_info; + while (1) { + // get a single packet from the transport layer buff = _props[index].get_buff(timeout); - if (buff.get() == nullptr) return PACKET_TIMEOUT_ERROR; + if (buff.get() == nullptr) + return PACKET_TIMEOUT_ERROR; - #ifdef ERROR_INJECT_DROPPED_PACKETS - if (++recvd_packets > 1000) - { +#ifdef ERROR_INJECT_DROPPED_PACKETS + if (++recvd_packets > 1000) { recvd_packets = 0; buff.reset(); buff = _props[index].get_buff(timeout); - if (buff.get() == nullptr) return PACKET_TIMEOUT_ERROR; + if (buff.get() == nullptr) + return PACKET_TIMEOUT_ERROR; } - #endif +#endif - //bounds check before extract - const size_t num_packet_words32 = buff->size()/sizeof(uint32_t); - if (num_packet_words32 <= _header_offset_words32){ + // bounds check before extract + const size_t num_packet_words32 = buff->size() / sizeof(uint32_t); + if (num_packet_words32 <= _header_offset_words32) { throw std::runtime_error("recv buffer smaller than vrt packet offset"); } - //extract packet info - memset(&info.ifpi, 0, sizeof (vrt::if_packet_info_t)); + // extract packet info + memset(&info.ifpi, 0, sizeof(vrt::if_packet_info_t)); info.ifpi.num_packet_words32 = num_packet_words32 - _header_offset_words32; - info.vrt_hdr = buff->cast<const uint32_t *>() + _header_offset_words32; + info.vrt_hdr = buff->cast<const uint32_t*>() + _header_offset_words32; _vrt_unpacker(info.vrt_hdr, info.ifpi); - info.time = info.ifpi.tsf; //assumes has_tsf is true - info.copy_buff = reinterpret_cast<const char *>(info.vrt_hdr + info.ifpi.num_header_words32); - - //handle flow control - if (_props[index].handle_flowctrl) - { - if ((info.ifpi.packet_count % _props[index].fc_update_window) == 0) - { + info.time = info.ifpi.tsf; // assumes has_tsf is true + info.copy_buff = reinterpret_cast<const char*>( + info.vrt_hdr + info.ifpi.num_header_words32); + + // handle flow control + if (_props[index].handle_flowctrl) { + if ((info.ifpi.packet_count % _props[index].fc_update_window) == 0) { _props[index].handle_flowctrl(info.ifpi.packet_count); } } - //handle flow control ack - if (info.ifpi.fc_ack){ + // handle flow control ack + if (info.ifpi.fc_ack) { if (_props[index].handle_flowctrl_ack) { - _props[index].handle_flowctrl_ack(reinterpret_cast<const uint32_t *>(info.copy_buff)); + _props[index].handle_flowctrl_ack( + reinterpret_cast<const uint32_t*>(info.copy_buff)); } // Process the next packet buff.reset(); @@ -433,18 +470,20 @@ private: //-- The order of these checks is HOLY. //-------------------------------------------------------------- - //1) check for inline IF message packets - if (info.ifpi.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA){ + // 1) check for inline IF message packets + if (info.ifpi.packet_type != vrt::if_packet_info_t::PACKET_TYPE_DATA) { return PACKET_INLINE_MESSAGE; } - //2) check for sequence errors - #ifndef SRPH_DONT_CHECK_SEQUENCE - const size_t seq_mask = (info.ifpi.link_type == vrt::if_packet_info_t::LINK_TYPE_NONE)? 0xf : 0xfff; +// 2) check for sequence errors +#ifndef SRPH_DONT_CHECK_SEQUENCE + const size_t seq_mask = + (info.ifpi.link_type == vrt::if_packet_info_t::LINK_TYPE_NONE) ? 0xf : 0xfff; const size_t expected_packet_count = _props[index].packet_count; - _props[index].packet_count = (info.ifpi.packet_count + 1) & seq_mask; - if (expected_packet_count != info.ifpi.packet_count){ - //UHD_LOGGER_INFO("STREAMER") << "expected: " << expected_packet_count << " got: " << info.ifpi.packet_count; + _props[index].packet_count = (info.ifpi.packet_count + 1) & seq_mask; + if (expected_packet_count != info.ifpi.packet_count) { + // UHD_LOGGER_INFO("STREAMER") << "expected: " << expected_packet_count << " + // got: " << info.ifpi.packet_count; if (_props[index].handle_flowctrl) { // Always update flow control in this case, because we don't // know which packet was dropped and what state the upstream @@ -453,14 +492,14 @@ private: } return PACKET_SEQUENCE_ERROR; } - #endif +#endif - //3) check for out of order timestamps - if (info.ifpi.has_tsf and prev_buffer_info.time > info.time){ + // 3) check for out of order timestamps + if (info.ifpi.has_tsf and prev_buffer_info.time > info.time) { return PACKET_TIMESTAMP_ERROR; } - //4) otherwise the packet is normal! + // 4) otherwise the packet is normal! return PACKET_IF_DATA; } @@ -470,25 +509,22 @@ private: get_curr_buffer_info().reset(); get_next_buffer_info().reset(); - for (size_t i = 0; i < _props.size(); i++) - { + for (size_t i = 0; i < _props.size(); i++) { per_buffer_info_type prev_buffer_info, curr_buffer_info; prev_buffer_info.reset(); curr_buffer_info.reset(); - while (true) - { - //receive a single packet from the transport - try - { + while (true) { + // receive a single packet from the transport + try { // call into get_and_process_single_packet() // to make sure flow control is handled if (get_and_process_single_packet( - i, - prev_buffer_info, - curr_buffer_info, - timeout) == PACKET_TIMEOUT_ERROR) break; - } catch(...){} - curr_buffer_info.buff.reset(); // Let my buffer go! + i, prev_buffer_info, curr_buffer_info, timeout) + == PACKET_TIMEOUT_ERROR) + break; + } catch (...) { + } + curr_buffer_info.buff.reset(); // Let my buffer go! prev_buffer_info = curr_buffer_info; curr_buffer_info.reset(); } @@ -499,34 +535,31 @@ private: * Alignment check: * Check the received packet for alignment and mark accordingly. ******************************************************************/ - UHD_INLINE void alignment_check( - const size_t index, buffers_info_type &info - ){ - //if alignment time was not valid or if the sequence id is newer: + UHD_INLINE void alignment_check(const size_t index, buffers_info_type& info) + { + // if alignment time was not valid or if the sequence id is newer: // use this index's time as the alignment time // reset the indexes list and remove this index - if (not info.alignment_time_valid or info[index].time > info.alignment_time){ + if (not info.alignment_time_valid or info[index].time > info.alignment_time) { info.alignment_time_valid = true; - info.alignment_time = info[index].time; + info.alignment_time = info[index].time; info.indexes_todo.set(); info.indexes_todo.reset(index); // release the other buffers - for (size_t i = 0; i < info.size(); i++) - { - if (i != index) - { + for (size_t i = 0; i < info.size(); i++) { + if (i != index) { info[i].reset(); } } info.data_bytes_to_copy = info[index].ifpi.num_payload_bytes; // reset start_of_burst and end_of_burst states info.metadata.start_of_burst = info[index].ifpi.sob; - info.metadata.end_of_burst = info[index].ifpi.eob; + info.metadata.end_of_burst = info[index].ifpi.eob; } - //if the sequence id matches: + // if the sequence id matches: // remove this index from the list and continue - else if (info[index].time == info.alignment_time){ + else if (info[index].time == info.alignment_time) { info.indexes_todo.reset(index); // All channels should have sob set at the same time, so only // set start_of burst if all channels have sob set. @@ -539,9 +572,9 @@ private: info[index].reset(); } - //if the sequence id is older: + // if the sequence id is older: // continue with the same index to try again - //else if (info[index].time < info.alignment_time)... + // else if (info[index].time < info.alignment_time)... } /******************************************************************* @@ -550,127 +583,139 @@ private: * Handle all of the edge cases like inline messages and errors. * The logic will throw out older packets until it finds a match. ******************************************************************/ - UHD_INLINE void get_aligned_buffs(double timeout){ - - get_prev_buffer_info().reset(); // no longer need the previous info - reset it for future use + UHD_INLINE void get_aligned_buffs(double timeout) + { + get_prev_buffer_info() + .reset(); // no longer need the previous info - reset it for future use - increment_buffer_info(); //increment to next buffer + increment_buffer_info(); // increment to next buffer - buffers_info_type &prev_info = get_prev_buffer_info(); - buffers_info_type &curr_info = get_curr_buffer_info(); - buffers_info_type &next_info = get_next_buffer_info(); + buffers_info_type& prev_info = get_prev_buffer_info(); + buffers_info_type& curr_info = get_curr_buffer_info(); + buffers_info_type& next_info = get_next_buffer_info(); curr_info.metadata.error_code = rx_metadata_t::ERROR_CODE_NONE; - //Loop until we get a message of an aligned set of buffers: + // Loop until we get a message of an aligned set of buffers: // - Receive a single packet and extract its info. // - Handle the packet type yielded by the receive. // - Check the timestamps for alignment conditions. size_t iterations = 0; - while (curr_info.indexes_todo.any()){ - - //get the index to process for this iteration + while (curr_info.indexes_todo.any()) { + // get the index to process for this iteration const size_t index = curr_info.indexes_todo.find_first(); packet_type packet; - //receive a single packet from the transport - try{ + // receive a single packet from the transport + try { packet = get_and_process_single_packet( - index, prev_info[index], curr_info[index], timeout - ); + index, prev_info[index], curr_info[index], timeout); } - //handle the case where a bad header exists - catch(const uhd::value_error &e){ - UHD_LOGGER_ERROR("STREAMER") << boost::format( - "The receive packet handler caught a value exception.\n%s" - ) % e.what(); - std::swap(curr_info, next_info); //save progress from curr -> next + // handle the case where a bad header exists + catch (const uhd::value_error& e) { + UHD_LOGGER_ERROR("STREAMER") + << boost::format( + "The receive packet handler caught a value exception.\n%s") + % e.what(); + std::swap(curr_info, next_info); // save progress from curr -> next curr_info.metadata.error_code = rx_metadata_t::ERROR_CODE_BAD_PACKET; return; } - switch(packet){ - case PACKET_IF_DATA: - alignment_check(index, curr_info); - break; - - case PACKET_TIMESTAMP_ERROR: - //If the user changes the device time while streaming or without flushing, - //we can receive a packet that comes before the previous packet in time. - //This could cause the alignment logic to discard future received packets. - //Therefore, when this occurs, we reset the info to restart from scratch. - if (curr_info.alignment_time_valid and curr_info.alignment_time != curr_info[index].time){ - curr_info.alignment_time_valid = false; - } - alignment_check(index, curr_info); - break; + switch (packet) { + case PACKET_IF_DATA: + alignment_check(index, curr_info); + break; + + case PACKET_TIMESTAMP_ERROR: + // If the user changes the device time while streaming or without + // flushing, we can receive a packet that comes before the previous + // packet in time. This could cause the alignment logic to discard + // future received packets. Therefore, when this occurs, we reset the + // info to restart from scratch. + if (curr_info.alignment_time_valid + and curr_info.alignment_time != curr_info[index].time) { + curr_info.alignment_time_valid = false; + } + alignment_check(index, curr_info); + break; + + case PACKET_INLINE_MESSAGE: + curr_info[index].buff.reset(); // No data, so release the buffer + curr_info[index].copy_buff = nullptr; + std::swap(curr_info, next_info); // save progress from curr -> next + curr_info.metadata.has_time_spec = next_info[index].ifpi.has_tsf; + curr_info.metadata.time_spec = + time_spec_t::from_ticks(next_info[index].time, _tick_rate); + curr_info.metadata.error_code = + rx_metadata_t::error_code_t(get_context_code( + next_info[index].vrt_hdr, next_info[index].ifpi)); + if (curr_info.metadata.error_code + == rx_metadata_t::ERROR_CODE_OVERFLOW) { + // Not sending flow control would cause timeouts due to source + // flow control locking up. Send first as the overrun handler may + // flush the receive buffers which could contain packets with + // sequence numbers after this packet's sequence number! + if (_props[index].handle_flowctrl) { + _props[index].handle_flowctrl( + next_info[index].ifpi.packet_count); + } + + rx_metadata_t metadata = curr_info.metadata; + _props[index].handle_overflow(); + curr_info.metadata = metadata; + UHD_LOG_FASTPATH("O"); + } + return; - case PACKET_INLINE_MESSAGE: - curr_info[index].buff.reset(); // No data, so release the buffer - curr_info[index].copy_buff = nullptr; - std::swap(curr_info, next_info); //save progress from curr -> next - curr_info.metadata.has_time_spec = next_info[index].ifpi.has_tsf; - curr_info.metadata.time_spec = time_spec_t::from_ticks(next_info[index].time, _tick_rate); - curr_info.metadata.error_code = rx_metadata_t::error_code_t(get_context_code(next_info[index].vrt_hdr, next_info[index].ifpi)); - if (curr_info.metadata.error_code == rx_metadata_t::ERROR_CODE_OVERFLOW){ - // Not sending flow control would cause timeouts due to source flow control locking up. - // Send first as the overrun handler may flush the receive buffers which could contain - // packets with sequence numbers after this packet's sequence number! - if(_props[index].handle_flowctrl) { + case PACKET_TIMEOUT_ERROR: + std::swap(curr_info, next_info); // save progress from curr -> next + if (_props[index].handle_flowctrl) { _props[index].handle_flowctrl(next_info[index].ifpi.packet_count); } - - rx_metadata_t metadata = curr_info.metadata; - _props[index].handle_overflow(); - curr_info.metadata = metadata; - UHD_LOG_FASTPATH("O"); - } - return; - - case PACKET_TIMEOUT_ERROR: - std::swap(curr_info, next_info); //save progress from curr -> next - if(_props[index].handle_flowctrl) { - _props[index].handle_flowctrl(next_info[index].ifpi.packet_count); - } - curr_info.metadata.error_code = rx_metadata_t::ERROR_CODE_TIMEOUT; - return; - - case PACKET_SEQUENCE_ERROR: - alignment_check(index, curr_info); - std::swap(curr_info, next_info); //save progress from curr -> next - curr_info.metadata.has_time_spec = prev_info.metadata.has_time_spec; - curr_info.metadata.time_spec = prev_info.metadata.time_spec + time_spec_t::from_ticks( - prev_info[index].ifpi.num_payload_words32*sizeof(uint32_t)/_bytes_per_otw_item, _samp_rate); - curr_info.metadata.out_of_sequence = true; - curr_info.metadata.error_code = rx_metadata_t::ERROR_CODE_OVERFLOW; - UHD_LOG_FASTPATH("D"); - return; - + curr_info.metadata.error_code = rx_metadata_t::ERROR_CODE_TIMEOUT; + return; + + case PACKET_SEQUENCE_ERROR: + alignment_check(index, curr_info); + std::swap(curr_info, next_info); // save progress from curr -> next + curr_info.metadata.has_time_spec = prev_info.metadata.has_time_spec; + curr_info.metadata.time_spec = + prev_info.metadata.time_spec + + time_spec_t::from_ticks( + prev_info[index].ifpi.num_payload_words32 * sizeof(uint32_t) + / _bytes_per_otw_item, + _samp_rate); + curr_info.metadata.out_of_sequence = true; + curr_info.metadata.error_code = rx_metadata_t::ERROR_CODE_OVERFLOW; + UHD_LOG_FASTPATH("D"); + return; } - //too many iterations: detect alignment failure - if (iterations++ > _alignment_failure_threshold){ - UHD_LOGGER_ERROR("STREAMER") << boost::format( - "The receive packet handler failed to time-align packets.\n" - "%u received packets were processed by the handler.\n" - "However, a timestamp match could not be determined.\n" - ) % iterations << std::endl; - std::swap(curr_info, next_info); //save progress from curr -> next + // too many iterations: detect alignment failure + if (iterations++ > _alignment_failure_threshold) { + UHD_LOGGER_ERROR("STREAMER") + << boost::format( + "The receive packet handler failed to time-align packets.\n" + "%u received packets were processed by the handler.\n" + "However, a timestamp match could not be determined.\n") + % iterations + << std::endl; + std::swap(curr_info, next_info); // save progress from curr -> next curr_info.metadata.error_code = rx_metadata_t::ERROR_CODE_ALIGNMENT; _props[index].handle_overflow(); return; } - } - //set the metadata from the buffer information at index zero + // set the metadata from the buffer information at index zero curr_info.metadata.has_time_spec = curr_info[0].ifpi.has_tsf; - curr_info.metadata.time_spec = time_spec_t::from_ticks(curr_info[0].time, _tick_rate); - curr_info.metadata.more_fragments = false; + curr_info.metadata.time_spec = + time_spec_t::from_ticks(curr_info[0].time, _tick_rate); + curr_info.metadata.more_fragments = false; curr_info.metadata.fragment_offset = 0; - curr_info.metadata.error_code = rx_metadata_t::ERROR_CODE_NONE; - + curr_info.metadata.error_code = rx_metadata_t::ERROR_CODE_NONE; } /******************************************************************* @@ -679,50 +724,50 @@ private: * When no fragments are available, call the get aligned buffers. * Then copy-convert available data into the user's IO buffers. ******************************************************************/ - UHD_INLINE size_t recv_one_packet( - const uhd::rx_streamer::buffs_type &buffs, + UHD_INLINE size_t recv_one_packet(const uhd::rx_streamer::buffs_type& buffs, const size_t nsamps_per_buff, - uhd::rx_metadata_t &metadata, + uhd::rx_metadata_t& metadata, const double timeout, - const size_t buffer_offset_bytes = 0 - ){ - //get the next buffer if the current one has expired - if (get_curr_buffer_info().data_bytes_to_copy == 0) - { - //perform receive with alignment logic + const size_t buffer_offset_bytes = 0) + { + // get the next buffer if the current one has expired + if (get_curr_buffer_info().data_bytes_to_copy == 0) { + // perform receive with alignment logic get_aligned_buffs(timeout); } - buffers_info_type &info = get_curr_buffer_info(); - metadata = info.metadata; + buffers_info_type& info = get_curr_buffer_info(); + metadata = info.metadata; - //interpolate the time spec (useful when this is a fragment) - metadata.time_spec += time_spec_t::from_ticks(info.fragment_offset_in_samps, _samp_rate); + // interpolate the time spec (useful when this is a fragment) + metadata.time_spec += + time_spec_t::from_ticks(info.fragment_offset_in_samps, _samp_rate); - //extract the number of samples available to copy - const size_t nsamps_available = info.data_bytes_to_copy/_bytes_per_otw_item; - const size_t nsamps_to_copy = std::min(nsamps_per_buff*_num_outputs, nsamps_available); - const size_t bytes_to_copy = nsamps_to_copy*_bytes_per_otw_item; - const size_t nsamps_to_copy_per_io_buff = nsamps_to_copy/_num_outputs; + // extract the number of samples available to copy + const size_t nsamps_available = info.data_bytes_to_copy / _bytes_per_otw_item; + const size_t nsamps_to_copy = + std::min(nsamps_per_buff * _num_outputs, nsamps_available); + const size_t bytes_to_copy = nsamps_to_copy * _bytes_per_otw_item; + const size_t nsamps_to_copy_per_io_buff = nsamps_to_copy / _num_outputs; - //setup the data to share with converter threads - _convert_nsamps = nsamps_to_copy_per_io_buff; - _convert_buffs = &buffs; + // setup the data to share with converter threads + _convert_nsamps = nsamps_to_copy_per_io_buff; + _convert_buffs = &buffs; _convert_buffer_offset_bytes = buffer_offset_bytes; - _convert_bytes_to_copy = bytes_to_copy; + _convert_bytes_to_copy = bytes_to_copy; - //perform N channels of conversion + // perform N channels of conversion for (size_t i = 0; i < this->size(); i++) { convert_to_out_buff(i); } - //update the copy buffer's availability + // update the copy buffer's availability info.data_bytes_to_copy -= bytes_to_copy; - //setup the fragment flags and offset - metadata.more_fragments = info.data_bytes_to_copy != 0; + // setup the fragment flags and offset + metadata.more_fragments = info.data_bytes_to_copy != 0; metadata.fragment_offset = info.fragment_offset_in_samps; - info.fragment_offset_in_samps += nsamps_to_copy; //set for next call + info.fragment_offset_in_samps += nsamps_to_copy; // set for next call return nsamps_to_copy_per_io_buff; } @@ -736,34 +781,34 @@ private: */ inline void convert_to_out_buff(const size_t index) { - //shortcut references to local data structures - buffers_info_type &buff_info = get_curr_buffer_info(); - per_buffer_info_type &info = buff_info[index]; - const rx_streamer::buffs_type &buffs = *_convert_buffs; - - //fill IO buffs with pointers into the output buffer - void *io_buffs[4/*max interleave*/]; - for (size_t i = 0; i < _num_outputs; i++){ - char *b = reinterpret_cast<char *>(buffs[index*_num_outputs + i]); + // shortcut references to local data structures + buffers_info_type& buff_info = get_curr_buffer_info(); + per_buffer_info_type& info = buff_info[index]; + const rx_streamer::buffs_type& buffs = *_convert_buffs; + + // fill IO buffs with pointers into the output buffer + void* io_buffs[4 /*max interleave*/]; + for (size_t i = 0; i < _num_outputs; i++) { + char* b = reinterpret_cast<char*>(buffs[index * _num_outputs + i]); io_buffs[i] = b + _convert_buffer_offset_bytes; } - const ref_vector<void *> out_buffs(io_buffs, _num_outputs); + const ref_vector<void*> out_buffs(io_buffs, _num_outputs); - //perform the conversion operation + // perform the conversion operation _converter->conv(info.copy_buff, out_buffs, _convert_nsamps); - //advance the pointer for the source buffer + // advance the pointer for the source buffer info.copy_buff += _convert_bytes_to_copy; - //release the buffer if fully consumed - if (buff_info.data_bytes_to_copy == _convert_bytes_to_copy){ - info.buff.reset(); //effectively a release + // release the buffer if fully consumed + if (buff_info.data_bytes_to_copy == _convert_bytes_to_copy) { + info.buff.reset(); // effectively a release } } //! Shared variables for the worker threads size_t _convert_nsamps; - const rx_streamer::buffs_type *_convert_buffs; + const rx_streamer::buffs_type* _convert_buffs; size_t _convert_buffer_offset_bytes; size_t _convert_bytes_to_copy; @@ -773,10 +818,24 @@ private: * Gathered data can be used to post process it with external tools. */ #ifdef UHD_TXRX_DEBUG_PRINTS - struct dbg_recv_stat_t { - dbg_recv_stat_t(long wc, size_t nspb, size_t nsr, uhd::rx_metadata_t md, double to, bool op, double rate): - wallclock(wc), nsamps_per_buff(nspb), nsamps_recv(nsr), metadata(md), timeout(to), one_packet(op), samp_rate(rate) - {} + struct dbg_recv_stat_t + { + dbg_recv_stat_t(long wc, + size_t nspb, + size_t nsr, + uhd::rx_metadata_t md, + double to, + bool op, + double rate) + : wallclock(wc) + , nsamps_per_buff(nspb) + , nsamps_recv(nsr) + , metadata(md) + , timeout(to) + , one_packet(op) + , samp_rate(rate) + { + } long wallclock; size_t nsamps_per_buff; size_t nsamps_recv; @@ -785,42 +844,47 @@ private: bool one_packet; double samp_rate; // Create a formatted print line for all the info gathered in this struct. - std::string print_line() { + std::string print_line() + { boost::format fmt("recv,%ld,%f,%i,%i,%s,%i,%s,%s,%s,%i,%s,%ld"); fmt % wallclock; - fmt % timeout % (int)nsamps_per_buff % (int) nsamps_recv; - fmt % (one_packet ? "true":"false"); + fmt % timeout % (int)nsamps_per_buff % (int)nsamps_recv; + fmt % (one_packet ? "true" : "false"); fmt % metadata.error_code; - fmt % (metadata.start_of_burst ? "true":"false") % (metadata.end_of_burst ? "true":"false"); - fmt % (metadata.more_fragments ? "true":"false") % (int)metadata.fragment_offset; - fmt % (metadata.has_time_spec ? "true":"false") % metadata.time_spec.to_ticks(samp_rate); + fmt % (metadata.start_of_burst ? "true" : "false") + % (metadata.end_of_burst ? "true" : "false"); + fmt % (metadata.more_fragments ? "true" : "false") + % (int)metadata.fragment_offset; + fmt % (metadata.has_time_spec ? "true" : "false") + % metadata.time_spec.to_ticks(samp_rate); return fmt.str(); } }; - void dbg_gather_data(const size_t nsamps_per_buff, const size_t nsamps_recv, - uhd::rx_metadata_t &metadata, const double timeout, - const bool one_packet, - bool dbg_print_directly = true - ) + void dbg_gather_data(const size_t nsamps_per_buff, + const size_t nsamps_recv, + uhd::rx_metadata_t& metadata, + const double timeout, + const bool one_packet, + bool dbg_print_directly = true) { - // Initialize a struct with all available data. It can return a formatted string with all infos if wanted. + // Initialize a struct with all available data. It can return a formatted string + // with all infos if wanted. dbg_recv_stat_t data(boost::get_system_time().time_of_day().total_microseconds(), - nsamps_per_buff, - nsamps_recv, - metadata, - timeout, - one_packet, - _samp_rate - ); - if(dbg_print_directly) { + nsamps_per_buff, + nsamps_recv, + metadata, + timeout, + one_packet, + _samp_rate); + if (dbg_print_directly) { dbg_print_err(data.print_line()); } } - - void dbg_print_err(std::string msg) { + void dbg_print_err(std::string msg) + { std::string dbg_prefix("super_recv_packet_handler,"); msg = dbg_prefix + msg; fprintf(stderr, "%s\n", msg.c_str()); @@ -828,31 +892,35 @@ private: #endif }; -class recv_packet_streamer : public recv_packet_handler, public rx_streamer{ +class recv_packet_streamer : public recv_packet_handler, public rx_streamer +{ public: - recv_packet_streamer(const size_t max_num_samps){ + recv_packet_streamer(const size_t max_num_samps) + { _max_num_samps = max_num_samps; } - size_t get_num_channels(void) const{ + size_t get_num_channels(void) const + { return this->size(); } - size_t get_max_num_samps(void) const{ + size_t get_max_num_samps(void) const + { return _max_num_samps; } - size_t recv( - const rx_streamer::buffs_type &buffs, + size_t recv(const rx_streamer::buffs_type& buffs, const size_t nsamps_per_buff, - uhd::rx_metadata_t &metadata, + uhd::rx_metadata_t& metadata, const double timeout, - const bool one_packet - ){ - return recv_packet_handler::recv(buffs, nsamps_per_buff, metadata, timeout, one_packet); + const bool one_packet) + { + return recv_packet_handler::recv( + buffs, nsamps_per_buff, metadata, timeout, one_packet); } - void issue_stream_cmd(const stream_cmd_t &stream_cmd) + void issue_stream_cmd(const stream_cmd_t& stream_cmd) { return recv_packet_handler::issue_stream_cmd(stream_cmd); } @@ -861,6 +929,6 @@ private: size_t _max_num_samps; }; -}}} //namespace +}}} // namespace uhd::transport::sph #endif /* INCLUDED_LIBUHD_TRANSPORT_SUPER_RECV_PACKET_HANDLER_HPP */ diff --git a/host/lib/transport/super_send_packet_handler.hpp b/host/lib/transport/super_send_packet_handler.hpp index b90ea8afd..af6ecaa5e 100644 --- a/host/lib/transport/super_send_packet_handler.hpp +++ b/host/lib/transport/super_send_packet_handler.hpp @@ -9,34 +9,32 @@ #define INCLUDED_LIBUHD_TRANSPORT_SUPER_SEND_PACKET_HANDLER_HPP #include <uhd/config.hpp> -#include <uhd/exception.hpp> #include <uhd/convert.hpp> +#include <uhd/exception.hpp> #include <uhd/stream.hpp> -#include <uhd/utils/tasks.hpp> -#include <uhd/utils/byteswap.hpp> -#include <uhd/utils/thread.hpp> -#include <uhd/types/metadata.hpp> #include <uhd/transport/vrt_if_packet.hpp> #include <uhd/transport/zero_copy.hpp> +#include <uhd/types/metadata.hpp> +#include <uhd/utils/byteswap.hpp> +#include <uhd/utils/tasks.hpp> +#include <uhd/utils/thread.hpp> #include <uhdlib/rfnoc/tx_stream_terminator.hpp> #include <boost/function.hpp> -#include <iostream> -#include <vector> #include <chrono> +#include <iostream> #include <thread> +#include <vector> #ifdef UHD_TXRX_DEBUG_PRINTS // Included for debugging -#include <boost/format.hpp> -#include <boost/thread/thread.hpp> -#include "boost/date_time/posix_time/posix_time.hpp" -#include <map> -#include <fstream> +# include "boost/date_time/posix_time/posix_time.hpp" +# include <boost/format.hpp> +# include <boost/thread/thread.hpp> +# include <fstream> +# include <map> #endif -namespace uhd { -namespace transport { -namespace sph { +namespace uhd { namespace transport { namespace sph { /*********************************************************************** * Super send packet handler @@ -45,52 +43,61 @@ namespace sph { * The channel group shares a common sample rate. * All channels are sent in unison in send(). **********************************************************************/ -class send_packet_handler{ +class send_packet_handler +{ public: typedef std::function<managed_send_buffer::sptr(double)> get_buff_type; typedef std::function<void(void)> post_send_cb_type; - typedef std::function<bool(uhd::async_metadata_t &, const double)> async_receiver_type; - typedef void(*vrt_packer_type)(uint32_t *, vrt::if_packet_info_t &); - //typedef std::function<void(uint32_t *, vrt::if_packet_info_t &)> vrt_packer_type; + typedef std::function<bool(uhd::async_metadata_t&, const double)> async_receiver_type; + typedef void (*vrt_packer_type)(uint32_t*, vrt::if_packet_info_t&); + // typedef std::function<void(uint32_t *, vrt::if_packet_info_t &)> vrt_packer_type; /*! * Make a new packet handler for send * \param size the number of transport channels */ - send_packet_handler(const size_t size = 1): - _next_packet_seq(0), _cached_metadata(false) + send_packet_handler(const size_t size = 1) + : _next_packet_seq(0), _cached_metadata(false) { this->set_enable_trailer(true); this->resize(size); } - ~send_packet_handler(void){ + ~send_packet_handler(void) + { /* NOP */ } //! Resize the number of transport channels - void resize(const size_t size){ - if (this->size() == size) return; + void resize(const size_t size) + { + if (this->size() == size) + return; _props.resize(size); static const uint64_t zero = 0; _zero_buffs.resize(size, &zero); } //! Get the channel width of this handler - size_t size(void) const{ + size_t size(void) const + { return _props.size(); } //! Setup the vrt packer function and offset - void set_vrt_packer(const vrt_packer_type &vrt_packer, const size_t header_offset_words32 = 0){ - _vrt_packer = vrt_packer; + void set_vrt_packer( + const vrt_packer_type& vrt_packer, const size_t header_offset_words32 = 0) + { + _vrt_packer = vrt_packer; _header_offset_words32 = header_offset_words32; } //! Set the stream ID for a specific channel (or no SID) - void set_xport_chan_sid(const size_t xport_chan, const bool has_sid, const uint32_t sid = 0){ + void set_xport_chan_sid( + const size_t xport_chan, const bool has_sid, const uint32_t sid = 0) + { _props.at(xport_chan).has_sid = has_sid; - _props.at(xport_chan).sid = sid; + _props.at(xport_chan).sid = sid; } void set_enable_trailer(const bool enable) @@ -99,12 +106,14 @@ public: } //! Set the rate of ticks per second - void set_tick_rate(const double rate){ + void set_tick_rate(const double rate) + { _tick_rate = rate; } //! Set the rate of samples per second - void set_samp_rate(const double rate){ + void set_samp_rate(const double rate) + { _samp_rate = rate; } @@ -113,7 +122,8 @@ public: * \param xport_chan which transport channel * \param get_buff the getter function */ - void set_xport_chan_get_buff(const size_t xport_chan, const get_buff_type &get_buff){ + void set_xport_chan_get_buff(const size_t xport_chan, const get_buff_type& get_buff) + { _props.at(xport_chan).get_buff = get_buff; } @@ -122,15 +132,17 @@ public: * \param xport_chan which transport channel * \param cb post-send callback */ - void set_xport_chan_post_send_cb(const size_t xport_chan, const post_send_cb_type &cb){ + void set_xport_chan_post_send_cb(const size_t xport_chan, const post_send_cb_type& cb) + { _props.at(xport_chan).go_postal = cb; } //! Set the conversion routine for all channels - void set_converter(const uhd::convert::id_type &id){ + void set_converter(const uhd::convert::id_type& id) + { _num_inputs = id.num_inputs; - _converter = uhd::convert::get_converter(id)(); - this->set_scale_factor(32767.); //update after setting converter + _converter = uhd::convert::get_converter(id)(); + this->set_scale_factor(32767.); // update after setting converter _bytes_per_otw_item = uhd::convert::get_bytes_per_item(id.output_format); _bytes_per_cpu_item = uhd::convert::get_bytes_per_item(id.input_format); } @@ -140,27 +152,29 @@ public: * Ex: A USRP1 in dual channel mode would be half. * \param num_samps the maximum samples in a packet */ - void set_max_samples_per_packet(const size_t num_samps){ + void set_max_samples_per_packet(const size_t num_samps) + { _max_samples_per_packet = num_samps; } //! Set the scale factor used in float conversion - void set_scale_factor(const double scale_factor){ + void set_scale_factor(const double scale_factor) + { _converter->set_scalar(scale_factor); } //! Set the callback to get async messages - void set_async_receiver(const async_receiver_type &async_receiver) + void set_async_receiver(const async_receiver_type& async_receiver) { _async_receiver = async_receiver; } //! Overload call to get async metadata - bool recv_async_msg( - uhd::async_metadata_t &async_metadata, double timeout = 0.1 - ){ - if (_async_receiver) return _async_receiver(async_metadata, timeout); - std::this_thread::sleep_for(std::chrono::microseconds(long(timeout*1e6))); + bool recv_async_msg(uhd::async_metadata_t& async_metadata, double timeout = 0.1) + { + if (_async_receiver) + return _async_receiver(async_metadata, timeout); + std::this_thread::sleep_for(std::chrono::microseconds(long(timeout * 1e6))); return false; } @@ -169,16 +183,15 @@ public: * The entry point for the fast-path send calls. * Dispatch into combinations of single packet send calls. ******************************************************************/ - UHD_INLINE size_t send( - const uhd::tx_streamer::buffs_type &buffs, + UHD_INLINE size_t send(const uhd::tx_streamer::buffs_type& buffs, const size_t nsamps_per_buff, - const uhd::tx_metadata_t &metadata, - const double timeout - ){ - //translate the metadata to vrt if packet info + const uhd::tx_metadata_t& metadata, + const double timeout) + { + // translate the metadata to vrt if packet info vrt::if_packet_info_t if_packet_info; if_packet_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_DATA; - //if_packet_info.has_sid = false; //set per channel + // if_packet_info.has_sid = false; //set per channel if_packet_info.has_cid = false; if_packet_info.has_tlr = _has_tlr; if_packet_info.has_tsi = false; @@ -186,99 +199,102 @@ public: if_packet_info.tsf = metadata.time_spec.to_ticks(_tick_rate); if_packet_info.sob = metadata.start_of_burst; if_packet_info.eob = metadata.end_of_burst; - if_packet_info.fc_ack = false; //This is a data packet + if_packet_info.fc_ack = false; // This is a data packet /* - * Metadata is cached when we get a send requesting a start of burst with no samples. - * It is applied here on the next call to send() that actually has samples to send. + * Metadata is cached when we get a send requesting a start of burst with no + * samples. It is applied here on the next call to send() that actually has + * samples to send. */ - if (_cached_metadata && nsamps_per_buff != 0) - { + if (_cached_metadata && nsamps_per_buff != 0) { // If the new metada has a time_spec, do not use the cached time_spec. - if (!metadata.has_time_spec) - { + if (!metadata.has_time_spec) { if_packet_info.has_tsf = _metadata_cache.has_time_spec; if_packet_info.tsf = _metadata_cache.time_spec.to_ticks(_tick_rate); } - if_packet_info.sob = _metadata_cache.start_of_burst; - if_packet_info.eob = _metadata_cache.end_of_burst; - _cached_metadata = false; + if_packet_info.sob = _metadata_cache.start_of_burst; + if_packet_info.eob = _metadata_cache.end_of_burst; + _cached_metadata = false; } - if (nsamps_per_buff <= _max_samples_per_packet){ - - //TODO remove this code when sample counts of zero are supported by hardware - #ifndef SSPH_DONT_PAD_TO_ONE - static const uint64_t zero = 0; - _zero_buffs.resize(buffs.size(), &zero); - - if (nsamps_per_buff == 0) - { - // if this is a start of a burst and there are no samples - if (metadata.start_of_burst) - { - // cache metadata and apply on the next send() - _metadata_cache = metadata; - _cached_metadata = true; - return 0; - } else { - // send requests with no samples are handled here (such as end of burst) - return send_one_packet(_zero_buffs, 1, if_packet_info, timeout) & 0x0; - } + if (nsamps_per_buff <= _max_samples_per_packet) { +// TODO remove this code when sample counts of zero are supported by hardware +#ifndef SSPH_DONT_PAD_TO_ONE + static const uint64_t zero = 0; + _zero_buffs.resize(buffs.size(), &zero); + + if (nsamps_per_buff == 0) { + // if this is a start of a burst and there are no samples + if (metadata.start_of_burst) { + // cache metadata and apply on the next send() + _metadata_cache = metadata; + _cached_metadata = true; + return 0; + } else { + // send requests with no samples are handled here (such as end of + // burst) + return send_one_packet(_zero_buffs, 1, if_packet_info, timeout) & 0x0; } - #endif + } +#endif - size_t nsamps_sent = send_one_packet(buffs, nsamps_per_buff, if_packet_info, timeout); + size_t nsamps_sent = + send_one_packet(buffs, nsamps_per_buff, if_packet_info, timeout); #ifdef UHD_TXRX_DEBUG_PRINTS - dbg_print_send(nsamps_per_buff, nsamps_sent, metadata, timeout); + dbg_print_send(nsamps_per_buff, nsamps_sent, metadata, timeout); #endif - return nsamps_sent; } + return nsamps_sent; + } size_t total_num_samps_sent = 0; - //false until final fragment + // false until final fragment if_packet_info.eob = false; - const size_t num_fragments = (nsamps_per_buff-1)/_max_samples_per_packet; - const size_t final_length = ((nsamps_per_buff-1)%_max_samples_per_packet)+1; - - //loop through the following fragment indexes - for (size_t i = 0; i < num_fragments; i++){ - - //send a fragment with the helper function - const size_t num_samps_sent = send_one_packet( - buffs, _max_samples_per_packet, - if_packet_info, timeout, - total_num_samps_sent*_bytes_per_cpu_item - ); + const size_t num_fragments = (nsamps_per_buff - 1) / _max_samples_per_packet; + const size_t final_length = ((nsamps_per_buff - 1) % _max_samples_per_packet) + 1; + + // loop through the following fragment indexes + for (size_t i = 0; i < num_fragments; i++) { + // send a fragment with the helper function + const size_t num_samps_sent = send_one_packet(buffs, + _max_samples_per_packet, + if_packet_info, + timeout, + total_num_samps_sent * _bytes_per_cpu_item); total_num_samps_sent += num_samps_sent; - if (num_samps_sent == 0) return total_num_samps_sent; + if (num_samps_sent == 0) + return total_num_samps_sent; - //setup metadata for the next fragment - const time_spec_t time_spec = metadata.time_spec + time_spec_t::from_ticks(total_num_samps_sent, _samp_rate); + // setup metadata for the next fragment + const time_spec_t time_spec = + metadata.time_spec + + time_spec_t::from_ticks(total_num_samps_sent, _samp_rate); if_packet_info.tsf = time_spec.to_ticks(_tick_rate); if_packet_info.sob = false; - } - //send the final fragment with the helper function + // send the final fragment with the helper function if_packet_info.eob = metadata.end_of_burst; - size_t nsamps_sent = total_num_samps_sent - + send_one_packet(buffs, final_length, if_packet_info, timeout, - total_num_samps_sent * _bytes_per_cpu_item); + size_t nsamps_sent = total_num_samps_sent + + send_one_packet(buffs, + final_length, + if_packet_info, + timeout, + total_num_samps_sent * _bytes_per_cpu_item); #ifdef UHD_TXRX_DEBUG_PRINTS - dbg_print_send(nsamps_per_buff, nsamps_sent, metadata, timeout); + dbg_print_send(nsamps_per_buff, nsamps_sent, metadata, timeout); #endif - return nsamps_sent; + return nsamps_sent; } private: - vrt_packer_type _vrt_packer; size_t _header_offset_words32; double _tick_rate, _samp_rate; - struct xport_chan_props_type{ - xport_chan_props_type(void):has_sid(false),sid(0){} + struct xport_chan_props_type + { + xport_chan_props_type(void) : has_sid(false), sid(0) {} get_buff_type get_buff; post_send_cb_type go_postal; bool has_sid; @@ -287,11 +303,11 @@ private: }; std::vector<xport_chan_props_type> _props; size_t _num_inputs; - size_t _bytes_per_otw_item; //used in conversion - size_t _bytes_per_cpu_item; //used in conversion - uhd::convert::converter::sptr _converter; //used in conversion + size_t _bytes_per_otw_item; // used in conversion + size_t _bytes_per_cpu_item; // used in conversion + uhd::convert::converter::sptr _converter; // used in conversion size_t _max_samples_per_packet; - std::vector<const void *> _zero_buffs; + std::vector<const void*> _zero_buffs; size_t _next_packet_seq; bool _has_tlr; async_receiver_type _async_receiver; @@ -299,10 +315,22 @@ private: uhd::tx_metadata_t _metadata_cache; #ifdef UHD_TXRX_DEBUG_PRINTS - struct dbg_send_stat_t { - dbg_send_stat_t(long wc, size_t nspb, size_t nss, uhd::tx_metadata_t md, double to, double rate): - wallclock(wc), nsamps_per_buff(nspb), nsamps_sent(nss), metadata(md), timeout(to), samp_rate(rate) - {} + struct dbg_send_stat_t + { + dbg_send_stat_t(long wc, + size_t nspb, + size_t nss, + uhd::tx_metadata_t md, + double to, + double rate) + : wallclock(wc) + , nsamps_per_buff(nspb) + , nsamps_sent(nss) + , metadata(md) + , timeout(to) + , samp_rate(rate) + { + } long wallclock; size_t nsamps_per_buff; size_t nsamps_sent; @@ -310,32 +338,37 @@ private: double timeout; double samp_rate; // Create a formatted print line for all the info gathered in this struct. - std::string print_line() { + std::string print_line() + { boost::format fmt("send,%ld,%f,%i,%i,%s,%s,%s,%ld"); fmt % wallclock; - fmt % timeout % (int)nsamps_per_buff % (int) nsamps_sent; - fmt % (metadata.start_of_burst ? "true":"false") % (metadata.end_of_burst ? "true":"false"); - fmt % (metadata.has_time_spec ? "true":"false") % metadata.time_spec.to_ticks(samp_rate); + fmt % timeout % (int)nsamps_per_buff % (int)nsamps_sent; + fmt % (metadata.start_of_burst ? "true" : "false") + % (metadata.end_of_burst ? "true" : "false"); + fmt % (metadata.has_time_spec ? "true" : "false") + % metadata.time_spec.to_ticks(samp_rate); return fmt.str(); } }; - void dbg_print_send(size_t nsamps_per_buff, size_t nsamps_sent, - const uhd::tx_metadata_t &metadata, const double timeout, - bool dbg_print_directly = true) + void dbg_print_send(size_t nsamps_per_buff, + size_t nsamps_sent, + const uhd::tx_metadata_t& metadata, + const double timeout, + bool dbg_print_directly = true) { dbg_send_stat_t data(boost::get_system_time().time_of_day().total_microseconds(), nsamps_per_buff, nsamps_sent, metadata, timeout, - _samp_rate - ); - if(dbg_print_directly){ + _samp_rate); + if (dbg_print_directly) { dbg_print_err(data.print_line()); } } - void dbg_print_err(std::string msg) { + void dbg_print_err(std::string msg) + { msg = "super_send_packet_handler," + msg; fprintf(stderr, "%s\n", msg.c_str()); } @@ -346,37 +379,39 @@ private: /******************************************************************* * Send a single packet: ******************************************************************/ - UHD_INLINE size_t send_one_packet( - const uhd::tx_streamer::buffs_type &buffs, + UHD_INLINE size_t send_one_packet(const uhd::tx_streamer::buffs_type& buffs, const size_t nsamps_per_buff, - vrt::if_packet_info_t &if_packet_info, + vrt::if_packet_info_t& if_packet_info, const double timeout, - const size_t buffer_offset_bytes = 0 - ){ - - //load the rest of the if_packet_info in here - if_packet_info.num_payload_bytes = nsamps_per_buff*_num_inputs*_bytes_per_otw_item; - if_packet_info.num_payload_words32 = (if_packet_info.num_payload_bytes + 3/*round up*/)/sizeof(uint32_t); + const size_t buffer_offset_bytes = 0) + { + // load the rest of the if_packet_info in here + if_packet_info.num_payload_bytes = + nsamps_per_buff * _num_inputs * _bytes_per_otw_item; + 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; - //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 + // 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 converter threads - _convert_nsamps = nsamps_per_buff; - _convert_buffs = &buffs; + // 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; + _convert_if_packet_info = &if_packet_info; - //perform N channels of conversion + // 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 + _next_packet_seq++; // increment sequence after commits return nsamps_per_buff; } @@ -389,75 +424,76 @@ private: */ UHD_INLINE void convert_to_in_buff(const size_t index) { - //shortcut references to local data structures - managed_send_buffer::sptr &buff = _props[index].buff; + // 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; + 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; + // 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); + 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; + // 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; + 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 + // 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 + // 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 - if (_props[index].go_postal) - { + if (_props[index].go_postal) { _props[index].go_postal(); } } //! Shared variables for the worker threads size_t _convert_nsamps; - const tx_streamer::buffs_type *_convert_buffs; + const tx_streamer::buffs_type* _convert_buffs; size_t _convert_buffer_offset_bytes; - vrt::if_packet_info_t *_convert_if_packet_info; - + vrt::if_packet_info_t* _convert_if_packet_info; }; -class send_packet_streamer : public send_packet_handler, public tx_streamer{ +class send_packet_streamer : public send_packet_handler, public tx_streamer +{ public: - send_packet_streamer(const size_t max_num_samps){ + send_packet_streamer(const size_t max_num_samps) + { _max_num_samps = max_num_samps; this->set_max_samples_per_packet(_max_num_samps); } - size_t get_num_channels(void) const{ + size_t get_num_channels(void) const + { return this->size(); } - size_t get_max_num_samps(void) const{ + size_t get_max_num_samps(void) const + { return _max_num_samps; } - size_t send( - const tx_streamer::buffs_type &buffs, + size_t send(const tx_streamer::buffs_type& buffs, const size_t nsamps_per_buff, - const uhd::tx_metadata_t &metadata, - const double timeout - ){ + const uhd::tx_metadata_t& metadata, + const double timeout) + { return send_packet_handler::send(buffs, nsamps_per_buff, metadata, timeout); } - bool recv_async_msg( - uhd::async_metadata_t &async_metadata, double timeout = 0.1 - ){ + bool recv_async_msg(uhd::async_metadata_t& async_metadata, double timeout = 0.1) + { return send_packet_handler::recv_async_msg(async_metadata, timeout); } @@ -465,8 +501,6 @@ private: size_t _max_num_samps; }; -} // namespace sph -} // namespace transport -} // namespace uhd +}}} // namespace uhd::transport::sph #endif /* INCLUDED_LIBUHD_TRANSPORT_SUPER_SEND_PACKET_HANDLER_HPP */ diff --git a/host/lib/transport/tcp_zero_copy.cpp b/host/lib/transport/tcp_zero_copy.cpp index a52d089a8..5cb713427 100644 --- a/host/lib/transport/tcp_zero_copy.cpp +++ b/host/lib/transport/tcp_zero_copy.cpp @@ -6,15 +6,15 @@ // #include "udp_common.hpp" -#include <uhd/transport/tcp_zero_copy.hpp> #include <uhd/transport/buffer_pool.hpp> +#include <uhd/transport/tcp_zero_copy.hpp> #include <uhd/utils/log.hpp> #include <uhdlib/utils/atomic.hpp> #include <boost/format.hpp> #include <boost/make_shared.hpp> -#include <vector> #include <chrono> #include <thread> +#include <vector> using namespace uhd; using namespace uhd::transport; @@ -27,38 +27,44 @@ static const size_t DEFAULT_FRAME_SIZE = 2048; * Reusable managed receiver buffer: * - get_new performs the recv operation **********************************************************************/ -class tcp_zero_copy_asio_mrb : public managed_recv_buffer{ +class tcp_zero_copy_asio_mrb : public managed_recv_buffer +{ public: - tcp_zero_copy_asio_mrb(void *mem, int sock_fd, const size_t frame_size): - _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size) { /*NOP*/ } + tcp_zero_copy_asio_mrb(void* mem, int sock_fd, const size_t frame_size) + : _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size) + { /*NOP*/ + } - void release(void){ + void release(void) + { _claimer.release(); } - UHD_INLINE sptr get_new(const double timeout, size_t &index){ - if (not _claimer.claim_with_wait(timeout)) return sptr(); + UHD_INLINE sptr get_new(const double timeout, size_t& index) + { + if (not _claimer.claim_with_wait(timeout)) + return sptr(); - #ifdef MSG_DONTWAIT //try a non-blocking recv() if supported - _len = ::recv(_sock_fd, (char *)_mem, _frame_size, MSG_DONTWAIT); - if (_len > 0){ - index++; //advances the caller's buffer +#ifdef MSG_DONTWAIT // try a non-blocking recv() if supported + _len = ::recv(_sock_fd, (char*)_mem, _frame_size, MSG_DONTWAIT); + if (_len > 0) { + index++; // advances the caller's buffer return make(this, _mem, size_t(_len)); } - #endif +#endif - if (wait_for_recv_ready(_sock_fd, timeout)){ - _len = ::recv(_sock_fd, (char *)_mem, _frame_size, 0); - index++; //advances the caller's buffer + if (wait_for_recv_ready(_sock_fd, timeout)) { + _len = ::recv(_sock_fd, (char*)_mem, _frame_size, 0); + index++; // advances the caller's buffer return make(this, _mem, size_t(_len)); } - _claimer.release(); //undo claim - return sptr(); //null for timeout + _claimer.release(); // undo claim + return sptr(); // null for timeout } private: - void *_mem; + void* _mem; int _sock_fd; size_t _frame_size; ssize_t _len; @@ -69,44 +75,50 @@ private: * Reusable managed send buffer: * - commit performs the send operation **********************************************************************/ -class tcp_zero_copy_asio_msb : public managed_send_buffer{ +class tcp_zero_copy_asio_msb : public managed_send_buffer +{ public: - tcp_zero_copy_asio_msb(void *mem, int sock_fd, const size_t frame_size): - _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size) { /*NOP*/ } - - void release(void){ - //Retry logic because send may fail with ENOBUFS. - //This is known to occur at least on some OSX systems. - //But it should be safe to always check for the error. - while (true) - { - this->commit(_frame_size); //always full size frames to avoid pkt coalescing - const ssize_t ret = ::send(_sock_fd, (const char *)_mem, size(), 0); - if (ret == ssize_t(size())) break; - if (ret == -1 and errno == ENOBUFS) - { + tcp_zero_copy_asio_msb(void* mem, int sock_fd, const size_t frame_size) + : _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size) + { /*NOP*/ + } + + void release(void) + { + // Retry logic because send may fail with ENOBUFS. + // This is known to occur at least on some OSX systems. + // But it should be safe to always check for the error. + while (true) { + this->commit(_frame_size); // always full size frames to avoid pkt coalescing + const ssize_t ret = ::send(_sock_fd, (const char*)_mem, size(), 0); + if (ret == ssize_t(size())) + break; + if (ret == -1 and errno == ENOBUFS) { std::this_thread::sleep_for(std::chrono::microseconds(1)); - continue; //try to send again + continue; // try to send again } UHD_ASSERT_THROW(ret == ssize_t(size())); } _claimer.release(); } - UHD_INLINE sptr get_new(const double timeout, size_t &index){ - if (not _claimer.claim_with_wait(timeout)) return sptr(); - index++; //advances the caller's buffer + UHD_INLINE sptr get_new(const double timeout, size_t& index) + { + if (not _claimer.claim_with_wait(timeout)) + return sptr(); + index++; // advances the caller's buffer return make(this, _mem, _frame_size); } private: - void *_mem; + void* _mem; int _sock_fd; size_t _frame_size; simple_claimer _claimer; }; -tcp_zero_copy::~tcp_zero_copy(void){ +tcp_zero_copy::~tcp_zero_copy(void) +{ /* NOP */ } @@ -117,51 +129,53 @@ tcp_zero_copy::~tcp_zero_copy(void){ * However, it is not a true zero copy implementation as each * send and recv requires a copy operation to/from userspace. **********************************************************************/ -class tcp_zero_copy_asio_impl : public tcp_zero_copy{ +class tcp_zero_copy_asio_impl : public tcp_zero_copy +{ public: typedef boost::shared_ptr<tcp_zero_copy_asio_impl> sptr; tcp_zero_copy_asio_impl( - const std::string &addr, - const std::string &port, - const device_addr_t &hints - ): - _recv_frame_size(size_t(hints.cast<double>("recv_frame_size", DEFAULT_FRAME_SIZE))), - _num_recv_frames(size_t(hints.cast<double>("num_recv_frames", DEFAULT_NUM_FRAMES))), - _send_frame_size(size_t(hints.cast<double>("send_frame_size", DEFAULT_FRAME_SIZE))), - _num_send_frames(size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_FRAMES))), - _recv_buffer_pool(buffer_pool::make(_num_recv_frames, _recv_frame_size)), - _send_buffer_pool(buffer_pool::make(_num_send_frames, _send_frame_size)), - _next_recv_buff_index(0), _next_send_buff_index(0) + const std::string& addr, const std::string& port, const device_addr_t& hints) + : _recv_frame_size( + size_t(hints.cast<double>("recv_frame_size", DEFAULT_FRAME_SIZE))) + , _num_recv_frames( + size_t(hints.cast<double>("num_recv_frames", DEFAULT_NUM_FRAMES))) + , _send_frame_size( + size_t(hints.cast<double>("send_frame_size", DEFAULT_FRAME_SIZE))) + , _num_send_frames( + size_t(hints.cast<double>("num_send_frames", DEFAULT_NUM_FRAMES))) + , _recv_buffer_pool(buffer_pool::make(_num_recv_frames, _recv_frame_size)) + , _send_buffer_pool(buffer_pool::make(_num_send_frames, _send_frame_size)) + , _next_recv_buff_index(0) + , _next_send_buff_index(0) { - UHD_LOGGER_TRACE("TCP") << boost::format("Creating tcp transport for %s %s") % addr % port ; + UHD_LOGGER_TRACE("TCP") + << boost::format("Creating tcp transport for %s %s") % addr % port; - //resolve the address + // resolve the address asio::ip::tcp::resolver resolver(_io_service); asio::ip::tcp::resolver::query query(asio::ip::tcp::v4(), addr, port); asio::ip::tcp::endpoint receiver_endpoint = *resolver.resolve(query); - //create, open, and connect the socket + // create, open, and connect the socket _socket.reset(new asio::ip::tcp::socket(_io_service)); _socket->connect(receiver_endpoint); _sock_fd = _socket->native_handle(); - //packets go out ASAP + // packets go out ASAP asio::ip::tcp::no_delay option(true); _socket->set_option(option); - //allocate re-usable managed receive buffers - for (size_t i = 0; i < get_num_recv_frames(); i++){ + // allocate re-usable managed receive buffers + for (size_t i = 0; i < get_num_recv_frames(); i++) { _mrb_pool.push_back(boost::make_shared<tcp_zero_copy_asio_mrb>( - _recv_buffer_pool->at(i), _sock_fd, get_recv_frame_size() - )); + _recv_buffer_pool->at(i), _sock_fd, get_recv_frame_size())); } - //allocate re-usable managed send buffers - for (size_t i = 0; i < get_num_send_frames(); i++){ + // allocate re-usable managed send buffers + for (size_t i = 0; i < get_num_send_frames(); i++) { _msb_pool.push_back(boost::make_shared<tcp_zero_copy_asio_msb>( - _send_buffer_pool->at(i), _sock_fd, get_send_frame_size() - )); + _send_buffer_pool->at(i), _sock_fd, get_send_frame_size())); } } @@ -169,51 +183,66 @@ public: * Receive implementation: * Block on the managed buffer's get call and advance the index. ******************************************************************/ - managed_recv_buffer::sptr get_recv_buff(double timeout){ - if (_next_recv_buff_index == _num_recv_frames) _next_recv_buff_index = 0; + managed_recv_buffer::sptr get_recv_buff(double timeout) + { + if (_next_recv_buff_index == _num_recv_frames) + _next_recv_buff_index = 0; return _mrb_pool[_next_recv_buff_index]->get_new(timeout, _next_recv_buff_index); } - size_t get_num_recv_frames(void) const {return _num_recv_frames;} - size_t get_recv_frame_size(void) const {return _recv_frame_size;} + size_t get_num_recv_frames(void) const + { + return _num_recv_frames; + } + size_t get_recv_frame_size(void) const + { + return _recv_frame_size; + } /******************************************************************* * Send implementation: * Block on the managed buffer's get call and advance the index. ******************************************************************/ - managed_send_buffer::sptr get_send_buff(double timeout){ - if (_next_send_buff_index == _num_send_frames) _next_send_buff_index = 0; + managed_send_buffer::sptr get_send_buff(double timeout) + { + if (_next_send_buff_index == _num_send_frames) + _next_send_buff_index = 0; return _msb_pool[_next_send_buff_index]->get_new(timeout, _next_send_buff_index); } - size_t get_num_send_frames(void) const {return _num_send_frames;} - size_t get_send_frame_size(void) const {return _send_frame_size;} + size_t get_num_send_frames(void) const + { + return _num_send_frames; + } + size_t get_send_frame_size(void) const + { + return _send_frame_size; + } private: - //memory management -> buffers and fifos + // memory management -> buffers and fifos const size_t _recv_frame_size, _num_recv_frames; const size_t _send_frame_size, _num_send_frames; buffer_pool::sptr _recv_buffer_pool, _send_buffer_pool; - std::vector<boost::shared_ptr<tcp_zero_copy_asio_msb> > _msb_pool; - std::vector<boost::shared_ptr<tcp_zero_copy_asio_mrb> > _mrb_pool; + std::vector<boost::shared_ptr<tcp_zero_copy_asio_msb>> _msb_pool; + std::vector<boost::shared_ptr<tcp_zero_copy_asio_mrb>> _mrb_pool; size_t _next_recv_buff_index, _next_send_buff_index; - //asio guts -> socket and service - asio::io_service _io_service; + // asio guts -> socket and service + asio::io_service _io_service; boost::shared_ptr<asio::ip::tcp::socket> _socket; - int _sock_fd; + int _sock_fd; }; /*********************************************************************** * TCP zero copy make function **********************************************************************/ zero_copy_if::sptr tcp_zero_copy::make( - const std::string &addr, - const std::string &port, - const device_addr_t &hints -){ + const std::string& addr, const std::string& port, const device_addr_t& hints) +{ zero_copy_if::sptr xport; xport.reset(new tcp_zero_copy_asio_impl(addr, port, hints)); - while (xport->get_recv_buff(0.0)){} //flush + while (xport->get_recv_buff(0.0)) { + } // flush return xport; } diff --git a/host/lib/transport/udp_common.hpp b/host/lib/transport/udp_common.hpp index 19457903b..f320e3d85 100644 --- a/host/lib/transport/udp_common.hpp +++ b/host/lib/transport/udp_common.hpp @@ -11,60 +11,61 @@ #include <uhd/config.hpp> #include <boost/asio.hpp> -namespace uhd{ namespace transport{ +namespace uhd { namespace transport { - // Jumbo frames can be up to 9600 bytes; - static const size_t MAX_ETHERNET_MTU = 9600; +// Jumbo frames can be up to 9600 bytes; +static const size_t MAX_ETHERNET_MTU = 9600; #if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) - // MacOS limits socket buffer size to 1 Mib - static const size_t MAX_BUFF_SIZE_ETH_MACOS = 0x100000; //1Mib +// MacOS limits socket buffer size to 1 Mib +static const size_t MAX_BUFF_SIZE_ETH_MACOS = 0x100000; // 1Mib #endif - typedef boost::shared_ptr<boost::asio::ip::udp::socket> socket_sptr; +typedef boost::shared_ptr<boost::asio::ip::udp::socket> socket_sptr; - /*! - * Wait for the socket to become ready for a receive operation. - * \param sock_fd the open socket file descriptor - * \param timeout the timeout duration in seconds - * \return true when the socket is ready for receive - */ - UHD_INLINE bool wait_for_recv_ready(int sock_fd, double timeout){ +/*! + * Wait for the socket to become ready for a receive operation. + * \param sock_fd the open socket file descriptor + * \param timeout the timeout duration in seconds + * \return true when the socket is ready for receive + */ +UHD_INLINE bool wait_for_recv_ready(int sock_fd, double timeout) +{ #ifdef UHD_PLATFORM_WIN32 // select is more portable than poll unfortunately - //setup timeval for timeout - timeval tv; - //If the tv_usec > 1 second on some platforms, select will - //error EINVAL: An invalid timeout interval was specified. - tv.tv_sec = int(timeout); - tv.tv_usec = int(timeout*1000000)%1000000; + // setup timeval for timeout + timeval tv; + // If the tv_usec > 1 second on some platforms, select will + // error EINVAL: An invalid timeout interval was specified. + tv.tv_sec = int(timeout); + tv.tv_usec = int(timeout * 1000000) % 1000000; - //setup rset for timeout - fd_set rset; - FD_ZERO(&rset); - FD_SET(sock_fd, &rset); + // setup rset for timeout + fd_set rset; + FD_ZERO(&rset); + FD_SET(sock_fd, &rset); - //http://www.gnu.org/s/hello/manual/libc/Interrupted-Primitives.html - //This macro is provided with gcc to properly deal with EINTR. - //If not provided, define an empty macro, assume that is OK - #ifndef TEMP_FAILURE_RETRY - #define TEMP_FAILURE_RETRY(x) (x) - #endif +// http://www.gnu.org/s/hello/manual/libc/Interrupted-Primitives.html +// This macro is provided with gcc to properly deal with EINTR. +// If not provided, define an empty macro, assume that is OK +# ifndef TEMP_FAILURE_RETRY +# define TEMP_FAILURE_RETRY(x) (x) +# endif - //call select with timeout on receive socket - return TEMP_FAILURE_RETRY(::select(sock_fd+1, &rset, NULL, NULL, &tv)) > 0; + // call select with timeout on receive socket + return TEMP_FAILURE_RETRY(::select(sock_fd + 1, &rset, NULL, NULL, &tv)) > 0; #else - //calculate the total timeout in milliseconds (from seconds) - int total_timeout = int(timeout*1000); + // calculate the total timeout in milliseconds (from seconds) + int total_timeout = int(timeout * 1000); - pollfd pfd_read; - pfd_read.fd = sock_fd; - pfd_read.events = POLLIN; + pollfd pfd_read; + pfd_read.fd = sock_fd; + pfd_read.events = POLLIN; - //call poll with timeout on receive socket - return ::poll(&pfd_read, 1, total_timeout) > 0; + // call poll with timeout on receive socket + return ::poll(&pfd_read, 1, total_timeout) > 0; #endif - } +} -}} //namespace uhd::transport +}} // namespace uhd::transport #endif /* INCLUDED_LIBUHD_TRANSPORT_VRT_PACKET_HANDLER_HPP */ diff --git a/host/lib/transport/udp_simple.cpp b/host/lib/transport/udp_simple.cpp index e3936afc2..48d7b500e 100644 --- a/host/lib/transport/udp_simple.cpp +++ b/host/lib/transport/udp_simple.cpp @@ -16,58 +16,68 @@ namespace asio = boost::asio; /*********************************************************************** * UDP simple implementation: connected and broadcast **********************************************************************/ -class udp_simple_impl : public udp_simple{ +class udp_simple_impl : public udp_simple +{ public: udp_simple_impl( - const std::string &addr, const std::string &port, bool bcast, bool connect - ):_connected(connect){ - UHD_LOGGER_TRACE("UDP") << boost::format("Creating udp transport for %s %s") % addr % port ; + const std::string& addr, const std::string& port, bool bcast, bool connect) + : _connected(connect) + { + UHD_LOGGER_TRACE("UDP") + << boost::format("Creating udp transport for %s %s") % addr % port; - //resolve the address + // resolve the address asio::ip::udp::resolver resolver(_io_service); - asio::ip::udp::resolver::query query(asio::ip::udp::v4(), addr, port, - asio::ip::resolver_query_base::all_matching); + asio::ip::udp::resolver::query query( + asio::ip::udp::v4(), addr, port, asio::ip::resolver_query_base::all_matching); _send_endpoint = *resolver.resolve(query); - //create and open the socket + // create and open the socket _socket = socket_sptr(new asio::ip::udp::socket(_io_service)); _socket->open(asio::ip::udp::v4()); - //allow broadcasting + // allow broadcasting _socket->set_option(asio::socket_base::broadcast(bcast)); - //connect the socket - if (connect) _socket->connect(_send_endpoint); - + // connect the socket + if (connect) + _socket->connect(_send_endpoint); } - size_t send(const asio::const_buffer &buff){ - if (_connected) return _socket->send(asio::buffer(buff)); + size_t send(const asio::const_buffer& buff) + { + if (_connected) + return _socket->send(asio::buffer(buff)); return _socket->send_to(asio::buffer(buff), _send_endpoint); } - size_t recv(const asio::mutable_buffer &buff, double timeout){ - if (not wait_for_recv_ready(_socket->native_handle(), timeout)) return 0; + size_t recv(const asio::mutable_buffer& buff, double timeout) + { + if (not wait_for_recv_ready(_socket->native_handle(), timeout)) + return 0; return _socket->receive_from(asio::buffer(buff), _recv_endpoint); } - std::string get_recv_addr(void){ + std::string get_recv_addr(void) + { return _recv_endpoint.address().to_string(); } - std::string get_send_addr(void){ + std::string get_send_addr(void) + { return _send_endpoint.address().to_string(); } private: - bool _connected; - asio::io_service _io_service; - socket_sptr _socket; + bool _connected; + asio::io_service _io_service; + socket_sptr _socket; asio::ip::udp::endpoint _send_endpoint; asio::ip::udp::endpoint _recv_endpoint; }; -udp_simple::~udp_simple(void){ +udp_simple::~udp_simple(void) +{ /* NOP */ } @@ -75,14 +85,14 @@ udp_simple::~udp_simple(void){ * UDP public make functions **********************************************************************/ udp_simple::sptr udp_simple::make_connected( - const std::string &addr, const std::string &port -){ + const std::string& addr, const std::string& port) +{ return sptr(new udp_simple_impl(addr, port, false, true /* no bcast, connect */)); } udp_simple::sptr udp_simple::make_broadcast( - const std::string &addr, const std::string &port -){ + const std::string& addr, const std::string& port) +{ return sptr(new udp_simple_impl(addr, port, true, false /* bcast, no connect */)); } @@ -90,36 +100,44 @@ udp_simple::sptr udp_simple::make_broadcast( * Simple UART over UDP **********************************************************************/ #include <boost/thread/thread.hpp> -class udp_simple_uart_impl : public uhd::uart_iface{ +class udp_simple_uart_impl : public uhd::uart_iface +{ public: - udp_simple_uart_impl(udp_simple::sptr udp){ + udp_simple_uart_impl(udp_simple::sptr udp) + { _udp = udp; _len = 0; _off = 0; - this->write_uart(""); //send an empty packet to init + this->write_uart(""); // send an empty packet to init } - void write_uart(const std::string &buf){ + void write_uart(const std::string& buf) + { _udp->send(asio::buffer(buf)); } - std::string read_uart(double timeout){ + std::string read_uart(double timeout) + { std::string line; - const boost::system_time exit_time = boost::get_system_time() + boost::posix_time::milliseconds(long(timeout*1000)); - do{ - //drain anything in current buffer - while (_off < _len){ + const boost::system_time exit_time = + boost::get_system_time() + + boost::posix_time::milliseconds(long(timeout * 1000)); + do { + // drain anything in current buffer + while (_off < _len) { const char ch = _buf[_off++]; _line += ch; - if (ch == '\n') - { + if (ch == '\n') { line.swap(_line); return line; } } - //recv a new packet into the buffer - _len = _udp->recv(asio::buffer(_buf), std::max((exit_time - boost::get_system_time()).total_milliseconds()/1000., 0.0)); + // recv a new packet into the buffer + _len = _udp->recv(asio::buffer(_buf), + std::max( + (exit_time - boost::get_system_time()).total_milliseconds() / 1000., + 0.0)); _off = 0; } while (_len != 0); @@ -133,6 +151,7 @@ private: std::string _line; }; -uhd::uart_iface::sptr udp_simple::make_uart(sptr udp){ +uhd::uart_iface::sptr udp_simple::make_uart(sptr udp) +{ return uart_iface::sptr(new udp_simple_uart_impl(udp)); } diff --git a/host/lib/transport/udp_wsa_zero_copy.cpp b/host/lib/transport/udp_wsa_zero_copy.cpp index 1bdf18095..c1eeb7cb1 100644 --- a/host/lib/transport/udp_wsa_zero_copy.cpp +++ b/host/lib/transport/udp_wsa_zero_copy.cpp @@ -6,10 +6,9 @@ // #include "udp_common.hpp" -#include <uhd/transport/udp_zero_copy.hpp> -#include <uhd/transport/udp_simple.hpp> //mtu #include <uhd/transport/buffer_pool.hpp> - +#include <uhd/transport/udp_simple.hpp> //mtu +#include <uhd/transport/udp_zero_copy.hpp> #include <uhd/utils/log.hpp> #include <boost/format.hpp> #include <vector> @@ -18,31 +17,38 @@ using namespace uhd; using namespace uhd::transport; namespace asio = boost::asio; -//A reasonable number of frames for send/recv and async/sync +// A reasonable number of frames for send/recv and async/sync constexpr size_t UDP_ZERO_COPY_DEFAULT_NUM_FRAMES = 1; -constexpr size_t UDP_ZERO_COPY_DEFAULT_FRAME_SIZE = 1472; // Based on common 1500 byte MTU for 1GbE. +constexpr size_t UDP_ZERO_COPY_DEFAULT_FRAME_SIZE = + 1472; // Based on common 1500 byte MTU for 1GbE. /*********************************************************************** * Check registry for correct fast-path setting (windows only) **********************************************************************/ #ifdef HAVE_ATLBASE_H -#define CHECK_REG_SEND_THRESH -#include <atlbase.h> //CRegKey -static void check_registry_for_fast_send_threshold(const size_t mtu){ +# define CHECK_REG_SEND_THRESH +# include <atlbase.h> //CRegKey +static void check_registry_for_fast_send_threshold(const size_t mtu) +{ static bool warned = false; - if (warned) return; //only allow one printed warning per process + if (warned) + return; // only allow one printed warning per process CRegKey reg_key; - DWORD threshold = 1024; //system default when threshold is not specified - if ( - reg_key.Open(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\AFD\\Parameters", KEY_READ) != ERROR_SUCCESS or - reg_key.QueryDWORDValue("FastSendDatagramThreshold", threshold) != ERROR_SUCCESS or threshold < mtu - ){ - UHD_LOGGER_WARNING("UDP") << boost::format( - "The MTU (%d) is larger than the FastSendDatagramThreshold (%d)!\n" - "This will negatively affect the transmit performance.\n" - "See the transport application notes for more detail.\n" - ) % mtu % threshold ; + DWORD threshold = 1024; // system default when threshold is not specified + if (reg_key.Open(HKEY_LOCAL_MACHINE, + "System\\CurrentControlSet\\Services\\AFD\\Parameters", + KEY_READ) + != ERROR_SUCCESS + or reg_key.QueryDWORDValue("FastSendDatagramThreshold", threshold) + != ERROR_SUCCESS + or threshold < mtu) { + UHD_LOGGER_WARNING("UDP") + << boost::format( + "The MTU (%d) is larger than the FastSendDatagramThreshold (%d)!\n" + "This will negatively affect the transmit performance.\n" + "See the transport application notes for more detail.\n") + % mtu % threshold; warned = true; } reg_key.Close(); @@ -52,13 +58,16 @@ static void check_registry_for_fast_send_threshold(const size_t mtu){ /*********************************************************************** * Static initialization to take care of WSA init and cleanup **********************************************************************/ -struct uhd_wsa_control{ - uhd_wsa_control(void){ +struct uhd_wsa_control +{ + uhd_wsa_control(void) + { WSADATA wsaData; WSAStartup(MAKEWORD(2, 2), &wsaData); /*windows socket startup */ } - ~uhd_wsa_control(void){ + ~uhd_wsa_control(void) + { WSACleanup(); } }; @@ -68,34 +77,38 @@ struct uhd_wsa_control{ * - Initialize with memory and a release callback. * - Call get new with a length in bytes to re-use. **********************************************************************/ -class udp_zero_copy_asio_mrb : public managed_recv_buffer{ +class udp_zero_copy_asio_mrb : public managed_recv_buffer +{ public: - udp_zero_copy_asio_mrb(void *mem, int sock_fd, const size_t frame_size): - _sock_fd(sock_fd), _frame_size(frame_size) + udp_zero_copy_asio_mrb(void* mem, int sock_fd, const size_t frame_size) + : _sock_fd(sock_fd), _frame_size(frame_size) { - _wsa_buff.buf = reinterpret_cast<char *>(mem); + _wsa_buff.buf = reinterpret_cast<char*>(mem); ZeroMemory(&_overlapped, sizeof(_overlapped)); _overlapped.hEvent = WSACreateEvent(); UHD_ASSERT_THROW(_overlapped.hEvent != WSA_INVALID_EVENT); - this->release(); //makes buffer available via get_new + this->release(); // makes buffer available via get_new } - ~udp_zero_copy_asio_mrb(void){ + ~udp_zero_copy_asio_mrb(void) + { WSACloseEvent(_overlapped.hEvent); } - void release(void){ + void release(void) + { _wsa_buff.len = _frame_size; - _flags = 0; + _flags = 0; WSARecv(_sock_fd, &_wsa_buff, 1, &_wsa_buff.len, &_flags, &_overlapped, NULL); } - UHD_INLINE sptr get_new(const double timeout, size_t &index){ + UHD_INLINE sptr get_new(const double timeout, size_t& index) + { const DWORD result = WSAWaitForMultipleEvents( - 1, &_overlapped.hEvent, true, DWORD(timeout*1000), true - ); - if (result == WSA_WAIT_TIMEOUT) return managed_recv_buffer::sptr(); - index++; //advances the caller's buffer + 1, &_overlapped.hEvent, true, DWORD(timeout * 1000), true); + if (result == WSA_WAIT_TIMEOUT) + return managed_recv_buffer::sptr(); + index++; // advances the caller's buffer WSAGetOverlappedResult(_sock_fd, &_overlapped, &_wsa_buff.len, true, &_flags); @@ -116,33 +129,37 @@ private: * - committing the buffer calls the asynchronous socket send * - getting a new buffer performs the blocking wait for completion **********************************************************************/ -class udp_zero_copy_asio_msb : public managed_send_buffer{ +class udp_zero_copy_asio_msb : public managed_send_buffer +{ public: - udp_zero_copy_asio_msb(void *mem, int sock_fd, const size_t frame_size): - _sock_fd(sock_fd), _frame_size(frame_size) + udp_zero_copy_asio_msb(void* mem, int sock_fd, const size_t frame_size) + : _sock_fd(sock_fd), _frame_size(frame_size) { - _wsa_buff.buf = reinterpret_cast<char *>(mem); + _wsa_buff.buf = reinterpret_cast<char*>(mem); ZeroMemory(&_overlapped, sizeof(_overlapped)); _overlapped.hEvent = WSACreateEvent(); UHD_ASSERT_THROW(_overlapped.hEvent != WSA_INVALID_EVENT); - WSASetEvent(_overlapped.hEvent); //makes buffer available via get_new + WSASetEvent(_overlapped.hEvent); // makes buffer available via get_new } - ~udp_zero_copy_asio_msb(void){ + ~udp_zero_copy_asio_msb(void) + { WSACloseEvent(_overlapped.hEvent); } - void release(void){ + void release(void) + { _wsa_buff.len = size(); WSASend(_sock_fd, &_wsa_buff, 1, NULL, 0, &_overlapped, NULL); } - UHD_INLINE sptr get_new(const double timeout, size_t &index){ + UHD_INLINE sptr get_new(const double timeout, size_t& index) + { const DWORD result = WSAWaitForMultipleEvents( - 1, &_overlapped.hEvent, true, DWORD(timeout*1000), true - ); - if (result == WSA_WAIT_TIMEOUT) return managed_send_buffer::sptr(); - index++; //advances the caller's buffer + 1, &_overlapped.hEvent, true, DWORD(timeout * 1000), true); + if (result == WSA_WAIT_TIMEOUT) + return managed_send_buffer::sptr(); + index++; // advances the caller's buffer WSAResetEvent(_overlapped.hEvent); _wsa_buff.len = _frame_size; @@ -166,87 +183,108 @@ private: * This has better performance than the overlapped IO. * For send, use overlapped IO to submit async sends. **********************************************************************/ -class udp_zero_copy_wsa_impl : public udp_zero_copy{ +class udp_zero_copy_wsa_impl : public udp_zero_copy +{ public: typedef boost::shared_ptr<udp_zero_copy_wsa_impl> sptr; - udp_zero_copy_wsa_impl( - const std::string &addr, - const std::string &port, + udp_zero_copy_wsa_impl(const std::string& addr, + const std::string& port, zero_copy_xport_params& xport_params, - const device_addr_t &hints - ): - _recv_frame_size(xport_params.recv_frame_size), - _num_recv_frames(xport_params.num_recv_frames), - _send_frame_size(xport_params.send_frame_size), - _num_send_frames(xport_params.num_send_frames), - _recv_buffer_pool(buffer_pool::make(xport_params.num_recv_frames, xport_params.recv_frame_size)), - _send_buffer_pool(buffer_pool::make(xport_params.num_send_frames, xport_params.send_frame_size)), - _next_recv_buff_index(0), _next_send_buff_index(0) + const device_addr_t& hints) + : _recv_frame_size(xport_params.recv_frame_size) + , _num_recv_frames(xport_params.num_recv_frames) + , _send_frame_size(xport_params.send_frame_size) + , _num_send_frames(xport_params.num_send_frames) + , _recv_buffer_pool(buffer_pool::make( + xport_params.num_recv_frames, xport_params.recv_frame_size)) + , _send_buffer_pool(buffer_pool::make( + xport_params.num_send_frames, xport_params.send_frame_size)) + , _next_recv_buff_index(0) + , _next_send_buff_index(0) { - #ifdef CHECK_REG_SEND_THRESH +#ifdef CHECK_REG_SEND_THRESH check_registry_for_fast_send_threshold(this->get_send_frame_size()); - #endif /*CHECK_REG_SEND_THRESH*/ +#endif /*CHECK_REG_SEND_THRESH*/ UHD_LOGGER_TRACE("UDP") - << boost::format("Creating WSA UDP transport to %s:%s") - % addr % port; + << boost::format("Creating WSA UDP transport to %s:%s") % addr % port; - static uhd_wsa_control uhd_wsa; //makes wsa start happen via lazy initialization + static uhd_wsa_control uhd_wsa; // makes wsa start happen via lazy initialization UHD_ASSERT_THROW(_num_send_frames <= WSA_MAXIMUM_WAIT_EVENTS); - //resolve the address + // resolve the address asio::io_service io_service; asio::ip::udp::resolver resolver(io_service); asio::ip::udp::resolver::query query(asio::ip::udp::v4(), addr, port); asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query); - //create the socket - _sock_fd = WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED); - if (_sock_fd == INVALID_SOCKET){ + // create the socket + _sock_fd = + WSASocket(AF_INET, SOCK_DGRAM, IPPROTO_UDP, NULL, 0, WSA_FLAG_OVERLAPPED); + if (_sock_fd == INVALID_SOCKET) { const DWORD error = WSAGetLastError(); - throw uhd::os_error(str(boost::format("WSASocket() failed with error %d") % error)); + throw uhd::os_error( + str(boost::format("WSASocket() failed with error %d") % error)); } - //set the socket non-blocking for recv - //u_long mode = 1; - //ioctlsocket(_sock_fd, FIONBIO, &mode); + // set the socket non-blocking for recv + // u_long mode = 1; + // ioctlsocket(_sock_fd, FIONBIO, &mode); - //resize the socket buffers + // resize the socket buffers const int recv_buff_size = int(hints.cast<double>("recv_buff_size", 0.0)); const int send_buff_size = int(hints.cast<double>("send_buff_size", 0.0)); - if (recv_buff_size > 0) setsockopt(_sock_fd, SOL_SOCKET, SO_RCVBUF, (const char *)&recv_buff_size, sizeof(recv_buff_size)); - if (send_buff_size > 0) setsockopt(_sock_fd, SOL_SOCKET, SO_SNDBUF, (const char *)&send_buff_size, sizeof(send_buff_size)); - - //connect the socket so we can send/recv - const asio::ip::udp::endpoint::data_type &servaddr = *receiver_endpoint.data(); - if (WSAConnect(_sock_fd, (const struct sockaddr *)&servaddr, sizeof(servaddr), NULL, NULL, NULL, NULL) != 0){ + if (recv_buff_size > 0) + setsockopt(_sock_fd, + SOL_SOCKET, + SO_RCVBUF, + (const char*)&recv_buff_size, + sizeof(recv_buff_size)); + if (send_buff_size > 0) + setsockopt(_sock_fd, + SOL_SOCKET, + SO_SNDBUF, + (const char*)&send_buff_size, + sizeof(send_buff_size)); + + // connect the socket so we can send/recv + const asio::ip::udp::endpoint::data_type& servaddr = *receiver_endpoint.data(); + if (WSAConnect(_sock_fd, + (const struct sockaddr*)&servaddr, + sizeof(servaddr), + NULL, + NULL, + NULL, + NULL) + != 0) { const DWORD error = WSAGetLastError(); closesocket(_sock_fd); - throw uhd::os_error(str(boost::format("WSAConnect() failed with error %d") % error)); + throw uhd::os_error( + str(boost::format("WSAConnect() failed with error %d") % error)); } - UHD_LOGGER_TRACE("UDP") - << boost::format("Local WSA UDP socket endpoint: %s:%s") - % get_local_addr() % get_local_port(); - - //allocate re-usable managed receive buffers - for (size_t i = 0; i < get_num_recv_frames(); i++){ - _mrb_pool.push_back(boost::shared_ptr<udp_zero_copy_asio_mrb>( - new udp_zero_copy_asio_mrb(_recv_buffer_pool->at(i), _sock_fd, get_recv_frame_size()) - )); + UHD_LOGGER_TRACE("UDP") << boost::format("Local WSA UDP socket endpoint: %s:%s") + % get_local_addr() % get_local_port(); + + // allocate re-usable managed receive buffers + for (size_t i = 0; i < get_num_recv_frames(); i++) { + _mrb_pool.push_back( + boost::shared_ptr<udp_zero_copy_asio_mrb>(new udp_zero_copy_asio_mrb( + _recv_buffer_pool->at(i), _sock_fd, get_recv_frame_size()))); } - //allocate re-usable managed send buffers - for (size_t i = 0; i < get_num_send_frames(); i++){ - _msb_pool.push_back(boost::shared_ptr<udp_zero_copy_asio_msb>( - new udp_zero_copy_asio_msb(_send_buffer_pool->at(i), _sock_fd, get_send_frame_size()) - )); + // allocate re-usable managed send buffers + for (size_t i = 0; i < get_num_send_frames(); i++) { + _msb_pool.push_back( + boost::shared_ptr<udp_zero_copy_asio_msb>(new udp_zero_copy_asio_msb( + _send_buffer_pool->at(i), _sock_fd, get_send_frame_size()))); } } - ~udp_zero_copy_wsa_impl(void){ + ~udp_zero_copy_wsa_impl(void) + { closesocket(_sock_fd); } @@ -254,45 +292,62 @@ public: * Receive implementation: * Block on the managed buffer's get call and advance the index. ******************************************************************/ - managed_recv_buffer::sptr get_recv_buff(double timeout){ - if (_next_recv_buff_index == _num_recv_frames) _next_recv_buff_index = 0; + managed_recv_buffer::sptr get_recv_buff(double timeout) + { + if (_next_recv_buff_index == _num_recv_frames) + _next_recv_buff_index = 0; return _mrb_pool[_next_recv_buff_index]->get_new(timeout, _next_recv_buff_index); } - size_t get_num_recv_frames(void) const {return _num_recv_frames;} - size_t get_recv_frame_size(void) const {return _recv_frame_size;} + size_t get_num_recv_frames(void) const + { + return _num_recv_frames; + } + size_t get_recv_frame_size(void) const + { + return _recv_frame_size; + } /******************************************************************* * Send implementation: * Block on the managed buffer's get call and advance the index. ******************************************************************/ - managed_send_buffer::sptr get_send_buff(double timeout){ - if (_next_send_buff_index == _num_send_frames) _next_send_buff_index = 0; + managed_send_buffer::sptr get_send_buff(double timeout) + { + if (_next_send_buff_index == _num_send_frames) + _next_send_buff_index = 0; return _msb_pool[_next_send_buff_index]->get_new(timeout, _next_send_buff_index); } - size_t get_num_send_frames(void) const {return _num_send_frames;} - size_t get_send_frame_size(void) const {return _send_frame_size;} + size_t get_num_send_frames(void) const + { + return _num_send_frames; + } + size_t get_send_frame_size(void) const + { + return _send_frame_size; + } - uint16_t get_local_port(void) const { + uint16_t get_local_port(void) const + { struct sockaddr_in addr_info; - int addr_len = sizeof(addr_info); + int addr_len = sizeof(addr_info); uint16_t local_port = 0; - if (getsockname( _sock_fd, (SOCKADDR*) &addr_info, - &addr_len) == 0){ + if (getsockname(_sock_fd, (SOCKADDR*)&addr_info, &addr_len) == 0) { local_port = ntohs(addr_info.sin_port); } return local_port; } - std::string get_local_addr(void) const { + std::string get_local_addr(void) const + { // Behold the beauty of winsock struct sockaddr_in addr_info; int addr_len = sizeof(addr_info); std::string local_addr; - if (getsockname(_sock_fd, (SOCKADDR*) &addr_info, &addr_len) == 0) { + if (getsockname(_sock_fd, (SOCKADDR*)&addr_info, &addr_len) == 0) { // inet_ntoa() guarantees either NULL or null-terminated array - char *local_ip = inet_ntoa(addr_info.sin_addr); + char* local_ip = inet_ntoa(addr_info.sin_addr); if (local_ip) { local_addr = std::string(local_ip); } @@ -301,86 +356,77 @@ public: } //! Read back the socket's buffer space reserved for receives - size_t get_recv_buff_size(void) { + size_t get_recv_buff_size(void) + { int recv_buff_size = 0; - int opt_len = sizeof(recv_buff_size); + int opt_len = sizeof(recv_buff_size); getsockopt( - _sock_fd, - SOL_SOCKET, - SO_RCVBUF, - (char *)&recv_buff_size, - (int *)&opt_len - ); + _sock_fd, SOL_SOCKET, SO_RCVBUF, (char*)&recv_buff_size, (int*)&opt_len); - return (size_t) recv_buff_size; + return (size_t)recv_buff_size; } //! Read back the socket's buffer space reserved for sends - size_t get_send_buff_size(void) { + size_t get_send_buff_size(void) + { int send_buff_size = 0; - int opt_len = sizeof(send_buff_size); + int opt_len = sizeof(send_buff_size); getsockopt( - _sock_fd, - SOL_SOCKET, - SO_SNDBUF, - (char *)&send_buff_size, - (int *)&opt_len - ); + _sock_fd, SOL_SOCKET, SO_SNDBUF, (char*)&send_buff_size, (int*)&opt_len); - return (size_t) send_buff_size; + return (size_t)send_buff_size; } private: - //memory management -> buffers and fifos + // memory management -> buffers and fifos const size_t _recv_frame_size, _num_recv_frames; const size_t _send_frame_size, _num_send_frames; buffer_pool::sptr _recv_buffer_pool, _send_buffer_pool; - std::vector<boost::shared_ptr<udp_zero_copy_asio_msb> > _msb_pool; - std::vector<boost::shared_ptr<udp_zero_copy_asio_mrb> > _mrb_pool; + std::vector<boost::shared_ptr<udp_zero_copy_asio_msb>> _msb_pool; + std::vector<boost::shared_ptr<udp_zero_copy_asio_mrb>> _mrb_pool; size_t _next_recv_buff_index, _next_send_buff_index; - //socket guts - SOCKET _sock_fd; + // socket guts + SOCKET _sock_fd; }; /*********************************************************************** * UDP zero copy make function **********************************************************************/ -void check_usr_buff_size( - size_t actual_buff_size, +void check_usr_buff_size(size_t actual_buff_size, size_t user_buff_size, // Set this to zero for no user-defined preference - const std::string tx_rx -){ - UHD_LOGGER_DEBUG("UDP") - << boost::format("Target/actual %s sock buff size: %d/%d bytes") - % tx_rx - % user_buff_size - % actual_buff_size - ; - if ((user_buff_size != 0.0) and (actual_buff_size < user_buff_size)) UHD_LOGGER_WARNING("UDP") << boost::format( - "The %s buffer could not be resized sufficiently.\n" - "Target sock buff size: %d bytes.\n" - "Actual sock buff size: %d bytes.\n" - "See the transport application notes on buffer resizing.\n" - ) % tx_rx % user_buff_size % actual_buff_size; + const std::string tx_rx) +{ + UHD_LOGGER_DEBUG("UDP") << boost::format( + "Target/actual %s sock buff size: %d/%d bytes") + % tx_rx % user_buff_size % actual_buff_size; + if ((user_buff_size != 0.0) and (actual_buff_size < user_buff_size)) + UHD_LOGGER_WARNING("UDP") + << boost::format("The %s buffer could not be resized sufficiently.\n" + "Target sock buff size: %d bytes.\n" + "Actual sock buff size: %d bytes.\n" + "See the transport application notes on buffer resizing.\n") + % tx_rx % user_buff_size % actual_buff_size; } - -udp_zero_copy::sptr udp_zero_copy::make( - const std::string &addr, - const std::string &port, - const zero_copy_xport_params &default_buff_args, +udp_zero_copy::sptr udp_zero_copy::make(const std::string& addr, + const std::string& port, + const zero_copy_xport_params& default_buff_args, udp_zero_copy::buff_params& buff_params_out, - const device_addr_t &hints -){ - //Initialize xport_params + const device_addr_t& hints) +{ + // Initialize xport_params zero_copy_xport_params xport_params = default_buff_args; - xport_params.recv_frame_size = size_t(hints.cast<double>("recv_frame_size", default_buff_args.recv_frame_size)); - xport_params.num_recv_frames = size_t(hints.cast<double>("num_recv_frames", default_buff_args.num_recv_frames)); - xport_params.send_frame_size = size_t(hints.cast<double>("send_frame_size", default_buff_args.send_frame_size)); - xport_params.num_send_frames = size_t(hints.cast<double>("num_send_frames", default_buff_args.num_send_frames)); + xport_params.recv_frame_size = + size_t(hints.cast<double>("recv_frame_size", default_buff_args.recv_frame_size)); + xport_params.num_recv_frames = + size_t(hints.cast<double>("num_recv_frames", default_buff_args.num_recv_frames)); + xport_params.send_frame_size = + size_t(hints.cast<double>("send_frame_size", default_buff_args.send_frame_size)); + xport_params.num_send_frames = + size_t(hints.cast<double>("num_send_frames", default_buff_args.num_send_frames)); if (xport_params.num_recv_frames == 0) { UHD_LOG_TRACE("UDP", @@ -405,27 +451,34 @@ udp_zero_copy::sptr udp_zero_copy::make( xport_params.send_frame_size = UDP_ZERO_COPY_DEFAULT_FRAME_SIZE; } - //extract buffer size hints from the device addr and check if they match up + // extract buffer size hints from the device addr and check if they match up size_t usr_recv_buff_size = size_t(hints.cast<double>("recv_buff_size", 0.0)); size_t usr_send_buff_size = size_t(hints.cast<double>("send_buff_size", 0.0)); if (hints.has_key("recv_buff_size")) { - if (usr_recv_buff_size < xport_params.recv_frame_size * xport_params.num_recv_frames) { - throw uhd::value_error((boost::format( - "recv_buff_size must be equal to or greater than (num_recv_frames * recv_frame_size) where num_recv_frames=%d, recv_frame_size=%d") - % xport_params.num_recv_frames % xport_params.recv_frame_size).str()); + if (usr_recv_buff_size + < xport_params.recv_frame_size * xport_params.num_recv_frames) { + throw uhd::value_error( + (boost::format( + "recv_buff_size must be equal to or greater than (num_recv_frames * " + "recv_frame_size) where num_recv_frames=%d, recv_frame_size=%d") + % xport_params.num_recv_frames % xport_params.recv_frame_size) + .str()); } } if (hints.has_key("send_buff_size")) { - if (usr_send_buff_size < xport_params.send_frame_size * xport_params.num_send_frames) { - throw uhd::value_error((boost::format( - "send_buff_size must be equal to or greater than (num_send_frames * send_frame_size) where num_send_frames=%d, send_frame_size=%d") - % xport_params.num_send_frames % xport_params.send_frame_size).str()); + if (usr_send_buff_size + < xport_params.send_frame_size * xport_params.num_send_frames) { + throw uhd::value_error( + (boost::format( + "send_buff_size must be equal to or greater than (num_send_frames * " + "send_frame_size) where num_send_frames=%d, send_frame_size=%d") + % xport_params.num_send_frames % xport_params.send_frame_size) + .str()); } } udp_zero_copy_wsa_impl::sptr udp_trans( - new udp_zero_copy_wsa_impl(addr, port, xport_params, hints) - ); + new udp_zero_copy_wsa_impl(addr, port, xport_params, hints)); // Read back the actual socket buffer sizes buff_params_out.recv_buff_size = udp_trans->get_recv_buff_size(); diff --git a/host/lib/transport/udp_zero_copy.cpp b/host/lib/transport/udp_zero_copy.cpp index 2b637639b..1ccee72a2 100644 --- a/host/lib/transport/udp_zero_copy.cpp +++ b/host/lib/transport/udp_zero_copy.cpp @@ -6,45 +6,52 @@ // #include "udp_common.hpp" -#include <uhd/transport/udp_zero_copy.hpp> -#include <uhd/transport/udp_simple.hpp> //mtu #include <uhd/transport/buffer_pool.hpp> - +#include <uhd/transport/udp_simple.hpp> //mtu +#include <uhd/transport/udp_zero_copy.hpp> #include <uhd/utils/log.hpp> #include <uhdlib/utils/atomic.hpp> #include <boost/format.hpp> #include <boost/make_shared.hpp> -#include <vector> #include <chrono> #include <thread> +#include <vector> using namespace uhd; using namespace uhd::transport; -namespace asio = boost::asio; +namespace asio = boost::asio; constexpr size_t UDP_ZERO_COPY_DEFAULT_NUM_FRAMES = 1; -constexpr size_t UDP_ZERO_COPY_DEFAULT_FRAME_SIZE = 1472; // Based on common 1500 byte MTU for 1GbE. -constexpr size_t UDP_ZERO_COPY_DEFAULT_BUFF_SIZE = 2500000; // 20ms of data for 1GbE link (in bytes) +constexpr size_t UDP_ZERO_COPY_DEFAULT_FRAME_SIZE = + 1472; // Based on common 1500 byte MTU for 1GbE. +constexpr size_t UDP_ZERO_COPY_DEFAULT_BUFF_SIZE = + 2500000; // 20ms of data for 1GbE link (in bytes) /*********************************************************************** * Check registry for correct fast-path setting (windows only) **********************************************************************/ #ifdef HAVE_ATLBASE_H -#define CHECK_REG_SEND_THRESH -#include <atlbase.h> //CRegKey -static void check_registry_for_fast_send_threshold(const size_t mtu){ +# define CHECK_REG_SEND_THRESH +# include <atlbase.h> //CRegKey +static void check_registry_for_fast_send_threshold(const size_t mtu) +{ static bool warned = false; - if (warned) return; //only allow one printed warning per process + if (warned) + return; // only allow one printed warning per process CRegKey reg_key; - DWORD threshold = 1024; //system default when threshold is not specified - if ( - reg_key.Open(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Services\\AFD\\Parameters", KEY_READ) != ERROR_SUCCESS or - reg_key.QueryDWORDValue("FastSendDatagramThreshold", threshold) != ERROR_SUCCESS or threshold < mtu - ){ - UHD_LOGGER_WARNING("UDP") << boost::format( - "The MTU (%d) is larger than the FastSendDatagramThreshold (%d)!\n" - "This will negatively affect the transmit performance.\n" - "See the transport application notes for more detail.\n" - ) % mtu % threshold ; + DWORD threshold = 1024; // system default when threshold is not specified + if (reg_key.Open(HKEY_LOCAL_MACHINE, + "System\\CurrentControlSet\\Services\\AFD\\Parameters", + KEY_READ) + != ERROR_SUCCESS + or reg_key.QueryDWORDValue("FastSendDatagramThreshold", threshold) + != ERROR_SUCCESS + or threshold < mtu) { + UHD_LOGGER_WARNING("UDP") + << boost::format( + "The MTU (%d) is larger than the FastSendDatagramThreshold (%d)!\n" + "This will negatively affect the transmit performance.\n" + "See the transport application notes for more detail.\n") + % mtu % threshold; warned = true; } reg_key.Close(); @@ -55,42 +62,49 @@ static void check_registry_for_fast_send_threshold(const size_t mtu){ * Reusable managed receiver buffer: * - get_new performs the recv operation **********************************************************************/ -class udp_zero_copy_asio_mrb : public managed_recv_buffer{ +class udp_zero_copy_asio_mrb : public managed_recv_buffer +{ public: - udp_zero_copy_asio_mrb(void *mem, int sock_fd, const size_t frame_size): - _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size), _len(0) { /*NOP*/ } + udp_zero_copy_asio_mrb(void* mem, int sock_fd, const size_t frame_size) + : _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size), _len(0) + { /*NOP*/ + } - void release(void){ + void release(void) + { _claimer.release(); } - UHD_INLINE sptr get_new(const double timeout, size_t &index){ - if (not _claimer.claim_with_wait(timeout)) return sptr(); + UHD_INLINE sptr get_new(const double timeout, size_t& index) + { + if (not _claimer.claim_with_wait(timeout)) + return sptr(); - #ifdef MSG_DONTWAIT //try a non-blocking recv() if supported - _len = ::recv(_sock_fd, (char *)_mem, _frame_size, MSG_DONTWAIT); - if (_len > 0){ - index++; //advances the caller's buffer +#ifdef MSG_DONTWAIT // try a non-blocking recv() if supported + _len = ::recv(_sock_fd, (char*)_mem, _frame_size, MSG_DONTWAIT); + if (_len > 0) { + index++; // advances the caller's buffer return make(this, _mem, size_t(_len)); } - #endif +#endif - if (wait_for_recv_ready(_sock_fd, timeout)){ - _len = ::recv(_sock_fd, (char *)_mem, _frame_size, 0); + if (wait_for_recv_ready(_sock_fd, timeout)) { + _len = ::recv(_sock_fd, (char*)_mem, _frame_size, 0); if (_len == 0) throw uhd::io_error("socket closed"); if (_len < 0) - throw uhd::io_error(str(boost::format("recv error on socket: %s") % strerror(errno))); - index++; //advances the caller's buffer + throw uhd::io_error( + str(boost::format("recv error on socket: %s") % strerror(errno))); + index++; // advances the caller's buffer return make(this, _mem, size_t(_len)); } - _claimer.release(); //undo claim - return sptr(); //null for timeout + _claimer.release(); // undo claim + return sptr(); // null for timeout } private: - void *_mem; + void* _mem; int _sock_fd; size_t _frame_size; ssize_t _len; @@ -101,41 +115,46 @@ private: * Reusable managed send buffer: * - commit performs the send operation **********************************************************************/ -class udp_zero_copy_asio_msb : public managed_send_buffer{ +class udp_zero_copy_asio_msb : public managed_send_buffer +{ public: - udp_zero_copy_asio_msb(void *mem, int sock_fd, const size_t frame_size): - _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size) { /*NOP*/ } - - void release(void){ - //Retry logic because send may fail with ENOBUFS. - //This is known to occur at least on some OSX systems. - //But it should be safe to always check for the error. - while (true) - { - const ssize_t ret = ::send(_sock_fd, (const char *)_mem, size(), 0); - if (ret == ssize_t(size())) break; - if (ret == -1 and errno == ENOBUFS) - { + udp_zero_copy_asio_msb(void* mem, int sock_fd, const size_t frame_size) + : _mem(mem), _sock_fd(sock_fd), _frame_size(frame_size) + { /*NOP*/ + } + + void release(void) + { + // Retry logic because send may fail with ENOBUFS. + // This is known to occur at least on some OSX systems. + // But it should be safe to always check for the error. + while (true) { + const ssize_t ret = ::send(_sock_fd, (const char*)_mem, size(), 0); + if (ret == ssize_t(size())) + break; + if (ret == -1 and errno == ENOBUFS) { std::this_thread::sleep_for(std::chrono::microseconds(1)); - continue; //try to send again + continue; // try to send again } - if (ret == -1) - { - throw uhd::io_error(str(boost::format("send error on socket: %s") % strerror(errno))); + if (ret == -1) { + throw uhd::io_error( + str(boost::format("send error on socket: %s") % strerror(errno))); } UHD_ASSERT_THROW(ret == ssize_t(size())); } _claimer.release(); } - UHD_INLINE sptr get_new(const double timeout, size_t &index){ - if (not _claimer.claim_with_wait(timeout)) return sptr(); - index++; //advances the caller's buffer + UHD_INLINE sptr get_new(const double timeout, size_t& index) + { + if (not _claimer.claim_with_wait(timeout)) + return sptr(); + index++; // advances the caller's buffer return make(this, _mem, _frame_size); } private: - void *_mem; + void* _mem; int _sock_fd; size_t _frame_size; simple_claimer _claimer; @@ -148,74 +167,74 @@ private: * However, it is not a true zero copy implementation as each * send and recv requires a copy operation to/from userspace. **********************************************************************/ -class udp_zero_copy_asio_impl : public udp_zero_copy{ +class udp_zero_copy_asio_impl : public udp_zero_copy +{ public: typedef boost::shared_ptr<udp_zero_copy_asio_impl> sptr; - udp_zero_copy_asio_impl( - const std::string &addr, - const std::string &port, - const zero_copy_xport_params& xport_params - ): - _recv_frame_size(xport_params.recv_frame_size), - _num_recv_frames(xport_params.num_recv_frames), - _send_frame_size(xport_params.send_frame_size), - _num_send_frames(xport_params.num_send_frames), - _recv_buffer_pool(buffer_pool::make(xport_params.num_recv_frames, xport_params.recv_frame_size)), - _send_buffer_pool(buffer_pool::make(xport_params.num_send_frames, xport_params.send_frame_size)), - _next_recv_buff_index(0), _next_send_buff_index(0) + udp_zero_copy_asio_impl(const std::string& addr, + const std::string& port, + const zero_copy_xport_params& xport_params) + : _recv_frame_size(xport_params.recv_frame_size) + , _num_recv_frames(xport_params.num_recv_frames) + , _send_frame_size(xport_params.send_frame_size) + , _num_send_frames(xport_params.num_send_frames) + , _recv_buffer_pool(buffer_pool::make( + xport_params.num_recv_frames, xport_params.recv_frame_size)) + , _send_buffer_pool(buffer_pool::make( + xport_params.num_send_frames, xport_params.send_frame_size)) + , _next_recv_buff_index(0) + , _next_send_buff_index(0) { UHD_LOGGER_TRACE("UDP") << boost::format("Creating UDP transport to %s:%s") % addr % port; - #ifdef CHECK_REG_SEND_THRESH +#ifdef CHECK_REG_SEND_THRESH check_registry_for_fast_send_threshold(this->get_send_frame_size()); - #endif /*CHECK_REG_SEND_THRESH*/ +#endif /*CHECK_REG_SEND_THRESH*/ - //resolve the address + // resolve the address asio::ip::udp::resolver resolver(_io_service); asio::ip::udp::resolver::query query(asio::ip::udp::v4(), addr, port); asio::ip::udp::endpoint receiver_endpoint = *resolver.resolve(query); - //create, open, and connect the socket + // create, open, and connect the socket _socket = socket_sptr(new asio::ip::udp::socket(_io_service)); _socket->open(asio::ip::udp::v4()); _socket->connect(receiver_endpoint); _sock_fd = _socket->native_handle(); - UHD_LOGGER_TRACE("UDP") - << boost::format("Local UDP socket endpoint: %s:%s") - % get_local_addr() % get_local_port(); + UHD_LOGGER_TRACE("UDP") << boost::format("Local UDP socket endpoint: %s:%s") + % get_local_addr() % get_local_port(); - //allocate re-usable managed receive buffers - for (size_t i = 0; i < get_num_recv_frames(); i++){ + // allocate re-usable managed receive buffers + for (size_t i = 0; i < get_num_recv_frames(); i++) { _mrb_pool.push_back(boost::make_shared<udp_zero_copy_asio_mrb>( - _recv_buffer_pool->at(i), _sock_fd, get_recv_frame_size() - )); + _recv_buffer_pool->at(i), _sock_fd, get_recv_frame_size())); } - //allocate re-usable managed send buffers - for (size_t i = 0; i < get_num_send_frames(); i++){ + // allocate re-usable managed send buffers + for (size_t i = 0; i < get_num_send_frames(); i++) { _msb_pool.push_back(boost::make_shared<udp_zero_copy_asio_msb>( - _send_buffer_pool->at(i), _sock_fd, get_send_frame_size() - )); + _send_buffer_pool->at(i), _sock_fd, get_send_frame_size())); } } - //get size for internal socket buffer - template <typename Opt> size_t get_buff_size(void) const{ + // get size for internal socket buffer + template <typename Opt> size_t get_buff_size(void) const + { Opt option; _socket->get_option(option); return option.value(); } - //set size for internal socket buffer + // set size for internal socket buffer template <typename Opt> size_t resize_buff(size_t num_bytes) { - #if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) - //limit buffer resize on macos or it will error - num_bytes = std::min(num_bytes, MAX_BUFF_SIZE_ETH_MACOS); - #endif +#if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) + // limit buffer resize on macos or it will error + num_bytes = std::min(num_bytes, MAX_BUFF_SIZE_ETH_MACOS); +#endif Opt option(num_bytes); _socket->set_option(option); return get_buff_size<Opt>(); @@ -225,25 +244,41 @@ public: * Receive implementation: * Block on the managed buffer's get call and advance the index. ******************************************************************/ - managed_recv_buffer::sptr get_recv_buff(double timeout){ - if (_next_recv_buff_index == _num_recv_frames) _next_recv_buff_index = 0; + managed_recv_buffer::sptr get_recv_buff(double timeout) + { + if (_next_recv_buff_index == _num_recv_frames) + _next_recv_buff_index = 0; return _mrb_pool[_next_recv_buff_index]->get_new(timeout, _next_recv_buff_index); } - size_t get_num_recv_frames(void) const {return _num_recv_frames;} - size_t get_recv_frame_size(void) const {return _recv_frame_size;} + size_t get_num_recv_frames(void) const + { + return _num_recv_frames; + } + size_t get_recv_frame_size(void) const + { + return _recv_frame_size; + } /******************************************************************* * Send implementation: * Block on the managed buffer's get call and advance the index. ******************************************************************/ - managed_send_buffer::sptr get_send_buff(double timeout){ - if (_next_send_buff_index == _num_send_frames) _next_send_buff_index = 0; + managed_send_buffer::sptr get_send_buff(double timeout) + { + if (_next_send_buff_index == _num_send_frames) + _next_send_buff_index = 0; return _msb_pool[_next_send_buff_index]->get_new(timeout, _next_send_buff_index); } - size_t get_num_send_frames(void) const {return _num_send_frames;} - size_t get_send_frame_size(void) const {return _send_frame_size;} + size_t get_num_send_frames(void) const + { + return _num_send_frames; + } + size_t get_send_frame_size(void) const + { + return _send_frame_size; + } uint16_t get_local_port(void) const { @@ -256,149 +291,153 @@ public: } private: - //memory management -> buffers and fifos + // memory management -> buffers and fifos const size_t _recv_frame_size, _num_recv_frames; const size_t _send_frame_size, _num_send_frames; buffer_pool::sptr _recv_buffer_pool, _send_buffer_pool; - std::vector<boost::shared_ptr<udp_zero_copy_asio_msb> > _msb_pool; - std::vector<boost::shared_ptr<udp_zero_copy_asio_mrb> > _mrb_pool; + std::vector<boost::shared_ptr<udp_zero_copy_asio_msb>> _msb_pool; + std::vector<boost::shared_ptr<udp_zero_copy_asio_mrb>> _mrb_pool; size_t _next_recv_buff_index, _next_send_buff_index; - //asio guts -> socket and service - asio::io_service _io_service; - socket_sptr _socket; - int _sock_fd; + // asio guts -> socket and service + asio::io_service _io_service; + socket_sptr _socket; + int _sock_fd; }; /*********************************************************************** * UDP zero copy make function **********************************************************************/ -template<typename Opt> static size_t resize_buff_helper( - udp_zero_copy_asio_impl::sptr udp_trans, +template <typename Opt> +static size_t resize_buff_helper(udp_zero_copy_asio_impl::sptr udp_trans, const size_t target_size, - const std::string &name -){ + const std::string& name) +{ size_t actual_size = 0; std::string help_message; - #if defined(UHD_PLATFORM_LINUX) - help_message = str(boost::format( - "Please run: sudo sysctl -w net.core.%smem_max=%d" - ) % ((name == "recv")?"r":"w") % target_size); - #endif /*defined(UHD_PLATFORM_LINUX)*/ - - //resize the buffer if size was provided - if (target_size > 0){ +#if defined(UHD_PLATFORM_LINUX) + help_message = str(boost::format("Please run: sudo sysctl -w net.core.%smem_max=%d") + % ((name == "recv") ? "r" : "w") % target_size); +#endif /*defined(UHD_PLATFORM_LINUX)*/ + + // resize the buffer if size was provided + if (target_size > 0) { actual_size = udp_trans->resize_buff<Opt>(target_size); UHD_LOGGER_TRACE("UDP") - << boost::format("Target/actual %s sock buff size: %d/%d bytes") - % name - % target_size - % actual_size - ; - if (actual_size < target_size) UHD_LOGGER_WARNING("UDP") << boost::format( - "The %s buffer could not be resized sufficiently.\n" - "Target sock buff size: %d bytes.\n" - "Actual sock buff size: %d bytes.\n" - "See the transport application notes on buffer resizing.\n%s" - ) % name % target_size % actual_size % help_message; + << boost::format("Target/actual %s sock buff size: %d/%d bytes") % name + % target_size % actual_size; + if (actual_size < target_size) + UHD_LOGGER_WARNING("UDP") + << boost::format( + "The %s buffer could not be resized sufficiently.\n" + "Target sock buff size: %d bytes.\n" + "Actual sock buff size: %d bytes.\n" + "See the transport application notes on buffer resizing.\n%s") + % name % target_size % actual_size % help_message; } return actual_size; } -udp_zero_copy::sptr udp_zero_copy::make( - const std::string &addr, - const std::string &port, - const zero_copy_xport_params &default_buff_args, +udp_zero_copy::sptr udp_zero_copy::make(const std::string& addr, + const std::string& port, + const zero_copy_xport_params& default_buff_args, udp_zero_copy::buff_params& buff_params_out, - const device_addr_t &hints -){ - //Initialize xport_params + const device_addr_t& hints) +{ + // Initialize xport_params zero_copy_xport_params xport_params = default_buff_args; - xport_params.recv_frame_size = size_t(hints.cast<double>("recv_frame_size", default_buff_args.recv_frame_size)); - xport_params.num_recv_frames = size_t(hints.cast<double>("num_recv_frames", default_buff_args.num_recv_frames)); - xport_params.send_frame_size = size_t(hints.cast<double>("send_frame_size", default_buff_args.send_frame_size)); - xport_params.num_send_frames = size_t(hints.cast<double>("num_send_frames", default_buff_args.num_send_frames)); - xport_params.recv_buff_size = size_t(hints.cast<double>("recv_buff_size", default_buff_args.recv_buff_size)); - xport_params.send_buff_size = size_t(hints.cast<double>("send_buff_size", default_buff_args.send_buff_size)); + xport_params.recv_frame_size = + size_t(hints.cast<double>("recv_frame_size", default_buff_args.recv_frame_size)); + xport_params.num_recv_frames = + size_t(hints.cast<double>("num_recv_frames", default_buff_args.num_recv_frames)); + xport_params.send_frame_size = + size_t(hints.cast<double>("send_frame_size", default_buff_args.send_frame_size)); + xport_params.num_send_frames = + size_t(hints.cast<double>("num_send_frames", default_buff_args.num_send_frames)); + xport_params.recv_buff_size = + size_t(hints.cast<double>("recv_buff_size", default_buff_args.recv_buff_size)); + xport_params.send_buff_size = + size_t(hints.cast<double>("send_buff_size", default_buff_args.send_buff_size)); if (xport_params.num_recv_frames == 0) { - UHD_LOG_TRACE("UDP", "Default value for num_recv_frames: " - << UDP_ZERO_COPY_DEFAULT_NUM_FRAMES - ); + UHD_LOG_TRACE("UDP", + "Default value for num_recv_frames: " << UDP_ZERO_COPY_DEFAULT_NUM_FRAMES); xport_params.num_recv_frames = UDP_ZERO_COPY_DEFAULT_NUM_FRAMES; } if (xport_params.num_send_frames == 0) { - UHD_LOG_TRACE("UDP", "Default value for no num_send_frames: " - << UDP_ZERO_COPY_DEFAULT_NUM_FRAMES - ); + UHD_LOG_TRACE("UDP", + "Default value for no num_send_frames: " << UDP_ZERO_COPY_DEFAULT_NUM_FRAMES); xport_params.num_send_frames = UDP_ZERO_COPY_DEFAULT_NUM_FRAMES; } if (xport_params.recv_frame_size == 0) { - UHD_LOG_TRACE("UDP", "Using default value for recv_frame_size: " - << UDP_ZERO_COPY_DEFAULT_FRAME_SIZE - ); + UHD_LOG_TRACE("UDP", + "Using default value for recv_frame_size: " + << UDP_ZERO_COPY_DEFAULT_FRAME_SIZE); xport_params.recv_frame_size = UDP_ZERO_COPY_DEFAULT_FRAME_SIZE; } if (xport_params.send_frame_size == 0) { - UHD_LOG_TRACE("UDP", "Using default value for send_frame_size, " - << UDP_ZERO_COPY_DEFAULT_FRAME_SIZE - ); + UHD_LOG_TRACE("UDP", + "Using default value for send_frame_size, " + << UDP_ZERO_COPY_DEFAULT_FRAME_SIZE); xport_params.send_frame_size = UDP_ZERO_COPY_DEFAULT_FRAME_SIZE; } if (xport_params.recv_buff_size == 0) { UHD_LOG_TRACE("UDP", "Using default value for recv_buff_size"); - xport_params.recv_buff_size = std::max( - UDP_ZERO_COPY_DEFAULT_BUFF_SIZE, - xport_params.num_recv_frames*MAX_ETHERNET_MTU - ); - UHD_LOG_TRACE("UDP", "Using default value for recv_buff_size" - << xport_params.recv_buff_size - ); + xport_params.recv_buff_size = std::max(UDP_ZERO_COPY_DEFAULT_BUFF_SIZE, + xport_params.num_recv_frames * MAX_ETHERNET_MTU); + UHD_LOG_TRACE("UDP", + "Using default value for recv_buff_size" << xport_params.recv_buff_size); } if (xport_params.send_buff_size == 0) { UHD_LOG_TRACE("UDP", "default_buff_args has no send_buff_size"); - xport_params.send_buff_size = std::max( - UDP_ZERO_COPY_DEFAULT_BUFF_SIZE, - xport_params.num_send_frames*MAX_ETHERNET_MTU - ); + xport_params.send_buff_size = std::max(UDP_ZERO_COPY_DEFAULT_BUFF_SIZE, + xport_params.num_send_frames * MAX_ETHERNET_MTU); } - #if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) - //limit default buffer size on macos to avoid the warning issued by resize_buff_helper - if (not hints.has_key("recv_buff_size") and xport_params.recv_buff_size > MAX_BUFF_SIZE_ETH_MACOS) - { - xport_params.recv_buff_size = MAX_BUFF_SIZE_ETH_MACOS; - } - if (not hints.has_key("send_buff_size") and xport_params.send_buff_size > MAX_BUFF_SIZE_ETH_MACOS) - { - xport_params.send_buff_size = MAX_BUFF_SIZE_ETH_MACOS; - } - #endif +#if defined(UHD_PLATFORM_MACOS) || defined(UHD_PLATFORM_BSD) + // limit default buffer size on macos to avoid the warning issued by + // resize_buff_helper + if (not hints.has_key("recv_buff_size") + and xport_params.recv_buff_size > MAX_BUFF_SIZE_ETH_MACOS) { + xport_params.recv_buff_size = MAX_BUFF_SIZE_ETH_MACOS; + } + if (not hints.has_key("send_buff_size") + and xport_params.send_buff_size > MAX_BUFF_SIZE_ETH_MACOS) { + xport_params.send_buff_size = MAX_BUFF_SIZE_ETH_MACOS; + } +#endif udp_zero_copy_asio_impl::sptr udp_trans( - new udp_zero_copy_asio_impl(addr, port, xport_params) - ); - - //call the helper to resize send and recv buffers - buff_params_out.recv_buff_size = resize_buff_helper<asio::socket_base::receive_buffer_size>( - udp_trans, xport_params.recv_buff_size, "recv"); - buff_params_out.send_buff_size = resize_buff_helper<asio::socket_base::send_buffer_size> ( - udp_trans, xport_params.send_buff_size, "send"); - - if (buff_params_out.recv_buff_size < xport_params.num_recv_frames * MAX_ETHERNET_MTU){ - UHD_LOG_WARNING("UDP", "The current recv_buff_size of " << xport_params.recv_buff_size - << " is less than the minimum recommended size of " - << xport_params.num_recv_frames * MAX_ETHERNET_MTU - << " and may result in dropped packets on some NICs"); + new udp_zero_copy_asio_impl(addr, port, xport_params)); + + // call the helper to resize send and recv buffers + buff_params_out.recv_buff_size = + resize_buff_helper<asio::socket_base::receive_buffer_size>( + udp_trans, xport_params.recv_buff_size, "recv"); + buff_params_out.send_buff_size = + resize_buff_helper<asio::socket_base::send_buffer_size>( + udp_trans, xport_params.send_buff_size, "send"); + + if (buff_params_out.recv_buff_size + < xport_params.num_recv_frames * MAX_ETHERNET_MTU) { + UHD_LOG_WARNING("UDP", + "The current recv_buff_size of " + << xport_params.recv_buff_size + << " is less than the minimum recommended size of " + << xport_params.num_recv_frames * MAX_ETHERNET_MTU + << " and may result in dropped packets on some NICs"); } - if (buff_params_out.send_buff_size < xport_params.num_send_frames * MAX_ETHERNET_MTU){ - UHD_LOG_WARNING("UDP", "The current send_buff_size of " << xport_params.send_buff_size - << " is less than the minimum recommended size of " - << xport_params.num_send_frames * MAX_ETHERNET_MTU - << " and may result in dropped packets on some NICs"); + if (buff_params_out.send_buff_size + < xport_params.num_send_frames * MAX_ETHERNET_MTU) { + UHD_LOG_WARNING("UDP", + "The current send_buff_size of " + << xport_params.send_buff_size + << " is less than the minimum recommended size of " + << xport_params.num_send_frames * MAX_ETHERNET_MTU + << " and may result in dropped packets on some NICs"); } return udp_trans; diff --git a/host/lib/transport/usb_dummy_impl.cpp b/host/lib/transport/usb_dummy_impl.cpp index 81aad97c6..8e5084a9b 100644 --- a/host/lib/transport/usb_dummy_impl.cpp +++ b/host/lib/transport/usb_dummy_impl.cpp @@ -5,44 +5,48 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#include <uhd/transport/usb_device_handle.hpp> +#include <uhd/exception.hpp> #include <uhd/transport/usb_control.hpp> +#include <uhd/transport/usb_device_handle.hpp> #include <uhd/transport/usb_zero_copy.hpp> -#include <uhd/exception.hpp> using namespace uhd; using namespace uhd::transport; -usb_control::~usb_control(void){ +usb_control::~usb_control(void) +{ /* NOP */ } -usb_device_handle::~usb_device_handle(void) { +usb_device_handle::~usb_device_handle(void) +{ /* NOP */ } -usb_zero_copy::~usb_zero_copy(void) { +usb_zero_copy::~usb_zero_copy(void) +{ /* NOP */ } -std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list(uint16_t, uint16_t){ - return std::vector<usb_device_handle::sptr>(); //empty list +std::vector<usb_device_handle::sptr> usb_device_handle::get_device_list( + uint16_t, uint16_t) +{ + return std::vector<usb_device_handle::sptr>(); // empty list } -usb_control::sptr usb_control::make( - usb_device_handle::sptr, - const int -) { - throw uhd::not_implemented_error("no usb support -> usb_control::make not implemented"); +usb_control::sptr usb_control::make(usb_device_handle::sptr, const int) +{ + throw uhd::not_implemented_error( + "no usb support -> usb_control::make not implemented"); } -usb_zero_copy::sptr usb_zero_copy::make( - usb_device_handle::sptr, +usb_zero_copy::sptr usb_zero_copy::make(usb_device_handle::sptr, const int, const unsigned char, const int, const unsigned char, - const device_addr_t & -){ - throw uhd::not_implemented_error("no usb support -> usb_zero_copy::make not implemented"); + const device_addr_t&) +{ + throw uhd::not_implemented_error( + "no usb support -> usb_zero_copy::make not implemented"); } diff --git a/host/lib/transport/xport_benchmarker.cpp b/host/lib/transport/xport_benchmarker.cpp index 0351d5106..67582ff2c 100644 --- a/host/lib/transport/xport_benchmarker.cpp +++ b/host/lib/transport/xport_benchmarker.cpp @@ -11,8 +11,7 @@ namespace uhd { namespace transport { -const device_addr_t& xport_benchmarker::benchmark_throughput_chdr -( +const device_addr_t& xport_benchmarker::benchmark_throughput_chdr( zero_copy_if::sptr tx_transport, zero_copy_if::sptr rx_transport, uint32_t sid, @@ -24,8 +23,16 @@ const device_addr_t& xport_benchmarker::benchmark_throughput_chdr _reset_counters(); boost::posix_time::ptime start_time(boost::posix_time::microsec_clock::local_time()); - _tx_thread.reset(new boost::thread(boost::bind(&xport_benchmarker::_stream_tx, this, tx_transport.get(), &pkt_info, big_endian))); - _rx_thread.reset(new boost::thread(boost::bind(&xport_benchmarker::_stream_rx, this, rx_transport.get(), &pkt_info, big_endian))); + _tx_thread.reset(new boost::thread(boost::bind(&xport_benchmarker::_stream_tx, + this, + tx_transport.get(), + &pkt_info, + big_endian))); + _rx_thread.reset(new boost::thread(boost::bind(&xport_benchmarker::_stream_rx, + this, + rx_transport.get(), + &pkt_info, + big_endian))); std::this_thread::sleep_for(std::chrono::milliseconds(duration_ms)); @@ -35,17 +42,19 @@ const device_addr_t& xport_benchmarker::benchmark_throughput_chdr _rx_thread->join(); boost::posix_time::ptime stop_time(boost::posix_time::microsec_clock::local_time()); - double duration_s = ((double)(stop_time-start_time).total_microseconds())/1e6; - - uint64_t tx_bytes = pkt_info.num_payload_words32*sizeof(uint32_t)*_num_tx_packets; - uint64_t rx_bytes = pkt_info.num_payload_words32*sizeof(uint32_t)*_num_rx_packets; - double tx_rate = (((double)tx_bytes)/duration_s); - double rx_rate = (((double)rx_bytes)/duration_s); - - _results["TX-Bytes"] = (boost::format("%.2fMB") % (tx_bytes/(1024*1024))).str(); - _results["RX-Bytes"] = (boost::format("%.2fMB") % (rx_bytes/(1024*1024))).str(); - _results["TX-Throughput"] = (boost::format("%.2fMB/s") % (tx_rate/(1024*1024))).str(); - _results["RX-Throughput"] = (boost::format("%.2fMB/s") % (rx_rate/(1024*1024))).str(); + double duration_s = ((double)(stop_time - start_time).total_microseconds()) / 1e6; + + uint64_t tx_bytes = pkt_info.num_payload_words32 * sizeof(uint32_t) * _num_tx_packets; + uint64_t rx_bytes = pkt_info.num_payload_words32 * sizeof(uint32_t) * _num_rx_packets; + double tx_rate = (((double)tx_bytes) / duration_s); + double rx_rate = (((double)rx_bytes) / duration_s); + + _results["TX-Bytes"] = (boost::format("%.2fMB") % (tx_bytes / (1024 * 1024))).str(); + _results["RX-Bytes"] = (boost::format("%.2fMB") % (rx_bytes / (1024 * 1024))).str(); + _results["TX-Throughput"] = + (boost::format("%.2fMB/s") % (tx_rate / (1024 * 1024))).str(); + _results["RX-Throughput"] = + (boost::format("%.2fMB/s") % (rx_rate / (1024 * 1024))).str(); _results["TX-Timeouts"] = std::to_string(_num_tx_timeouts); _results["RX-Timeouts"] = std::to_string(_num_rx_timeouts); _results["Data-Errors"] = std::to_string(_num_data_errors); @@ -53,20 +62,21 @@ const device_addr_t& xport_benchmarker::benchmark_throughput_chdr return _results; } -void xport_benchmarker::_stream_tx(zero_copy_if* transport, vrt::if_packet_info_t* pkt_info, bool big_endian) +void xport_benchmarker::_stream_tx( + zero_copy_if* transport, vrt::if_packet_info_t* pkt_info, bool big_endian) { while (not boost::this_thread::interruption_requested()) { managed_send_buffer::sptr buff = transport->get_send_buff(_tx_timeout); if (buff) { - uint32_t *packet_buff = buff->cast<uint32_t *>(); - //Populate packet + uint32_t* packet_buff = buff->cast<uint32_t*>(); + // Populate packet if (big_endian) { vrt::if_hdr_pack_be(packet_buff, *pkt_info); } else { vrt::if_hdr_pack_le(packet_buff, *pkt_info); } - //send the buffer over the interface - buff->commit(sizeof(uint32_t)*(pkt_info->num_packet_words32)); + // send the buffer over the interface + buff->commit(sizeof(uint32_t) * (pkt_info->num_packet_words32)); _num_tx_packets++; } else { _num_tx_timeouts++; @@ -74,20 +84,21 @@ void xport_benchmarker::_stream_tx(zero_copy_if* transport, vrt::if_packet_info_ } } -void xport_benchmarker::_stream_rx(zero_copy_if* transport, const vrt::if_packet_info_t* exp_pkt_info, bool big_endian) +void xport_benchmarker::_stream_rx( + zero_copy_if* transport, const vrt::if_packet_info_t* exp_pkt_info, bool big_endian) { while (not boost::this_thread::interruption_requested()) { managed_recv_buffer::sptr buff = transport->get_recv_buff(_rx_timeout); if (buff) { - //Extract packet info + // Extract packet info vrt::if_packet_info_t pkt_info; - pkt_info.link_type = exp_pkt_info->link_type; - pkt_info.num_packet_words32 = buff->size()/sizeof(uint32_t); - const uint32_t *packet_buff = buff->cast<const uint32_t *>(); + pkt_info.link_type = exp_pkt_info->link_type; + pkt_info.num_packet_words32 = buff->size() / sizeof(uint32_t); + const uint32_t* packet_buff = buff->cast<const uint32_t*>(); _num_rx_packets++; - //unpacking can fail + // unpacking can fail try { if (big_endian) { vrt::if_hdr_unpack_be(packet_buff, pkt_info); @@ -95,11 +106,11 @@ void xport_benchmarker::_stream_rx(zero_copy_if* transport, const vrt::if_packet vrt::if_hdr_unpack_le(packet_buff, pkt_info); } - if (exp_pkt_info->packet_type != pkt_info.packet_type || - exp_pkt_info->num_payload_bytes != pkt_info.num_payload_bytes) { + if (exp_pkt_info->packet_type != pkt_info.packet_type + || exp_pkt_info->num_payload_bytes != pkt_info.num_payload_bytes) { _num_data_errors++; } - } catch(const std::exception &ex) { + } catch (const std::exception& ex) { _num_data_errors++; } } else { @@ -110,15 +121,14 @@ void xport_benchmarker::_stream_rx(zero_copy_if* transport, const vrt::if_packet void xport_benchmarker::_reset_counters(void) { - _num_tx_packets = 0; - _num_rx_packets = 0; + _num_tx_packets = 0; + _num_rx_packets = 0; _num_tx_timeouts = 0; _num_rx_timeouts = 0; _num_data_errors = 0; } -void xport_benchmarker::_initialize_chdr( - zero_copy_if::sptr tx_transport, +void xport_benchmarker::_initialize_chdr(zero_copy_if::sptr tx_transport, zero_copy_if::sptr rx_transport, uint32_t sid, vrt::if_packet_info_t& pkt_info) @@ -126,22 +136,23 @@ void xport_benchmarker::_initialize_chdr( _tx_timeout = 0.5; _rx_timeout = 0.5; - size_t frame_size = std::min(tx_transport->get_send_frame_size(), rx_transport->get_recv_frame_size()); + size_t frame_size = std::min( + tx_transport->get_send_frame_size(), rx_transport->get_recv_frame_size()); - pkt_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR; - pkt_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_DATA; - pkt_info.num_packet_words32 = (frame_size/sizeof(uint32_t)); + pkt_info.link_type = vrt::if_packet_info_t::LINK_TYPE_CHDR; + pkt_info.packet_type = vrt::if_packet_info_t::PACKET_TYPE_DATA; + pkt_info.num_packet_words32 = (frame_size / sizeof(uint32_t)); pkt_info.num_payload_words32 = pkt_info.num_packet_words32 - 2; - pkt_info.num_payload_bytes = pkt_info.num_payload_words32*sizeof(uint32_t); - pkt_info.packet_count = 0; - pkt_info.sob = false; - pkt_info.eob = false; - pkt_info.sid = sid; - pkt_info.has_sid = true; - pkt_info.has_cid = false; - pkt_info.has_tsi = false; - pkt_info.has_tsf = false; - pkt_info.has_tlr = false; + pkt_info.num_payload_bytes = pkt_info.num_payload_words32 * sizeof(uint32_t); + pkt_info.packet_count = 0; + pkt_info.sob = false; + pkt_info.eob = false; + pkt_info.sid = sid; + pkt_info.has_sid = true; + pkt_info.has_cid = false; + pkt_info.has_tsi = false; + pkt_info.has_tsf = false; + pkt_info.has_tlr = false; } -}} +}} // namespace uhd::transport diff --git a/host/lib/transport/xport_benchmarker.hpp b/host/lib/transport/xport_benchmarker.hpp index c9ddee0e3..bd12c0ad8 100644 --- a/host/lib/transport/xport_benchmarker.hpp +++ b/host/lib/transport/xport_benchmarker.hpp @@ -8,20 +8,20 @@ #ifndef INCLUDED_LIBUHD_XPORT_BENCHMARKER_HPP #define INCLUDED_LIBUHD_XPORT_BENCHMARKER_HPP +#include <uhd/transport/vrt_if_packet.hpp> #include <uhd/transport/zero_copy.hpp> #include <uhd/types/device_addr.hpp> #include <uhd/utils/log.hpp> #include <boost/shared_ptr.hpp> #include <boost/thread/thread.hpp> -#include <uhd/transport/vrt_if_packet.hpp> namespace uhd { namespace transport { -//Test class to benchmark a low-level transport object with a VITA/C-VITA data stream -class xport_benchmarker : boost::noncopyable { +// Test class to benchmark a low-level transport object with a VITA/C-VITA data stream +class xport_benchmarker : boost::noncopyable +{ public: - const device_addr_t& benchmark_throughput_chdr( - zero_copy_if::sptr tx_transport, + const device_addr_t& benchmark_throughput_chdr(zero_copy_if::sptr tx_transport, zero_copy_if::sptr rx_transport, uint32_t sid, bool big_endian, @@ -29,39 +29,35 @@ public: private: void _stream_tx( - zero_copy_if* transport, - vrt::if_packet_info_t* pkt_info, - bool big_endian); + zero_copy_if* transport, vrt::if_packet_info_t* pkt_info, bool big_endian); - void _stream_rx( - zero_copy_if* transport, + void _stream_rx(zero_copy_if* transport, const vrt::if_packet_info_t* exp_pkt_info, bool big_endian); - void _initialize_chdr( - zero_copy_if::sptr tx_transport, + void _initialize_chdr(zero_copy_if::sptr tx_transport, zero_copy_if::sptr rx_transport, uint32_t sid, vrt::if_packet_info_t& pkt_info); void _reset_counters(void); - boost::shared_ptr<boost::thread> _tx_thread; - boost::shared_ptr<boost::thread> _rx_thread; + boost::shared_ptr<boost::thread> _tx_thread; + boost::shared_ptr<boost::thread> _rx_thread; - uint64_t _num_tx_packets; - uint64_t _num_rx_packets; - uint64_t _num_tx_timeouts; - uint64_t _num_rx_timeouts; - uint64_t _num_data_errors; + uint64_t _num_tx_packets; + uint64_t _num_rx_packets; + uint64_t _num_tx_timeouts; + uint64_t _num_rx_timeouts; + uint64_t _num_data_errors; - double _tx_timeout; - double _rx_timeout; + double _tx_timeout; + double _rx_timeout; - device_addr_t _results; + device_addr_t _results; }; -}} //namespace +}} // namespace uhd::transport #endif /* INCLUDED_LIBUHD_XPORT_BENCHMARKER_HPP */ diff --git a/host/lib/transport/zero_copy_flow_ctrl.cpp b/host/lib/transport/zero_copy_flow_ctrl.cpp index 25be35569..7d1ddd7e0 100644 --- a/host/lib/transport/zero_copy_flow_ctrl.cpp +++ b/host/lib/transport/zero_copy_flow_ctrl.cpp @@ -5,16 +5,16 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#include <uhd/transport/zero_copy_flow_ctrl.hpp> #include <uhd/transport/bounded_buffer.hpp> #include <uhd/transport/buffer_pool.hpp> +#include <uhd/transport/zero_copy_flow_ctrl.hpp> #include <uhd/utils/log.hpp> #include <uhd/utils/safe_call.hpp> +#include <boost/bind.hpp> #include <boost/format.hpp> #include <boost/make_shared.hpp> #include <boost/thread/mutex.hpp> #include <boost/thread/thread.hpp> -#include <boost/bind.hpp> using namespace uhd; using namespace uhd::transport; @@ -24,11 +24,8 @@ typedef bounded_buffer<managed_send_buffer::sptr> bounded_buffer_t; class zero_copy_flow_ctrl_msb : public managed_send_buffer { public: - zero_copy_flow_ctrl_msb( - flow_ctrl_func flow_ctrl - ) : - _mb(nullptr), - _flow_ctrl(flow_ctrl) + zero_copy_flow_ctrl_msb(flow_ctrl_func flow_ctrl) + : _mb(nullptr), _flow_ctrl(flow_ctrl) { /* NOP */ } @@ -40,18 +37,18 @@ public: void release() { - if (_mb) - { + if (_mb) { _mb->commit(size()); - while (_flow_ctrl and not _flow_ctrl(_mb)) {} + while (_flow_ctrl and not _flow_ctrl(_mb)) { + } _mb.reset(); } } - UHD_INLINE sptr get(sptr &mb) + UHD_INLINE sptr get(sptr& mb) { _mb = mb; - return make(this, _mb->cast<void *>(), _mb->size()); + return make(this, _mb->cast<void*>(), _mb->size()); } private: @@ -62,11 +59,7 @@ private: class zero_copy_flow_ctrl_mrb : public managed_recv_buffer { public: - zero_copy_flow_ctrl_mrb( - flow_ctrl_func flow_ctrl - ) : - _mb(NULL), - _flow_ctrl(flow_ctrl) + zero_copy_flow_ctrl_mrb(flow_ctrl_func flow_ctrl) : _mb(NULL), _flow_ctrl(flow_ctrl) { /* NOP */ } @@ -78,17 +71,17 @@ public: void release() { - if (_mb) - { + if (_mb) { _mb.reset(); } } - UHD_INLINE sptr get(sptr &mb) + UHD_INLINE sptr get(sptr& mb) { _mb = mb; - while (_flow_ctrl and not _flow_ctrl(_mb)) {} - return make(this, _mb->cast<void *>(), _mb->size()); + while (_flow_ctrl and not _flow_ctrl(_mb)) { + } + return make(this, _mb->cast<void*>(), _mb->size()); } private: @@ -101,36 +94,35 @@ private: * An intermediate transport that utilizes threading to free * the main thread from any receive work. **********************************************************************/ -class zero_copy_flow_ctrl_impl : public zero_copy_flow_ctrl { +class zero_copy_flow_ctrl_impl : public zero_copy_flow_ctrl +{ public: typedef boost::shared_ptr<zero_copy_flow_ctrl_impl> sptr; zero_copy_flow_ctrl_impl(zero_copy_if::sptr transport, flow_ctrl_func send_flow_ctrl, - flow_ctrl_func recv_flow_ctrl) : - _transport(transport), - _send_buffers(transport->get_num_send_frames()), - _recv_buffers(transport->get_num_recv_frames()), - _send_buff_index(0), - _recv_buff_index(0), - _send_flow_ctrl(send_flow_ctrl), - _recv_flow_ctrl(recv_flow_ctrl) + flow_ctrl_func recv_flow_ctrl) + : _transport(transport) + , _send_buffers(transport->get_num_send_frames()) + , _recv_buffers(transport->get_num_recv_frames()) + , _send_buff_index(0) + , _recv_buff_index(0) + , _send_flow_ctrl(send_flow_ctrl) + , _recv_flow_ctrl(recv_flow_ctrl) { UHD_LOG_TRACE("TRANSPORT", "Created zero_copy_flow_ctrl"); - for (size_t i = 0; i < transport->get_num_send_frames(); i++) - { - _send_buffers[i] = boost::make_shared<zero_copy_flow_ctrl_msb>(_send_flow_ctrl); + for (size_t i = 0; i < transport->get_num_send_frames(); i++) { + _send_buffers[i] = + boost::make_shared<zero_copy_flow_ctrl_msb>(_send_flow_ctrl); } - for (size_t i = 0; i < transport->get_num_recv_frames(); i++) - { - _recv_buffers[i] = boost::make_shared<zero_copy_flow_ctrl_mrb>(_recv_flow_ctrl); + for (size_t i = 0; i < transport->get_num_recv_frames(); i++) { + _recv_buffers[i] = + boost::make_shared<zero_copy_flow_ctrl_mrb>(_recv_flow_ctrl); } } - ~zero_copy_flow_ctrl_impl() - { - } + ~zero_copy_flow_ctrl_impl() {} /******************************************************************* * Receive implementation: @@ -140,9 +132,9 @@ public: { managed_recv_buffer::sptr ptr; managed_recv_buffer::sptr buff = _transport->get_recv_buff(timeout); - if (buff) - { - boost::shared_ptr<zero_copy_flow_ctrl_mrb> mb = _recv_buffers[_recv_buff_index++]; + if (buff) { + boost::shared_ptr<zero_copy_flow_ctrl_mrb> mb = + _recv_buffers[_recv_buff_index++]; _recv_buff_index %= _recv_buffers.size(); ptr = mb->get(buff); } @@ -167,9 +159,9 @@ public: { managed_send_buffer::sptr ptr; managed_send_buffer::sptr buff = _transport->get_send_buff(timeout); - if (buff) - { - boost::shared_ptr<zero_copy_flow_ctrl_msb> mb = _send_buffers[_send_buff_index++]; + if (buff) { + boost::shared_ptr<zero_copy_flow_ctrl_msb> mb = + _send_buffers[_send_buff_index++]; _send_buff_index %= _send_buffers.size(); ptr = mb->get(buff); } @@ -191,8 +183,8 @@ private: zero_copy_if::sptr _transport; // buffers - std::vector< boost::shared_ptr<zero_copy_flow_ctrl_msb> > _send_buffers; - std::vector< boost::shared_ptr<zero_copy_flow_ctrl_mrb> > _recv_buffers; + std::vector<boost::shared_ptr<zero_copy_flow_ctrl_msb>> _send_buffers; + std::vector<boost::shared_ptr<zero_copy_flow_ctrl_mrb>> _recv_buffers; size_t _send_buff_index; size_t _recv_buff_index; @@ -201,15 +193,12 @@ private: flow_ctrl_func _recv_flow_ctrl; }; -zero_copy_flow_ctrl::sptr zero_copy_flow_ctrl::make( - zero_copy_if::sptr transport, - flow_ctrl_func send_flow_ctrl, - flow_ctrl_func recv_flow_ctrl -) +zero_copy_flow_ctrl::sptr zero_copy_flow_ctrl::make(zero_copy_if::sptr transport, + flow_ctrl_func send_flow_ctrl, + flow_ctrl_func recv_flow_ctrl) { zero_copy_flow_ctrl_impl::sptr zero_copy_flow_ctrl( - new zero_copy_flow_ctrl_impl(transport, send_flow_ctrl, recv_flow_ctrl) - ); + new zero_copy_flow_ctrl_impl(transport, send_flow_ctrl, recv_flow_ctrl)); return zero_copy_flow_ctrl; } diff --git a/host/lib/transport/zero_copy_recv_offload.cpp b/host/lib/transport/zero_copy_recv_offload.cpp index 4a8a07a0c..7329dbdf3 100644 --- a/host/lib/transport/zero_copy_recv_offload.cpp +++ b/host/lib/transport/zero_copy_recv_offload.cpp @@ -5,18 +5,17 @@ // SPDX-License-Identifier: GPL-3.0-or-later // -#include <uhd/transport/zero_copy_recv_offload.hpp> #include <uhd/transport/bounded_buffer.hpp> #include <uhd/transport/buffer_pool.hpp> - +#include <uhd/transport/zero_copy_recv_offload.hpp> #include <uhd/utils/log.hpp> #include <uhd/utils/safe_call.hpp> #include <uhd/utils/thread.hpp> +#include <boost/bind.hpp> #include <boost/format.hpp> #include <boost/make_shared.hpp> #include <boost/thread/mutex.hpp> #include <boost/thread/thread.hpp> -#include <boost/bind.hpp> using namespace uhd; using namespace uhd::transport; @@ -28,23 +27,23 @@ typedef bounded_buffer<managed_recv_buffer::sptr> bounded_buffer_t; * An intermediate transport that utilizes threading to free * the main thread from any receive work. **********************************************************************/ -class zero_copy_recv_offload_impl : public zero_copy_recv_offload { +class zero_copy_recv_offload_impl : public zero_copy_recv_offload +{ public: typedef boost::shared_ptr<zero_copy_recv_offload_impl> sptr; - zero_copy_recv_offload_impl(zero_copy_if::sptr transport, - const double timeout) : - _transport(transport), _timeout(timeout), - _inbox(transport->get_num_recv_frames()), - _recv_done(false) + zero_copy_recv_offload_impl(zero_copy_if::sptr transport, const double timeout) + : _transport(transport) + , _timeout(timeout) + , _inbox(transport->get_num_recv_frames()) + , _recv_done(false) { - UHD_LOGGER_TRACE("XPORT") << "Created threaded transport" ; + UHD_LOGGER_TRACE("XPORT") << "Created threaded transport"; // Create the receive and send threads to offload // the system calls onto other threads - _recv_thread = boost::thread( - boost::bind(&zero_copy_recv_offload_impl::enqueue_recv, this) - ); + _recv_thread = + boost::thread(boost::bind(&zero_copy_recv_offload_impl::enqueue_recv, this)); set_thread_name(&_recv_thread, "zero_copy_recv"); } @@ -67,9 +66,7 @@ public: set_recv_done(); // Wait for them to join - UHD_SAFE_CALL( - _recv_thread.join(); - ) + UHD_SAFE_CALL(_recv_thread.join();) } // The receive thread function is responsible for @@ -78,7 +75,8 @@ public: { while (not is_recv_done()) { managed_recv_buffer::sptr buff = _transport->get_recv_buff(_timeout); - if (not buff) continue; + if (not buff) + continue; _inbox.push_with_timed_wait(buff, _timeout); } } @@ -135,16 +133,14 @@ private: // Threading bool _recv_done; boost::thread _recv_thread; - boost::mutex _recv_mutex; + boost::mutex _recv_mutex; }; zero_copy_recv_offload::sptr zero_copy_recv_offload::make( - zero_copy_if::sptr transport, - const double timeout) + zero_copy_if::sptr transport, const double timeout) { zero_copy_recv_offload_impl::sptr zero_copy_recv_offload( - new zero_copy_recv_offload_impl(transport, timeout) - ); + new zero_copy_recv_offload_impl(transport, timeout)); return zero_copy_recv_offload; } |