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 2, 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>
45 gr_vmcircbuf_mmap_tmpfile::gr_vmcircbuf_mmap_tmpfile (int size)
48 #if !defined(HAVE_MMAP)
49 fprintf (stderr, "gr_vmcircbuf_mmap_tmpfile: mmap or mkstemp is not available\n");
50 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
53 if (size <= 0 || (size % gr_pagesize ()) != 0){
54 fprintf (stderr, "gr_vmcircbuf_mmap_tmpfile: invalid size = %d\n", size);
55 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
61 static int s_seg_counter = 0;
64 // open a temporary file that we'll map in a bit later
67 snprintf (seg_name, sizeof (seg_name),
68 "%s/gnuradio-%d-%d-XXXXXX", gr_tmp_path (), getpid (), s_seg_counter);
71 seg_fd = open (seg_name, O_RDWR | O_CREAT | O_EXCL, 0600);
73 if (errno == EEXIST) // File already exists (shouldn't happen). Try again
77 snprintf (msg, sizeof (msg),
78 "gr_vmcircbuf_mmap_tmpfile: open [%s]", seg_name);
80 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
85 if (unlink (seg_name) == -1){
86 perror ("gr_vmcircbuf_mmap_tmpfile: unlink");
87 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
90 // We've got a valid file descriptor to a tmp file.
91 // Now set it's length to 2x what we really want and mmap it in.
93 if (ftruncate (seg_fd, (off_t) 2 * size) == -1){
94 close (seg_fd); // cleanup
95 perror ("gr_vmcircbuf_mmap_tmpfile: ftruncate (1)");
96 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
99 void *first_copy = mmap (0, 2 * size,
100 PROT_READ | PROT_WRITE, MAP_SHARED,
103 if (first_copy == MAP_FAILED){
104 close (seg_fd); // cleanup
105 perror ("gr_vmcircbuf_mmap_tmpfile: mmap (1)");
106 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
109 // unmap the 2nd half
110 if (munmap ((char *) first_copy + size, size) == -1){
111 close (seg_fd); // cleanup
112 perror ("gr_vmcircbuf_mmap_tmpfile: munmap (1)");
113 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
116 // map the first half into the now available hole where the
117 // second half used to be.
119 void *second_copy = mmap ((char *) first_copy + size, size,
120 PROT_READ | PROT_WRITE, MAP_SHARED,
123 if (second_copy == MAP_FAILED){
124 munmap(first_copy, size); // cleanup
126 perror ("gr_vmcircbuf_mmap_tmpfile: mmap (2)");
127 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
130 // check for contiguity
131 if ((char *) second_copy != (char *) first_copy + size){
132 munmap(first_copy, size); // cleanup
133 munmap(second_copy, size);
135 perror ("gr_vmcircbuf_mmap_tmpfile: non-contiguous second copy");
136 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
139 // cut the tmp file down to size
140 if (ftruncate (seg_fd, (off_t) size) == -1){
141 munmap(first_copy, size); // cleanup
142 munmap(second_copy, size);
144 perror ("gr_vmcircbuf_mmap_tmpfile: ftruncate (2)");
145 throw std::runtime_error ("gr_vmcircbuf_mmap_tmpfile");
148 close (seg_fd); // fd no longer needed. The mapping is retained.
150 // Now remember the important stuff
152 d_base = (char *) first_copy;
157 gr_vmcircbuf_mmap_tmpfile::~gr_vmcircbuf_mmap_tmpfile ()
159 #if defined(HAVE_MMAP)
160 if (munmap (d_base, 2 * d_size) == -1){
161 perror ("gr_vmcircbuf_mmap_tmpfile: munmap (2)");
166 // ----------------------------------------------------------------
167 // The factory interface
168 // ----------------------------------------------------------------
171 gr_vmcircbuf_factory *gr_vmcircbuf_mmap_tmpfile_factory::s_the_factory = 0;
173 gr_vmcircbuf_factory *
174 gr_vmcircbuf_mmap_tmpfile_factory::singleton ()
177 return s_the_factory;
179 s_the_factory = new gr_vmcircbuf_mmap_tmpfile_factory ();
180 return s_the_factory;
184 gr_vmcircbuf_mmap_tmpfile_factory::granularity ()
186 return gr_pagesize ();
190 gr_vmcircbuf_mmap_tmpfile_factory::make (int size)
193 return new gr_vmcircbuf_mmap_tmpfile (size);