diff options
author | Tom Rondeau <trondeau@vt.edu> | 2013-04-17 13:43:52 -0400 |
---|---|---|
committer | Tom Rondeau <trondeau@vt.edu> | 2013-04-29 14:52:56 -0400 |
commit | f3e2e07201c50033bf6c9d0c6a6f068557b4f17f (patch) | |
tree | 140b3c2d20a951ffd4abd564c3378ee2e2f9fc7c /gnuradio-runtime/lib/vmcircbuf_mmap_shm_open.cc | |
parent | 35303ae975a5b1bdecc2492bc96e2b8e89b62a3d (diff) |
runtime: converting runtime core to gr namespace, gnuradio include dir.
Diffstat (limited to 'gnuradio-runtime/lib/vmcircbuf_mmap_shm_open.cc')
-rw-r--r-- | gnuradio-runtime/lib/vmcircbuf_mmap_shm_open.cc | 204 |
1 files changed, 204 insertions, 0 deletions
diff --git a/gnuradio-runtime/lib/vmcircbuf_mmap_shm_open.cc b/gnuradio-runtime/lib/vmcircbuf_mmap_shm_open.cc new file mode 100644 index 0000000000..7b461bc26b --- /dev/null +++ b/gnuradio-runtime/lib/vmcircbuf_mmap_shm_open.cc @@ -0,0 +1,204 @@ +/* -*- c++ -*- */ +/* + * Copyright 2003,2011,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 "vmcircbuf_mmap_shm_open.h" +#include <stdexcept> +#include <assert.h> +#include <unistd.h> +#include <fcntl.h> +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif +#include <errno.h> +#include <stdio.h> +#include "pagesize.h" +#include <gnuradio/sys_paths.h> + +namespace gr { + + vmcircbuf_mmap_shm_open::vmcircbuf_mmap_shm_open(int size) + : gr::vmcircbuf(size) + { +#if !defined(HAVE_MMAP) || !defined(HAVE_SHM_OPEN) + fprintf(stderr, "gr::vmcircbuf_mmap_shm_open: mmap or shm_open is not available\n"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); +#else + static int s_seg_counter = 0; + + if(size <= 0 || (size % gr::pagesize ()) != 0) { + fprintf(stderr, "gr::vmcircbuf_mmap_shm_open: invalid size = %d\n", size); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + + int shm_fd = -1; + char seg_name[1024]; + static bool portable_format = true; + + // open a new named shared memory segment + while(1) { + if(portable_format) { + + // This is the POSIX recommended "portable format". + // Of course the "portable format" doesn't work on some systems... + + snprintf(seg_name, sizeof(seg_name), + "/gnuradio-%d-%d", getpid(), s_seg_counter); + } + else { + + // Where the "portable format" doesn't work, we try building + // a full filesystem pathname pointing into a suitable temporary directory. + + snprintf(seg_name, sizeof(seg_name), + "%s/gnuradio-%d-%d", gr::tmp_path(), getpid(), s_seg_counter); + } + + shm_fd = shm_open(seg_name, O_RDWR | O_CREAT | O_EXCL, 0600); + if(shm_fd == -1 && errno == EACCES && portable_format) { + portable_format = false; + continue; // try again using "non-portable format" + } + + s_seg_counter++; + + if(shm_fd == -1) { + if(errno == EEXIST) // Named segment already exists (shouldn't happen). Try again + continue; + + char msg[1024]; + snprintf(msg, sizeof(msg), "gr::vmcircbuf_mmap_shm_open: shm_open [%s]", seg_name); + perror(msg); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + break; + } + + // We've got a new shared memory segment fd open. + // Now set it's length to 2x what we really want and mmap it in. + if(ftruncate(shm_fd, (off_t)2 * size) == -1) { + close(shm_fd); // cleanup + perror("gr::vmcircbuf_mmap_shm_open: ftruncate (1)"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + + void *first_copy = mmap(0, 2 * size, + PROT_READ | PROT_WRITE, MAP_SHARED, + shm_fd, (off_t) 0); + + if(first_copy == MAP_FAILED) { + close(shm_fd); // cleanup + perror("gr::vmcircbuf_mmap_shm_open: mmap (1)"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + + // unmap the 2nd half + if(munmap ((char *) first_copy + size, size) == -1) { + close(shm_fd); // cleanup + perror("gr::vmcircbuf_mmap_shm_open: munmap (1)"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + + // map the first half into the now available hole where the + // second half used to be. + void *second_copy = mmap((char*)first_copy + size, size, + PROT_READ | PROT_WRITE, MAP_SHARED, + shm_fd, (off_t)0); + + if(second_copy == MAP_FAILED) { + close(shm_fd); // cleanup + perror("gr::vmcircbuf_mmap_shm_open: mmap (2)"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + +#if 0 // OS/X doesn't allow you to resize the segment + + // cut the shared memory segment down to size + if(ftruncate(shm_fd, (off_t)size) == -1) { + close(shm_fd); // cleanup + perror("gr::vmcircbuf_mmap_shm_open: ftruncate (2)"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } +#endif + + close(shm_fd); // fd no longer needed. The mapping is retained. + + if(shm_unlink(seg_name) == -1) { // unlink the seg_name. + perror("gr::vmcircbuf_mmap_shm_open: shm_unlink"); + throw std::runtime_error("gr::vmcircbuf_mmap_shm_open"); + } + + // Now remember the important stuff + d_base = (char*)first_copy; + d_size = size; +#endif + } + + vmcircbuf_mmap_shm_open::~vmcircbuf_mmap_shm_open() + { +#if defined(HAVE_MMAP) + if(munmap (d_base, 2 * d_size) == -1) { + perror("gr::vmcircbuf_mmap_shm_open: munmap (2)"); + } +#endif + } + + // ---------------------------------------------------------------- + // The factory interface + // ---------------------------------------------------------------- + + gr::vmcircbuf_factory *vmcircbuf_mmap_shm_open_factory::s_the_factory = 0; + + gr::vmcircbuf_factory * + vmcircbuf_mmap_shm_open_factory::singleton() + { + if(s_the_factory) + return s_the_factory; + + s_the_factory = new gr::vmcircbuf_mmap_shm_open_factory(); + return s_the_factory; + } + + int + vmcircbuf_mmap_shm_open_factory::granularity() + { + return gr::pagesize(); + } + + gr::vmcircbuf * + vmcircbuf_mmap_shm_open_factory::make(int size) + { + try { + return new vmcircbuf_mmap_shm_open(size); + } + catch (...) { + return 0; + } + } + +} /* namespace gr */ |