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/lib/include/uhdlib/transport/link_base.hpp | |
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/lib/include/uhdlib/transport/link_base.hpp')
-rw-r--r-- | host/lib/include/uhdlib/transport/link_base.hpp | 233 |
1 files changed, 233 insertions, 0 deletions
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 */ |