GNU Radio 3.7.1 C++ API
buffer.h
Go to the documentation of this file.
00001 /* -*- c++ -*- */
00002 /*
00003  * Copyright 2004,2009-2011,2013 Free Software Foundation, Inc.
00004  *
00005  * This file is part of GNU Radio
00006  *
00007  * GNU Radio is free software; you can redistribute it and/or modify
00008  * it under the terms of the GNU General Public License as published by
00009  * the Free Software Foundation; either version 3, or (at your option)
00010  * any later version.
00011  *
00012  * GNU Radio is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with GNU Radio; see the file COPYING.  If not, write to
00019  * the Free Software Foundation, Inc., 51 Franklin Street,
00020  * Boston, MA 02110-1301, USA.
00021  */
00022 
00023 #ifndef INCLUDED_GR_RUNTIME_BUFFER_H
00024 #define INCLUDED_GR_RUNTIME_BUFFER_H
00025 
00026 #include <gnuradio/api.h>
00027 #include <gnuradio/runtime_types.h>
00028 #include <gnuradio/tags.h>
00029 #include <boost/weak_ptr.hpp>
00030 #include <gnuradio/thread/thread.h>
00031 #include <deque>
00032 
00033 namespace gr {
00034   
00035   class vmcircbuf;
00036 
00037   /*!
00038    * \brief Allocate a buffer that holds at least \p nitems of size \p sizeof_item.
00039    *
00040    * The total size of the buffer will be rounded up to a system
00041    * dependent boundary. This is typically the system page size, but
00042    * under MS windows is 64KB.
00043    *
00044    * \param nitems is the minimum number of items the buffer will hold.
00045    * \param sizeof_item is the size of an item in bytes.
00046    * \param link is the block that writes to this buffer.
00047    */
00048   GR_RUNTIME_API buffer_sptr make_buffer(int nitems, size_t sizeof_item,
00049                                          block_sptr link=block_sptr());
00050 
00051   /*!
00052    * \brief Single writer, multiple reader fifo.
00053    * \ingroup internal
00054    */
00055   class GR_RUNTIME_API buffer
00056   {
00057   public:
00058     virtual ~buffer();
00059 
00060     /*!
00061      * \brief return number of items worth of space available for writing
00062      */
00063     int space_available();
00064 
00065     /*!
00066      * \brief return size of this buffer in items
00067      */
00068     int bufsize() const { return d_bufsize; }
00069 
00070     /*!
00071      * \brief return pointer to write buffer.
00072      *
00073      * The return value points at space that can hold at least
00074      * space_available() items.
00075      */
00076     void *write_pointer();
00077 
00078     /*!
00079      * \brief tell buffer that we wrote \p nitems into it
00080      */
00081     void update_write_pointer(int nitems);
00082 
00083     void set_done(bool done);
00084     bool done() const { return d_done; }
00085 
00086     /*!
00087      * \brief Return the block that writes to this buffer.
00088      */
00089     block_sptr link() { return block_sptr(d_link); }
00090 
00091     size_t nreaders() const { return d_readers.size(); }
00092     buffer_reader* reader(size_t index) { return d_readers[index]; }
00093 
00094     gr::thread::mutex *mutex() { return &d_mutex; }
00095 
00096     uint64_t nitems_written() { return d_abs_write_offset; }
00097 
00098     size_t get_sizeof_item() { return d_sizeof_item; }
00099 
00100     /*!
00101      * \brief  Adds a new tag to the buffer.
00102      *
00103      * \param tag        the new tag
00104      */
00105     void add_item_tag(const tag_t &tag);
00106 
00107     /*!
00108      * \brief  Removes an existing tag from the buffer.
00109      *
00110      * If no such tag is found, does nothing.
00111      * Note: Doesn't actually physically delete the tag, but
00112      * marks it as deleted. For the user, this has the same effect:
00113      * Any subsequent calls to get_tags_in_range() will not return
00114      * the tag.
00115      *
00116      * \param tag        the tag that needs to be removed
00117      * \param id         the unique ID of the block calling this function
00118      */
00119     void remove_item_tag(const tag_t &tag, long id);
00120 
00121     /*!
00122      * \brief  Removes all tags before \p max_time from buffer
00123      *
00124      * \param max_time        the time (item number) to trim up until.
00125      */
00126     void prune_tags(uint64_t max_time);
00127 
00128     std::deque<tag_t>::iterator get_tags_begin() { return d_item_tags.begin(); }
00129     std::deque<tag_t>::iterator get_tags_end() { return d_item_tags.end(); }
00130 
00131     // -------------------------------------------------------------------------
00132 
00133   private:
00134     friend class buffer_reader;
00135     friend GR_RUNTIME_API buffer_sptr make_buffer(int nitems, size_t sizeof_item, block_sptr link);
00136     friend GR_RUNTIME_API buffer_reader_sptr buffer_add_reader(buffer_sptr buf, int nzero_preload, block_sptr link);
00137 
00138   protected:
00139     char                               *d_base;         // base address of buffer
00140     unsigned int                        d_bufsize;      // in items
00141   private:
00142     gr::vmcircbuf                      *d_vmcircbuf;
00143     size_t                              d_sizeof_item;  // in bytes
00144     std::vector<buffer_reader *>        d_readers;
00145     boost::weak_ptr<block>              d_link;         // block that writes to this buffer
00146 
00147     //
00148     // The mutex protects d_write_index, d_abs_write_offset, d_done, d_item_tags
00149     // and the d_read_index's and d_abs_read_offset's in the buffer readers.
00150     //
00151     gr::thread::mutex                   d_mutex;
00152     unsigned int                        d_write_index;  // in items [0,d_bufsize)
00153     uint64_t                            d_abs_write_offset; // num items written since the start
00154     bool                                d_done;
00155     std::deque<tag_t>                d_item_tags;
00156     uint64_t                            d_last_min_items_read;
00157 
00158     unsigned index_add(unsigned a, unsigned b)
00159     {
00160       unsigned s = a + b;
00161 
00162       if(s >= d_bufsize)
00163         s -= d_bufsize;
00164 
00165       assert(s < d_bufsize);
00166       return s;
00167     }
00168 
00169     unsigned index_sub(unsigned a, unsigned b)
00170     {
00171       int s = a - b;
00172 
00173       if(s < 0)
00174         s += d_bufsize;
00175 
00176       assert((unsigned) s < d_bufsize);
00177       return s;
00178     }
00179 
00180     virtual bool allocate_buffer(int nitems, size_t sizeof_item);
00181 
00182     /*!
00183      * \brief constructor is private.  Use gr_make_buffer to create instances.
00184      *
00185      * Allocate a buffer that holds at least \p nitems of size \p sizeof_item.
00186      *
00187      * \param nitems is the minimum number of items the buffer will hold.
00188      * \param sizeof_item is the size of an item in bytes.
00189      * \param link is the block that writes to this buffer.
00190      *
00191      * The total size of the buffer will be rounded up to a system
00192      * dependent boundary.  This is typically the system page size, but
00193      * under MS windows is 64KB.
00194      */
00195     buffer(int nitems, size_t sizeof_item, block_sptr link);
00196 
00197     /*!
00198      * \brief disassociate \p reader from this buffer
00199      */
00200     void drop_reader(buffer_reader *reader);
00201   };
00202 
00203   /*!
00204    * \brief Create a new gr::buffer_reader and attach it to buffer \p buf
00205    * \param buf is the buffer the \p gr::buffer_reader reads from.
00206    * \param nzero_preload -- number of zero items to "preload" into buffer.
00207    * \param link is the block that reads from the buffer using this gr::buffer_reader.
00208    */
00209   GR_RUNTIME_API buffer_reader_sptr
00210     buffer_add_reader(buffer_sptr buf, int nzero_preload, block_sptr link=block_sptr());
00211 
00212   //! returns # of buffers currently allocated
00213   GR_RUNTIME_API long buffer_ncurrently_allocated();
00214 
00215 
00216   // ---------------------------------------------------------------------------
00217 
00218   /*!
00219    * \brief How we keep track of the readers of a gr::buffer.
00220    * \ingroup internal
00221    */
00222   class GR_RUNTIME_API buffer_reader
00223   {
00224   public:
00225     ~buffer_reader();
00226 
00227     /*!
00228      * \brief Return number of items available for reading.
00229      */
00230     int items_available() const;
00231 
00232     /*!
00233      * \brief Return buffer this reader reads from.
00234      */
00235     buffer_sptr buffer() const { return d_buffer; }
00236 
00237     /*!
00238      * \brief Return maximum number of items that could ever be available for reading.
00239      * This is used as a sanity check in the scheduler to avoid looping forever.
00240      */
00241     int max_possible_items_available() const { return d_buffer->d_bufsize - 1; }
00242 
00243     /*!
00244      * \brief return pointer to read buffer.
00245      *
00246      * The return value points to items_available() number of items
00247      */
00248     const void *read_pointer();
00249 
00250     /*
00251      * \brief tell buffer we read \p items from it
00252      */
00253     void update_read_pointer(int nitems);
00254 
00255     void set_done(bool done) { d_buffer->set_done(done); }
00256     bool done() const { return d_buffer->done(); }
00257 
00258     gr::thread::mutex *mutex() { return d_buffer->mutex(); }
00259 
00260     uint64_t nitems_read() { return d_abs_read_offset; }
00261 
00262     size_t get_sizeof_item() { return d_buffer->get_sizeof_item(); }
00263 
00264     /*!
00265      * \brief Return the block that reads via this reader.
00266      *
00267      */
00268     block_sptr link() { return block_sptr(d_link); }
00269 
00270     /*!
00271      * \brief Given a [start,end), returns a vector all tags in the range.
00272      *
00273      * Get a vector of tags in given range. Range of counts is from start to end-1.
00274      *
00275      * Tags are tuples of:
00276      *      (item count, source id, key, value)
00277      *
00278      * \param v            a vector reference to return tags into
00279      * \param abs_start    a uint64 count of the start of the range of interest
00280      * \param abs_end      a uint64 count of the end of the range of interest
00281      * \param id           the unique ID of the block to make sure already deleted tags are not returned
00282      */
00283     void get_tags_in_range(std::vector<tag_t> &v,
00284                            uint64_t abs_start,
00285                            uint64_t abs_end,
00286                            long id);
00287 
00288     // -------------------------------------------------------------------------
00289 
00290   private:
00291     friend class buffer;
00292     friend GR_RUNTIME_API buffer_reader_sptr
00293       buffer_add_reader(buffer_sptr buf, int nzero_preload, block_sptr link);
00294 
00295     buffer_sptr  d_buffer;
00296     unsigned int d_read_index;       // in items [0,d->buffer.d_bufsize)
00297     uint64_t     d_abs_read_offset;  // num items seen since the start
00298     boost::weak_ptr<block> d_link;   // block that reads via this buffer reader
00299 
00300     //! constructor is private.  Use gr::buffer::add_reader to create instances
00301     buffer_reader(buffer_sptr buffer, unsigned int read_index, block_sptr link);
00302   };
00303 
00304   //! returns # of buffer_readers currently allocated
00305   GR_RUNTIME_API long buffer_reader_ncurrently_allocated ();
00306 
00307 } /* namespace gr */
00308 
00309 #endif /* INCLUDED_GR_RUNTIME_BUFFER_H */