Imported Upstream version 3.0.4
[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 3, 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., 51 Franklin Street,
20  * Boston, MA 02110-1301, 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 #ifdef HAVE_CREATEFILEMAPPING
43 // Print Windows error (could/should be global?)
44 static void
45 werror( char *where, DWORD last_error )
46 {
47   char buf[1024];
48
49   FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,
50                  NULL,
51                  last_error,
52                  0,    // default language
53                  buf,
54                  sizeof(buf)/sizeof(TCHAR),    // buffer size
55                  NULL );
56   fprintf( stderr, "%s: Error %d: %s", where, last_error, buf );
57   return;
58 }
59 #endif
60
61
62 gr_vmcircbuf_createfilemapping::gr_vmcircbuf_createfilemapping (int size)
63   : gr_vmcircbuf (size)
64 {
65 #if !defined(HAVE_CREATEFILEMAPPING)
66   fprintf (stderr, "%s: createfilemapping is not available\n",__FUNCTION__);
67   throw std::runtime_error ("gr_vmcircbuf_createfilemapping");
68 #else
69   static int s_seg_counter = 0;
70
71   if (size <= 0 || (size % gr_pagesize ()) != 0){
72     fprintf (stderr, "gr_vmcircbuf_createfilemapping: invalid size = %d\n", size);
73     throw std::runtime_error ("gr_vmcircbuf_createfilemapping");
74   }
75
76   char    seg_name[1024];
77   snprintf (seg_name, sizeof (seg_name), "/gnuradio-%d-%d", getpid (), s_seg_counter);
78
79   d_handle = CreateFileMapping(INVALID_HANDLE_VALUE,    // use paging file
80                                NULL,                    // default security
81                                PAGE_READWRITE,          // read/write access
82                                0,                       // max. object size
83                                size,                    // buffer size
84                                seg_name);               // name of mapping object
85
86   s_seg_counter++;
87   if (d_handle == NULL || d_handle == INVALID_HANDLE_VALUE){
88     char msg[1024];
89     snprintf( msg, sizeof(msg),
90               "gr_vmcircbuf_mmap_createfilemapping: CreateFileMapping [%s]",
91               seg_name );
92     werror( msg, GetLastError() );
93     throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping");
94   }
95
96   // Allocate virtual memory of the needed size, then free it so we can use it
97   LPVOID first_tmp;
98   first_tmp = VirtualAlloc( NULL, 2*size, MEM_RESERVE, PAGE_NOACCESS );
99   if (first_tmp == NULL){
100     werror( "gr_vmcircbuf_mmap_createfilemapping: VirtualAlloc", GetLastError());
101     CloseHandle(d_handle);         // cleanup
102     throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping");
103   }
104
105   if (VirtualFree(first_tmp, 0, MEM_RELEASE) == 0){
106     werror( "gr_vmcircbuf_mmap_createfilemapping: VirtualFree", GetLastError());
107     CloseHandle(d_handle);         // cleanup
108     throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping");
109   }
110
111   d_first_copy =  MapViewOfFileEx((HANDLE)d_handle,   // handle to map object
112                                    FILE_MAP_WRITE,    // read/write permission
113                                    0,
114                                    0,
115                                    size,
116                                    first_tmp);
117   if (d_first_copy != first_tmp){
118     werror( "gr_vmcircbuf_mmap_createfilemapping: MapViewOfFileEx(1)", GetLastError());
119     CloseHandle(d_handle);         // cleanup
120     throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping");
121   }
122
123   d_second_copy =  MapViewOfFileEx((HANDLE)d_handle,   // handle to map object
124                                    FILE_MAP_WRITE,     // read/write permission
125                                    0,
126                                    0,
127                                    size,
128                                    (char *)first_tmp + size);//(LPVOID) ((char *)d_first_copy + size));
129
130   if (d_second_copy != (char *)first_tmp + size){
131     werror( "gr_vmcircbuf_mmap_createfilemapping: MapViewOfFileEx(2)", GetLastError());
132     UnmapViewOfFile(d_first_copy);
133     CloseHandle(d_handle);                      // cleanup
134     throw std::runtime_error ("gr_vmcircbuf_mmap_createfilemapping");
135   }
136
137 #ifdef DEBUG
138   fprintf (stderr,"gr_vmcircbuf_mmap_createfilemapping: contiguous? mmap %p %p %p %p\n",
139            (char *)d_first_copy, (char *)d_second_copy, size, (char *)d_first_copy + size);
140 #endif
141
142   // Now remember the important stuff
143   d_base = (char *) d_first_copy;
144   d_size = size;
145 #endif /*HAVE_CREATEFILEMAPPING*/
146 }
147
148 gr_vmcircbuf_createfilemapping::~gr_vmcircbuf_createfilemapping ()
149 {
150 #ifdef HAVE_CREATEFILEMAPPING
151   if (UnmapViewOfFile(d_first_copy) == 0)
152   {
153     werror("gr_vmcircbuf_createfilemapping: UnmapViewOfFile(d_first_copy)", GetLastError());
154   }
155   d_base=NULL;
156   if (UnmapViewOfFile(d_second_copy) == 0)
157   {
158     werror("gr_vmcircbuf_createfilemapping: UnmapViewOfFile(d_second_copy)", GetLastError());
159   }
160   //d_second=NULL;
161   CloseHandle(d_handle);
162 #endif
163 }
164
165 // ----------------------------------------------------------------
166 //      The factory interface
167 // ----------------------------------------------------------------
168
169
170 gr_vmcircbuf_factory *gr_vmcircbuf_createfilemapping_factory::s_the_factory = 0;
171
172 gr_vmcircbuf_factory *
173 gr_vmcircbuf_createfilemapping_factory::singleton ()
174 {
175   if (s_the_factory)
176     return s_the_factory;
177   s_the_factory = new gr_vmcircbuf_createfilemapping_factory ();
178   return s_the_factory;
179 }
180
181 int
182 gr_vmcircbuf_createfilemapping_factory::granularity ()
183 {
184 #ifdef HAVE_CREATEFILEMAPPING
185   //  return 65536;//TODO, check, is this needed or can we just use gr_pagesize()
186   SYSTEM_INFO system_info;
187   GetSystemInfo(&system_info);
188   //fprintf(stderr,"win32 AllocationGranularity %p\n",(int)system_info.dwAllocationGranularity);
189   return (int)system_info.dwAllocationGranularity;
190 #else
191   return gr_pagesize ();
192 #endif
193 }
194
195 gr_vmcircbuf *
196 gr_vmcircbuf_createfilemapping_factory::make (int size)
197 {
198   try
199   {
200     return new gr_vmcircbuf_createfilemapping (size);
201   }
202   catch (...)
203   {
204     return 0;
205   }
206 }