MemoryMap.cpp
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 SYSTEM_INFO MemoryMap::system_info;
00034 static bool need_system_info = 1;
00035 #else
00036 #include <sys/mman.h>
00037 #endif
00038
00039 #ifndef MAP_POPULATE
00040 #define MAP_POPULATE 0x0000
00041 #endif
00042 #ifndef MAP_NONBLOCK
00043 #define MAP_NONBLOCK 0x0000
00044 #endif
00045
00046 MemoryMap::MemoryMap()
00047 {
00048 constructor_clear();
00049 #if defined(WIN32)
00050 if (need_system_info)
00051 {
00052 GetSystemInfo(&system_info);
00053 need_system_info = false;
00054 }
00055 page_size = system_info.dwAllocationGranularity;
00056 #else
00057 page_size = sysconf(_SC_PAGE_SIZE);
00058 #endif
00059 };
00060
00061 MemoryMap::~MemoryMap()
00062 {
00063 destructor_clear();
00064 };
00065
00066 void MemoryMap::debug_print()
00067 {
00068 #if defined(WIN32)
00069 std::cout << "fd = " << file_handle << std::endl;
00070 #else
00071 std::cout << "fd = " << fd << std::endl;
00072 #endif
00073 std::cout << "data = 0x" << std::hex << data << std::endl;
00074 std::cout << "offset = 0x" << std::hex << offset << std::endl;
00075 std::cout << "mapped_length = 0x" << std::hex << mapped_length << std::endl;
00076 std::cout << "total_length = 0x" << std::hex << total_length << std::endl;
00077 std::cout << "page_size = 0x" << std::hex << page_size << std::endl;
00078 };
00079
00080 void MemoryMap::constructor_clear()
00081 {
00082 #if defined(WIN32)
00083 file_handle = 0;
00084 #else
00085 fd = -1;
00086 #endif
00087 data = (void *) NULL;
00088 offset = 0;
00089 mapped_length = 0;
00090 total_length = 0;
00091 useMemoryMapFlag = true;
00092 };
00093
00094 void MemoryMap::destructor_clear()
00095 {
00096 if (data!=NULL)
00097 {
00098 #if defined(WIN32)
00099 UnmapViewOfFile((LPVOID) data);
00100 #else
00101 munmap(data, mapped_length);
00102 #endif
00103 }
00104 #if !defined(WIN32)
00105 if (fd!=-1)
00106 {
00107 ::close(fd);
00108 }
00109 #endif
00110 constructor_clear();
00111 };
00112
00113 #if defined(WIN32)
00114
00115
00116 #else
00117 bool MemoryMap::open(const char * file, int flags)
00118 {
00119
00120 struct stat buf;
00121
00122 int mmap_prot_flag = PROT_READ;
00123 if (flags != O_RDONLY) mmap_prot_flag = PROT_WRITE;
00124
00125 fd = ::open(file, flags);
00126 if (fd==-1)
00127 {
00128 fprintf(stderr, "MemoryMap::open: file %s not found\n", (const char *) file);
00129 constructor_clear();
00130 return true;
00131 }
00132 if (fstat(fd, &buf))
00133 {
00134 perror("MemoryMap::open");
00135 constructor_clear();
00136 return true;
00137 }
00138 mapped_length = buf.st_size;
00139 total_length = mapped_length;
00140
00141 if (useMemoryMapFlag)
00142 {
00143
00144 int additionalFlags = 0;
00145
00146
00147
00148
00149 #if defined(USE_LOCKED_MMAP)
00150
00151
00152 if (flags != O_RDONLY)
00153 {
00154
00155
00156 additionalFlags |= MAP_POPULATE;
00157 additionalFlags |= MAP_PRIVATE;
00158 }
00159 else
00160 {
00161 additionalFlags |= MAP_SHARED;
00162 }
00163 #else
00164 additionalFlags |= MAP_SHARED;
00165 #endif
00166
00167 data = ::mmap(
00168 NULL,
00169 mapped_length,
00170 mmap_prot_flag,
00171 additionalFlags,
00172 fd,
00173 offset
00174 );
00175 if (data == MAP_FAILED)
00176 {
00177 ::close(fd);
00178 std::cerr << "Error: Attempting to map " << mapped_length << " bytes of file "
00179 << file << ":" << std::endl;
00180 perror("MemoryMap::open");
00181 constructor_clear();
00182 return true;
00183 }
00184
00185 #if defined(USE_LOCKED_MMAP)
00186
00187
00188
00189
00190
00191
00192 if (mlock(data, mapped_length))
00193 {
00194 std::cerr << "Warning: Attempting to lock " << mapped_length << " bytes of file " << file << ":" << std::endl;
00195 perror("unable to lock memory");
00196
00197 }
00198 #endif
00199
00200
00201
00202
00203
00204 madvise(data, mapped_length, MADV_WILLNEED);
00205
00206 }
00207 else
00208 {
00209 data = (void *) malloc(mapped_length);
00210 if (data==NULL)
00211 {
00212 ::close(fd);
00213 perror("MemoryMap::open");
00214 constructor_clear();
00215 return true;
00216 }
00217 ssize_t resultSize = read(fd, data, mapped_length);
00218 if (resultSize!=(ssize_t) mapped_length)
00219 {
00220 ::close(fd);
00221 perror("MemoryMap::open");
00222 constructor_clear();
00223 return true;
00224 }
00225 }
00226 return false;
00227 }
00228
00229 bool MemoryMap::create(const char *file, size_t size)
00230 {
00231
00232 if (file==NULL)
00233 {
00234 data = calloc(size, 1);
00235 if (data==NULL) return true;
00236 }
00237 else
00238 {
00239 int mmap_prot_flag = PROT_READ | PROT_WRITE;
00240
00241 fd = ::open(file, O_RDWR|O_CREAT|O_TRUNC, 0666);
00242 if (fd==-1)
00243 {
00244 fprintf(stderr, "MemoryMap::open: can't create file '%s'\n",(const char *) file);
00245 constructor_clear();
00246 return true;
00247 }
00248
00249 lseek(fd, (off_t) size - 1, SEEK_SET);
00250 char ch = 0;
00251 if(write(fd, &ch, 1)!=1) {
00252 perror("MemoryMap::create:");
00253 throw std::logic_error("unable to write at end of file");
00254 }
00255
00256 data = ::mmap(
00257 NULL,
00258 size,
00259 mmap_prot_flag,
00260 MAP_SHARED,
00261 fd,
00262 offset
00263 );
00264 if (data == MAP_FAILED)
00265 {
00266 ::close(fd);
00267 unlink(file);
00268 perror("MemoryMap::open");
00269 constructor_clear();
00270 return true;
00271 }
00272 mapped_length = size;
00273 total_length = size;
00274 }
00275 return false;
00276 }
00277 #endif
00278
00279 bool MemoryMap::create(size_t size)
00280 {
00281 return create(NULL, size);
00282 }
00283
00284 bool MemoryMap::close()
00285 {
00286 destructor_clear();
00287 return false;
00288 };
00289
00290 void MemoryMap::test()
00291 {
00292 int result;
00293
00294 result = this->open("test/test_memmap_data.txt");
00295 assert(result == 0);
00296 assert(data!=NULL);
00297 assert(mapped_length == 183);
00298 close();
00299
00300
00301 useMemoryMap(false);
00302 result = this->open("test/test_memmap_data.txt");
00303 assert(result == 0);
00304 assert(data!=NULL);
00305 assert(mapped_length == 183);
00306 close();
00307 }
00308
00309 int MemoryMap::prefetch()
00310 {
00311 int sum = 0;
00312 size_t i;
00313
00314 for (i=0; i<mapped_length; i += page_size) sum += *(i + (char *) data);
00315
00316 return sum;
00317 }
00318
00319 #if defined(TEST)
00320
00321
00322
00323
00324
00325 int main(int argc, const char *argv)
00326 {
00327 MemoryMap map;
00328
00329 map.test();
00330
00331
00332
00333 exit(0);
00334 }
00335 #endif
00336