CASToR  3.2
Tomographic Reconstruction (PET/SPECT/CT)
src/datafile/oMemoryMapped.cc
Go to the documentation of this file.
1 
13 #include "oMemoryMapped.hh"
14 
15 #include <stdexcept>
16 #include <cstdio>
17 #include <iostream>
18 
19 // OS-specific
20 #if defined(_WIN32) || defined(CASTOR_USE_MINGW)
21 // Windows
22 #include <windows.h>
23 #else
24 // Linux
25 // enable large file support on 32 bit systems
26 #ifndef _LARGEFILE64_SOURCE
27 #define _LARGEFILE64_SOURCE
28 #endif
29 #ifdef _FILE_OFFSET_BITS
30 #undef _FILE_OFFSET_BITS
31 #endif
32 #define _FILE_OFFSET_BITS 64
33 // and include needed headers
34 #include <sys/stat.h>
35 #include <sys/mman.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #endif
40 
41 // =====================================================================
42 // ---------------------------------------------------------------------
43 // ---------------------------------------------------------------------
44 // =====================================================================
45 
48 : _filename (),
49  _filesize (0),
50  _hint (Normal),
51  _mappedBytes(0),
52 #if defined(_WIN32) || defined(CASTOR_USE_MINGW)
53  _mappedFile (NULL),
54 #endif
55  _file (0),
56  _mappedView (NULL)
57 {
58 }
59 
60 // =====================================================================
61 // ---------------------------------------------------------------------
62 // ---------------------------------------------------------------------
63 // =====================================================================
64 
66 oMemoryMapped::oMemoryMapped(const std::string& filename, size_t mappedBytes, CacheHint hint)
67 : _filename (filename),
68  _filesize (0),
69  _hint (hint),
70  _mappedBytes(mappedBytes),
71 #if defined(_WIN32) || defined(CASTOR_USE_MINGW)
72  _mappedFile (NULL),
73 #endif
74  _file (0),
75  _mappedView (NULL)
76 {
77  Open(filename, mappedBytes, hint);
78 }
79 
80 // =====================================================================
81 // ---------------------------------------------------------------------
82 // ---------------------------------------------------------------------
83 // =====================================================================
84 
87 {
88  Close();
89 }
90 
91 // =====================================================================
92 // ---------------------------------------------------------------------
93 // ---------------------------------------------------------------------
94 // =====================================================================
95 
97 int oMemoryMapped::Open(const std::string& filename, size_t mappedBytes, CacheHint hint)
98 {
99  // already open ?
100  if (IsValid())
101  {
102  Cerr("***** oMemoryMapped::Open() -> File is already open !" << endl);
103  return 1;
104  }
105 
106  _file = 0;
107  _filesize = 0;
108  _hint = hint;
109 #if defined(_WIN32) || defined(CASTOR_USE_MINGW)
110  _mappedFile = NULL;
111 #endif
112  _mappedView = NULL;
113 
114 #if defined(_WIN32) || defined(CASTOR_USE_MINGW)
115 
116  // ===================================================================
117  // Windows
118  // ===================================================================
119 
120  DWORD winHint = 0;
121  switch (_hint)
122  {
123  case Normal: winHint = FILE_ATTRIBUTE_NORMAL; break;
124  case SequentialScan: winHint = FILE_FLAG_SEQUENTIAL_SCAN; break;
125  case RandomAccess: winHint = FILE_FLAG_RANDOM_ACCESS; break;
126  default: break;
127  }
128 
129  // open file
130  _file = ::CreateFileA(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, winHint, NULL);
131  if (!_file)
132  {
133  Cerr("***** oMemoryMapped::Open() -> Failed to create windows file from function CreateFileA() !" << endl);
134  return 1;
135  }
136 
137  // file size
138  LARGE_INTEGER result;
139  if (!GetFileSizeEx(_file, &result))
140  {
141  Cerr("***** oMemoryMapped::Open() -> Failed to get file size from windows function GetFileSizeEx() !" << endl);
142  return 1;
143  }
144  _filesize = static_cast<uint64_t>(result.QuadPart);
145 
146  // convert to mapped mode
147  _mappedFile = ::CreateFileMapping(_file, NULL, PAGE_READONLY, 0, 0, NULL);
148  if (!_mappedFile)
149  {
150  Cerr("***** oMemoryMapped::Open() -> Failed to convert file to mapped mode from windows function CreateFileMapping() !" << endl);
151  return 1;
152  }
153 
154 #else
155 
156  // ===================================================================
157  // Linux
158  // ===================================================================
159 
160  // open file
161  //_file = ::open(filename.c_str(), O_RDONLY | O_LARGEFILE);
162  _file = ::open(filename.c_str(), O_RDONLY);
163 
164  if (_file == -1)
165  {
166  _file = 0;
167  Cerr("***** oMemoryMapped::Open() -> Failed to open file from unix function open() !" << endl);
168  return 1;
169  }
170 
171  // file size
172  struct stat statInfo;
173  if (fstat(_file, &statInfo) < 0)
174  {
175  Cerr("***** oMemoryMapped::Open() -> Failed to get correct file size from unix function fstat() !" << endl);
176  return 1;
177  }
178 
179  _filesize = statInfo.st_size;
180 #endif
181 
182  // initial mapping
183  if (Remap(0, mappedBytes))
184  {
185  Cerr("***** oMemoryMapped::Open() -> A problem occurred while calling the oMemoryMapped::Remap() function !" << endl);
186  return 1;
187  }
188 
189  // check
190  if (!_mappedView)
191  {
192  Cerr("***** oMemoryMapped::Open() -> Failed to get a correct mapped view after calling the oMemoryMapped::Remap() function !" << endl);
193  return 1;
194  }
195 
196  // everything's fine
197  return 0;
198 }
199 
200 // =====================================================================
201 // ---------------------------------------------------------------------
202 // ---------------------------------------------------------------------
203 // =====================================================================
204 
207 {
208  // kill pointer
209  if (_mappedView)
210  {
211 #if defined(_WIN32) || defined(CASTOR_USE_MINGW)
212  ::UnmapViewOfFile(_mappedView);
213 #else
214  ::munmap(_mappedView, _filesize);
215 #endif
216  _mappedView = NULL;
217  }
218 
219 #if defined(_WIN32) || defined(CASTOR_USE_MINGW)
220  if (_mappedFile)
221  {
222  ::CloseHandle(_mappedFile);
223  _mappedFile = NULL;
224  }
225 #endif
226 
227  // close underlying file
228  if (_file)
229  {
230 #if defined(_WIN32) || defined(CASTOR_USE_MINGW)
231  ::CloseHandle(_file);
232 #else
233  ::close(_file);
234 #endif
235  _file = 0;
236  }
237 
238  _filesize = 0;
239 }
240 
241 // =====================================================================
242 // ---------------------------------------------------------------------
243 // ---------------------------------------------------------------------
244 // =====================================================================
245 
247 unsigned char oMemoryMapped::operator[](size_t offset) const
248 {
249  return ((unsigned char*)_mappedView)[offset];
250 }
251 
252 // =====================================================================
253 // ---------------------------------------------------------------------
254 // ---------------------------------------------------------------------
255 // =====================================================================
256 
258 unsigned char oMemoryMapped::at(size_t offset) const
259 {
260  // checks
261  if (!_mappedView)
262  throw std::invalid_argument("No view mapped");
263  if (offset >= _filesize)
264  throw std::out_of_range("View is not large enough");
265 
266  return operator[](offset);
267 }
268 
269 // =====================================================================
270 // ---------------------------------------------------------------------
271 // ---------------------------------------------------------------------
272 // =====================================================================
273 
275 const unsigned char* oMemoryMapped::GetData() const
276 {
277  return (const unsigned char*)_mappedView;
278 }
279 
280 // =====================================================================
281 // ---------------------------------------------------------------------
282 // ---------------------------------------------------------------------
283 // =====================================================================
284 
286 bool oMemoryMapped::IsValid() const
287 {
288  return _mappedView != NULL;
289 }
290 
291 // =====================================================================
292 // ---------------------------------------------------------------------
293 // ---------------------------------------------------------------------
294 // =====================================================================
295 
297 uint64_t oMemoryMapped::size() const
298 {
299  return _filesize;
300 }
301 
302 // =====================================================================
303 // ---------------------------------------------------------------------
304 // ---------------------------------------------------------------------
305 // =====================================================================
306 
308 size_t oMemoryMapped::mappedSize() const
309 {
310  return _mappedBytes;
311 }
312 
313 // =====================================================================
314 // ---------------------------------------------------------------------
315 // ---------------------------------------------------------------------
316 // =====================================================================
317 
319 int oMemoryMapped::Remap(uint64_t offset, size_t mappedBytes)
320 {
321  if (!_file)
322  {
323  Cerr("***** oMemoryMapped::Remap() -> Cannot remap a file that has not been created !" << endl);
324  return 1;
325  }
326 
327  if (mappedBytes == WholeFile)
328  mappedBytes = _filesize;
329 
330  // close old mapping
331  if (_mappedView)
332  {
333 #if defined(_WIN32) || defined(CASTOR_USE_MINGW)
334  ::UnmapViewOfFile(_mappedView);
335 #else
336  ::munmap(_mappedView, _mappedBytes);
337 #endif
338  _mappedView = NULL;
339  }
340 
341  // don't go further than end of file
342  if (offset > _filesize)
343  {
344  Cerr("***** oMemoryMapped::Remap() -> Provided offset is after the end of file !" << endl);
345  return 1;
346  }
347  if (offset + mappedBytes > _filesize)
348  mappedBytes = size_t(_filesize - offset);
349 
350 #if defined(_WIN32) || defined(CASTOR_USE_MINGW)
351 
352  // ===================================================================
353  // Windows
354  // ===================================================================
355 
356  DWORD offsetLow = DWORD(offset & 0xFFFFFFFF);
357  DWORD offsetHigh = DWORD(offset >> 32);
358  _mappedBytes = mappedBytes;
359 
360  // get memory address
361  _mappedView = ::MapViewOfFile(_mappedFile, FILE_MAP_READ, offsetHigh, offsetLow, mappedBytes);
362 
363  if (_mappedView == NULL)
364  {
365  _mappedBytes = 0;
366  _mappedView = NULL;
367  Cerr("***** oMemoryMapped::Remap() -> Mapped view is null after calling windows function MapViewOfFile() !" << endl);
368  return 1;
369  }
370 
371 #else
372 
373  // ===================================================================
374  // Linux
375  // ===================================================================
376 
377  // new mapping
378  //_mappedView = ::mmap64(NULL, mappedBytes, PROT_READ, MAP_SHARED, _file, offset);
379  _mappedView = ::mmap(NULL, mappedBytes, PROT_READ, MAP_SHARED, _file, offset);
380 
381  if (_mappedView == MAP_FAILED)
382  {
383  _mappedBytes = 0;
384  _mappedView = NULL;
385  Cerr("***** oMemoryMapped::Remap() -> Mapping failed after calling the unix function mmap64() !" << endl);
386  return 1;
387  }
388 
389  _mappedBytes = mappedBytes;
390 
391  // tweak performance
392  int linuxHint = 0;
393  switch (_hint)
394  {
395  case Normal: linuxHint = MADV_NORMAL; break;
396  case SequentialScan: linuxHint = MADV_SEQUENTIAL; break;
397  case RandomAccess: linuxHint = MADV_RANDOM; break;
398  default: break;
399  }
400  // assume that file will be accessed soon
401  //linuxHint |= MADV_WILLNEED;
402  // assume that file will be large
403  //linuxHint |= MADV_HUGEPAGE;
404 // linuxHint [= MADV_NOHUGEPAGE;
405 
406  ::madvise(_mappedView, _mappedBytes, linuxHint);
407 
408 #endif
409 
410  // end
411  return 0;
412 }
413 
414 // =====================================================================
415 // ---------------------------------------------------------------------
416 // ---------------------------------------------------------------------
417 // =====================================================================
418 
421 {
422 #if defined(_WIN32) || defined(CASTOR_USE_MINGW)
423  SYSTEM_INFO sysInfo;
424  GetSystemInfo(&sysInfo);
425  return sysInfo.dwAllocationGranularity;
426 #else
427  return sysconf(_SC_PAGESIZE); //::getpagesize();
428 #endif
429 }
430 
431 // =====================================================================
432 // ---------------------------------------------------------------------
433 // ---------------------------------------------------------------------
434 // =====================================================================
read file only once with few seeks
everything ... be careful when file is larger than memory
int Remap(uint64_t offset, size_t mappedBytes)
replace mapping by a new one of the same file, offset MUST be a multiple of the page size ...
void * _mappedView
pointer to the file contents mapped into memory
#define Cerr(MESSAGE)
bool IsValid() const
true, if file successfully opened
int Open(const std::string &filename, size_t mappedBytes=WholeFile, CacheHint hint=Normal)
open file, mappedBytes = 0 maps the whole file
oMemoryMapped()
do nothing, must use open()
size_t mappedSize() const
get number of actually mapped bytes
uint64_t size() const
get file size
unsigned char at(size_t offset) const
access position, including range checking
static int GetPageSize()
get OS page size (for remap)
unsigned char operator[](size_t offset) const
access position, no range checking (faster)
~oMemoryMapped()
close file (see close() )
const unsigned char * GetData() const
raw access
CacheHint _hint
caching strategy