diff options
Diffstat (limited to 'gnuradio-runtime/lib/vmcircbuf.cc')
-rw-r--r-- | gnuradio-runtime/lib/vmcircbuf.cc | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/gnuradio-runtime/lib/vmcircbuf.cc b/gnuradio-runtime/lib/vmcircbuf.cc new file mode 100644 index 0000000000..0fccb3d914 --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf.cc @@ -0,0 +1,299 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2013 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 3, 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., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <assert.h> +#include <stdexcept> +#include <stdio.h> +#include <string.h> +#include <vector> +#include <boost/format.hpp> +#include "vmcircbuf.h" +#include "vmcircbuf_prefs.h" +#include "local_sighandler.h" + +// all the factories we know about +#include "vmcircbuf_createfilemapping.h" +#include "vmcircbuf_sysv_shm.h" +#include "vmcircbuf_mmap_shm_open.h" +#include "vmcircbuf_mmap_tmpfile.h" + +namespace gr { + + static const char *FACTORY_PREF_KEY = "vmcircbuf_default_factory"; + + vmcircbuf::~vmcircbuf() + { + } + + vmcircbuf_factory::~vmcircbuf_factory() + { + } + + // ---------------------------------------------------------------- + + static vmcircbuf_factory *s_default_factory = 0; + + vmcircbuf_factory * + vmcircbuf_sysconfig::get_default_factory() + { + if(s_default_factory) + return s_default_factory; + + bool verbose = false; + + std::vector<gr::vmcircbuf_factory *> all = all_factories (); + + const char *name = gr::vmcircbuf_prefs::get(FACTORY_PREF_KEY); + + if(name) { + for(unsigned int i = 0; i < all.size (); i++) { + if(strcmp(name, all[i]->name ()) == 0) { + s_default_factory = all[i]; + if(verbose) + fprintf(stderr, "gr::vmcircbuf_sysconfig: using %s\n", + s_default_factory->name()); + return s_default_factory; + } + } + } + + // either we don't have a default, or the default named is not in our + // list of factories. Find the first factory that works. + + if(verbose) + fprintf(stderr, "gr::vmcircbuf_sysconfig: finding a working factory...\n"); + + for(unsigned int i = 0; i < all.size (); i++) { + if(test_factory(all[i], verbose)) { + set_default_factory(all[i]); + return s_default_factory; + } + } + + // We're screwed! + fprintf(stderr, "gr::vmcircbuf_sysconfig: unable to find a working factory!\n"); + throw std::runtime_error("gr::vmcircbuf_sysconfig"); + } + + std::vector<vmcircbuf_factory *> + vmcircbuf_sysconfig::all_factories() + { + std::vector<vmcircbuf_factory*> result; + + result.push_back(gr::vmcircbuf_createfilemapping_factory::singleton()); +#ifdef TRY_SHM_VMCIRCBUF + result.push_back(gr::vmcircbuf_sysv_shm_factory::singleton()); + result.push_back(gr::vmcircbuf_mmap_shm_open_factory::singleton()); +#endif + result.push_back (gr::vmcircbuf_mmap_tmpfile_factory::singleton()); + + return result; + } + + void + vmcircbuf_sysconfig::set_default_factory(vmcircbuf_factory *f) + { + gr::vmcircbuf_prefs::set(FACTORY_PREF_KEY, f->name()); + s_default_factory = f; + } + + + // ------------------------------------------------------------------------ + // test code for vmcircbuf factories + // ------------------------------------------------------------------------ + + static void + init_buffer(vmcircbuf *c, int counter, int size) + { + unsigned int *p = (unsigned int*)c->pointer_to_first_copy(); + for(unsigned int i = 0; i < size / sizeof(int); i++) + p[i] = counter + i; + } + + static bool + check_mapping(vmcircbuf *c, int counter, int size, const char *msg, bool verbose) + { + bool ok = true; + + if(verbose) + fprintf(stderr, "... %s", msg); + + unsigned int *p1 = (unsigned int *)c->pointer_to_first_copy(); + unsigned int *p2 = (unsigned int *)c->pointer_to_second_copy(); + + // fprintf(stderr, "p1 = %p, p2 = %p\n", p1, p2); + + for(unsigned int i = 0; i < size / sizeof (int); i++) { + if(p1[i] != counter + i) { + ok = false; + if(verbose) + fprintf(stderr, " p1[%d] == %u, expected %u\n", i, p1[i], counter + i); + break; + } + if(p2[i] != counter + i) { + if(verbose) + fprintf(stderr, " p2[%d] == %u, expected %u\n", i, p2[i], counter + i); + ok = false; + break; + } + } + + if(ok && verbose) { + fprintf(stderr, " OK\n"); + } + return ok; + } + + static const char * + memsize(int size) + { + static std::string buf; + if(size >= (1 << 20)) { + buf = str(boost::format("%dMB") % (size / (1 << 20))); + } + else if(size >= (1 << 10)){ + buf = str(boost::format("%dKB") % (size / (1 << 10))); + } + else { + buf = str(boost::format("%d") % size); + } + return buf.c_str(); + } + + static bool + test_a_bunch(vmcircbuf_factory *factory, int n, int size, int *start_ptr, bool verbose) + { + bool ok = true; + std::vector<int> counter(n); + std::vector<vmcircbuf*> c(n); + int cum_size = 0; + + for(int i = 0; i < n; i++) { + counter[i] = *start_ptr; + *start_ptr += size; + if((c[i] = factory->make (size)) == 0) { + if(verbose) + fprintf(stderr, + "Failed to allocate gr::vmcircbuf number %d of size %d (cum = %s)\n", + i + 1, size, memsize(cum_size)); + return false; + } + init_buffer(c[i], counter[i], size); + cum_size += size; + } + + for(int i = 0; i < n; i++) { + std::string msg = str(boost::format("test_a_bunch_%dx%s[%d]") % n % memsize(size) % i); + ok &= check_mapping(c[i], counter[i], size, msg.c_str(), verbose); + } + + for(int i = 0; i < n; i++) { + delete c[i]; + c[i] = 0; + } + + return ok; + } + + static bool + standard_tests(vmcircbuf_factory *f, int verbose) + { + if(verbose >= 1) + fprintf(stderr, "Testing %s...\n", f->name()); + + bool v = verbose >= 2; + int granularity = f->granularity(); + int start = 0; + bool ok = true; + + ok &= test_a_bunch(f, 1, 1 * granularity, &start, v); // 1 x 4KB = 4KB + + if(ok) { + ok &= test_a_bunch(f, 64, 4 * granularity, &start, v); // 64 x 16KB = 1MB + ok &= test_a_bunch(f, 4, 4 * (1L << 20), &start, v); // 4 x 4MB = 16MB + // ok &= test_a_bunch(f, 256, 256 * (1L << 10), &start, v); // 256 x 256KB = 64MB + } + + if(verbose >= 1) + fprintf(stderr, "....... %s: %s", f->name(), ok ? "OK\n" : "Doesn't work\n"); + + return ok; + } + + bool + vmcircbuf_sysconfig::test_factory(vmcircbuf_factory *f, int verbose) + { + // Install local signal handlers for SIGSEGV and SIGBUS. + // If something goes wrong, these signals may be invoked. + +#ifdef SIGSEGV + gr::local_sighandler sigsegv (SIGSEGV, gr::local_sighandler::throw_signal); +#endif +#ifdef SIGBUS + gr::local_sighandler sigbus (SIGBUS, gr::local_sighandler::throw_signal); +#endif +#ifdef SIGSYS + gr::local_sighandler sigsys (SIGSYS, gr::local_sighandler::throw_signal); +#endif + + try { + return standard_tests (f, verbose); + } + catch(gr::signal &sig) { + if(verbose) { + fprintf(stderr, "....... %s: %s", f->name(), "Doesn't work\n"); + fprintf(stderr, + "gr::vmcircbuf_factory::test_factory (%s): caught %s\n", + f->name(), sig.name().c_str()); + return false; + } + } + catch (...) { + if(verbose) { + fprintf(stderr, "....... %s: %s", f->name(), "Doesn't work\n"); + fprintf(stderr, + "gr::vmcircbuf_factory::test_factory (%s): some kind of uncaught exception\n", + f->name()); + } + return false; + } + return false; // never gets here. shut compiler up. + } + + bool + vmcircbuf_sysconfig::test_all_factories(int verbose) + { + bool ok = false; + + std::vector<vmcircbuf_factory *> all = all_factories(); + + for(unsigned int i = 0; i < all.size (); i++) + ok |= test_factory(all[i], verbose); + + return ok; + } + +} /* namespace gr */ |