Statistics
| Branch: | Tag: | Revision:

root / gnuradio-core / src / lib / runtime / gr_buffer.cc @ 68a36d3e

History | View | Annotate | Download (9.5 kB)

1 5d69a524 jcorgan
/* -*- c++ -*- */
2 5d69a524 jcorgan
/*
3 70ca24e7 Tom Rondeau
 * Copyright 2004,2009,2010 Free Software Foundation, Inc.
4 5d69a524 jcorgan
 * 
5 5d69a524 jcorgan
 * This file is part of GNU Radio
6 5d69a524 jcorgan
 * 
7 5d69a524 jcorgan
 * GNU Radio is free software; you can redistribute it and/or modify
8 5d69a524 jcorgan
 * it under the terms of the GNU General Public License as published by
9 937b719d eb
 * the Free Software Foundation; either version 3, or (at your option)
10 5d69a524 jcorgan
 * any later version.
11 5d69a524 jcorgan
 * 
12 5d69a524 jcorgan
 * GNU Radio is distributed in the hope that it will be useful,
13 5d69a524 jcorgan
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 5d69a524 jcorgan
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 5d69a524 jcorgan
 * GNU General Public License for more details.
16 5d69a524 jcorgan
 * 
17 5d69a524 jcorgan
 * You should have received a copy of the GNU General Public License
18 5d69a524 jcorgan
 * along with GNU Radio; see the file COPYING.  If not, write to
19 86f5c924 eb
 * the Free Software Foundation, Inc., 51 Franklin Street,
20 86f5c924 eb
 * Boston, MA 02110-1301, USA.
21 5d69a524 jcorgan
 */
22 5d69a524 jcorgan
23 5d69a524 jcorgan
#ifdef HAVE_CONFIG_H
24 5d69a524 jcorgan
#include "config.h"
25 5d69a524 jcorgan
#endif
26 5d69a524 jcorgan
27 5d69a524 jcorgan
#include <gr_buffer.h>
28 5d69a524 jcorgan
#include <gr_vmcircbuf.h>
29 5d69a524 jcorgan
#include <gr_math.h>
30 5d69a524 jcorgan
#include <stdexcept>
31 5d69a524 jcorgan
#include <iostream>
32 5d69a524 jcorgan
#include <assert.h>
33 5d69a524 jcorgan
#include <algorithm>
34 48f9ca90 Josh Blum
#include <boost/math/common_factor_rt.hpp>
35 5d69a524 jcorgan
36 5d69a524 jcorgan
static long s_buffer_count = 0;                // counts for debugging storage mgmt
37 5d69a524 jcorgan
static long s_buffer_reader_count = 0;
38 5d69a524 jcorgan
39 5d69a524 jcorgan
// ----------------------------------------------------------------------------
40 5d69a524 jcorgan
//                        Notes on storage management
41 5d69a524 jcorgan
//
42 5d69a524 jcorgan
// Pretty much all the fundamental classes are now using the
43 5d69a524 jcorgan
// shared_ptr stuff for automatic reference counting.  To ensure that
44 5d69a524 jcorgan
// no mistakes are made, we make the constructors for classes private,
45 5d69a524 jcorgan
// and then provide a free factory function that returns a smart
46 5d69a524 jcorgan
// pointer to the desired class.
47 5d69a524 jcorgan
//
48 5d69a524 jcorgan
// gr_buffer and gr_buffer_reader are no exceptions.  However, they
49 5d69a524 jcorgan
// both want pointers to each other, and unless we do something, we'll
50 5d69a524 jcorgan
// never delete any of them because of the circular structure.
51 5d69a524 jcorgan
// They'll always have a reference count of at least one.  We could
52 5d69a524 jcorgan
// use boost::weak_ptr's from gr_buffer to gr_buffer_reader but that
53 5d69a524 jcorgan
// introduces it's own problems.  (gr_buffer_reader's destructor needs
54 5d69a524 jcorgan
// to call gr_buffer::drop_reader, but has no easy way to get a
55 5d69a524 jcorgan
// shared_ptr to itself.)
56 5d69a524 jcorgan
//
57 5d69a524 jcorgan
// Instead, we solve this problem by having gr_buffer hold a raw
58 5d69a524 jcorgan
// pointer to gr_buffer_reader in its d_reader vector.
59 5d69a524 jcorgan
// gr_buffer_reader's destructor calls gr_buffer::drop_reader, so
60 5d69a524 jcorgan
// we're never left with an dangling pointer.  gr_buffer_reader still
61 5d69a524 jcorgan
// has a shared_ptr to the buffer ensuring that the buffer doesn't go
62 5d69a524 jcorgan
// away under it.  However, when the reference count of a
63 5d69a524 jcorgan
// gr_buffer_reader goes to zero, we can successfully reclaim it.
64 5d69a524 jcorgan
// ----------------------------------------------------------------------------
65 5d69a524 jcorgan
66 5d69a524 jcorgan
67 5d69a524 jcorgan
/*
68 5d69a524 jcorgan
 * Compute the minimum number of buffer items that work (i.e.,
69 5d69a524 jcorgan
 * address space wrap-around works).  To work is to satisfy this
70 5d69a524 jcorgan
 * contraint for integer buffer_size and k:
71 5d69a524 jcorgan
 *
72 5d69a524 jcorgan
 *     type_size * nitems == k * page_size
73 5d69a524 jcorgan
 */
74 5d69a524 jcorgan
static long
75 5d69a524 jcorgan
minimum_buffer_items (long type_size, long page_size)
76 5d69a524 jcorgan
{
77 48f9ca90 Josh Blum
  return page_size / boost::math::gcd (type_size, page_size);
78 5d69a524 jcorgan
}
79 5d69a524 jcorgan
80 5d69a524 jcorgan
81 2c8ea58e eb
gr_buffer::gr_buffer (int nitems, size_t sizeof_item, gr_block_sptr link)
82 5d69a524 jcorgan
  : d_base (0), d_bufsize (0), d_vmcircbuf (0),
83 2c8ea58e eb
    d_sizeof_item (sizeof_item), d_link(link),
84 c11a4310 Tom Rondeau
    d_write_index (0), d_abs_write_offset(0), d_done (false),
85 c11a4310 Tom Rondeau
    d_last_min_items_read(0)
86 5d69a524 jcorgan
{
87 5d69a524 jcorgan
  if (!allocate_buffer (nitems, sizeof_item))
88 5d69a524 jcorgan
    throw std::bad_alloc ();
89 5d69a524 jcorgan
90 5d69a524 jcorgan
  s_buffer_count++;
91 5d69a524 jcorgan
}
92 5d69a524 jcorgan
93 5d69a524 jcorgan
gr_buffer_sptr 
94 2c8ea58e eb
gr_make_buffer (int nitems, size_t sizeof_item, gr_block_sptr link)
95 5d69a524 jcorgan
{
96 2c8ea58e eb
  return gr_buffer_sptr (new gr_buffer (nitems, sizeof_item, link));
97 5d69a524 jcorgan
}
98 5d69a524 jcorgan
99 5d69a524 jcorgan
gr_buffer::~gr_buffer ()
100 5d69a524 jcorgan
{
101 5d69a524 jcorgan
  delete d_vmcircbuf;
102 5d69a524 jcorgan
  assert (d_readers.size() == 0);
103 5d69a524 jcorgan
  s_buffer_count--;
104 5d69a524 jcorgan
}
105 5d69a524 jcorgan
106 5d69a524 jcorgan
/*!
107 5d69a524 jcorgan
 * sets d_vmcircbuf, d_base, d_bufsize.
108 5d69a524 jcorgan
 * returns true iff successful.
109 5d69a524 jcorgan
 */
110 5d69a524 jcorgan
bool
111 5d69a524 jcorgan
gr_buffer::allocate_buffer (int nitems, size_t sizeof_item)
112 5d69a524 jcorgan
{
113 5d69a524 jcorgan
  int        orig_nitems = nitems;
114 5d69a524 jcorgan
  
115 5d69a524 jcorgan
  // Any buffersize we come up with must be a multiple of min_nitems.
116 5d69a524 jcorgan
117 5d69a524 jcorgan
  int granularity = gr_vmcircbuf_sysconfig::granularity ();
118 5d69a524 jcorgan
  int min_nitems =  minimum_buffer_items (sizeof_item, granularity);
119 5d69a524 jcorgan
120 5d69a524 jcorgan
  // Round-up nitems to a multiple of min_nitems.
121 5d69a524 jcorgan
122 5d69a524 jcorgan
  if (nitems % min_nitems != 0)
123 5d69a524 jcorgan
    nitems = ((nitems / min_nitems) + 1) * min_nitems;
124 5d69a524 jcorgan
125 5d69a524 jcorgan
  // If we rounded-up a whole bunch, give the user a heads up.
126 5d69a524 jcorgan
  // This only happens if sizeof_item is not a power of two.
127 5d69a524 jcorgan
128 5d69a524 jcorgan
  if (nitems > 2 * orig_nitems && nitems * (int) sizeof_item > granularity){
129 5d69a524 jcorgan
    std::cerr << "gr_buffer::allocate_buffer: warning: tried to allocate\n"
130 5d69a524 jcorgan
              << "   " << orig_nitems << " items of size "
131 5d69a524 jcorgan
              << sizeof_item << ". Due to alignment requirements\n"
132 5d69a524 jcorgan
              << "   " << nitems << " were allocated.  If this isn't OK, consider padding\n"
133 5d69a524 jcorgan
              << "   your structure to a power-of-two bytes.\n"
134 5d69a524 jcorgan
              << "   On this platform, our allocation granularity is " << granularity << " bytes.\n";
135 5d69a524 jcorgan
  }
136 5d69a524 jcorgan
137 5d69a524 jcorgan
  d_bufsize = nitems;
138 5d69a524 jcorgan
  d_vmcircbuf = gr_vmcircbuf_sysconfig::make (d_bufsize * d_sizeof_item);
139 5d69a524 jcorgan
  if (d_vmcircbuf == 0){
140 5d69a524 jcorgan
    std::cerr << "gr_buffer::allocate_buffer: failed to allocate buffer of size "
141 5d69a524 jcorgan
              << d_bufsize * d_sizeof_item / 1024 << " KB\n";
142 5d69a524 jcorgan
    return false;
143 5d69a524 jcorgan
  }
144 5d69a524 jcorgan
145 5d69a524 jcorgan
  d_base = (char *) d_vmcircbuf->pointer_to_first_copy ();
146 5d69a524 jcorgan
  return true;
147 5d69a524 jcorgan
}
148 5d69a524 jcorgan
149 5d69a524 jcorgan
150 5d69a524 jcorgan
int
151 2c8ea58e eb
gr_buffer::space_available ()
152 5d69a524 jcorgan
{
153 5d69a524 jcorgan
  if (d_readers.empty ())
154 5d69a524 jcorgan
    return d_bufsize - 1;        // See comment below
155 5d69a524 jcorgan
156 5d69a524 jcorgan
  else {
157 5d69a524 jcorgan
158 5d69a524 jcorgan
    // Find out the maximum amount of data available to our readers
159 5d69a524 jcorgan
160 5d69a524 jcorgan
    int        most_data = d_readers[0]->items_available ();
161 a6b5781e Tom Rondeau
    uint64_t min_items_read = d_readers[0]->nitems_read();
162 a6b5781e Tom Rondeau
    for (size_t i = 1; i < d_readers.size (); i++) {
163 5d69a524 jcorgan
      most_data = std::max (most_data, d_readers[i]->items_available ());
164 a6b5781e Tom Rondeau
      min_items_read = std::min(min_items_read, d_readers[i]->nitems_read());
165 a6b5781e Tom Rondeau
    }
166 a6b5781e Tom Rondeau
167 99c2b220 Tom Rondeau
    if(min_items_read != d_last_min_items_read) {
168 99c2b220 Tom Rondeau
      prune_tags(d_last_min_items_read);
169 99c2b220 Tom Rondeau
      d_last_min_items_read = min_items_read;
170 99c2b220 Tom Rondeau
    }
171 5d69a524 jcorgan
172 5d69a524 jcorgan
    // The -1 ensures that the case d_write_index == d_read_index is
173 5d69a524 jcorgan
    // unambiguous.  It indicates that there is no data for the reader
174 5d69a524 jcorgan
175 5d69a524 jcorgan
    return d_bufsize - most_data - 1;
176 5d69a524 jcorgan
  }
177 5d69a524 jcorgan
}
178 5d69a524 jcorgan
179 5d69a524 jcorgan
void *
180 5d69a524 jcorgan
gr_buffer::write_pointer ()
181 5d69a524 jcorgan
{
182 5d69a524 jcorgan
  return &d_base[d_write_index * d_sizeof_item];
183 5d69a524 jcorgan
}
184 5d69a524 jcorgan
185 5d69a524 jcorgan
void
186 5d69a524 jcorgan
gr_buffer::update_write_pointer (int nitems)
187 5d69a524 jcorgan
{
188 4b4da485 jcorgan
  gruel::scoped_lock guard(*mutex());
189 5d69a524 jcorgan
  d_write_index = index_add (d_write_index, nitems);
190 c3725a72 Tom Rondeau
  d_abs_write_offset += nitems;
191 5d69a524 jcorgan
}
192 5d69a524 jcorgan
193 2c8ea58e eb
void
194 2c8ea58e eb
gr_buffer::set_done (bool done)
195 2c8ea58e eb
{
196 4b4da485 jcorgan
  gruel::scoped_lock guard(*mutex());
197 2c8ea58e eb
  d_done = done;
198 2c8ea58e eb
}
199 2c8ea58e eb
200 5d69a524 jcorgan
gr_buffer_reader_sptr
201 2c8ea58e eb
gr_buffer_add_reader (gr_buffer_sptr buf, int nzero_preload, gr_block_sptr link)
202 5d69a524 jcorgan
{
203 62959cd5 eb
  if (nzero_preload < 0)
204 62959cd5 eb
    throw std::invalid_argument("gr_buffer_add_reader: nzero_preload must be >= 0");
205 62959cd5 eb
206 5d69a524 jcorgan
  gr_buffer_reader_sptr r (new gr_buffer_reader (buf,
207 5d69a524 jcorgan
                                                 buf->index_sub(buf->d_write_index,
208 2c8ea58e eb
                                                                nzero_preload),
209 2c8ea58e eb
                                                 link));
210 5d69a524 jcorgan
  buf->d_readers.push_back (r.get ());
211 5d69a524 jcorgan
212 5d69a524 jcorgan
  return r;
213 5d69a524 jcorgan
}
214 5d69a524 jcorgan
215 5d69a524 jcorgan
void
216 5d69a524 jcorgan
gr_buffer::drop_reader (gr_buffer_reader *reader)
217 5d69a524 jcorgan
{
218 5d69a524 jcorgan
  // isn't C++ beautiful...    GAG!
219 5d69a524 jcorgan
220 5d69a524 jcorgan
  std::vector<gr_buffer_reader *>::iterator result =
221 5d69a524 jcorgan
    std::find (d_readers.begin (), d_readers.end (), reader);
222 5d69a524 jcorgan
223 5d69a524 jcorgan
  if (result == d_readers.end ())
224 5d69a524 jcorgan
    throw std::invalid_argument ("gr_buffer::drop_reader");    // we didn't find it...
225 5d69a524 jcorgan
226 5d69a524 jcorgan
  d_readers.erase (result);
227 5d69a524 jcorgan
}
228 5d69a524 jcorgan
229 70ca24e7 Tom Rondeau
void
230 c1721c76 Josh Blum
gr_buffer::add_item_tag(const gr_tag_t &tag)
231 70ca24e7 Tom Rondeau
{
232 ab8c921b Tom Rondeau
  gruel::scoped_lock guard(*mutex());
233 70ca24e7 Tom Rondeau
  d_item_tags.push_back(tag);
234 70ca24e7 Tom Rondeau
}
235 70ca24e7 Tom Rondeau
236 2ce754d5 Tom Rondeau
void
237 2ce754d5 Tom Rondeau
gr_buffer::prune_tags(uint64_t max_time)
238 2ce754d5 Tom Rondeau
{
239 b3436047 Tom Rondeau
  /* NOTE: this function _should_ lock the mutex before editing
240 b3436047 Tom Rondeau
     d_item_tags. In practice, this function is only called at
241 b3436047 Tom Rondeau
     runtime by min_available_space in gr_block_executor.cc,
242 b3436047 Tom Rondeau
     which locks the mutex itself.
243 b3436047 Tom Rondeau
     
244 b3436047 Tom Rondeau
     If this function is used elsewhere, remember to lock the
245 b3436047 Tom Rondeau
     buffer's mutex al la the scoped_lock line below.
246 b3436047 Tom Rondeau
  */
247 2ce754d5 Tom Rondeau
  //gruel::scoped_lock guard(*mutex());
248 c1721c76 Josh Blum
  std::deque<gr_tag_t>::iterator itr = d_item_tags.begin();
249 2ce754d5 Tom Rondeau
250 2ce754d5 Tom Rondeau
  uint64_t item_time;
251 6925ccc6 Tom Rondeau
252 6925ccc6 Tom Rondeau
  // Since tags are not guarenteed to be in any particular order,
253 6925ccc6 Tom Rondeau
  // we need to erase here instead of pop_front. An erase in the
254 6925ccc6 Tom Rondeau
  // middle invalidates all iterators; so this resets the iterator
255 6925ccc6 Tom Rondeau
  // to find more. Mostly, we wil be erasing from the front and
256 6925ccc6 Tom Rondeau
  // therefore lose little time this way.
257 6925ccc6 Tom Rondeau
  while(itr != d_item_tags.end()) {
258 c1721c76 Josh Blum
    item_time = (*itr).offset;
259 2ce754d5 Tom Rondeau
    if(item_time < max_time) {
260 6925ccc6 Tom Rondeau
      d_item_tags.erase(itr);
261 6925ccc6 Tom Rondeau
      itr = d_item_tags.begin();
262 2ce754d5 Tom Rondeau
    }
263 6925ccc6 Tom Rondeau
    else
264 6925ccc6 Tom Rondeau
      itr++;
265 2ce754d5 Tom Rondeau
  }
266 2ce754d5 Tom Rondeau
}
267 2ce754d5 Tom Rondeau
268 5d69a524 jcorgan
long
269 5d69a524 jcorgan
gr_buffer_ncurrently_allocated ()
270 5d69a524 jcorgan
{
271 5d69a524 jcorgan
  return s_buffer_count;
272 5d69a524 jcorgan
}
273 5d69a524 jcorgan
274 5d69a524 jcorgan
// ----------------------------------------------------------------------------
275 5d69a524 jcorgan
276 2c8ea58e eb
gr_buffer_reader::gr_buffer_reader(gr_buffer_sptr buffer, unsigned int read_index,
277 2c8ea58e eb
                                   gr_block_sptr link)
278 e70f8a0d Tom Rondeau
  : d_buffer(buffer), d_read_index(read_index), d_abs_read_offset(0), d_link(link)
279 5d69a524 jcorgan
{
280 5d69a524 jcorgan
  s_buffer_reader_count++;
281 5d69a524 jcorgan
}
282 5d69a524 jcorgan
283 5d69a524 jcorgan
gr_buffer_reader::~gr_buffer_reader ()
284 5d69a524 jcorgan
{
285 5d69a524 jcorgan
  d_buffer->drop_reader(this);
286 5d69a524 jcorgan
  s_buffer_reader_count--;
287 5d69a524 jcorgan
}
288 5d69a524 jcorgan
   
289 5d69a524 jcorgan
int
290 5d69a524 jcorgan
gr_buffer_reader::items_available () const
291 5d69a524 jcorgan
{
292 5d69a524 jcorgan
  return d_buffer->index_sub (d_buffer->d_write_index, d_read_index);
293 5d69a524 jcorgan
}
294 5d69a524 jcorgan
295 5d69a524 jcorgan
const void *
296 5d69a524 jcorgan
gr_buffer_reader::read_pointer ()
297 5d69a524 jcorgan
{
298 5d69a524 jcorgan
  return &d_buffer->d_base[d_read_index * d_buffer->d_sizeof_item];
299 5d69a524 jcorgan
}
300 5d69a524 jcorgan
301 5d69a524 jcorgan
void
302 5d69a524 jcorgan
gr_buffer_reader::update_read_pointer (int nitems)
303 5d69a524 jcorgan
{
304 4b4da485 jcorgan
  gruel::scoped_lock guard(*mutex());
305 5d69a524 jcorgan
  d_read_index = d_buffer->index_add (d_read_index, nitems);
306 e70f8a0d Tom Rondeau
  d_abs_read_offset += nitems;
307 5d69a524 jcorgan
}
308 5d69a524 jcorgan
309 6d439361 Tom Rondeau
void
310 c1721c76 Josh Blum
gr_buffer_reader::get_tags_in_range(std::vector<gr_tag_t> &v,
311 6d439361 Tom Rondeau
                                    uint64_t abs_start,
312 95eaad32 Tom Rondeau
                                    uint64_t abs_end)
313 70ca24e7 Tom Rondeau
{
314 ab8c921b Tom Rondeau
  gruel::scoped_lock guard(*mutex());
315 ab8c921b Tom Rondeau
316 6d439361 Tom Rondeau
  v.resize(0);
317 c1721c76 Josh Blum
  std::deque<gr_tag_t>::iterator itr = d_buffer->get_tags_begin();
318 70ca24e7 Tom Rondeau
  
319 95eaad32 Tom Rondeau
  uint64_t item_time;
320 d58d250c Tom Rondeau
  while(itr != d_buffer->get_tags_end()) {
321 c1721c76 Josh Blum
    item_time = (*itr).offset;
322 70ca24e7 Tom Rondeau
323 7c78b850 Tom Rondeau
    if((item_time >= abs_start) && (item_time < abs_end)) {
324 6d439361 Tom Rondeau
      v.push_back(*itr);
325 70ca24e7 Tom Rondeau
    }
326 70ca24e7 Tom Rondeau
327 70ca24e7 Tom Rondeau
    itr++;
328 70ca24e7 Tom Rondeau
  }
329 70ca24e7 Tom Rondeau
}
330 70ca24e7 Tom Rondeau
331 5d69a524 jcorgan
long
332 5d69a524 jcorgan
gr_buffer_reader_ncurrently_allocated ()
333 5d69a524 jcorgan
{
334 5d69a524 jcorgan
  return s_buffer_reader_count;
335 5d69a524 jcorgan
}