summaryrefslogtreecommitdiffstats
path: root/host/include
diff options
context:
space:
mode:
Diffstat (limited to 'host/include')
-rw-r--r--host/include/uhd/transport/CMakeLists.txt2
-rw-r--r--host/include/uhd/transport/alignment_buffer.hpp134
-rw-r--r--host/include/uhd/transport/bounded_buffer.hpp146
-rw-r--r--host/include/uhd/transport/zero_copy.hpp19
4 files changed, 301 insertions, 0 deletions
diff --git a/host/include/uhd/transport/CMakeLists.txt b/host/include/uhd/transport/CMakeLists.txt
index 4cefffa24..23a4aae94 100644
--- a/host/include/uhd/transport/CMakeLists.txt
+++ b/host/include/uhd/transport/CMakeLists.txt
@@ -17,6 +17,8 @@
INSTALL(FILES
+ alignment_buffer.hpp
+ bounded_buffer.hpp
convert_types.hpp
if_addrs.hpp
udp_simple.hpp
diff --git a/host/include/uhd/transport/alignment_buffer.hpp b/host/include/uhd/transport/alignment_buffer.hpp
new file mode 100644
index 000000000..dc6ccc3ed
--- /dev/null
+++ b/host/include/uhd/transport/alignment_buffer.hpp
@@ -0,0 +1,134 @@
+//
+// 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/>.
+//
+
+#ifndef INCLUDED_UHD_TRANSPORT_ALIGNMENT_BUFFER_HPP
+#define INCLUDED_UHD_TRANSPORT_ALIGNMENT_BUFFER_HPP
+
+#include <uhd/config.hpp>
+#include <uhd/transport/bounded_buffer.hpp>
+#include <boost/thread/condition_variable.hpp>
+#include <boost/shared_ptr.hpp>
+#include <utility>
+#include <vector>
+
+namespace uhd{ namespace transport{
+
+ /*!
+ * Imlement a templated alignment buffer:
+ * Used for aligning asynchronously pushed elements with matching ids.
+ */
+ template <typename elem_type, typename seq_type> class alignment_buffer{
+ public:
+ typedef boost::shared_ptr<alignment_buffer<elem_type, seq_type> > sptr;
+
+ /*!
+ * Make a new alignment buffer object.
+ * \param capacity the maximum elements per index
+ * \param width the number of elements to align
+ */
+ static sptr make(size_t capacity, size_t width){
+ return sptr(new alignment_buffer(capacity, width));
+ }
+
+ /*!
+ * Push an element with sequence id into the buffer at index.
+ * \param elem the element to push
+ * \param seq the sequence identifier
+ * \param index the buffer index
+ * \return true if the element fit without popping for space
+ */
+ UHD_INLINE bool push_with_pop_on_full(
+ const elem_type &elem,
+ const seq_type &seq,
+ size_t index
+ ){
+ return _buffs[index]->push_with_pop_on_full(buff_contents_type(elem, seq));
+ }
+
+ /*!
+ * Pop an aligned set of elements from this alignment buffer.
+ * \param elems a collection to store the aligned elements
+ * \param time the timeout time
+ * \return false when the operation times out
+ */
+ template <typename elems_type, typename time_type>
+ bool pop_elems_with_timed_wait(elems_type &elems, const time_type &time){
+ buff_contents_type buff_contents_tmp;
+ std::list<size_t> indexes_to_do(_all_indexes);
+
+ //do an initial pop to load an initial sequence id
+ size_t index = indexes_to_do.front();
+ if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false;
+ elems[index] = buff_contents_tmp.first;
+ seq_type expected_seq_id = buff_contents_tmp.second;
+ indexes_to_do.pop_front();
+
+ //get an aligned set of elements from the buffers:
+ while(indexes_to_do.size() != 0){
+ //pop an element off for this index
+ index = indexes_to_do.front();
+ if (not _buffs[index]->pop_with_timed_wait(buff_contents_tmp, time)) return false;
+
+ //if the sequence id matches:
+ // store the popped element into the output,
+ // remove this index from the list and continue
+ if (buff_contents_tmp.second == expected_seq_id){
+ elems[index] = buff_contents_tmp.first;
+ indexes_to_do.pop_front();
+ continue;
+ }
+
+ //if the sequence id is older:
+ // continue with the same index to try again
+ if (buff_contents_tmp.second < expected_seq_id){
+ continue;
+ }
+
+ //if the sequence id is newer:
+ // store the popped element into the output,
+ // add all other indexes back into the list
+ if (buff_contents_tmp.second > expected_seq_id){
+ elems[index] = buff_contents_tmp.first;
+ expected_seq_id = buff_contents_tmp.second;
+ indexes_to_do = _all_indexes;
+ indexes_to_do.remove(index);
+ continue;
+ }
+ }
+ return true;
+ }
+
+ private:
+ //a vector of bounded buffers for each index
+ typedef std::pair<elem_type, seq_type> buff_contents_type;
+ typedef bounded_buffer<buff_contents_type> bounded_buffer_type;
+ typedef boost::shared_ptr<bounded_buffer_type> bounded_buffer_sptr;
+ std::vector<bounded_buffer_sptr> _buffs;
+ std::list<size_t> _all_indexes;
+
+ //private constructor
+ alignment_buffer(size_t capacity, size_t width){
+ for (size_t i = 0; i < width; i++){
+ _buffs.push_back(bounded_buffer_type::make(capacity));
+ _all_indexes.push_back(i);
+ }
+ }
+ };
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_ALIGNMENT_BUFFER_HPP */
diff --git a/host/include/uhd/transport/bounded_buffer.hpp b/host/include/uhd/transport/bounded_buffer.hpp
new file mode 100644
index 000000000..baecd6382
--- /dev/null
+++ b/host/include/uhd/transport/bounded_buffer.hpp
@@ -0,0 +1,146 @@
+//
+// 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/>.
+//
+
+#ifndef INCLUDED_UHD_TRANSPORT_BOUNDED_BUFFER_HPP
+#define INCLUDED_UHD_TRANSPORT_BOUNDED_BUFFER_HPP
+
+#include <uhd/config.hpp>
+#include <boost/bind.hpp>
+#include <boost/shared_ptr.hpp>
+#include <boost/circular_buffer.hpp>
+#include <boost/thread/condition.hpp>
+
+namespace uhd{ namespace transport{
+
+ /*!
+ * Imlement a templated bounded buffer:
+ * Used for passing elements between threads in a producer-consumer model.
+ * The bounded buffer implemented waits and timed waits with condition variables.
+ * The pop operation blocks on the bounded_buffer to become non empty.
+ * The push operation blocks on the bounded_buffer to become non full.
+ */
+ template <typename elem_type> class bounded_buffer{
+ public:
+ typedef boost::shared_ptr<bounded_buffer<elem_type> > sptr;
+
+ /*!
+ * Make a new bounded buffer object.
+ * \param capacity the bounded_buffer capacity
+ */
+ static sptr make(size_t capacity){
+ return sptr(new bounded_buffer(capacity));
+ }
+
+ /*!
+ * Push a new element into the bounded buffer.
+ * If the buffer is full prior to the push,
+ * make room by poping the oldest element.
+ * \param elem the new element to push
+ * \return true if the element fit without popping for space
+ */
+ UHD_INLINE bool push_with_pop_on_full(const elem_type &elem){
+ boost::unique_lock<boost::mutex> lock(_mutex);
+ if(_buffer.full()){
+ _buffer.pop_back();
+ _buffer.push_front(elem);
+ lock.unlock();
+ _empty_cond.notify_one();
+ return false;
+ }
+ else{
+ _buffer.push_front(elem);
+ lock.unlock();
+ _empty_cond.notify_one();
+ return true;
+ }
+ }
+
+ /*!
+ * Push a new element into the bounded_buffer.
+ * Wait until the bounded_buffer becomes non-full.
+ * \param elem the new element to push
+ */
+ UHD_INLINE void push_with_wait(const elem_type &elem){
+ boost::unique_lock<boost::mutex> lock(_mutex);
+ _full_cond.wait(lock, boost::bind(&bounded_buffer<elem_type>::not_full, this));
+ _buffer.push_front(elem);
+ lock.unlock();
+ _empty_cond.notify_one();
+ }
+
+ /*!
+ * Push a new element into the bounded_buffer.
+ * Wait until the bounded_buffer becomes non-full or timeout.
+ * \param elem the new element to push
+ * \param time the timeout time
+ * \return false when the operation times out
+ */
+ template<typename time_type> UHD_INLINE
+ bool push_with_timed_wait(const elem_type &elem, const time_type &time){
+ boost::unique_lock<boost::mutex> lock(_mutex);
+ if (not _full_cond.timed_wait(lock, time, boost::bind(&bounded_buffer<elem_type>::not_full, this))) return false;
+ _buffer.push_front(elem);
+ lock.unlock();
+ _empty_cond.notify_one();
+ return true;
+ }
+
+ /*!
+ * Pop an element from the bounded_buffer.
+ * Wait until the bounded_buffer becomes non-empty.
+ * \param elem the element reference pop to
+ */
+ UHD_INLINE void pop_with_wait(elem_type &elem){
+ boost::unique_lock<boost::mutex> lock(_mutex);
+ _empty_cond.wait(lock, boost::bind(&bounded_buffer<elem_type>::not_empty, this));
+ elem = _buffer.back(); _buffer.pop_back();
+ lock.unlock();
+ _full_cond.notify_one();
+ }
+
+ /*!
+ * Pop an element from the bounded_buffer.
+ * Wait until the bounded_buffer becomes non-empty or timeout.
+ * \param elem the element reference pop to
+ * \param time the timeout time
+ * \return false when the operation times out
+ */
+ template<typename time_type> UHD_INLINE
+ bool pop_with_timed_wait(elem_type &elem, const time_type &time){
+ boost::unique_lock<boost::mutex> lock(_mutex);
+ if (not _empty_cond.timed_wait(lock, time, boost::bind(&bounded_buffer<elem_type>::not_empty, this))) return false;
+ elem = _buffer.back(); _buffer.pop_back();
+ lock.unlock();
+ _full_cond.notify_one();
+ return true;
+ }
+
+ private:
+ boost::mutex _mutex;
+ boost::condition _empty_cond, _full_cond;
+ boost::circular_buffer<elem_type> _buffer;
+
+ bool not_full(void) const{return not _buffer.full();}
+ bool not_empty(void) const{return not _buffer.empty();}
+
+ //private constructor
+ bounded_buffer(size_t capacity) : _buffer(capacity){}
+ };
+
+}} //namespace
+
+#endif /* INCLUDED_UHD_TRANSPORT_BOUNDED_BUFFER_HPP */
diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp
index 2efabaccf..d6eb89a91 100644
--- a/host/include/uhd/transport/zero_copy.hpp
+++ b/host/include/uhd/transport/zero_copy.hpp
@@ -124,9 +124,28 @@ namespace uhd{ namespace transport{
virtual managed_recv_buffer::sptr get_recv_buff(void) = 0;
/*!
+ * Get the maximum number of receive frames:
+ * The maximum number of valid managed recv buffers,
+ * or the maximum number of frames in the ring buffer,
+ * depending upon the underlying implementation.
+ * \return number of frames
+ */
+ virtual size_t get_num_recv_frames(void) const = 0;
+
+ /*!
* Get a new send buffer from this transport object.
*/
virtual managed_send_buffer::sptr get_send_buff(void) = 0;
+
+ /*!
+ * Get the maximum number of send frames:
+ * The maximum number of valid managed send buffers,
+ * or the maximum number of frames in the ring buffer,
+ * depending upon the underlying implementation.
+ * \return number of frames
+ */
+ virtual size_t get_num_send_frames(void) const = 0;
+
};
/*!