libStatGen Software 1
Loading...
Searching...
No Matches
MemoryMap.cpp
1/*
2 * Copyright (C) 2010 Regents of the University of Michigan
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18#include <sys/stat.h>
19#include <sys/types.h>
20#include <assert.h>
21#include <errno.h>
22#include <fcntl.h>
23#include <iostream>
24#include <stdio.h>
25#include <stdexcept>
26#include <stdlib.h>
27#include <string>
28
29#include "MemoryMap.h"
30
31#ifndef _WIN32
32#include <sys/mman.h>
33#include <unistd.h>
34#endif
35
36#ifndef MAP_POPULATE
37#define MAP_POPULATE 0x0000
38#endif
39#ifndef MAP_NONBLOCK
40#define MAP_NONBLOCK 0x0000
41#endif
42
43MemoryMap::MemoryMap()
44{
45 constructor_clear();
46#if defined(_WIN32)
47 SYSTEM_INFO sysinfo = {0};
48 ::GetSystemInfo(&sysinfo);
49 DWORD cbView = sysinfo.dwAllocationGranularity;
50#else
51 page_size = sysconf(_SC_PAGE_SIZE);
52#endif
53}
54
55MemoryMap::~MemoryMap()
56{
57 destructor_clear();
58};
59
60void MemoryMap::debug_print()
61{
62#if defined(_WIN32)
63 std::cout << "fd = " << file_handle << std::endl;
64#else
65 std::cout << "fd = " << fd << std::endl;
66#endif
67 std::cout << "data = 0x" << std::hex << data << std::endl;
68 std::cout << "offset = 0x" << std::hex << offset << std::endl;
69 std::cout << "mapped_length = 0x" << std::hex << mapped_length << std::endl;
70 std::cout << "total_length = 0x" << std::hex << total_length << std::endl;
71 std::cout << "page_size = 0x" << std::hex << page_size << std::endl;
72};
73
74void MemoryMap::constructor_clear()
75{
76#if defined(_WIN32)
77 file_handle = NULL;
78 map_handle = NULL;
79#else
80 fd = -1;
81#endif
82 data = (void *) NULL;
83 offset = 0;
84 mapped_length = 0;
85 total_length = 0;
86 useMemoryMapFlag = true;
87};
88
89void MemoryMap::destructor_clear()
90{
91#if defined(_WIN32)
92 if (data!=NULL)
93 {
94 // free windows mapped object
95 ::UnmapViewOfFile((LPVOID) data);
96 }
97 if (map_handle != NULL)
98 ::CloseHandle(map_handle);
99 if (file_handle != NULL)
100 ::CloseHandle(file_handle);
101#else
102 if (data!=NULL)
103 {
104 // free unix mapped object
105 munmap(data, mapped_length);
106 }
107 // free unix resources
108 if (fd!=-1)
109 {
110 ::close(fd);
111 }
112#endif
113
114 constructor_clear();
115}
116
117
118bool MemoryMap::allocate()
119{
120 data = (void *) malloc(mapped_length);
121
122 if (data == NULL)
123 {
124#ifdef __WIN32__
125 ::CloseHandle(file_handle);
126#else
127 ::close(fd);
128#endif
129 perror("MemoryMap::open");
130 constructor_clear();
131 return true;
132 }
133
134#ifdef __WIN32__
135 DWORD resultSize = 0;
136 ReadFile(file_handle, data, mapped_length, &resultSize, NULL);
137#else
138 size_t resultSize = read(fd, data, mapped_length);
139#endif
140
141 if ( resultSize != mapped_length)
142 {
143#ifdef __WIN32__
144 ::CloseHandle(file_handle);
145#else
146 ::close(fd);
147#endif
148 perror("MemoryMap::open");
149 constructor_clear();
150 return true;
151 }
152 return false;
153}
154
155
156bool MemoryMap::open(const char * file, int flags)
157{
158 const char * message = "MemoryMap::open - problem opening file %s";
159#if defined(_WIN32)
160 file_handle = CreateFile(file,
161 (flags==O_RDONLY) ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE),
162 FILE_SHARE_READ | FILE_SHARE_WRITE, // subsequent opens may either read or write
163 NULL,
164 OPEN_EXISTING,
165 FILE_ATTRIBUTE_NORMAL,
166 NULL);
167
168 if(file_handle == INVALID_HANDLE_VALUE)
169 {
170 fprintf(stderr, message, file);
171 constructor_clear();
172 return true;
173 }
174
175 LARGE_INTEGER file_size = {0};
176 ::GetFileSizeEx(file_handle, &file_size);
177 mapped_length = total_length = file_size.QuadPart;
178
179#else
180 struct stat buf;
181 fd = ::open(file, flags);
182 if ((fd==-1) || (fstat(fd, &buf) != 0))
183 {
184 fprintf(stderr, message, file);
185 constructor_clear();
186 return true;
187 }
188 mapped_length = total_length = buf.st_size;
189#endif
190
191 if(!useMemoryMapFlag)
192 {
193 return allocate();
194 }
195
196#if defined(_WIN32)
197 assert(offset == 0);
198
199 map_handle = CreateFileMapping(file_handle, NULL,
200 (flags==O_RDONLY) ? PAGE_READONLY : PAGE_READWRITE,
201 file_size.HighPart, // upper 32 bits of map size
202 file_size.LowPart, // lower 32 bits of map size
203 NULL);
204
205 if(map_handle == NULL)
206 {
207 ::CloseHandle(file_handle);
208 fprintf(stderr, message, file);
209 constructor_clear();
210 return true;
211 }
212
213 data = MapViewOfFile(map_handle,
214 (flags == O_RDONLY) ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS,
215 0, 0, mapped_length);
216
217 if (data == NULL)
218 {
219 CloseHandle(map_handle);
220 CloseHandle(file_handle);
221
222 fprintf(stderr, message, file);
223 constructor_clear();
224 return true;
225 }
226#else
227 data = ::mmap(NULL, mapped_length,
228 (flags == O_RDONLY) ? PROT_READ : PROT_READ | PROT_WRITE,
229 MAP_SHARED, fd, offset);
230
231 if (data == MAP_FAILED)
232 {
233 ::close(fd);
234 fprintf(stderr, message, file);
235 constructor_clear();
236 return true;
237 }
238#endif
239 return false;
240}
241
242
243bool MemoryMap::create(const char *file, size_t size)
244{
245 if (file==NULL)
246 {
247 data = calloc(size, 1);
248 return(data==NULL);
249 }
250
251 const char * message = "MemoryMap::create - problem creating file %s";
252
253#ifdef __WIN32__
254 file_handle = CreateFile(file,
255 GENERIC_READ | GENERIC_WRITE,
256 FILE_SHARE_READ | FILE_SHARE_WRITE,
257 NULL,
258 CREATE_ALWAYS,
259 FILE_ATTRIBUTE_NORMAL,
260 NULL);
261
262 if (file_handle == INVALID_HANDLE_VALUE)
263 {
264 fprintf(stderr, message, file);
265 constructor_clear();
266 return true;
267 }
268
269 SetFilePointer(file_handle, size - 1, NULL, FILE_BEGIN);
270 char dummy = 0;
271 DWORD check = 0;
272 WriteFile(file_handle, &dummy, 1, &check, NULL);
273
274 if (check != 0)
275 {
276 CloseHandle(file_handle);
277 DeleteFile(file);
278 fprintf(stderr, message, file);
279 constructor_clear();
280 return true;
281 }
282 CloseHandle(file_handle);
283 open(file, O_RDWR);
284#else
285 fd = ::open(file, O_RDWR|O_CREAT|O_TRUNC, 0666);
286 if(fd == -1)
287 {
288 fprintf(stderr, message, file);
289 constructor_clear();
290 return true;
291 }
292
293 lseek(fd, (off_t) size - 1, SEEK_SET);
294 char dummy = 0;
295 if(write(fd, &dummy, 1)!=1)
296 {
297 fprintf(stderr, message, file);
298 constructor_clear();
299 return true;
300 }
301
302 data = ::mmap(NULL, size, PROT_READ|PROT_WRITE,
303 MAP_SHARED, fd, offset);
304
305 if (data == MAP_FAILED)
306 {
307 ::close(fd);
308 unlink(file);
309 fprintf(stderr, message, file);
310 constructor_clear();
311 return true;
312 }
313 mapped_length = total_length = size;
314#endif
315 return false;
316}
317
318
319bool MemoryMap::create(size_t size)
320{
321 return create(NULL, size);
322}
323
324bool MemoryMap::close()
325{
326 destructor_clear();
327 return false;
328}
329
330void MemoryMap::test()
331{
332 int result;
333
334 result = this->open("test/test_memmap_data.txt");
335 assert(result == 0);
336 assert(data!=NULL);
337 assert(mapped_length == 183); // length of the above file
338 close();
339
340 // now try non memory mapped (direct slow file I/O)
341 useMemoryMap(false);
342 result = this->open("test/test_memmap_data.txt");
343 assert(result == 0);
344 assert(data!=NULL);
345 assert(mapped_length == 183); // length of the above file
346 close();
347}
348
349int MemoryMap::prefetch()
350{
351 int sum = 0;
352 size_t i;
353
354 for (i=0; i<mapped_length; i += page_size) sum += *(i + (char *) data);
355
356 return sum;
357}
358
359#if defined(TEST)
360//
361// compile test using:
362// g++ -DTEST -o testMemoryMap MemoryMap.cpp Error.o -lz
363//
364
365int main(int argc, const char *argv)
366{
367 MemoryMap map;
368
369 map.test();
370
371// map.debug_print();
372
373 exit(0);
374}
375#endif
376
There are a pair of related data structures in the operating system, and also a few simple algorithms...
Definition MemoryMap.h:156
virtual bool open(const char *file, int flags=O_RDONLY)
open a previously created mapped vector
virtual bool create(const char *file, size_t size)
create the memory mapped file on disk