Statistics
| Branch: | Tag: | Revision:

root / gnuradio-core / src / lib / runtime / gr_vmcircbuf_mmap_shm_open.cc @ cbe1628f

History | View | Annotate | Download (5.7 kB)

1 5d69a524 jcorgan
/* -*- c++ -*- */
2 5d69a524 jcorgan
/*
3 5d69a524 jcorgan
 * Copyright 2003 Free Software Foundation, Inc.
4 5d69a524 jcorgan
 * 
5 5d69a524 jcorgan
 * This file is part of GNU Radio
6 5d69a524 jcorgan
 * 
7 5d69a524 jcorgan
 * GNU Radio is free software; you can redistribute it and/or modify
8 5d69a524 jcorgan
 * it under the terms of the GNU General Public License as published by
9 5d69a524 jcorgan
 * the Free Software Foundation; either version 2, or (at your option)
10 5d69a524 jcorgan
 * any later version.
11 5d69a524 jcorgan
 * 
12 5d69a524 jcorgan
 * GNU Radio is distributed in the hope that it will be useful,
13 5d69a524 jcorgan
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 5d69a524 jcorgan
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 5d69a524 jcorgan
 * GNU General Public License for more details.
16 5d69a524 jcorgan
 * 
17 5d69a524 jcorgan
 * You should have received a copy of the GNU General Public License
18 5d69a524 jcorgan
 * along with GNU Radio; see the file COPYING.  If not, write to
19 86f5c924 eb
 * the Free Software Foundation, Inc., 51 Franklin Street,
20 86f5c924 eb
 * Boston, MA 02110-1301, USA.
21 5d69a524 jcorgan
 */
22 5d69a524 jcorgan
23 5d69a524 jcorgan
#ifdef HAVE_CONFIG_H
24 5d69a524 jcorgan
#include "config.h"
25 5d69a524 jcorgan
#endif
26 5d69a524 jcorgan
#include <gr_vmcircbuf_mmap_shm_open.h>
27 5d69a524 jcorgan
#include <stdexcept>
28 5d69a524 jcorgan
#include <assert.h>
29 5d69a524 jcorgan
#include <unistd.h>
30 5d69a524 jcorgan
#include <fcntl.h>
31 5d69a524 jcorgan
#ifdef HAVE_SYS_TYPES_H
32 5d69a524 jcorgan
#include <sys/types.h>
33 5d69a524 jcorgan
#endif
34 5d69a524 jcorgan
#ifdef HAVE_SYS_MMAN_H
35 5d69a524 jcorgan
#include <sys/mman.h>
36 5d69a524 jcorgan
#endif
37 5d69a524 jcorgan
#include <errno.h>
38 5d69a524 jcorgan
#include <stdio.h>
39 5d69a524 jcorgan
#include <gr_pagesize.h>
40 5d69a524 jcorgan
#include <gr_tmp_path.h>
41 5d69a524 jcorgan
42 5d69a524 jcorgan
43 5d69a524 jcorgan
gr_vmcircbuf_mmap_shm_open::gr_vmcircbuf_mmap_shm_open (int size)
44 5d69a524 jcorgan
  : gr_vmcircbuf (size)
45 5d69a524 jcorgan
{
46 5d69a524 jcorgan
#if !defined(HAVE_MMAP) || !defined(HAVE_SHM_OPEN)
47 5d69a524 jcorgan
  fprintf (stderr, "gr_vmcircbuf_mmap_shm_open: mmap or shm_open is not available\n");
48 5d69a524 jcorgan
  throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
49 5d69a524 jcorgan
#else
50 5d69a524 jcorgan
  static int s_seg_counter = 0;
51 5d69a524 jcorgan
52 5d69a524 jcorgan
  if (size <= 0 || (size % gr_pagesize ()) != 0){
53 5d69a524 jcorgan
    fprintf (stderr, "gr_vmcircbuf_mmap_shm_open: invalid size = %d\n", size);
54 5d69a524 jcorgan
    throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
55 5d69a524 jcorgan
  }
56 5d69a524 jcorgan
57 5d69a524 jcorgan
  int                shm_fd = -1;
58 5d69a524 jcorgan
  char                 seg_name[1024];
59 5d69a524 jcorgan
  static bool        portable_format = true;
60 5d69a524 jcorgan
  
61 5d69a524 jcorgan
  // open a new named shared memory segment
62 5d69a524 jcorgan
63 5d69a524 jcorgan
  while (1){
64 5d69a524 jcorgan
    if (portable_format){
65 5d69a524 jcorgan
66 5d69a524 jcorgan
      // This is the POSIX recommended "portable format".
67 5d69a524 jcorgan
      // Of course the "portable format" doesn't work on some systems...
68 5d69a524 jcorgan
      
69 5d69a524 jcorgan
      snprintf (seg_name, sizeof (seg_name),
70 5d69a524 jcorgan
                "/gnuradio-%d-%d", getpid (), s_seg_counter);
71 5d69a524 jcorgan
    }
72 5d69a524 jcorgan
    else {
73 5d69a524 jcorgan
74 5d69a524 jcorgan
      // Where the "portable format" doesn't work, we try building
75 5d69a524 jcorgan
      // a full filesystem pathname pointing into a suitable temporary directory.
76 5d69a524 jcorgan
      
77 5d69a524 jcorgan
      snprintf (seg_name, sizeof (seg_name),
78 5d69a524 jcorgan
                "%s/gnuradio-%d-%d", gr_tmp_path (), getpid (), s_seg_counter);
79 5d69a524 jcorgan
    }
80 5d69a524 jcorgan
81 5d69a524 jcorgan
    shm_fd = shm_open (seg_name, O_RDWR | O_CREAT | O_EXCL, 0600);
82 5d69a524 jcorgan
    if (shm_fd == -1 && errno == EACCES && portable_format){
83 5d69a524 jcorgan
      portable_format = false;
84 5d69a524 jcorgan
      continue;                        // try again using "non-portable format"
85 5d69a524 jcorgan
    }
86 5d69a524 jcorgan
87 5d69a524 jcorgan
    s_seg_counter++;
88 5d69a524 jcorgan
89 5d69a524 jcorgan
    if (shm_fd == -1){
90 5d69a524 jcorgan
      if (errno == EEXIST)        // Named segment already exists (shouldn't happen).  Try again
91 5d69a524 jcorgan
        continue;
92 5d69a524 jcorgan
93 5d69a524 jcorgan
      char msg[1024];
94 5d69a524 jcorgan
      snprintf (msg, sizeof (msg), "gr_vmcircbuf_mmap_shm_open: shm_open [%s]", seg_name);
95 5d69a524 jcorgan
      perror (msg);
96 5d69a524 jcorgan
      throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
97 5d69a524 jcorgan
    }
98 5d69a524 jcorgan
    break;
99 5d69a524 jcorgan
  }
100 5d69a524 jcorgan
101 5d69a524 jcorgan
  // We've got a new shared memory segment fd open.
102 5d69a524 jcorgan
  // Now set it's length to 2x what we really want and mmap it in.
103 5d69a524 jcorgan
104 5d69a524 jcorgan
  if (ftruncate (shm_fd, (off_t) 2 * size) == -1){
105 5d69a524 jcorgan
    close (shm_fd);                                                // cleanup
106 5d69a524 jcorgan
    perror ("gr_vmcircbuf_mmap_shm_open: ftruncate (1)");
107 5d69a524 jcorgan
    throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
108 5d69a524 jcorgan
  }
109 5d69a524 jcorgan
110 5d69a524 jcorgan
  void *first_copy = mmap (0, 2 * size,
111 5d69a524 jcorgan
                           PROT_READ | PROT_WRITE, MAP_SHARED,
112 5d69a524 jcorgan
                           shm_fd, (off_t) 0);
113 5d69a524 jcorgan
114 5d69a524 jcorgan
  if (first_copy == MAP_FAILED){
115 5d69a524 jcorgan
    close (shm_fd);                                                // cleanup
116 5d69a524 jcorgan
    perror ("gr_vmcircbuf_mmap_shm_open: mmap (1)");
117 5d69a524 jcorgan
    throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
118 5d69a524 jcorgan
  }
119 5d69a524 jcorgan
120 5d69a524 jcorgan
  // unmap the 2nd half
121 5d69a524 jcorgan
  if (munmap ((char *) first_copy + size, size) == -1){
122 5d69a524 jcorgan
    close (shm_fd);                                                // cleanup
123 5d69a524 jcorgan
    perror ("gr_vmcircbuf_mmap_shm_open: munmap (1)");
124 5d69a524 jcorgan
    throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
125 5d69a524 jcorgan
  }
126 5d69a524 jcorgan
127 5d69a524 jcorgan
  // map the first half into the now available hole where the
128 5d69a524 jcorgan
  // second half used to be.
129 5d69a524 jcorgan
130 5d69a524 jcorgan
  void *second_copy = mmap ((char *) first_copy + size, size,
131 5d69a524 jcorgan
                            PROT_READ | PROT_WRITE, MAP_SHARED,
132 5d69a524 jcorgan
                            shm_fd, (off_t) 0);
133 5d69a524 jcorgan
134 5d69a524 jcorgan
  if (second_copy == MAP_FAILED){
135 5d69a524 jcorgan
    close (shm_fd);                                                // cleanup
136 5d69a524 jcorgan
    perror ("gr_vmcircbuf_mmap_shm_open: mmap (2)");
137 5d69a524 jcorgan
    throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
138 5d69a524 jcorgan
  }
139 5d69a524 jcorgan
140 5d69a524 jcorgan
#if 0  // OS/X doesn't allow you to resize the segment
141 5d69a524 jcorgan
142 5d69a524 jcorgan
  // cut the shared memory segment down to size
143 5d69a524 jcorgan
  if (ftruncate (shm_fd, (off_t) size) == -1){
144 5d69a524 jcorgan
    close (shm_fd);                                                // cleanup
145 5d69a524 jcorgan
    perror ("gr_vmcircbuf_mmap_shm_open: ftruncate (2)");
146 5d69a524 jcorgan
    throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
147 5d69a524 jcorgan
  }
148 5d69a524 jcorgan
#endif
149 5d69a524 jcorgan
150 5d69a524 jcorgan
  close (shm_fd);        // fd no longer needed.  The mapping is retained.
151 5d69a524 jcorgan
152 5d69a524 jcorgan
  if (shm_unlink (seg_name) == -1){        // unlink the seg_name.  
153 5d69a524 jcorgan
    perror ("gr_vmcircbuf_mmap_shm_open: shm_unlink");
154 5d69a524 jcorgan
    throw std::runtime_error ("gr_vmcircbuf_mmap_shm_open");
155 5d69a524 jcorgan
  }
156 5d69a524 jcorgan
157 5d69a524 jcorgan
  // Now remember the important stuff
158 5d69a524 jcorgan
159 5d69a524 jcorgan
  d_base = (char *) first_copy;
160 5d69a524 jcorgan
  d_size = size;
161 5d69a524 jcorgan
#endif
162 5d69a524 jcorgan
}
163 5d69a524 jcorgan
164 5d69a524 jcorgan
gr_vmcircbuf_mmap_shm_open::~gr_vmcircbuf_mmap_shm_open ()
165 5d69a524 jcorgan
{
166 5d69a524 jcorgan
#if defined(HAVE_MMAP)  
167 5d69a524 jcorgan
  if (munmap (d_base, 2 * d_size) == -1){
168 5d69a524 jcorgan
    perror ("gr_vmcircbuf_mmap_shm_open: munmap (2)");
169 5d69a524 jcorgan
  }
170 5d69a524 jcorgan
#endif
171 5d69a524 jcorgan
}
172 5d69a524 jcorgan
173 5d69a524 jcorgan
// ----------------------------------------------------------------
174 5d69a524 jcorgan
//                        The factory interface
175 5d69a524 jcorgan
// ----------------------------------------------------------------
176 5d69a524 jcorgan
177 5d69a524 jcorgan
178 5d69a524 jcorgan
gr_vmcircbuf_factory *gr_vmcircbuf_mmap_shm_open_factory::s_the_factory = 0;
179 5d69a524 jcorgan
180 5d69a524 jcorgan
gr_vmcircbuf_factory *
181 5d69a524 jcorgan
gr_vmcircbuf_mmap_shm_open_factory::singleton ()
182 5d69a524 jcorgan
{
183 5d69a524 jcorgan
  if (s_the_factory)
184 5d69a524 jcorgan
    return s_the_factory;
185 5d69a524 jcorgan
186 5d69a524 jcorgan
  s_the_factory = new gr_vmcircbuf_mmap_shm_open_factory ();
187 5d69a524 jcorgan
  return s_the_factory;
188 5d69a524 jcorgan
}
189 5d69a524 jcorgan
190 5d69a524 jcorgan
int
191 5d69a524 jcorgan
gr_vmcircbuf_mmap_shm_open_factory::granularity ()
192 5d69a524 jcorgan
{
193 5d69a524 jcorgan
  return gr_pagesize ();
194 5d69a524 jcorgan
}
195 5d69a524 jcorgan
196 5d69a524 jcorgan
gr_vmcircbuf *
197 5d69a524 jcorgan
gr_vmcircbuf_mmap_shm_open_factory::make (int size)
198 5d69a524 jcorgan
{
199 5d69a524 jcorgan
  try {
200 5d69a524 jcorgan
    return new gr_vmcircbuf_mmap_shm_open (size);
201 5d69a524 jcorgan
  }
202 5d69a524 jcorgan
  catch (...){
203 5d69a524 jcorgan
    return 0;
204 5d69a524 jcorgan
  }
205 5d69a524 jcorgan
}