diff options
author | jcorgan | 2006-08-03 04:51:51 +0000 |
---|---|---|
committer | jcorgan | 2006-08-03 04:51:51 +0000 |
commit | 5d69a524f81f234b3fbc41d49ba18d6f6886baba (patch) | |
tree | b71312bf7f1e8d10fef0f3ac6f28784065e73e72 /gnuradio-core/src/lib/runtime/gr_buffer.cc | |
download | gnuradio-5d69a524f81f234b3fbc41d49ba18d6f6886baba.tar.gz gnuradio-5d69a524f81f234b3fbc41d49ba18d6f6886baba.tar.bz2 gnuradio-5d69a524f81f234b3fbc41d49ba18d6f6886baba.zip |
Houston, we have a trunk.
git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@3122 221aa14e-8319-0410-a670-987f0aec2ac5
Diffstat (limited to 'gnuradio-core/src/lib/runtime/gr_buffer.cc')
-rw-r--r-- | gnuradio-core/src/lib/runtime/gr_buffer.cc | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/gnuradio-core/src/lib/runtime/gr_buffer.cc b/gnuradio-core/src/lib/runtime/gr_buffer.cc new file mode 100644 index 000000000..d3d123096 --- /dev/null +++ b/gnuradio-core/src/lib/runtime/gr_buffer.cc @@ -0,0 +1,248 @@ +/* -*- c++ -*- */ +/* + * Copyright 2004 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio 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 2, or (at your option) + * any later version. + * + * GNU Radio 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 GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <gr_buffer.h> +#include <gr_vmcircbuf.h> +#include <gr_math.h> +#include <stdexcept> +#include <iostream> +#include <assert.h> +#include <algorithm> + +static long s_buffer_count = 0; // counts for debugging storage mgmt +static long s_buffer_reader_count = 0; + +// ---------------------------------------------------------------------------- +// Notes on storage management +// +// Pretty much all the fundamental classes are now using the +// shared_ptr stuff for automatic reference counting. To ensure that +// no mistakes are made, we make the constructors for classes private, +// and then provide a free factory function that returns a smart +// pointer to the desired class. +// +// gr_buffer and gr_buffer_reader are no exceptions. However, they +// both want pointers to each other, and unless we do something, we'll +// never delete any of them because of the circular structure. +// They'll always have a reference count of at least one. We could +// use boost::weak_ptr's from gr_buffer to gr_buffer_reader but that +// introduces it's own problems. (gr_buffer_reader's destructor needs +// to call gr_buffer::drop_reader, but has no easy way to get a +// shared_ptr to itself.) +// +// Instead, we solve this problem by having gr_buffer hold a raw +// pointer to gr_buffer_reader in its d_reader vector. +// gr_buffer_reader's destructor calls gr_buffer::drop_reader, so +// we're never left with an dangling pointer. gr_buffer_reader still +// has a shared_ptr to the buffer ensuring that the buffer doesn't go +// away under it. However, when the reference count of a +// gr_buffer_reader goes to zero, we can successfully reclaim it. +// ---------------------------------------------------------------------------- + + +/* + * Compute the minimum number of buffer items that work (i.e., + * address space wrap-around works). To work is to satisfy this + * contraint for integer buffer_size and k: + * + * type_size * nitems == k * page_size + */ +static long +minimum_buffer_items (long type_size, long page_size) +{ + return page_size / gr_gcd (type_size, page_size); +} + + +gr_buffer::gr_buffer (int nitems, size_t sizeof_item) + : d_base (0), d_bufsize (0), d_vmcircbuf (0), + d_sizeof_item (sizeof_item), d_write_index (0), + d_done (false) +{ + if (!allocate_buffer (nitems, sizeof_item)) + throw std::bad_alloc (); + + s_buffer_count++; +} + +gr_buffer_sptr +gr_make_buffer (int nitems, size_t sizeof_item) +{ + return gr_buffer_sptr (new gr_buffer (nitems, sizeof_item)); +} + +gr_buffer::~gr_buffer () +{ + delete d_vmcircbuf; + assert (d_readers.size() == 0); + s_buffer_count--; +} + +/*! + * sets d_vmcircbuf, d_base, d_bufsize. + * returns true iff successful. + */ +bool +gr_buffer::allocate_buffer (int nitems, size_t sizeof_item) +{ + int orig_nitems = nitems; + + // Any buffersize we come up with must be a multiple of min_nitems. + + int granularity = gr_vmcircbuf_sysconfig::granularity (); + int min_nitems = minimum_buffer_items (sizeof_item, granularity); + + // Round-up nitems to a multiple of min_nitems. + + if (nitems % min_nitems != 0) + nitems = ((nitems / min_nitems) + 1) * min_nitems; + + // If we rounded-up a whole bunch, give the user a heads up. + // This only happens if sizeof_item is not a power of two. + + if (nitems > 2 * orig_nitems && nitems * (int) sizeof_item > granularity){ + std::cerr << "gr_buffer::allocate_buffer: warning: tried to allocate\n" + << " " << orig_nitems << " items of size " + << sizeof_item << ". Due to alignment requirements\n" + << " " << nitems << " were allocated. If this isn't OK, consider padding\n" + << " your structure to a power-of-two bytes.\n" + << " On this platform, our allocation granularity is " << granularity << " bytes.\n"; + } + + d_bufsize = nitems; + d_vmcircbuf = gr_vmcircbuf_sysconfig::make (d_bufsize * d_sizeof_item); + if (d_vmcircbuf == 0){ + std::cerr << "gr_buffer::allocate_buffer: failed to allocate buffer of size " + << d_bufsize * d_sizeof_item / 1024 << " KB\n"; + return false; + } + + d_base = (char *) d_vmcircbuf->pointer_to_first_copy (); + return true; +} + + +int +gr_buffer::space_available () const +{ + if (d_readers.empty ()) + return d_bufsize - 1; // See comment below + + else { + + // Find out the maximum amount of data available to our readers + + int most_data = d_readers[0]->items_available (); + for (unsigned int i = 1; i < d_readers.size (); i++) + most_data = std::max (most_data, d_readers[i]->items_available ()); + + // The -1 ensures that the case d_write_index == d_read_index is + // unambiguous. It indicates that there is no data for the reader + + return d_bufsize - most_data - 1; + } +} + +void * +gr_buffer::write_pointer () +{ + return &d_base[d_write_index * d_sizeof_item]; +} + +void +gr_buffer::update_write_pointer (int nitems) +{ + d_write_index = index_add (d_write_index, nitems); +} + +gr_buffer_reader_sptr +gr_buffer_add_reader (gr_buffer_sptr buf, int history) +{ + gr_buffer_reader_sptr r (new gr_buffer_reader (buf, + buf->index_sub(buf->d_write_index, + history-1))); + buf->d_readers.push_back (r.get ()); + + return r; +} + +void +gr_buffer::drop_reader (gr_buffer_reader *reader) +{ + // isn't C++ beautiful... GAG! + + std::vector<gr_buffer_reader *>::iterator result = + std::find (d_readers.begin (), d_readers.end (), reader); + + if (result == d_readers.end ()) + throw std::invalid_argument ("gr_buffer::drop_reader"); // we didn't find it... + + d_readers.erase (result); +} + +long +gr_buffer_ncurrently_allocated () +{ + return s_buffer_count; +} + +// ---------------------------------------------------------------------------- + +gr_buffer_reader::gr_buffer_reader (gr_buffer_sptr buffer, unsigned int read_index) + : d_buffer (buffer), d_read_index (read_index) +{ + s_buffer_reader_count++; +} + +gr_buffer_reader::~gr_buffer_reader () +{ + d_buffer->drop_reader(this); + s_buffer_reader_count--; +} + +int +gr_buffer_reader::items_available () const +{ + return d_buffer->index_sub (d_buffer->d_write_index, d_read_index); +} + +const void * +gr_buffer_reader::read_pointer () +{ + return &d_buffer->d_base[d_read_index * d_buffer->d_sizeof_item]; +} + +void +gr_buffer_reader::update_read_pointer (int nitems) +{ + d_read_index = d_buffer->index_add (d_read_index, nitems); +} + +long +gr_buffer_reader_ncurrently_allocated () +{ + return s_buffer_reader_count; +} |