Houston, we have a trunk.
[debian/gnuradio] / gnuradio-core / src / lib / runtime / gr_vmcircbuf_createfilemapping.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2003,2005 Free Software Foundation, Inc.
4  *
5  * This file is part of GNU Radio
6  *
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)
10  * any later version.
11  *
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.
16  *
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., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include <stdexcept>
27 #include <assert.h>
28 #include <unistd.h>
29 #include <fcntl.h>
30 #ifdef HAVE_SYS_TYPES_H
31 #include <sys/types.h>
32 #endif
33 #ifdef HAVE_SYS_MMAN_H
34 #include <sys/mman.h>
35 #endif
36 #include <errno.h>
37 #include <stdio.h>
38 #include <gr_pagesize.h>
39 #include <gr_tmp_path.h>
40 #include <gr_vmcircbuf_createfilemapping.h>
41
42
43 gr_vmcircbuf_createfilemapping::gr_vmcircbuf_createfilemapping (int size)
44   : gr_vmcircbuf (size)
45 {
46 #if !defined(HAVE_CREATEFILEMAPPING)
47   fprintf (stderr, "%s: createfilemapping is not available\n",__FUNCTION__);
48   throw std::runtime_error ("gr_vmcircbuf_createfilemapping");
49 #else
50   static int s_seg_counter = 0;
51
52   if (size <= 0 || (size % gr_pagesize ()) != 0){
53     fprintf (stderr, "gr_vmcircbuf_createfilemapping: invalid size = %d\n", size);
54     throw std::runtime_error ("gr_vmcircbuf_createfilemapping");
55   }
56
57   char    seg_name[1024];
58   snprintf (seg_name, sizeof (seg_name), "/gnuradio-%d-%d", getpid (), s_seg_counter);
59
60   d_handle = CreateFileMapping(INVALID_HANDLE_VALUE,    // use paging file
61                                NULL,                    // default security
62                                PAGE_READWRITE,          // read/write access
63                                0,                       // max. object size
64                                size,                    // buffer size
65                                seg_name);               // name of mapping object
66
67   s_seg_counter++;
68   if (d_handle == NULL || d_handle == INVALID_HANDLE_VALUE){
69     char msg[1024];
70     snprintf (msg, sizeof (msg), "gr_vmcircbuf_mmap_createfilemapping: CreateFileMapping [%s] :%d", seg_name,(int)GetLastError());
71     perror (msg);
72     throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping");
73   }
74
75   int i = 0;
76   d_first_copy = d_second_copy = NULL;
77     
78   while (i++ < 8 && d_second_copy == NULL){
79     // keep the first map allocation to force allocation in a new address
80     // space
81     LPVOID first_tmp = d_first_copy;
82         
83     d_first_copy =  MapViewOfFile((HANDLE)d_handle,   // handle to map object
84                                   FILE_MAP_WRITE,     // read/write permission
85                                   0,
86                                   0,
87                                   size);
88    
89     if (d_first_copy == NULL){
90       if (first_tmp)
91         UnmapViewOfFile(first_tmp);
92
93       CloseHandle(d_handle);         // cleanup
94       char msg[1024];
95       snprintf (msg, sizeof (msg),
96                 "gr_vmcircbuf_mmap_createfilemapping: MapViewOfFile (1) :%d", (int)GetLastError());
97       perror (msg);
98       throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping");
99     }
100
101     // NOTE: d_second_copy will be NULL if MapViewFileEx() fails to allocate the
102     //       requested address space
103     d_second_copy =  MapViewOfFileEx((HANDLE)d_handle,   // handle to map object
104                                      FILE_MAP_WRITE,     // read/write permission
105                                      0,
106                                      0,
107                                      size,
108                                      (char *)d_first_copy + size);//(LPVOID) ((char *)d_first_copy + size));
109
110     if (first_tmp)
111       UnmapViewOfFile(first_tmp);
112
113 #ifdef DEBUG
114     fprintf (stderr,"gr_vmcircbuf_mmap_createfilemapping: contiguous? mmap %p %p %p %p, %d\n",
115              (char *)d_first_copy, (char *)d_second_copy, size, (char *)d_first_copy + size,i);
116 #endif
117   }
118
119   if (d_second_copy == NULL){    // cleanup
120     fprintf (stderr,"gr_vmcircbuf_mmap_createfilemapping: non contiguous mmap - %p %p %p %p\n",
121              d_first_copy, d_second_copy, size, (char *)d_first_copy + size);
122     UnmapViewOfFile(d_first_copy);
123     CloseHandle(d_handle);                      // cleanup
124     throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping");
125   }
126
127   // Now remember the important stuff
128   d_base = (char *) d_first_copy;
129   d_size = size;
130 #endif /*HAVE_CREATEFILEMAPPING*/
131 }
132
133 gr_vmcircbuf_createfilemapping::~gr_vmcircbuf_createfilemapping ()
134 {
135 #ifdef HAVE_CREATEFILEMAPPING
136   if (UnmapViewOfFile(d_first_copy) == 0)
137   {
138     perror ("gr_vmcircbuf_createfilemapping: UnmapViewOfFile(d_first_copy)");
139   }
140   d_base=NULL;
141   if (UnmapViewOfFile(d_second_copy) == 0)
142   {
143     perror ("gr_vmcircbuf_createfilemapping: UnmapViewOfFile(d_second_copy)");
144   }
145   //d_second=NULL;
146   CloseHandle(d_handle);
147 #endif
148 }
149
150 // ----------------------------------------------------------------
151 //      The factory interface
152 // ----------------------------------------------------------------
153
154
155 gr_vmcircbuf_factory *gr_vmcircbuf_createfilemapping_factory::s_the_factory = 0;
156
157 gr_vmcircbuf_factory *
158 gr_vmcircbuf_createfilemapping_factory::singleton ()
159 {
160   if (s_the_factory)
161     return s_the_factory;
162   s_the_factory = new gr_vmcircbuf_createfilemapping_factory ();
163   return s_the_factory;
164 }
165
166 int
167 gr_vmcircbuf_createfilemapping_factory::granularity ()
168 {
169 #ifdef HAVE_CREATEFILEMAPPING
170   //  return 65536;//TODO, check, is this needed or can we just use gr_pagesize()
171   SYSTEM_INFO system_info;
172   GetSystemInfo(&system_info);
173   //fprintf(stderr,"win32 AllocationGranularity %p\n",(int)system_info.dwAllocationGranularity);
174   return (int)system_info.dwAllocationGranularity;
175 #else
176   return gr_pagesize ();
177 #endif
178 }
179
180 gr_vmcircbuf *
181 gr_vmcircbuf_createfilemapping_factory::make (int size)
182 {
183   try
184   {
185     return new gr_vmcircbuf_createfilemapping (size);
186   }
187   catch (...)
188   {
189     return 0;
190   }
191 }