1 /* -*- c++ -*- */
2 /*
3 * Copyright 2003,2013 Free Software Foundation, Inc.
4 *
5 * This file is part of GNU Radio
6 *
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
11 *
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "local_sighandler.h"
28 #include "vmcircbuf.h"
29 #include "vmcircbuf_prefs.h"
30 #include <assert.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <boost/format.hpp>
34 #include <stdexcept>
35 #include <vector>
36
37 // all the factories we know about
38 #include "vmcircbuf_createfilemapping.h"
39 #include "vmcircbuf_mmap_shm_open.h"
40 #include "vmcircbuf_mmap_tmpfile.h"
41 #include "vmcircbuf_sysv_shm.h"
42
43 gr::thread::mutex s_vm_mutex;
44
45 namespace gr {
46
47 static const char* FACTORY_PREF_KEY = "vmcircbuf_default_factory";
48
~vmcircbuf()49 vmcircbuf::~vmcircbuf() {}
50
~vmcircbuf_factory()51 vmcircbuf_factory::~vmcircbuf_factory() {}
52
53 // ----------------------------------------------------------------
54
55 static vmcircbuf_factory* s_default_factory = 0;
56
get_default_factory()57 vmcircbuf_factory* vmcircbuf_sysconfig::get_default_factory()
58 {
59 if (s_default_factory)
60 return s_default_factory;
61
62 bool verbose = false;
63
64 std::vector<gr::vmcircbuf_factory*> all = all_factories();
65
66 char name[1024];
67 if (gr::vmcircbuf_prefs::get(FACTORY_PREF_KEY, name, sizeof(name)) >= 0) {
68 for (unsigned int i = 0; i < all.size(); i++) {
69 if (strncmp(name, all[i]->name(), strlen(all[i]->name())) == 0) {
70 s_default_factory = all[i];
71 if (verbose)
72 fprintf(stderr,
73 "gr::vmcircbuf_sysconfig: using %s\n",
74 s_default_factory->name());
75 return s_default_factory;
76 }
77 }
78 }
79
80 // either we don't have a default, or the default named is not in our
81 // list of factories. Find the first factory that works.
82
83 if (verbose)
84 fprintf(stderr, "gr::vmcircbuf_sysconfig: finding a working factory...\n");
85
86 for (unsigned int i = 0; i < all.size(); i++) {
87 if (test_factory(all[i], verbose)) {
88 set_default_factory(all[i]);
89 return s_default_factory;
90 }
91 }
92
93 // We're screwed!
94 fprintf(stderr, "gr::vmcircbuf_sysconfig: unable to find a working factory!\n");
95 throw std::runtime_error("gr::vmcircbuf_sysconfig");
96 }
97
all_factories()98 std::vector<vmcircbuf_factory*> vmcircbuf_sysconfig::all_factories()
99 {
100 std::vector<vmcircbuf_factory*> result;
101
102 result.push_back(gr::vmcircbuf_createfilemapping_factory::singleton());
103 #ifdef TRY_SHM_VMCIRCBUF
104 result.push_back(gr::vmcircbuf_sysv_shm_factory::singleton());
105 result.push_back(gr::vmcircbuf_mmap_shm_open_factory::singleton());
106 #endif
107 result.push_back(gr::vmcircbuf_mmap_tmpfile_factory::singleton());
108
109 return result;
110 }
111
set_default_factory(vmcircbuf_factory * f)112 void vmcircbuf_sysconfig::set_default_factory(vmcircbuf_factory* f)
113 {
114 gr::vmcircbuf_prefs::set(FACTORY_PREF_KEY, f->name());
115 s_default_factory = f;
116 }
117
118
119 // ------------------------------------------------------------------------
120 // test code for vmcircbuf factories
121 // ------------------------------------------------------------------------
122
init_buffer(vmcircbuf * c,int counter,int size)123 static void init_buffer(vmcircbuf* c, int counter, int size)
124 {
125 unsigned int* p = (unsigned int*)c->pointer_to_first_copy();
126 for (unsigned int i = 0; i < size / sizeof(int); i++)
127 p[i] = counter + i;
128 }
129
130 static bool
check_mapping(vmcircbuf * c,int counter,int size,const char * msg,bool verbose)131 check_mapping(vmcircbuf* c, int counter, int size, const char* msg, bool verbose)
132 {
133 bool ok = true;
134
135 if (verbose)
136 fprintf(stderr, "... %s", msg);
137
138 unsigned int* p1 = (unsigned int*)c->pointer_to_first_copy();
139 unsigned int* p2 = (unsigned int*)c->pointer_to_second_copy();
140
141 // fprintf(stderr, "p1 = %p, p2 = %p\n", p1, p2);
142
143 for (unsigned int i = 0; i < size / sizeof(int); i++) {
144 if (p1[i] != counter + i) {
145 ok = false;
146 if (verbose)
147 fprintf(stderr, " p1[%d] == %u, expected %u\n", i, p1[i], counter + i);
148 break;
149 }
150 if (p2[i] != counter + i) {
151 if (verbose)
152 fprintf(stderr, " p2[%d] == %u, expected %u\n", i, p2[i], counter + i);
153 ok = false;
154 break;
155 }
156 }
157
158 if (ok && verbose) {
159 fprintf(stderr, " OK\n");
160 }
161 return ok;
162 }
163
memsize(int size)164 static const char* memsize(int size)
165 {
166 static std::string buf;
167 if (size >= (1 << 20)) {
168 buf = str(boost::format("%dMB") % (size / (1 << 20)));
169 } else if (size >= (1 << 10)) {
170 buf = str(boost::format("%dKB") % (size / (1 << 10)));
171 } else {
172 buf = str(boost::format("%d") % size);
173 }
174 return buf.c_str();
175 }
176
177 static bool
test_a_bunch(vmcircbuf_factory * factory,int n,int size,int * start_ptr,bool verbose)178 test_a_bunch(vmcircbuf_factory* factory, int n, int size, int* start_ptr, bool verbose)
179 {
180 bool ok = true;
181 std::vector<int> counter(n);
182 std::vector<vmcircbuf*> c(n);
183 int cum_size = 0;
184
185 for (int i = 0; i < n; i++) {
186 counter[i] = *start_ptr;
187 *start_ptr += size;
188 if ((c[i] = factory->make(size)) == 0) {
189 if (verbose)
190 fprintf(
191 stderr,
192 "Failed to allocate gr::vmcircbuf number %d of size %d (cum = %s)\n",
193 i + 1,
194 size,
195 memsize(cum_size));
196 return false;
197 }
198 init_buffer(c[i], counter[i], size);
199 cum_size += size;
200 }
201
202 for (int i = 0; i < n; i++) {
203 std::string msg =
204 str(boost::format("test_a_bunch_%dx%s[%d]") % n % memsize(size) % i);
205 ok &= check_mapping(c[i], counter[i], size, msg.c_str(), verbose);
206 }
207
208 for (int i = 0; i < n; i++) {
209 delete c[i];
210 c[i] = 0;
211 }
212
213 return ok;
214 }
215
standard_tests(vmcircbuf_factory * f,int verbose)216 static bool standard_tests(vmcircbuf_factory* f, int verbose)
217 {
218 if (verbose >= 1)
219 fprintf(stderr, "Testing %s...\n", f->name());
220
221 bool v = verbose >= 2;
222 int granularity = f->granularity();
223 int start = 0;
224 bool ok = true;
225
226 ok &= test_a_bunch(f, 1, 1 * granularity, &start, v); // 1 x 4KB = 4KB
227
228 if (ok) {
229 ok &= test_a_bunch(f, 64, 4 * granularity, &start, v); // 64 x 16KB = 1MB
230 ok &= test_a_bunch(f, 4, 4 * (1L << 20), &start, v); // 4 x 4MB = 16MB
231 // ok &= test_a_bunch(f, 256, 256 * (1L << 10), &start, v); // 256 x 256KB =
232 // 64MB
233 }
234
235 if (verbose >= 1)
236 fprintf(stderr, "....... %s: %s", f->name(), ok ? "OK\n" : "Doesn't work\n");
237
238 return ok;
239 }
240
test_factory(vmcircbuf_factory * f,int verbose)241 bool vmcircbuf_sysconfig::test_factory(vmcircbuf_factory* f, int verbose)
242 {
243 // Install local signal handlers for SIGSEGV and SIGBUS.
244 // If something goes wrong, these signals may be invoked.
245
246 #ifdef SIGSEGV
247 gr::local_sighandler sigsegv(SIGSEGV, gr::local_sighandler::throw_signal);
248 #endif
249 #ifdef SIGBUS
250 gr::local_sighandler sigbus(SIGBUS, gr::local_sighandler::throw_signal);
251 #endif
252 #ifdef SIGSYS
253 gr::local_sighandler sigsys(SIGSYS, gr::local_sighandler::throw_signal);
254 #endif
255
256 try {
257 return standard_tests(f, verbose);
258 } catch (gr::signal& sig) {
259 if (verbose) {
260 fprintf(stderr, "....... %s: %s", f->name(), "Doesn't work\n");
261 fprintf(stderr,
262 "gr::vmcircbuf_factory::test_factory (%s): caught %s\n",
263 f->name(),
264 sig.name().c_str());
265 return false;
266 }
267 } catch (...) {
268 if (verbose) {
269 fprintf(stderr, "....... %s: %s", f->name(), "Doesn't work\n");
270 fprintf(stderr,
271 "gr::vmcircbuf_factory::test_factory (%s): some kind of uncaught "
272 "exception\n",
273 f->name());
274 }
275 return false;
276 }
277 return false; // never gets here. shut compiler up.
278 }
279
test_all_factories(int verbose)280 bool vmcircbuf_sysconfig::test_all_factories(int verbose)
281 {
282 bool ok = false;
283
284 std::vector<vmcircbuf_factory*> all = all_factories();
285
286 for (unsigned int i = 0; i < all.size(); i++)
287 ok |= test_factory(all[i], verbose);
288
289 return ok;
290 }
291
292 } /* namespace gr */
293