diff options
author | Ciro Nishiguchi <ciro.nishiguchi@ni.com> | 2019-03-25 12:41:34 -0500 |
---|---|---|
committer | Martin Braun <martin.braun@ettus.com> | 2019-11-26 11:49:18 -0800 |
commit | 9c2d90292b9a613fb290c5a04e99014d1a9118ab (patch) | |
tree | e240e14d30e0d40e0a1b4f8aff12542d1efb4ba8 /host | |
parent | 6ec8cf3eeac70d4458ad7a4f7f1eea4f082c140d (diff) | |
download | uhd-9c2d90292b9a613fb290c5a04e99014d1a9118ab.tar.gz uhd-9c2d90292b9a613fb290c5a04e99014d1a9118ab.tar.bz2 uhd-9c2d90292b9a613fb290c5a04e99014d1a9118ab.zip |
uhd: add new transport interface and base class implementation
New interface aimed to replace zero_copy_if for new code, including new
RFNoC development and redesign of streamer objects.
Generic implementation of send and receive transport interfaces to allow
reuse by various transport types. Derived classes implement
transport-specific functions that are invoked by the base classes
through CRTP.
Diffstat (limited to 'host')
-rw-r--r-- | host/include/uhd/transport/CMakeLists.txt | 1 | ||||
-rw-r--r-- | host/include/uhd/transport/frame_buff.hpp | 69 | ||||
-rw-r--r-- | host/lib/include/uhdlib/transport/link_base.hpp | 233 | ||||
-rw-r--r-- | host/lib/include/uhdlib/transport/link_if.hpp | 101 |
4 files changed, 404 insertions, 0 deletions
diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt index d0810e502..400b3db0b 100644 --- a/host/include/uhd/transport/CMakeLists.txt +++ b/host/include/uhd/transport/CMakeLists.txt @@ -10,6 +10,7 @@ UHD_INSTALL(FILES bounded_buffer.ipp buffer_pool.hpp chdr.hpp + frame_buff.hpp if_addrs.hpp udp_constants.hpp udp_simple.hpp diff --git a/host/include/uhd/transport/frame_buff.hpp b/host/include/uhd/transport/frame_buff.hpp new file mode 100644 index 000000000..c335f0c4b --- /dev/null +++ b/host/include/uhd/transport/frame_buff.hpp @@ -0,0 +1,69 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_UHD_TRANSPORT_FRAME_BUFF_HPP +#define INCLUDED_UHD_TRANSPORT_FRAME_BUFF_HPP + +#include <memory> + +namespace uhd { namespace transport { + +/*! + * Contains a reference to a frame buffer managed by a link. + */ +class frame_buff +{ +public: + /*! + * No-op deleter to prevent unique_ptr from deleting the buffer if the + * pointer goes out of scope. The lifetime of the buffers is controlled + * by the links. + */ + struct deleter + { + void operator()(frame_buff*) {} + }; + + using uptr = std::unique_ptr<frame_buff, deleter>; + + /*! + * Get the raw data buffer contained within the frame buffer + * \return a pointer to the buffer memory. + */ + void* data() const + { + return _data; + } + + /*! + * Returns the size of the packet + * \return the size of the packet contained in the frame buffer, in bytes. + */ + size_t packet_size() const + { + return _packet_size; + } + + /*! + * Sets the size of the packet contained in the frame buffer, in bytes. + * \param size Number of bytes occupied in the buffer + */ + void set_packet_size(size_t size) + { + _packet_size = size; + } + +protected: + /*! Pointer to data of current frame */ + void* _data = nullptr; + + /*! Size of packet in current frame */ + size_t _packet_size = 0; +}; + +}} // namespace uhd::transport + +#endif /* INCLUDED_UHD_TRANSPORT_FRAME_BUFF_HPP */ diff --git a/host/lib/include/uhdlib/transport/link_base.hpp b/host/lib/include/uhdlib/transport/link_base.hpp new file mode 100644 index 000000000..e4d329e2a --- /dev/null +++ b/host/lib/include/uhdlib/transport/link_base.hpp @@ -0,0 +1,233 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#ifndef INCLUDED_UHDLIB_TRANSPORT_LINK_BASE_HPP +#define INCLUDED_UHDLIB_TRANSPORT_LINK_BASE_HPP + +#include <uhdlib/transport/link_if.hpp> +#include <cassert> +#include <vector> + +namespace uhd { namespace transport { +namespace detail { + +/*! + * Container for free buffers used by link base classes. + */ +class free_buff_pool +{ +public: + free_buff_pool(const size_t capacity) + { + _buffs.reserve(capacity); + } + + frame_buff* pop() + { + // Free buffer pool should not be empty unless user has requested more + // buffers than the number of frames in the link. + assert(!_buffs.empty()); + + frame_buff* buff = _buffs.back(); + _buffs.pop_back(); + return buff; + } + + void push(frame_buff* buff) + { + _buffs.push_back(buff); + } + +private: + std::vector<frame_buff*> _buffs; +}; + +} // namespace detail + +/*! + * Reusable base class implementation of send_link_iface. Link implementations + * should derive from this template and pass their own type as the derived_t + * template parameter. + * + * The base class template manages a pool of frame_buff pointers and implements + * the link interface methods. + * + * This template requires the following methods in the derived class: + * bool get_send_buf_derived(frame_buff& buf, int32_t timeout_ms); + * void release_send_buf_derived(frame_buff& buf); + * + * Additionally, the subclass must call preload_free_buf for each frame_buff + * object it owns during initialization to add it to the free buffer pool. + * + * \param derived_t type of the derived class + */ +template <typename derived_t> +class send_link_base : public virtual send_link_if +{ +public: + send_link_base(const size_t num_frames, const size_t frame_size) + : _send_frame_size(frame_size) + , _num_send_frames(num_frames) + , _free_send_buffs(num_frames) + { + } + + virtual size_t get_num_send_frames() const + { + return _num_send_frames; + } + + virtual size_t get_send_frame_size() const + { + return _send_frame_size; + } + + virtual frame_buff::uptr get_send_buff(int32_t timeout_ms) + { + frame_buff* buff = _free_send_buffs.pop(); + + // Call the derived class for link-specific implementation + auto* derived = static_cast<derived_t*>(this); + + if (!derived->get_send_buff_derived(*buff, timeout_ms)) { + _free_send_buffs.push(buff); + return frame_buff::uptr(); + } + + return frame_buff::uptr(buff); + } + + virtual void release_send_buff(frame_buff::uptr buff) + { + frame_buff* buff_ptr = buff.release(); + assert(buff_ptr); + + if (buff_ptr->packet_size() != 0) { + // Call the derived class for link-specific implementation + auto* derived = static_cast<derived_t*>(this); + derived->release_send_buff_derived(*buff_ptr); + } + + // Reset buff and re-add to free pool + buff_ptr->set_packet_size(0); + _free_send_buffs.push(buff_ptr); + } + +protected: + /*! + * Add buffer pointer to free buffer pool. + * + * Derived classes should call this method during initialization for each + * frame buffer it owns. + * + * \param buffer pointer to the buffer to add to the free buffer pool. + */ + void preload_free_buff(frame_buff* buff) + { + _free_send_buffs.push(buff); + } + +private: + size_t _send_frame_size; + size_t _num_send_frames; + detail::free_buff_pool _free_send_buffs; +}; + +/*! + * Reusable base class implementation of recv_link_if. Link implementations + * should derive from this template and pass their own type as the derived_t + * template parameter. + * + * The base class template manages a pool of free_buff pointers and implements + * the link interface methods. + * + * This template requires the following methods in the derived class: + * bool get_recv_buff_derived(frame_buff& buff, int32_t timeout_ms); + * void release_recv_buff_derived(frame_buff& buff); + * + * Additionally, the subclass must call preload_free_buff for each + * frame_buff object it owns during initialization to add it to the free + * buff pool. + * + * \param derived_t type of the derived class + */ +template <typename derived_t> +class recv_link_base : public virtual recv_link_if +{ +public: + recv_link_base(const size_t num_frames, const size_t frame_size) + : _recv_frame_size(frame_size) + , _num_recv_frames(num_frames) + , _free_recv_buffs(num_frames) + { + } + + virtual size_t get_num_recv_frames() const + { + return _num_recv_frames; + } + + virtual size_t get_recv_frame_size() const + { + return _recv_frame_size; + } + + virtual frame_buff::uptr get_recv_buff(int32_t timeout_ms) + { + frame_buff* buff = _free_recv_buffs.pop(); + + // Call the derived class for link specific implementation + auto* derived = static_cast<derived_t*>(this); + + size_t len = derived->get_recv_buff_derived(*buff, timeout_ms); + + if (len == 0) { + _free_recv_buffs.push(buff); + return frame_buff::uptr(); + } else { + buff->set_packet_size(len); + return frame_buff::uptr(buff); + } + } + + virtual void release_recv_buff(frame_buff::uptr buff) + { + frame_buff* buff_ptr = buff.release(); + assert(buff_ptr); + + // Call the derived class for link specific implementation + auto* derived = static_cast<derived_t*>(this); + + derived->release_recv_buff_derived(*buff_ptr); + + // Reset buffer and re-add to free pool + buff_ptr->set_packet_size(0); + _free_recv_buffs.push(buff_ptr); + } + +protected: + /*! + * Add buffer pointer to free buffer pool. + * + * Derived classes should call this method during initialization for each + * frame buffer it owns. + * + * \param buffer pointer to the buffer to add to the free buffer pool. + */ + void preload_free_buff(frame_buff* buff) + { + _free_recv_buffs.push(buff); + } + +private: + size_t _recv_frame_size; + size_t _num_recv_frames; + detail::free_buff_pool _free_recv_buffs; +}; + +}} // namespace uhd::transport + +#endif /* INCLUDED_UHDLIB_TRANSPORT_LINK_BASE_HPP */ diff --git a/host/lib/include/uhdlib/transport/link_if.hpp b/host/lib/include/uhdlib/transport/link_if.hpp new file mode 100644 index 000000000..60376e571 --- /dev/null +++ b/host/lib/include/uhdlib/transport/link_if.hpp @@ -0,0 +1,101 @@ +// +// Copyright 2019 Ettus Research, a National Instruments Brand +// +// SPDX-License-Identifier: GPL-3.0-or-later +// + +#include <uhd/transport/frame_buff.hpp> +#include <memory> + +#ifndef INCLUDED_UHDLIB_TRANSPORT_LINK_IF_HPP +# define INCLUDED_UHDLIB_TRANSPORT_LINK_IF_HPP + +namespace uhd { namespace transport { + +/*! + * Link interface for transmitting packets. + */ +class send_link_if +{ +public: + using sptr = std::shared_ptr<send_link_if>; + + /*! + * Get the number of frame buffers that can be queued by this link. + */ + virtual size_t get_num_send_frames() const = 0; + + /*! + * Get the maximum capacity of a frame buffer. + */ + virtual size_t get_send_frame_size() const = 0; + + /*! + * Get an empty frame buffer in which to write packet contents. + * + * \param timeout_ms a positive timeout value specifies the maximum number + of ms to wait, a negative value specifies to block + until successful, and a value of 0 specifies no wait. + * \return a frame buffer, or null uptr if timeout occurs + */ + virtual frame_buff::uptr get_send_buff(int32_t timeout_ms) = 0; + + /*! + * Send a packet with the contents of the frame buffer and release the + * buffer, allowing the link driver to reuse it. If the size of the frame + * buffer is 0, the buffer is released with no packet being sent. + * + * \param buffer frame buffer containing packet data + * + * Throws an exception if an I/O error occurs while sending + */ + virtual void release_send_buff(frame_buff::uptr buff) = 0; + + send_link_if() = default; + send_link_if(const send_link_if&) = delete; + send_link_if& operator=(const send_link_if&) = delete; +}; + +/*! + * Link interface for receiving packets. + */ +class recv_link_if +{ +public: + using sptr = std::shared_ptr<recv_link_if>; + + /*! + * Get the number of frame buffers that can be queued by this link. + */ + virtual size_t get_num_recv_frames() const = 0; + + /*! + * Get the maximum capacity of a frame buffer. + */ + virtual size_t get_recv_frame_size() const = 0; + + /*! + * Receive a packet and return a frame buffer containing the packet data. + * + * \param timeout_ms a positive timeout value specifies the maximum number + of ms to wait, a negative value specifies to block + until successful, and a value of 0 specifies no wait. + * \return a frame buffer, or null uptr if timeout occurs + */ + virtual frame_buff::uptr get_recv_buff(int32_t timeout_ms) = 0; + + /*! + * Release a frame buffer, allowing the link driver to reuse it. + * + * \param buffer frame buffer to release for reuse by the link + */ + virtual void release_recv_buff(frame_buff::uptr buff) = 0; + + recv_link_if() = default; + recv_link_if(const recv_link_if&) = delete; + recv_link_if& operator=(const recv_link_if&) = delete; +}; + +}} // namespace uhd::transport + +#endif /* INCLUDED_UHDLIB_TRANSPORT_LINK_IF_HPP */ |