summaryrefslogtreecommitdiffstats
path: root/host/include
diff options
context:
space:
mode:
Diffstat (limited to 'host/include')
-rw-r--r--host/include/uhd/config.hpp3
-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/udp_zero_copy.hpp2
-rw-r--r--host/include/uhd/transport/zero_copy.hpp264
-rw-r--r--host/include/uhd/usrp/dboard_base.hpp4
-rw-r--r--host/include/uhd/utils/CMakeLists.txt1
-rw-r--r--host/include/uhd/utils/exception.hpp7
-rw-r--r--host/include/uhd/utils/pimpl.hpp55
10 files changed, 525 insertions, 93 deletions
diff --git a/host/include/uhd/config.hpp b/host/include/uhd/config.hpp
index fea95145c..b23a4dc00 100644
--- a/host/include/uhd/config.hpp
+++ b/host/include/uhd/config.hpp
@@ -31,10 +31,11 @@
# pragma warning(disable: 4251) // class 'A<T>' needs to have dll-interface to be used by clients of class 'B'
//# pragma warning(disable: 4127) // conditional expression is constant
//# pragma warning(disable: 4290) // C++ exception specification ignored except to ...
-//# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored
+# pragma warning(disable: 4180) // qualifier applied to function type has no meaning; ignored
# pragma warning(disable: 4275) // non dll-interface class ... used as base for dll-interface class ...
//# pragma warning(disable: 4267) // 'var' : conversion from 'size_t' to 'type', possible loss of data
//# pragma warning(disable: 4511) // 'class' : copy constructor could not be generated
+# pragma warning(disable: 4250) // 'class' : inherits 'method' via dominance
#endif
//define logical operators
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/udp_zero_copy.hpp b/host/include/uhd/transport/udp_zero_copy.hpp
index 525606a9f..818709973 100644
--- a/host/include/uhd/transport/udp_zero_copy.hpp
+++ b/host/include/uhd/transport/udp_zero_copy.hpp
@@ -34,7 +34,7 @@ namespace uhd{ namespace transport{
* If no platform specific solution is available, make returns a boost asio
* implementation that wraps the functionality around a standard send/recv calls.
*/
-class UHD_API udp_zero_copy : public zero_copy_if{
+class UHD_API udp_zero_copy : public virtual zero_copy_if{
public:
typedef boost::shared_ptr<udp_zero_copy> sptr;
diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp
index 52c6d4143..2815e3189 100644
--- a/host/include/uhd/transport/zero_copy.hpp
+++ b/host/include/uhd/transport/zero_copy.hpp
@@ -19,115 +19,201 @@
#define INCLUDED_UHD_TRANSPORT_ZERO_COPY_HPP
#include <uhd/config.hpp>
+#include <uhd/utils/pimpl.hpp>
#include <boost/asio/buffer.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
namespace uhd{ namespace transport{
-/*!
- * A managed receive buffer:
- * Contains a reference to transport-managed memory,
- * and a method to release the memory after reading.
- */
-class UHD_API managed_recv_buffer : boost::noncopyable{
-public:
- typedef boost::shared_ptr<managed_recv_buffer> sptr;
-
- /*!
- * Managed recv buffer destructor:
- * Signal to the transport that we are done with the buffer.
- * This should be called to release the buffer to the transport.
- * After calling, the referenced memory should be considered invalid.
- */
- virtual ~managed_recv_buffer(void){};
-
- /*!
- * Get the size of the underlying buffer.
- * \return the number of bytes
- */
- size_t size(void) const{
- return boost::asio::buffer_size(this->get());
- }
-
- /*!
- * Get a pointer to the underlying buffer.
- * \return a pointer into memory
- */
- template <class T> T cast(void) const{
- return boost::asio::buffer_cast<T>(this->get());
- }
-
-private:
- /*!
- * Get a reference to the internal const buffer.
- * The buffer has a reference to memory and a size.
- * \return a boost asio const buffer
- */
- virtual const boost::asio::const_buffer &get(void) const = 0;
-};
-
-/*!
- * A managed send buffer:
- * Contains a reference to transport-managed memory,
- * and a method to release the memory after writing.
- */
-class UHD_API managed_send_buffer : boost::noncopyable{
-public:
- typedef boost::shared_ptr<managed_send_buffer> sptr;
-
- /*!
- * Signal to the transport that we are done with the buffer.
- * This should be called to commit the write to the transport object.
- * After calling, the referenced memory should be considered invalid.
- * \param num_bytes the number of bytes written into the buffer
- */
- virtual void commit(size_t num_bytes) = 0;
-
/*!
- * Get the size of the underlying buffer.
- * \return the number of bytes
+ * A managed receive buffer:
+ * Contains a reference to transport-managed memory,
+ * and a method to release the memory after reading.
*/
- size_t size(void) const{
- return boost::asio::buffer_size(this->get());
- }
+ class UHD_API managed_recv_buffer : boost::noncopyable{
+ public:
+ typedef boost::shared_ptr<managed_recv_buffer> sptr;
+
+ /*!
+ * Managed recv buffer destructor:
+ * Signal to the transport that we are done with the buffer.
+ * This should be called to release the buffer to the transport.
+ * After calling, the referenced memory should be considered invalid.
+ */
+ virtual ~managed_recv_buffer(void) = 0;
+
+ /*!
+ * Get the size of the underlying buffer.
+ * \return the number of bytes
+ */
+ size_t size(void) const{
+ return boost::asio::buffer_size(this->get());
+ }
+
+ /*!
+ * Get a pointer to the underlying buffer.
+ * \return a pointer into memory
+ */
+ template <class T> T cast(void) const{
+ return boost::asio::buffer_cast<T>(this->get());
+ }
+
+ private:
+ /*!
+ * Get a reference to the internal const buffer.
+ * The buffer has a reference to memory and a size.
+ * \return a boost asio const buffer
+ */
+ virtual const boost::asio::const_buffer &get(void) const = 0;
+ };
/*!
- * Get a pointer to the underlying buffer.
- * \return a pointer into memory
+ * A managed send buffer:
+ * Contains a reference to transport-managed memory,
+ * and a method to release the memory after writing.
*/
- template <class T> T cast(void) const{
- return boost::asio::buffer_cast<T>(this->get());
- }
+ class UHD_API managed_send_buffer : boost::noncopyable{
+ public:
+ typedef boost::shared_ptr<managed_send_buffer> sptr;
+
+ /*!
+ * Signal to the transport that we are done with the buffer.
+ * This should be called to commit the write to the transport object.
+ * After calling, the referenced memory should be considered invalid.
+ * \param num_bytes the number of bytes written into the buffer
+ */
+ virtual void commit(size_t num_bytes) = 0;
+
+ /*!
+ * Get the size of the underlying buffer.
+ * \return the number of bytes
+ */
+ size_t size(void) const{
+ return boost::asio::buffer_size(this->get());
+ }
+
+ /*!
+ * Get a pointer to the underlying buffer.
+ * \return a pointer into memory
+ */
+ template <class T> T cast(void) const{
+ return boost::asio::buffer_cast<T>(this->get());
+ }
+
+ private:
+ /*!
+ * Get a reference to the internal mutable buffer.
+ * The buffer has a reference to memory and a size.
+ * \return a boost asio mutable buffer
+ */
+ virtual const boost::asio::mutable_buffer &get(void) const = 0;
+ };
-private:
/*!
- * Get a reference to the internal mutable buffer.
- * The buffer has a reference to memory and a size.
- * \return a boost asio mutable buffer
+ * A zero-copy interface for transport objects.
+ * Provides a way to get send and receive buffers
+ * with memory managed by the transport object.
*/
- virtual const boost::asio::mutable_buffer &get(void) const = 0;
-};
-
-/*!
- * A zero-copy interface for transport objects.
- * Provides a way to get send and receive buffers
- * with memory managed by the transport object.
- */
-class UHD_API zero_copy_if : boost::noncopyable{
-public:
- typedef boost::shared_ptr<zero_copy_if> sptr;
+ class UHD_API zero_copy_if : boost::noncopyable{
+ public:
+ typedef boost::shared_ptr<zero_copy_if> sptr;
+
+ /*!
+ * Get a new receive buffer from this transport object.
+ */
+ 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;
+
+ };
/*!
- * Get a new receive buffer from this transport object.
+ * A phony-zero-copy interface for transport objects that
+ * provides a zero-copy interface on top of copying transport.
+ * This interface implements the get managed recv buffer,
+ * the base class must implement the private recv method.
*/
- virtual managed_recv_buffer::sptr get_recv_buff(void) = 0;
+ class UHD_API phony_zero_copy_recv_if : public virtual zero_copy_if{
+ public:
+ /*!
+ * Create a phony zero copy recv interface.
+ * \param max_buff_size max buffer size in bytes
+ */
+ phony_zero_copy_recv_if(size_t max_buff_size);
+
+ //! destructor
+ virtual ~phony_zero_copy_recv_if(void);
+
+ /*!
+ * Get a new receive buffer from this transport object.
+ */
+ managed_recv_buffer::sptr get_recv_buff(void);
+
+ private:
+ /*!
+ * Perform a private copying recv.
+ * \param buff the buffer to write data into
+ * \return the number of bytes written to buff
+ */
+ virtual size_t recv(const boost::asio::mutable_buffer &buff) = 0;
+
+ UHD_PIMPL_DECL(impl) _impl;
+ };
/*!
- * Get a new send buffer from this transport object.
+ * A phony-zero-copy interface for transport objects that
+ * provides a zero-copy interface on top of copying transport.
+ * This interface implements the get managed send buffer,
+ * the base class must implement the private send method.
*/
- virtual managed_send_buffer::sptr get_send_buff(void) = 0;
-};
+ class UHD_API phony_zero_copy_send_if : public virtual zero_copy_if{
+ public:
+ /*!
+ * Create a phony zero copy send interface.
+ * \param max_buff_size max buffer size in bytes
+ */
+ phony_zero_copy_send_if(size_t max_buff_size);
+
+ //! destructor
+ virtual ~phony_zero_copy_send_if(void);
+
+ /*!
+ * Get a new send buffer from this transport object.
+ */
+ managed_send_buffer::sptr get_send_buff(void);
+
+ private:
+ /*!
+ * Perform a private copying send.
+ * \param buff the buffer to read data from
+ * \return the number of bytes read from buff
+ */
+ virtual size_t send(const boost::asio::const_buffer &buff) = 0;
+
+ UHD_PIMPL_DECL(impl) _impl;
+ };
}} //namespace
diff --git a/host/include/uhd/usrp/dboard_base.hpp b/host/include/uhd/usrp/dboard_base.hpp
index 28bf2ae66..e88d39876 100644
--- a/host/include/uhd/usrp/dboard_base.hpp
+++ b/host/include/uhd/usrp/dboard_base.hpp
@@ -20,6 +20,7 @@
#include <uhd/config.hpp>
#include <uhd/wax.hpp>
+#include <uhd/utils/pimpl.hpp>
#include <boost/utility.hpp>
#include <boost/shared_ptr.hpp>
#include <uhd/usrp/dboard_id.hpp>
@@ -58,8 +59,7 @@ protected:
dboard_id_t get_tx_id(void);
private:
- struct dboard_base_impl;
- dboard_base_impl *_impl;
+ UHD_PIMPL_DECL(impl) _impl;
};
/*!
diff --git a/host/include/uhd/utils/CMakeLists.txt b/host/include/uhd/utils/CMakeLists.txt
index f588c6310..391e684c8 100644
--- a/host/include/uhd/utils/CMakeLists.txt
+++ b/host/include/uhd/utils/CMakeLists.txt
@@ -20,6 +20,7 @@ INSTALL(FILES
assert.hpp
exception.hpp
gain_handler.hpp
+ pimpl.hpp
props.hpp
safe_main.hpp
static.hpp
diff --git a/host/include/uhd/utils/exception.hpp b/host/include/uhd/utils/exception.hpp
index 40e81fae0..e74c19b9c 100644
--- a/host/include/uhd/utils/exception.hpp
+++ b/host/include/uhd/utils/exception.hpp
@@ -35,4 +35,11 @@
" at " + std::string(__FILE__) + ":" + BOOST_STRINGIZE(__LINE__) + "\n" \
)
+/*!
+ * Throws an invalid code path exception with throw-site information.
+ * Use this macro in places that code execution is not supposed to go.
+ */
+#define UHD_THROW_INVALID_CODE_PATH() \
+ throw std::runtime_error(UHD_THROW_SITE_INFO("invalid code path"))
+
#endif /* INCLUDED_UHD_UTILS_EXCEPTION_HPP */
diff --git a/host/include/uhd/utils/pimpl.hpp b/host/include/uhd/utils/pimpl.hpp
new file mode 100644
index 000000000..09bf0c0a2
--- /dev/null
+++ b/host/include/uhd/utils/pimpl.hpp
@@ -0,0 +1,55 @@
+//
+// 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_UTILS_PIMPL_HPP
+#define INCLUDED_UHD_UTILS_PIMPL_HPP
+
+#include <uhd/config.hpp>
+#include <boost/shared_ptr.hpp>
+
+/*! \file pimpl.hpp
+ * "Pimpl idiom" (pointer to implementation idiom).
+ * The UHD_PIMPL_* macros simplify code overhead for declaring and making pimpls.
+ *
+ * Each pimpl is implemented as a shared pointer to the implementation:
+ * - The container class will not have to deallocate the pimpl.
+ * - The container class will use the pimpl as a regular pointer.
+ * - Usage: _impl->method(arg0, arg1)
+ * - Usage: _impl->member = value;
+ *
+ * \see http://en.wikipedia.org/wiki/Opaque_pointer
+ */
+
+/*!
+ * Make a declaration for a pimpl in a header file.
+ * - Usage: UHD_PIMPL_DECL(impl) _impl;
+ * \param _name the name of the pimpl class
+ */
+#define UHD_PIMPL_DECL(_name) \
+ struct _name; boost::shared_ptr<_name>
+
+/*!
+ * Make an instance of a pimpl in a source file.
+ * - Usage: _impl = UHD_PIMPL_MAKE(impl, ());
+ * - Usage: _impl = UHD_PIMPL_MAKE(impl, (a0, a1));
+ * \param _name the name of the pimpl class
+ * \param _args the constructor args for the pimpl
+ */
+#define UHD_PIMPL_MAKE(_name, _args) \
+ boost::shared_ptr<_name>(new _name _args)
+
+#endif /* INCLUDED_UHD_UTILS_PIMPL_HPP */