00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <sys/stat.h>
00019 #include <sys/types.h>
00020 #include <assert.h>
00021 #include <errno.h>
00022 #include <fcntl.h>
00023 #include <iostream>
00024 #include <stdio.h>
00025 #include <stdexcept>
00026 #include <stdlib.h>
00027 #include <string>
00028 #include <unistd.h>
00029
00030 #include "MemoryMap.h"
00031
00032 #if defined(WIN32)
00033
00034 SYSTEM_INFO MemoryMap::system_info;
00035 static bool need_system_info = true;
00036 #include <windows.h>
00037
00038 #if !defined(__CYGWIN__)
00039 typedef char * caddr_t;
00040 #endif
00041
00042 #else
00043 #include <sys/mman.h>
00044 #endif
00045
00046 #ifndef MAP_POPULATE
00047 #define MAP_POPULATE 0x0000
00048 #endif
00049 #ifndef MAP_NONBLOCK
00050 #define MAP_NONBLOCK 0x0000
00051 #endif
00052
00053 MemoryMap::MemoryMap()
00054 {
00055 constructor_clear();
00056 #if defined(WIN32)
00057 if (need_system_info)
00058 {
00059 GetSystemInfo(&system_info);
00060 need_system_info = false;
00061 }
00062 page_size = system_info.dwAllocationGranularity;
00063 #else
00064 page_size = sysconf(_SC_PAGE_SIZE);
00065 #endif
00066 };
00067
00068 MemoryMap::~MemoryMap()
00069 {
00070 destructor_clear();
00071 };
00072
00073 void MemoryMap::debug_print()
00074 {
00075 #if defined(WIN32)
00076 std::cout << "fd = " << file_handle << std::endl;
00077 #else
00078 std::cout << "fd = " << fd << std::endl;
00079 #endif
00080 std::cout << "data = 0x" << std::hex << data << std::endl;
00081 std::cout << "offset = 0x" << std::hex << offset << std::endl;
00082 std::cout << "mapped_length = 0x" << std::hex << mapped_length << std::endl;
00083 std::cout << "total_length = 0x" << std::hex << total_length << std::endl;
00084 std::cout << "page_size = 0x" << std::hex << page_size << std::endl;
00085 };
00086
00087 void MemoryMap::constructor_clear()
00088 {
00089 #if defined(WIN32)
00090 file_handle = 0;
00091 map_handle = 0;
00092 #else
00093 fd = -1;
00094 #endif
00095 data = (void *) NULL;
00096 offset = 0;
00097 mapped_length = 0;
00098 total_length = 0;
00099 useMemoryMapFlag = true;
00100 };
00101
00102 void MemoryMap::destructor_clear()
00103 {
00104 if (data!=NULL)
00105 {
00106 #if defined(WIN32)
00107
00108 UnmapViewOfFile((LPVOID) data);
00109 #else
00110
00111 munmap(data, mapped_length);
00112 #endif
00113 }
00114
00115 #if !defined(WIN32)
00116
00117 if (fd!=-1)
00118 {
00119 ::close(fd);
00120 }
00121 #endif
00122
00123 constructor_clear();
00124 };
00125
00126 #if defined(WIN32)
00127 bool MemoryMap::open(const char * file, int flags)
00128 {
00129 const off_t offset = 0;
00130 const size_t size = 0;
00131
00132
00133
00134
00135
00136
00137
00138 BY_HANDLE_FILE_INFORMATION file_handle_information;
00139
00140
00141
00142
00143
00144
00145
00146 file_handle = CreateFile(
00147 file,
00148 (flags==O_RDWR) ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ,
00149 FILE_SHARE_READ | FILE_SHARE_WRITE,
00150 NULL,
00151 OPEN_ALWAYS,
00152 FILE_ATTRIBUTE_NORMAL,
00153 NULL);
00154
00155 #ifdef DEBUG_MAP
00156 fprintf(stderr,"MemoryMap::open: file_handle=%x\n", h->file_handle);
00157 #endif
00158
00159 if(file_handle == INVALID_HANDLE_VALUE) {
00160 std::cerr << "MemoryMap::open: CreateFile(" << file << ") failed." << std::endl;
00161 return true;
00162 }
00163
00164 GetFileInformationByHandle(file_handle, &file_handle_information);
00165
00166 mapped_length = size;
00167
00168 if(size==0) mapped_length = file_handle_information.nFileSizeLow - offset;
00169
00170 #if !defined(__MINGW32__)
00171 if(mapped_length+offset > file_handle_information.nFileSizeLow)
00172 #else
00173
00174 if((unsigned)mapped_length+offset > file_handle_information.nFileSizeLow)
00175 #endif
00176 #if 0
00177
00178 CloseHandle(file_handle); ??
00179 FreeResource(file_handle); ??
00180 #endif
00181 {
00182 std::cerr << "MemoryMap::open: unable to map file " << file << " at offset " << offset << "." << std::endl;
00183 constructor_clear();
00184 return true;
00185 }
00186
00187 map_handle = CreateFileMapping(
00188 file_handle,
00189 NULL,
00190 (flags==O_RDWR) ? PAGE_READWRITE : PAGE_READONLY,
00191 0,
00192 size,
00193 NULL
00194 );
00195
00196 #ifdef DEBUG_MAP
00197 std::cout << "MemoryMap::open: map_handle = " << h->map_handle << std::endl;
00198 #endif
00199
00200
00201 if(map_handle == NULL) {
00202 std::cerr << "MemoryMap::open: unable to map file " << file << "." << std::endl;
00203 constructor_clear();
00204 return true;
00205 }
00206
00207 #ifdef DEBUG_MAP
00208 std::cerr << "MemoryMap::open: calling MapViewOfFile(offset=" << offset << ", mapped_length=" << mapped_length << ")." << std::endl;
00209 #endif
00210 LPVOID map_pointer = MapViewOfFile(
00211 map_handle,
00212 (flags==O_RDWR) ? (FILE_MAP_WRITE | FILE_MAP_READ) : FILE_MAP_READ,
00213 (DWORD) 0,
00214 (DWORD) offset,
00215 mapped_length
00216 );
00217
00218 #ifdef DEBUG_MAP
00219 DWORD e = GetLastError();
00220 std::cerr << "MemoryMap::open: map_pointer = " << map_pointer << ", error = " << error << std::endl;
00221 #endif
00222
00223 data = (caddr_t) map_pointer;
00224
00225 return false;
00226 }
00227
00228 bool MemoryMap::create(const char *file, size_t size)
00229 {
00230
00231
00232
00233 struct stat sb;
00234
00235 if(stat(file,&sb)!=0) {
00236 if(size==0) {
00237 std::cerr << "MemoryMap::create requires non zero size when creating a new file." << std::endl;
00238 return true;
00239 }
00240 int d = ::open(file, O_RDWR);
00241 off_t result = lseek(d, (off_t) size - 1, SEEK_SET);
00242 ::close(d);
00243 }
00244
00245 return open(file, O_RDWR);
00246 }
00247
00248 #else
00249 bool MemoryMap::open(const char * file, int flags)
00250 {
00251
00252 struct stat buf;
00253
00254 int mmap_prot_flag = PROT_READ;
00255 if (flags != O_RDONLY) mmap_prot_flag = PROT_WRITE;
00256
00257 fd = ::open(file, flags);
00258 if (fd==-1)
00259 {
00260 fprintf(stderr, "MemoryMap::open: file %s not found\n", (const char *) file);
00261 constructor_clear();
00262 return true;
00263 }
00264 if (fstat(fd, &buf))
00265 {
00266 perror("MemoryMap::open");
00267 constructor_clear();
00268 return true;
00269 }
00270 mapped_length = buf.st_size;
00271 total_length = mapped_length;
00272
00273 if (useMemoryMapFlag)
00274 {
00275
00276 int additionalFlags = 0;
00277
00278
00279
00280
00281 #if defined(USE_LOCKED_MMAP)
00282
00283
00284 if (flags != O_RDONLY)
00285 {
00286
00287
00288 additionalFlags |= MAP_POPULATE;
00289 additionalFlags |= MAP_PRIVATE;
00290 }
00291 else
00292 {
00293 additionalFlags |= MAP_SHARED;
00294 }
00295 #else
00296 additionalFlags |= MAP_SHARED;
00297 #endif
00298
00299 data = ::mmap(
00300 NULL,
00301 mapped_length,
00302 mmap_prot_flag,
00303 additionalFlags,
00304 fd,
00305 offset
00306 );
00307 if (data == MAP_FAILED)
00308 {
00309 ::close(fd);
00310 std::cerr << "Error: Attempting to map " << mapped_length << " bytes of file "
00311 << file << ":" << std::endl;
00312 perror("MemoryMap::open");
00313 constructor_clear();
00314 return true;
00315 }
00316
00317 #if defined(USE_LOCKED_MMAP)
00318
00319
00320
00321
00322
00323
00324 if (mlock(data, mapped_length))
00325 {
00326 std::cerr << "Warning: Attempting to lock " << mapped_length << " bytes of file " << file << ":" << std::endl;
00327 perror("unable to lock memory");
00328
00329 }
00330 #endif
00331
00332
00333
00334
00335
00336 madvise(data, mapped_length, MADV_WILLNEED);
00337
00338 }
00339 else
00340 {
00341 data = (void *) malloc(mapped_length);
00342 if (data==NULL)
00343 {
00344 ::close(fd);
00345 perror("MemoryMap::open");
00346 constructor_clear();
00347 return true;
00348 }
00349 ssize_t resultSize = read(fd, data, mapped_length);
00350 if (resultSize!=(ssize_t) mapped_length)
00351 {
00352 ::close(fd);
00353 perror("MemoryMap::open");
00354 constructor_clear();
00355 return true;
00356 }
00357 }
00358 return false;
00359 }
00360
00361 bool MemoryMap::create(const char *file, size_t size)
00362 {
00363
00364 if (file==NULL)
00365 {
00366 data = calloc(size, 1);
00367 if (data==NULL) return true;
00368 }
00369 else
00370 {
00371 int mmap_prot_flag = PROT_READ | PROT_WRITE;
00372
00373 fd = ::open(file, O_RDWR|O_CREAT|O_TRUNC, 0666);
00374 if (fd==-1)
00375 {
00376 fprintf(stderr, "MemoryMap::open: can't create file '%s'\n",(const char *) file);
00377 constructor_clear();
00378 return true;
00379 }
00380
00381 lseek(fd, (off_t) size - 1, SEEK_SET);
00382 char ch = 0;
00383 if(write(fd, &ch, 1)!=1) {
00384 perror("MemoryMap::create:");
00385 throw std::logic_error("unable to write at end of file");
00386 }
00387
00388 data = ::mmap(
00389 NULL,
00390 size,
00391 mmap_prot_flag,
00392 MAP_SHARED,
00393 fd,
00394 offset
00395 );
00396 if (data == MAP_FAILED)
00397 {
00398 ::close(fd);
00399 unlink(file);
00400 perror("MemoryMap::open");
00401 constructor_clear();
00402 return true;
00403 }
00404 mapped_length = size;
00405 total_length = size;
00406 }
00407 return false;
00408 }
00409 #endif
00410
00411 bool MemoryMap::create(size_t size)
00412 {
00413 return create(NULL, size);
00414 }
00415
00416 bool MemoryMap::close()
00417 {
00418 destructor_clear();
00419 return false;
00420 };
00421
00422 void MemoryMap::test()
00423 {
00424 int result;
00425
00426 result = this->open("test/test_memmap_data.txt");
00427 assert(result == 0);
00428 assert(data!=NULL);
00429 assert(mapped_length == 183);
00430 close();
00431
00432
00433 useMemoryMap(false);
00434 result = this->open("test/test_memmap_data.txt");
00435 assert(result == 0);
00436 assert(data!=NULL);
00437 assert(mapped_length == 183);
00438 close();
00439 }
00440
00441 int MemoryMap::prefetch()
00442 {
00443 int sum = 0;
00444 size_t i;
00445
00446 for (i=0; i<mapped_length; i += page_size) sum += *(i + (char *) data);
00447
00448 return sum;
00449 }
00450
00451 #if defined(TEST)
00452
00453
00454
00455
00456
00457 int main(int argc, const char *argv)
00458 {
00459 MemoryMap map;
00460
00461 map.test();
00462
00463
00464
00465 exit(0);
00466 }
00467 #endif
00468