libStatGen Software
1
|
00001 /* 00002 * Copyright (C) 2010 Regents of the University of Michigan 00003 * 00004 * This program is free software: you can redistribute it and/or modify 00005 * it under the terms of the GNU General Public License as published by 00006 * the Free Software Foundation, either version 3 of the License, or 00007 * (at your option) any later version. 00008 * 00009 * This program is distributed in the hope that it will be useful, 00010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 * GNU General Public License for more details. 00013 * 00014 * You should have received a copy of the GNU General Public License 00015 * along with this program. If not, see <http://www.gnu.org/licenses/>. 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 00029 #include "MemoryMap.h" 00030 00031 #ifndef _WIN32 00032 #include <sys/mman.h> 00033 #include <unistd.h> 00034 #endif 00035 00036 #ifndef MAP_POPULATE 00037 #define MAP_POPULATE 0x0000 00038 #endif 00039 #ifndef MAP_NONBLOCK 00040 #define MAP_NONBLOCK 0x0000 00041 #endif 00042 00043 MemoryMap::MemoryMap() 00044 { 00045 constructor_clear(); 00046 #if defined(_WIN32) 00047 SYSTEM_INFO sysinfo = {0}; 00048 ::GetSystemInfo(&sysinfo); 00049 DWORD cbView = sysinfo.dwAllocationGranularity; 00050 #else 00051 page_size = sysconf(_SC_PAGE_SIZE); 00052 #endif 00053 } 00054 00055 MemoryMap::~MemoryMap() 00056 { 00057 destructor_clear(); 00058 }; 00059 00060 void MemoryMap::debug_print() 00061 { 00062 #if defined(_WIN32) 00063 std::cout << "fd = " << file_handle << std::endl; 00064 #else 00065 std::cout << "fd = " << fd << std::endl; 00066 #endif 00067 std::cout << "data = 0x" << std::hex << data << std::endl; 00068 std::cout << "offset = 0x" << std::hex << offset << std::endl; 00069 std::cout << "mapped_length = 0x" << std::hex << mapped_length << std::endl; 00070 std::cout << "total_length = 0x" << std::hex << total_length << std::endl; 00071 std::cout << "page_size = 0x" << std::hex << page_size << std::endl; 00072 }; 00073 00074 void MemoryMap::constructor_clear() 00075 { 00076 #if defined(_WIN32) 00077 file_handle = NULL; 00078 map_handle = NULL; 00079 #else 00080 fd = -1; 00081 #endif 00082 data = (void *) NULL; 00083 offset = 0; 00084 mapped_length = 0; 00085 total_length = 0; 00086 useMemoryMapFlag = true; 00087 }; 00088 00089 void MemoryMap::destructor_clear() 00090 { 00091 #if defined(_WIN32) 00092 if (data!=NULL) 00093 { 00094 // free windows mapped object 00095 ::UnmapViewOfFile((LPVOID) data); 00096 } 00097 if (map_handle != NULL) 00098 ::CloseHandle(map_handle); 00099 if (file_handle != NULL) 00100 ::CloseHandle(file_handle); 00101 #else 00102 if (data!=NULL) 00103 { 00104 // free unix mapped object 00105 munmap(data, mapped_length); 00106 } 00107 // free unix resources 00108 if (fd!=-1) 00109 { 00110 ::close(fd); 00111 } 00112 #endif 00113 00114 constructor_clear(); 00115 } 00116 00117 00118 bool MemoryMap::allocate() 00119 { 00120 data = (void *) malloc(mapped_length); 00121 00122 if (data == NULL) 00123 { 00124 #ifdef __WIN32__ 00125 ::CloseHandle(file_handle); 00126 #else 00127 ::close(fd); 00128 #endif 00129 perror("MemoryMap::open"); 00130 constructor_clear(); 00131 return true; 00132 } 00133 00134 #ifdef __WIN32__ 00135 DWORD resultSize = 0; 00136 ReadFile(file_handle, data, mapped_length, &resultSize, NULL); 00137 #else 00138 size_t resultSize = read(fd, data, mapped_length); 00139 #endif 00140 00141 if ( resultSize != mapped_length) 00142 { 00143 #ifdef __WIN32__ 00144 ::CloseHandle(file_handle); 00145 #else 00146 ::close(fd); 00147 #endif 00148 perror("MemoryMap::open"); 00149 constructor_clear(); 00150 return true; 00151 } 00152 return false; 00153 } 00154 00155 00156 bool MemoryMap::open(const char * file, int flags) 00157 { 00158 const char * message = "MemoryMap::open - problem opening file %s"; 00159 #if defined(_WIN32) 00160 file_handle = CreateFile(file, 00161 (flags==O_RDONLY) ? GENERIC_READ : (GENERIC_READ | GENERIC_WRITE), 00162 FILE_SHARE_READ | FILE_SHARE_WRITE, // subsequent opens may either read or write 00163 NULL, 00164 OPEN_EXISTING, 00165 FILE_ATTRIBUTE_NORMAL, 00166 NULL); 00167 00168 if(file_handle == INVALID_HANDLE_VALUE) 00169 { 00170 fprintf(stderr, message, file); 00171 constructor_clear(); 00172 return true; 00173 } 00174 00175 LARGE_INTEGER file_size = {0}; 00176 ::GetFileSizeEx(file_handle, &file_size); 00177 mapped_length = total_length = file_size.QuadPart; 00178 00179 #else 00180 struct stat buf; 00181 fd = ::open(file, flags); 00182 if ((fd==-1) || (fstat(fd, &buf) != 0)) 00183 { 00184 fprintf(stderr, message, file); 00185 constructor_clear(); 00186 return true; 00187 } 00188 mapped_length = total_length = buf.st_size; 00189 #endif 00190 00191 if(!useMemoryMapFlag) 00192 { 00193 return allocate(); 00194 } 00195 00196 #if defined(_WIN32) 00197 assert(offset == 0); 00198 00199 map_handle = CreateFileMapping(file_handle, NULL, 00200 (flags==O_RDONLY) ? PAGE_READONLY : PAGE_READWRITE, 00201 file_size.HighPart, // upper 32 bits of map size 00202 file_size.LowPart, // lower 32 bits of map size 00203 NULL); 00204 00205 if(map_handle == NULL) 00206 { 00207 ::CloseHandle(file_handle); 00208 fprintf(stderr, message, file); 00209 constructor_clear(); 00210 return true; 00211 } 00212 00213 data = MapViewOfFile(map_handle, 00214 (flags == O_RDONLY) ? FILE_MAP_READ : FILE_MAP_ALL_ACCESS, 00215 0, 0, mapped_length); 00216 00217 if (data == NULL) 00218 { 00219 CloseHandle(map_handle); 00220 CloseHandle(file_handle); 00221 00222 fprintf(stderr, message, file); 00223 constructor_clear(); 00224 return true; 00225 } 00226 #else 00227 data = ::mmap(NULL, mapped_length, 00228 (flags == O_RDONLY) ? PROT_READ : PROT_READ | PROT_WRITE, 00229 MAP_SHARED, fd, offset); 00230 00231 if (data == MAP_FAILED) 00232 { 00233 ::close(fd); 00234 fprintf(stderr, message, file); 00235 constructor_clear(); 00236 return true; 00237 } 00238 #endif 00239 return false; 00240 } 00241 00242 00243 bool MemoryMap::create(const char *file, size_t size) 00244 { 00245 if (file==NULL) 00246 { 00247 data = calloc(size, 1); 00248 return(data==NULL); 00249 } 00250 00251 const char * message = "MemoryMap::create - problem creating file %s"; 00252 00253 #ifdef __WIN32__ 00254 file_handle = CreateFile(file, 00255 GENERIC_READ | GENERIC_WRITE, 00256 FILE_SHARE_READ | FILE_SHARE_WRITE, 00257 NULL, 00258 CREATE_ALWAYS, 00259 FILE_ATTRIBUTE_NORMAL, 00260 NULL); 00261 00262 if (file_handle == INVALID_HANDLE_VALUE) 00263 { 00264 fprintf(stderr, message, file); 00265 constructor_clear(); 00266 return true; 00267 } 00268 00269 SetFilePointer(file_handle, size - 1, NULL, FILE_BEGIN); 00270 char dummy = 0; 00271 DWORD check = 0; 00272 WriteFile(file_handle, &dummy, 1, &check, NULL); 00273 00274 if (check != 0) 00275 { 00276 CloseHandle(file_handle); 00277 DeleteFile(file); 00278 fprintf(stderr, message, file); 00279 constructor_clear(); 00280 return true; 00281 } 00282 CloseHandle(file_handle); 00283 open(file, O_RDWR); 00284 #else 00285 fd = ::open(file, O_RDWR|O_CREAT|O_TRUNC, 0666); 00286 if(fd == -1) 00287 { 00288 fprintf(stderr, message, file); 00289 constructor_clear(); 00290 return true; 00291 } 00292 00293 lseek(fd, (off_t) size - 1, SEEK_SET); 00294 char dummy = 0; 00295 if(write(fd, &dummy, 1)!=1) 00296 { 00297 fprintf(stderr, message, file); 00298 constructor_clear(); 00299 return true; 00300 } 00301 00302 data = ::mmap(NULL, size, PROT_READ|PROT_WRITE, 00303 MAP_SHARED, fd, offset); 00304 00305 if (data == MAP_FAILED) 00306 { 00307 ::close(fd); 00308 unlink(file); 00309 fprintf(stderr, message, file); 00310 constructor_clear(); 00311 return true; 00312 } 00313 mapped_length = total_length = size; 00314 #endif 00315 return false; 00316 } 00317 00318 00319 bool MemoryMap::create(size_t size) 00320 { 00321 return create(NULL, size); 00322 } 00323 00324 bool MemoryMap::close() 00325 { 00326 destructor_clear(); 00327 return false; 00328 } 00329 00330 void MemoryMap::test() 00331 { 00332 int result; 00333 00334 result = this->open("test/test_memmap_data.txt"); 00335 assert(result == 0); 00336 assert(data!=NULL); 00337 assert(mapped_length == 183); // length of the above file 00338 close(); 00339 00340 // now try non memory mapped (direct slow file I/O) 00341 useMemoryMap(false); 00342 result = this->open("test/test_memmap_data.txt"); 00343 assert(result == 0); 00344 assert(data!=NULL); 00345 assert(mapped_length == 183); // length of the above file 00346 close(); 00347 } 00348 00349 int MemoryMap::prefetch() 00350 { 00351 int sum = 0; 00352 size_t i; 00353 00354 for (i=0; i<mapped_length; i += page_size) sum += *(i + (char *) data); 00355 00356 return sum; 00357 } 00358 00359 #if defined(TEST) 00360 // 00361 // compile test using: 00362 // g++ -DTEST -o testMemoryMap MemoryMap.cpp Error.o -lz 00363 // 00364 00365 int main(int argc, const char *argv) 00366 { 00367 MemoryMap map; 00368 00369 map.test(); 00370 00371 // map.debug_print(); 00372 00373 exit(0); 00374 } 00375 #endif 00376