3 * Copyright 2003 Free Software Foundation, Inc.
5 * This file is part of GNU Radio
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)
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.
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.
26 #include <gr_vmcircbuf_mmap_shm_open.h>
31 #ifdef HAVE_SYS_TYPES_H
32 #include <sys/types.h>
34 #ifdef HAVE_SYS_MMAN_H
39 #include <gr_pagesize.h>
40 #include <gr_tmp_path.h>
43 gr_vmcircbuf_mmap_shm_open::gr_vmcircbuf_mmap_shm_open (int size)
46 #if !defined(HAVE_MMAP) || !defined(HAVE_SHM_OPEN)
47 fprintf (stderr, "gr_vmcircbuf_mmap_shm_open: mmap or shm_open is not available\n");
48 throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
50 static int s_seg_counter = 0;
52 if (size <= 0 || (size % gr_pagesize ()) != 0){
53 fprintf (stderr, "gr_vmcircbuf_mmap_shm_open: invalid size = %d\n", size);
54 throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
59 static bool portable_format = true;
61 // open a new named shared memory segment
66 // This is the POSIX recommended "portable format".
67 // Of course the "portable format" doesn't work on some systems...
69 snprintf (seg_name, sizeof (seg_name),
70 "/gnuradio-%d-%d", getpid (), s_seg_counter);
74 // Where the "portable format" doesn't work, we try building
75 // a full filesystem pathname pointing into a suitable temporary directory.
77 snprintf (seg_name, sizeof (seg_name),
78 "%s/gnuradio-%d-%d", gr_tmp_path (), getpid (), s_seg_counter);
81 shm_fd = shm_open (seg_name, O_RDWR | O_CREAT | O_EXCL, 0600);
82 if (shm_fd == -1 && errno == EACCES && portable_format){
83 portable_format = false;
84 continue; // try again using "non-portable format"
90 if (errno == EEXIST) // Named segment already exists (shouldn't happen). Try again
94 snprintf (msg, sizeof (msg), "gr_vmcircbuf_mmap_shm_open: shm_open [%s]", seg_name);
96 throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
101 // We've got a new shared memory segment fd open.
102 // Now set it's length to 2x what we really want and mmap it in.
104 if (ftruncate (shm_fd, (off_t) 2 * size) == -1){
105 close (shm_fd); // cleanup
106 perror ("gr_vmcircbuf_mmap_shm_open: ftruncate (1)");
107 throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
110 void *first_copy = mmap (0, 2 * size,
111 PROT_READ | PROT_WRITE, MAP_SHARED,
114 if (first_copy == MAP_FAILED){
115 close (shm_fd); // cleanup
116 perror ("gr_vmcircbuf_mmap_shm_open: mmap (1)");
117 throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
120 // unmap the 2nd half
121 if (munmap ((char *) first_copy + size, size) == -1){
122 close (shm_fd); // cleanup
123 perror ("gr_vmcircbuf_mmap_shm_open: munmap (1)");
124 throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
127 // map the first half into the now available hole where the
128 // second half used to be.
130 void *second_copy = mmap ((char *) first_copy + size, size,
131 PROT_READ | PROT_WRITE, MAP_SHARED,
134 if (second_copy == MAP_FAILED){
135 close (shm_fd); // cleanup
136 perror ("gr_vmcircbuf_mmap_shm_open: mmap (2)");
137 throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
140 #if 0 // OS/X doesn't allow you to resize the segment
142 // cut the shared memory segment down to size
143 if (ftruncate (shm_fd, (off_t) size) == -1){
144 close (shm_fd); // cleanup
145 perror ("gr_vmcircbuf_mmap_shm_open: ftruncate (2)");
146 throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
150 close (shm_fd); // fd no longer needed. The mapping is retained.
152 if (shm_unlink (seg_name) == -1){ // unlink the seg_name.
153 perror ("gr_vmcircbuf_mmap_shm_open: shm_unlink");
154 throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
157 // Now remember the important stuff
159 d_base = (char *) first_copy;
164 gr_vmcircbuf_mmap_shm_open::~gr_vmcircbuf_mmap_shm_open ()
166 #if defined(HAVE_MMAP)
167 if (munmap (d_base, 2 * d_size) == -1){
168 perror ("gr_vmcircbuf_mmap_shm_open: munmap (2)");
173 // ----------------------------------------------------------------
174 // The factory interface
175 // ----------------------------------------------------------------
178 gr_vmcircbuf_factory *gr_vmcircbuf_mmap_shm_open_factory::s_the_factory = 0;
180 gr_vmcircbuf_factory *
181 gr_vmcircbuf_mmap_shm_open_factory::singleton ()
184 return s_the_factory;
186 s_the_factory = new gr_vmcircbuf_mmap_shm_open_factory ();
187 return s_the_factory;
191 gr_vmcircbuf_mmap_shm_open_factory::granularity ()
193 return gr_pagesize ();
197 gr_vmcircbuf_mmap_shm_open_factory::make (int size)
200 return new gr_vmcircbuf_mmap_shm_open (size);