diff options
| -rw-r--r-- | host/include/uhd/transport/zero_copy.hpp | 30 | ||||
| -rw-r--r-- | host/lib/transport/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | host/lib/transport/zero_copy.cpp | 114 | ||||
| -rw-r--r-- | host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp | 160 | 
4 files changed, 112 insertions, 193 deletions
| diff --git a/host/include/uhd/transport/zero_copy.hpp b/host/include/uhd/transport/zero_copy.hpp index 18eb3fb6d..092028d09 100644 --- a/host/include/uhd/transport/zero_copy.hpp +++ b/host/include/uhd/transport/zero_copy.hpp @@ -21,7 +21,6 @@  #include <uhd/config.hpp>  #include <boost/utility.hpp>  #include <boost/shared_ptr.hpp> -#include <boost/function.hpp>  namespace uhd{ namespace transport{ @@ -33,20 +32,6 @@ namespace uhd{ namespace transport{      class UHD_API managed_recv_buffer{      public:          typedef boost::shared_ptr<managed_recv_buffer> sptr; -        typedef boost::function<void(void)> release_fcn_t; - -        /*! -         * Make a safe managed receive buffer: -         * A safe managed buffer ensures that release is called once, -         * either by the user or automatically upon deconstruction. -         * \param buff a pointer into read-only memory -         * \param size the length of the buffer in bytes -         * \param release_fcn callback to release the memory -         * \return a new managed receive buffer -         */ -        static sptr make_safe( -            const void *buff, size_t size, const release_fcn_t &release_fcn -        );          /*!           * Signal to the transport that we are done with the buffer. @@ -84,21 +69,6 @@ namespace uhd{ namespace transport{      class UHD_API managed_send_buffer{      public:          typedef boost::shared_ptr<managed_send_buffer> sptr; -        typedef boost::function<void(size_t)> commit_fcn_t; - -        /*! -         * Make a safe managed send buffer: -         * A safe managed buffer ensures that commit is called once, -         * either by the user or automatically upon deconstruction. -         * In the later case, the deconstructor will call commit(0). -         * \param buff a pointer into writable memory -         * \param size the length of the buffer in bytes -         * \param commit_fcn callback to commit the memory -         * \return a new managed send buffer -         */ -        static sptr make_safe( -            void *buff, size_t size, const commit_fcn_t &commit_fcn -        );          /*!           * Signal to the transport that we are done with the buffer. diff --git a/host/lib/transport/CMakeLists.txt b/host/lib/transport/CMakeLists.txt index 8765c6703..a66a58d32 100644 --- a/host/lib/transport/CMakeLists.txt +++ b/host/lib/transport/CMakeLists.txt @@ -77,5 +77,4 @@ LIBUHD_APPEND_SOURCES(      ${CMAKE_CURRENT_SOURCE_DIR}/udp_simple.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/udp_zero_copy_asio.cpp      ${CMAKE_CURRENT_SOURCE_DIR}/vrt_packet_handler.hpp -    ${CMAKE_CURRENT_SOURCE_DIR}/zero_copy.cpp  ) diff --git a/host/lib/transport/zero_copy.cpp b/host/lib/transport/zero_copy.cpp deleted file mode 100644 index b91eaae1d..000000000 --- a/host/lib/transport/zero_copy.cpp +++ /dev/null @@ -1,114 +0,0 @@ -// -// Copyright 2010-2011 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> - -using namespace uhd::transport; - -/*********************************************************************** - * Safe managed receive buffer - **********************************************************************/ -static void release_nop(void){ -    /* NOP */ -} - -class safe_managed_receive_buffer : public managed_recv_buffer{ -public: -    safe_managed_receive_buffer( -        const void *buff, size_t size, const release_fcn_t &release_fcn -    ): -        _buff(buff), _size(size), _release_fcn(release_fcn) -    { -        /* NOP */ -    } - -    ~safe_managed_receive_buffer(void){ -        _release_fcn(); -    } - -    void release(void){ -        release_fcn_t release_fcn = _release_fcn; -        _release_fcn = &release_nop; -        return release_fcn(); -    } - -private: -    const void *get_buff(void) const{ -        return _buff; -    } - -    size_t get_size(void) const{ -        return _size; -    } - -    const void *_buff; -    size_t _size; -    release_fcn_t _release_fcn; -}; - -managed_recv_buffer::sptr managed_recv_buffer::make_safe( -    const void *buff, size_t size, const release_fcn_t &release_fcn -){ -    return sptr(new safe_managed_receive_buffer(buff, size, release_fcn)); -} - -/*********************************************************************** - * Safe managed send buffer - **********************************************************************/ -static void commit_nop(size_t){ -    /* NOP */ -} - -class safe_managed_send_buffer : public managed_send_buffer{ -public: -    safe_managed_send_buffer( -        void *buff, size_t size, const commit_fcn_t &commit_fcn -    ): -        _buff(buff), _size(size), _commit_fcn(commit_fcn) -    { -        /* NOP */ -    } - -    ~safe_managed_send_buffer(void){ -        _commit_fcn(0); -    } - -    void commit(size_t num_bytes){ -        commit_fcn_t commit_fcn = _commit_fcn; -        _commit_fcn = &commit_nop; -        return commit_fcn(num_bytes); -    } - -private: -    void *get_buff(void) const{ -        return _buff; -    } - -    size_t get_size(void) const{ -        return _size; -    } - -    void *_buff; -    size_t _size; -    commit_fcn_t _commit_fcn; -}; - -safe_managed_send_buffer::sptr managed_send_buffer::make_safe( -    void *buff, size_t size, const commit_fcn_t &commit_fcn -){ -    return sptr(new safe_managed_send_buffer(buff, size, commit_fcn)); -} diff --git a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp b/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp index 4e0137fdb..c155d426a 100644 --- a/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp +++ b/host/lib/usrp/usrp_e100/usrp_e100_mmap_zero_copy.cpp @@ -22,7 +22,7 @@  #include <sys/mman.h> //mmap  #include <unistd.h> //getpagesize  #include <poll.h> //poll -#include <boost/bind.hpp> +#include <vector>  #include <iostream>  using namespace uhd; @@ -33,6 +33,82 @@ static const bool sp_verbose = false; //slow-path verbose  static const size_t poll_breakout = 10; //how many poll timeouts constitute a full timeout  /*********************************************************************** + * Reusable managed receiver buffer: + *  - The buffer knows how to claim and release a frame. + **********************************************************************/ +class usrp_e100_mmap_zero_copy_mrb : public managed_recv_buffer{ +public: +    usrp_e100_mmap_zero_copy_mrb(void *mem, ring_buffer_info *info): +        _mem(mem), _info(info) { /* NOP */ } + +    void release(void){ +        if (_info->flags != RB_USER_PROCESS) return; +        if (fp_verbose) std::cout << "recv buff: release" << std::endl; +        _info->flags = RB_KERNEL; //release the frame +    } + +    bool ready(void){return _info->flags & RB_USER;} + +    sptr get_new(void){ +        if (fp_verbose) std::cout << "  make_recv_buff: " << get_size() << std::endl; +        _info->flags = RB_USER_PROCESS; //claim the frame +        return sptr(this, &usrp_e100_mmap_zero_copy_mrb::fake_deleter); +    } + +private: +    static void fake_deleter(void *obj){ +        static_cast<usrp_e100_mmap_zero_copy_mrb *>(obj)->release(); +    } + +    const void *get_buff(void) const{return _mem;} +    size_t get_size(void) const{return _info->len;} + +    void *_mem; +    ring_buffer_info *_info; +}; + +/*********************************************************************** + * Reusable managed send buffer: + *  - The buffer knows how to claim and release a frame. + **********************************************************************/ +class usrp_e100_mmap_zero_copy_msb : public managed_send_buffer{ +public: +    usrp_e100_mmap_zero_copy_msb(void *mem, ring_buffer_info *info, size_t len, int fd): +        _mem(mem), _info(info), _len(len), _fd(fd) { /* NOP */ } + +    void commit(size_t len){ +        if (_info->flags != RB_USER_PROCESS) return; +        if (fp_verbose) std::cout << "send buff: commit " << len << std::endl; +        _info->len = len; +        _info->flags = RB_USER; //release the frame +        if (::write(_fd, NULL, 0) < 0){ //notifies the kernel +            std::cerr << UHD_THROW_SITE_INFO("write error") << std::endl; +        } +    } + +    bool ready(void){return _info->flags & RB_KERNEL;} + +    sptr get_new(void){ +        if (fp_verbose) std::cout << "  make_send_buff: " << get_size() << std::endl; +        _info->flags = RB_USER_PROCESS; //claim the frame +        return sptr(this, &usrp_e100_mmap_zero_copy_msb::fake_deleter); +    } + +private: +    static void fake_deleter(void *obj){ +        static_cast<usrp_e100_mmap_zero_copy_msb *>(obj)->commit(0); +    } + +    void *get_buff(void) const{return _mem;} +    size_t get_size(void) const{return _len;} + +    void *_mem; +    ring_buffer_info *_info; +    size_t _len; +    int _fd; +}; + +/***********************************************************************   * The zero copy interface implementation   **********************************************************************/  class usrp_e100_mmap_zero_copy_impl : public zero_copy_if{ @@ -81,13 +157,32 @@ public:              std::cout << "send_buff_off: " << send_buff_off << std::endl;          } +        //pointers to sections in the mapped memory +        ring_buffer_info (*recv_info)[], (*send_info)[]; +        char *recv_buff, *send_buff; +          //set the internal pointers for info and buffers          typedef ring_buffer_info (*rbi_pta)[];          char *rb_ptr = reinterpret_cast<char *>(_mapped_mem); -        _recv_info = reinterpret_cast<rbi_pta>(rb_ptr + recv_info_off); -        _recv_buff = rb_ptr + recv_buff_off; -        _send_info = reinterpret_cast<rbi_pta>(rb_ptr + send_info_off); -        _send_buff = rb_ptr + send_buff_off; +        recv_info = reinterpret_cast<rbi_pta>(rb_ptr + recv_info_off); +        recv_buff = rb_ptr + recv_buff_off; +        send_info = reinterpret_cast<rbi_pta>(rb_ptr + send_info_off); +        send_buff = rb_ptr + send_buff_off; + +        //initialize the managed receive buffers +        for (size_t i = 0; i < get_num_recv_frames(); i++){ +            _mrb_pool.push_back(usrp_e100_mmap_zero_copy_mrb( +                recv_buff + get_recv_frame_size()*i, (*recv_info) + i +            )); +        } + +        //initialize the managed send buffers +        for (size_t i = 0; i < get_num_recv_frames(); i++){ +            _msb_pool.push_back(usrp_e100_mmap_zero_copy_msb( +                send_buff + get_send_frame_size()*i, (*send_info) + i, +                get_send_frame_size(), _fd +            )); +        }      }      ~usrp_e100_mmap_zero_copy_impl(void){ @@ -97,13 +192,10 @@ public:      managed_recv_buffer::sptr get_recv_buff(double timeout){          if (fp_verbose) std::cout << "get_recv_buff: " << _recv_index << std::endl; - -        //grab pointers to the info and buffer -        ring_buffer_info *info = (*_recv_info) + _recv_index; -        void *mem = _recv_buff + _frame_size*_recv_index; +        usrp_e100_mmap_zero_copy_mrb &mrb = _mrb_pool[_recv_index];          //poll/wait for a ready frame -        if (not (info->flags & RB_USER)){ +        if (not mrb.ready()){              for (size_t i = 0; i < poll_breakout; i++){                  pollfd pfd;                  pfd.fd = _fd; @@ -115,18 +207,11 @@ public:              return managed_recv_buffer::sptr(); //timed-out for real          } found_user_frame: -        //the process has claimed the frame -        info->flags = RB_USER_PROCESS; -          //increment the index for the next call -        if (++_recv_index == size_t(_rb_size.num_rx_frames)) _recv_index = 0; +        if (++_recv_index == get_num_recv_frames()) _recv_index = 0;          //return the managed buffer for this frame -        if (fp_verbose) std::cout << "  make_recv_buff: " << info->len << std::endl; -        return managed_recv_buffer::make_safe( -            mem, info->len, -            boost::bind(&usrp_e100_mmap_zero_copy_impl::release, this, info) -        ); +        return mrb.get_new();      }      size_t get_num_recv_frames(void) const{ @@ -139,13 +224,10 @@ public:      managed_send_buffer::sptr get_send_buff(double timeout){          if (fp_verbose) std::cout << "get_send_buff: " << _send_index << std::endl; - -        //grab pointers to the info and buffer -        ring_buffer_info *info = (*_send_info) + _send_index; -        void *mem = _send_buff + _frame_size*_send_index; +        usrp_e100_mmap_zero_copy_msb &msb = _msb_pool[_send_index];          //poll/wait for a ready frame -        if (not (info->flags & RB_KERNEL)){ +        if (not msb.ready()){              pollfd pfd;              pfd.fd = _fd;              pfd.events = POLLOUT; @@ -155,14 +237,10 @@ public:          }          //increment the index for the next call -        if (++_send_index == size_t(_rb_size.num_tx_frames)) _send_index = 0; +        if (++_send_index == get_num_send_frames()) _send_index = 0;          //return the managed buffer for this frame -        if (fp_verbose) std::cout << "  make_send_buff: " << _frame_size << std::endl; -        return managed_send_buffer::make_safe( -            mem, _frame_size, -            boost::bind(&usrp_e100_mmap_zero_copy_impl::commit, this, info, _1) -        ); +        return msb.get_new();      }      size_t get_num_send_frames(void) const{ @@ -174,21 +252,7 @@ public:      }  private: - -    void release(ring_buffer_info *info){ -        if (fp_verbose) std::cout << "recv buff: release" << std::endl; -        info->flags = RB_KERNEL; -    } - -    void commit(ring_buffer_info *info, size_t len){ -        if (fp_verbose) std::cout << "send buff: commit " << len << std::endl; -        info->len = len; -        info->flags = RB_USER; -        if (::write(_fd, NULL, 0) < 0){ -            std::cerr << UHD_THROW_SITE_INFO("write error") << std::endl; -        } -    } - +    //file descriptor for mmap      int _fd;      //the mapped memory itself @@ -198,9 +262,9 @@ private:      usrp_e_ring_buffer_size_t _rb_size;      size_t _frame_size, _map_size; -    //pointers to sections in the mapped memory -    ring_buffer_info (*_recv_info)[], (*_send_info)[]; -    char *_recv_buff, *_send_buff; +    //re-usable managed buffers +    std::vector<usrp_e100_mmap_zero_copy_mrb> _mrb_pool; +    std::vector<usrp_e100_mmap_zero_copy_msb> _msb_pool;      //indexes into sub-sections of mapped memory      size_t _recv_index, _send_index; | 
