diff options
Diffstat (limited to 'host/lib')
-rw-r--r-- | host/lib/transport/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/lib/transport/udp_zero_copy_asio.cpp | 99 | ||||
-rw-r--r-- | host/lib/transport/zero_copy.cpp | 140 |
3 files changed, 158 insertions, 82 deletions
diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index ed8c35225..a74f7d527 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -50,4 +50,5 @@ LIBUHD_APPEND_SOURCES( ${CMAKE_SOURCE_DIR}/lib/transport/udp_simple.cpp ${CMAKE_SOURCE_DIR}/lib/transport/udp_zero_copy_asio.cpp ${CMAKE_SOURCE_DIR}/lib/transport/vrt_packet_handler.hpp + ${CMAKE_SOURCE_DIR}/lib/transport/zero_copy.cpp ) diff --git a/host/lib/transport/udp_zero_copy_asio.cpp b/host/lib/transport/udp_zero_copy_asio.cpp index d6b3a8336..0c604811a 100644 --- a/host/lib/transport/udp_zero_copy_asio.cpp +++ b/host/lib/transport/udp_zero_copy_asio.cpp @@ -32,63 +32,17 @@ static const size_t MAX_DGRAM_SIZE = 2048; //assume max size on send and recv static const double RECV_TIMEOUT = 0.1; // 100 ms /*********************************************************************** - * Managed receive buffer implementation for udp zero-copy asio: - **********************************************************************/ -class managed_recv_buffer_impl : public managed_recv_buffer{ -public: - managed_recv_buffer_impl(const boost::asio::const_buffer &buff) : _buff(buff){ - /* NOP */ - } - - ~managed_recv_buffer_impl(void){ - delete [] this->cast<const boost::uint8_t *>(); - } - -private: - const boost::asio::const_buffer &get(void) const{ - return _buff; - } - - const boost::asio::const_buffer _buff; -}; - -/*********************************************************************** - * Managed send buffer implementation for udp zero-copy asio: - **********************************************************************/ -class managed_send_buffer_impl : public managed_send_buffer{ -public: - managed_send_buffer_impl( - const boost::asio::mutable_buffer &buff, - boost::asio::ip::udp::socket *socket - ) : _buff(buff), _socket(socket){ - /* NOP */ - } - - ~managed_send_buffer_impl(void){ - /* NOP */ - } - - void commit(size_t num_bytes){ - _socket->send(boost::asio::buffer(_buff, num_bytes)); - } - -private: - const boost::asio::mutable_buffer &get(void) const{ - return _buff; - } - - const boost::asio::mutable_buffer _buff; - boost::asio::ip::udp::socket *_socket; -}; - -/*********************************************************************** * Zero Copy UDP implementation with ASIO: * This is the portable zero copy implementation for systems * where a faster, platform specific solution is not available. * 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_impl : public udp_zero_copy{ +class udp_zero_copy_impl: + public virtual phony_zero_copy_recv_if, + public virtual phony_zero_copy_send_if, + public virtual udp_zero_copy +{ public: typedef boost::shared_ptr<udp_zero_copy_impl> sptr; @@ -96,17 +50,14 @@ public: udp_zero_copy_impl(const std::string &addr, const std::string &port); ~udp_zero_copy_impl(void); - //send/recv - managed_recv_buffer::sptr get_recv_buff(void); - managed_send_buffer::sptr get_send_buff(void); - - //manage buffer + //get size for internal socket buffer template <typename Opt> size_t get_buff_size(void){ Opt option; _socket->get_option(option); return option.value(); } + //set size for internal socket buffer template <typename Opt> size_t resize_buff(size_t num_bytes){ Opt option(num_bytes); _socket->set_option(option); @@ -117,13 +68,19 @@ private: boost::asio::ip::udp::socket *_socket; boost::asio::io_service _io_service; - //send and recv buffer memory (allocated once) - boost::uint8_t _send_mem[MIN_SOCK_BUFF_SIZE]; + size_t recv(const boost::asio::mutable_buffer &buff){ + return _socket->receive(boost::asio::buffer(buff)); + } - managed_send_buffer::sptr _send_buff; + size_t send(const boost::asio::const_buffer &buff){ + return _socket->send(boost::asio::buffer(buff)); + } }; -udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port){ +udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::string &port): + phony_zero_copy_recv_if(MAX_DGRAM_SIZE), + phony_zero_copy_send_if(MAX_DGRAM_SIZE) +{ //std::cout << boost::format("Creating udp transport for %s %s") % addr % port << std::endl; // resolve the address @@ -136,11 +93,6 @@ udp_zero_copy_impl::udp_zero_copy_impl(const std::string &addr, const std::strin _socket->open(boost::asio::ip::udp::v4()); _socket->connect(receiver_endpoint); - // create the managed send buff (just once) - _send_buff = managed_send_buffer::sptr(new managed_send_buffer_impl( - boost::asio::buffer(_send_mem, MIN_SOCK_BUFF_SIZE), _socket - )); - // set recv timeout timeval tv; tv.tv_sec = 0; @@ -156,23 +108,6 @@ udp_zero_copy_impl::~udp_zero_copy_impl(void){ delete _socket; } -managed_recv_buffer::sptr udp_zero_copy_impl::get_recv_buff(void){ - //allocate memory - boost::uint8_t *recv_mem = new boost::uint8_t[MAX_DGRAM_SIZE]; - - //call recv() with timeout option - size_t num_bytes = _socket->receive(boost::asio::buffer(recv_mem, MAX_DGRAM_SIZE)); - - //create a new managed buffer to house the data - return managed_recv_buffer::sptr( - new managed_recv_buffer_impl(boost::asio::buffer(recv_mem, num_bytes)) - ); -} - -managed_send_buffer::sptr udp_zero_copy_impl::get_send_buff(void){ - return _send_buff; //FIXME there is only ever one send buff, we assume that the caller doesnt hang onto these -} - /*********************************************************************** * UDP zero copy make function **********************************************************************/ diff --git a/host/lib/transport/zero_copy.cpp b/host/lib/transport/zero_copy.cpp new file mode 100644 index 000000000..f69fd2774 --- /dev/null +++ b/host/lib/transport/zero_copy.cpp @@ -0,0 +1,140 @@ +// +// Copyright 2010 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see <http://www.gnu.org/licenses/>. +// + +#include <uhd/transport/zero_copy.hpp> +#include <boost/cstdint.hpp> +#include <boost/function.hpp> +#include <boost/bind.hpp> + +using namespace uhd::transport; + +/*********************************************************************** + * The pure-virtual deconstructor needs an implementation to be happy + **********************************************************************/ +managed_recv_buffer::~managed_recv_buffer(void){ + /* NOP */ +} + +/*********************************************************************** + * Phony zero-copy recv interface implementation + **********************************************************************/ + +//! phony zero-copy recv buffer implementation +class managed_recv_buffer_impl : public managed_recv_buffer{ +public: + managed_recv_buffer_impl(const boost::asio::const_buffer &buff) : _buff(buff){ + /* NOP */ + } + + ~managed_recv_buffer_impl(void){ + delete [] this->cast<const boost::uint8_t *>(); + } + +private: + const boost::asio::const_buffer &get(void) const{ + return _buff; + } + + const boost::asio::const_buffer _buff; +}; + +//! phony zero-copy recv interface implementation +struct phony_zero_copy_recv_if::impl{ + size_t max_buff_size; +}; + +phony_zero_copy_recv_if::phony_zero_copy_recv_if(size_t max_buff_size){ + _impl = new impl; + _impl->max_buff_size = max_buff_size; +} + +phony_zero_copy_recv_if::~phony_zero_copy_recv_if(void){ + delete _impl; +} + +managed_recv_buffer::sptr phony_zero_copy_recv_if::get_recv_buff(void){ + //allocate memory + boost::uint8_t *recv_mem = new boost::uint8_t[_impl->max_buff_size]; + + //call recv() with timeout option + size_t num_bytes = this->recv(boost::asio::buffer(recv_mem, _impl->max_buff_size)); + + //create a new managed buffer to house the data + return managed_recv_buffer::sptr( + new managed_recv_buffer_impl(boost::asio::buffer(recv_mem, num_bytes)) + ); +} + +/*********************************************************************** + * Phony zero-copy send interface implementation + **********************************************************************/ + +//! phony zero-copy send buffer implementation +class managed_send_buffer_impl : public managed_send_buffer{ +public: + typedef boost::function<size_t(const boost::asio::const_buffer &)> send_fcn_t; + + managed_send_buffer_impl( + const boost::asio::mutable_buffer &buff, + const send_fcn_t &send_fcn + ): + _buff(buff), + _send_fcn(send_fcn) + { + /* NOP */ + } + + ~managed_send_buffer_impl(void){ + /* NOP */ + } + + void commit(size_t num_bytes){ + _send_fcn(boost::asio::buffer(_buff, num_bytes)); + } + +private: + const boost::asio::mutable_buffer &get(void) const{ + return _buff; + } + + const boost::asio::mutable_buffer _buff; + const send_fcn_t _send_fcn; +}; + +//! phony zero-copy send interface implementation +struct phony_zero_copy_send_if::impl{ + boost::uint8_t *send_mem; + managed_send_buffer::sptr send_buff; +}; + +phony_zero_copy_send_if::phony_zero_copy_send_if(size_t max_buff_size){ + _impl = new impl; + _impl->send_mem = new boost::uint8_t[max_buff_size]; + _impl->send_buff = managed_send_buffer::sptr(new managed_send_buffer_impl( + boost::asio::buffer(_impl->send_mem, max_buff_size), + boost::bind(&phony_zero_copy_send_if::send, this, _1) + )); +} + +phony_zero_copy_send_if::~phony_zero_copy_send_if(void){ + delete [] _impl->send_mem; + delete _impl; +} + +managed_send_buffer::sptr phony_zero_copy_send_if::get_send_buff(void){ + return _impl->send_buff; //FIXME there is only ever one send buff, we assume that the caller doesnt hang onto these +} |