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_tmpfile.h>
31 #ifdef HAVE_SYS_TYPES_H
32 #include <sys/types.h>
34 #ifdef HAVE_SYS_MMAN_H
41 #include <gr_pagesize.h>
42 #include <gr_tmp_path.h>
44 gr_vmcircbuf_mmap_tmpfile::gr_vmcircbuf_mmap_tmpfile (int size)
47 #if !defined(HAVE_MMAP)
48 fprintf (stderr, "gr_vmcircbuf_mmap_tmpfile: mmap or mkstemp is not available\n");
49 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
52 if (size <= 0 || (size % gr_pagesize ()) != 0){
53 fprintf (stderr, "gr_vmcircbuf_mmap_tmpfile: invalid size = %d\n", size);
54 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
60 static int s_seg_counter = 0;
63 // open a temporary file that we'll map in a bit later
66 snprintf (seg_name, sizeof (seg_name),
67 "%s/gnuradio-%d-%d-XXXXXX", gr_tmp_path (), getpid (), s_seg_counter);
70 seg_fd = open (seg_name, O_RDWR | O_CREAT | O_EXCL, 0600);
72 if (errno == EEXIST) // File already exists (shouldn't happen). Try again
76 snprintf (msg, sizeof (msg),
77 "gr_vmcircbuf_mmap_tmpfile: open [%s]", seg_name);
79 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
84 if (unlink (seg_name) == -1){
85 perror ("gr_vmcircbuf_mmap_tmpfile: unlink");
86 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
89 // We've got a valid file descriptor to a tmp file.
90 // Now set it's length to 2x what we really want and mmap it in.
92 if (ftruncate (seg_fd, (off_t) 2 * size) == -1){
93 close (seg_fd); // cleanup
94 perror ("gr_vmcircbuf_mmap_tmpfile: ftruncate (1)");
95 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
98 void *first_copy = mmap (0, 2 * size,
99 PROT_READ | PROT_WRITE, MAP_SHARED,
102 if (first_copy == MAP_FAILED){
103 close (seg_fd); // cleanup
104 perror ("gr_vmcircbuf_mmap_tmpfile: mmap (1)");
105 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
108 // unmap the 2nd half
109 if (munmap ((char *) first_copy + size, size) == -1){
110 close (seg_fd); // cleanup
111 perror ("gr_vmcircbuf_mmap_tmpfile: munmap (1)");
112 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
115 // map the first half into the now available hole where the
116 // second half used to be.
118 void *second_copy = mmap ((char *) first_copy + size, size,
119 PROT_READ | PROT_WRITE, MAP_SHARED,
122 if (second_copy == MAP_FAILED){
123 munmap(first_copy, size); // cleanup
125 perror ("gr_vmcircbuf_mmap_tmpfile: mmap (2)");
126 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
129 // check for contiguity
130 if ((char *) second_copy != (char *) first_copy + size){
131 munmap(first_copy, size); // cleanup
132 munmap(second_copy, size);
134 perror ("gr_vmcircbuf_mmap_tmpfile: non-contiguous second copy");
135 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
138 // cut the tmp file down to size
139 if (ftruncate (seg_fd, (off_t) size) == -1){
140 munmap(first_copy, size); // cleanup
141 munmap(second_copy, size);
143 perror ("gr_vmcircbuf_mmap_tmpfile: ftruncate (2)");
144 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
147 close (seg_fd); // fd no longer needed. The mapping is retained.
149 // Now remember the important stuff
151 d_base = (char *) first_copy;
156 gr_vmcircbuf_mmap_tmpfile::~gr_vmcircbuf_mmap_tmpfile ()
158 #if defined(HAVE_MMAP)
159 if (munmap (d_base, 2 * d_size) == -1){
160 perror ("gr_vmcircbuf_mmap_tmpfile: munmap (2)");
165 // ----------------------------------------------------------------
166 // The factory interface
167 // ----------------------------------------------------------------
170 gr_vmcircbuf_factory *gr_vmcircbuf_mmap_tmpfile_factory::s_the_factory = 0;
172 gr_vmcircbuf_factory *
173 gr_vmcircbuf_mmap_tmpfile_factory::singleton ()
176 return s_the_factory;
178 s_the_factory = new gr_vmcircbuf_mmap_tmpfile_factory ();
179 return s_the_factory;
183 gr_vmcircbuf_mmap_tmpfile_factory::granularity ()
185 return gr_pagesize ();
189 gr_vmcircbuf_mmap_tmpfile_factory::make (int size)
192 return new gr_vmcircbuf_mmap_tmpfile (size);