1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
/* -*- c++ -*- */
/*
* Copyright 2020 Free Software Foundation, Inc.
*
* This file is part of GNU Radio
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "vmcircbuf.h"
#include <gnuradio/block.h>
#include <gnuradio/buffer_double_mapped.h>
#include <gnuradio/buffer_reader.h>
#include <gnuradio/integer_math.h>
#include <gnuradio/math.h>
#include <assert.h>
#include <algorithm>
#include <iostream>
#include <stdexcept>
namespace gr {
/*
* Compute the minimum number of buffer items that work (i.e.,
* address space wrap-around works). To work is to satisfy this
* constraint for integer buffer_size and k:
*
* type_size * nitems == k * page_size
*/
static inline long minimum_buffer_items(long type_size, long page_size)
{
return page_size / GR_GCD(type_size, page_size);
}
buffer_double_mapped::buffer_double_mapped(int nitems,
size_t sizeof_item,
uint64_t downstream_lcm_nitems,
block_sptr link)
: buffer(BufferMappingType::DoubleMapped,
nitems,
sizeof_item,
downstream_lcm_nitems,
link)
{
gr::configure_default_loggers(d_logger, d_debug_logger, "buffer_double_mapped");
if (!allocate_buffer(nitems, sizeof_item))
throw std::bad_alloc();
#ifdef BUFFER_DEBUG
// BUFFER DEBUG
{
std::ostringstream msg;
msg << "[" << this << "] "
<< "buffer_double_mapped constructor -- history: " << link->history();
GR_LOG_DEBUG(d_logger, msg.str());
}
#endif
}
buffer_sptr make_buffer_double_mapped(int nitems,
size_t sizeof_item,
uint64_t downstream_lcm_nitems,
block_sptr link)
{
return buffer_sptr(
new buffer_double_mapped(nitems, sizeof_item, downstream_lcm_nitems, link));
}
buffer_double_mapped::~buffer_double_mapped() {}
/*!
* sets d_vmcircbuf, d_base, d_bufsize.
* returns true iff successful.
*/
bool buffer_double_mapped::allocate_buffer(int nitems, size_t sizeof_item)
{
int orig_nitems = nitems;
// Any buffer size 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) {
auto msg =
str(boost::format(
"allocate_buffer: tried to allocate"
" %d items of size %d. Due to alignment requirements"
" %d were allocated. If this isn't OK, consider padding"
" your structure to a power-of-two bytes."
" On this platform, our allocation granularity is %d bytes.") %
orig_nitems % sizeof_item % nitems % granularity);
GR_LOG_WARN(d_logger, msg.c_str());
}
d_bufsize = nitems;
d_vmcircbuf.reset(gr::vmcircbuf_sysconfig::make(d_bufsize * d_sizeof_item));
if (d_vmcircbuf == 0) {
std::ostringstream msg;
msg << "gr::buffer::allocate_buffer: failed to allocate buffer of size "
<< d_bufsize * d_sizeof_item / 1024 << " KB";
GR_LOG_ERROR(d_logger, msg.str());
return false;
}
d_base = (char*)d_vmcircbuf->pointer_to_first_copy();
return true;
}
int buffer_double_mapped::space_available()
{
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();
uint64_t min_items_read = d_readers[0]->nitems_read();
for (size_t i = 1; i < d_readers.size(); i++) {
most_data = std::max(most_data, d_readers[i]->items_available());
min_items_read = std::min(min_items_read, d_readers[i]->nitems_read());
}
if (min_items_read != d_last_min_items_read) {
prune_tags(d_last_min_items_read);
d_last_min_items_read = min_items_read;
}
#ifdef BUFFER_DEBUG
// BUFFER DEBUG
std::ostringstream msg;
msg << "[" << this << "] "
<< "space_available() called d_write_index: " << d_write_index
<< " -- space_available: " << (d_bufsize - most_data - 1);
GR_LOG_DEBUG(d_logger, msg.str());
#endif
// 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;
}
}
} /* namespace gr */
|