|
degate 0.1.1
|
00001 /* -*-c++-*- 00002 00003 This file is part of the IC reverse engineering tool degate. 00004 00005 Copyright 2008, 2009, 2010 by Martin Schobert 00006 00007 Degate is free software: you can redistribute it and/or modify 00008 it under the terms of the GNU General Public License as published by 00009 the Free Software Foundation, either version 3 of the License, or 00010 any later version. 00011 00012 Degate is distributed in the hope that it will be useful, 00013 but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 GNU General Public License for more details. 00016 00017 You should have received a copy of the GNU General Public License 00018 along with degate. If not, see <http://www.gnu.org/licenses/>. 00019 00020 */ 00021 00022 #ifndef __MEMORYMAP_H__ 00023 #define __MEMORYMAP_H__ 00024 00025 #include "globals.h" 00026 #include <string> 00027 00028 #include <stdio.h> 00029 #include <stdlib.h> 00030 #include <stdint.h> 00031 #include <unistd.h> 00032 #include <string.h> 00033 #include <time.h> 00034 #include <sys/types.h> 00035 #include <sys/mman.h> 00036 #include <fcntl.h> 00037 #include <assert.h> 00038 #include <limits.h> 00039 #include <math.h> 00040 #include <tr1/memory> 00041 #include <boost/utility.hpp> 00042 00043 namespace degate { 00044 00045 enum MAP_STORAGE_TYPE { 00046 MAP_STORAGE_TYPE_MEM = 0, 00047 MAP_STORAGE_TYPE_PERSISTENT_FILE = 1, 00048 MAP_STORAGE_TYPE_TEMP_FILE = 2, 00049 }; 00050 00051 00052 /* 00053 * Storage for data objects, that is mapped from files into memory. 00054 * 00055 * You should not use this class directly. 00056 */ 00057 template<typename T> 00058 class MemoryMap : boost::noncopyable { 00059 00060 private: 00061 unsigned int width, height; 00062 MAP_STORAGE_TYPE storage_type; 00063 00064 T * mem; 00065 std::string filename; 00066 int fd; 00067 size_t filesize; 00068 00069 private: 00070 ret_t alloc_memory(); 00071 ret_t map_temp_file(std::string const & filename_pattern); 00072 ret_t map_file(std::string const & filename); 00073 00074 ret_t map_file_by_fd(); 00075 00076 void * get_void_ptr(unsigned int x, unsigned int y) const; 00077 00078 bool is_temp_file() const { 00079 return storage_type == MAP_STORAGE_TYPE_TEMP_FILE; 00080 } 00081 00082 bool is_persistent_file() const { 00083 return storage_type == MAP_STORAGE_TYPE_PERSISTENT_FILE; 00084 } 00085 00086 bool is_mem() const { 00087 return storage_type == MAP_STORAGE_TYPE_MEM; 00088 } 00089 00090 public: 00091 00092 00093 /** 00094 * Allocate a heap based memory chunk. 00095 * @param width The width of a 2D map. 00096 * @param height The height of a 2D map. 00097 */ 00098 MemoryMap(unsigned int width, unsigned int height); 00099 00100 /** 00101 * Create a file based memory chunk. 00102 * The storage is filebases. The file is mapped into memory. 00103 * @param width The width of a 2D map. 00104 * @param height The height of a 2D map. 00105 * @param mode Is either MAP_STORAGE_TYPE_PERSISTENT_FILE or MAP_STORAGE_TYPE_TEMP_FILE. 00106 * @param file_to_map The name of the file, which should be mmap(). 00107 */ 00108 MemoryMap(unsigned int width, unsigned int height, 00109 MAP_STORAGE_TYPE mode, std::string const & file_to_map); 00110 00111 /** 00112 * The destructor. 00113 */ 00114 ~MemoryMap(); 00115 00116 int get_width() const { return width; } 00117 int get_height() const { return height; } 00118 00119 /** 00120 * Cear the whole memory map. 00121 */ 00122 void clear(); 00123 00124 void clear_area(unsigned int min_x, unsigned int min_y, 00125 unsigned int width, unsigned int height); 00126 00127 /** 00128 * Set the value of a memory element. 00129 */ 00130 inline void set(unsigned int x, unsigned int y, T new_val); 00131 00132 /** 00133 * Get the value of an memory element. 00134 */ 00135 inline T get(unsigned int x, unsigned int y) const; 00136 00137 /** 00138 * Copy the whole memory content into a buffer. Make sure that the buffer \p buf 00139 * is large enough to hold get_width() * get_height() * sizeof(T) bytes. 00140 */ 00141 void raw_copy(void * buf) const; 00142 00143 /** 00144 * Get the name of the mapped file. 00145 * @returns Returns a string with the mapped file. If the memory 00146 * chunk is heap and not file based, an empty string is returned. 00147 */ 00148 std::string const& get_filename() const { return filename; } 00149 00150 }; 00151 00152 template <typename T> 00153 MemoryMap<T>::MemoryMap(unsigned int _width, unsigned int _height) : 00154 width(_width), height(_height), 00155 storage_type(MAP_STORAGE_TYPE_MEM), 00156 mem(NULL), 00157 fd(-1), 00158 filesize(0) { 00159 00160 assert(width > 0 && height > 0); 00161 00162 ret_t ret = alloc_memory(); 00163 assert(ret == RET_OK); 00164 } 00165 00166 template <typename T> 00167 MemoryMap<T>::MemoryMap(unsigned int _width, unsigned int _height, 00168 MAP_STORAGE_TYPE mode, std::string const & file_to_map) : 00169 width(_width), height(_height), 00170 storage_type(mode), 00171 mem(NULL), 00172 filename(file_to_map), 00173 fd(-1), 00174 filesize(0) { 00175 00176 assert(mode == MAP_STORAGE_TYPE_PERSISTENT_FILE || 00177 mode == MAP_STORAGE_TYPE_TEMP_FILE); 00178 00179 assert(width > 0 && height > 0); 00180 00181 ret_t ret; 00182 00183 if(mode == MAP_STORAGE_TYPE_TEMP_FILE) { 00184 ret = map_temp_file(file_to_map); 00185 if(RET_IS_NOT_OK(ret)) 00186 debug(TM, "Can't open a temp file with pattern %s", file_to_map.c_str()); 00187 00188 assert(RET_IS_OK(ret)); 00189 } 00190 else if(mode == MAP_STORAGE_TYPE_PERSISTENT_FILE) { 00191 ret = map_file(file_to_map); 00192 if(RET_IS_NOT_OK(ret)) debug(TM, "Can't open file %s as persistent file", file_to_map.c_str()); 00193 assert(RET_IS_OK(ret)); 00194 } 00195 } 00196 00197 00198 template <typename T> 00199 MemoryMap<T>::~MemoryMap() { 00200 00201 switch(storage_type) { 00202 case MAP_STORAGE_TYPE_MEM: 00203 if(mem != NULL) free(mem); 00204 mem = NULL; 00205 break; 00206 case MAP_STORAGE_TYPE_PERSISTENT_FILE: 00207 case MAP_STORAGE_TYPE_TEMP_FILE: 00208 if(mem != NULL) { 00209 if(msync(mem, filesize, MS_SYNC) == -1) { 00210 perror("msync() failed"); 00211 } 00212 00213 if(munmap(mem, filesize) == -1) { 00214 perror("munmap failed"); 00215 } 00216 00217 mem = NULL; 00218 } 00219 00220 close(fd); 00221 00222 if(is_temp_file()) { 00223 if(unlink(filename.c_str()) == -1) { 00224 debug(TM, "Can't unlink temp file"); 00225 } 00226 } 00227 break; 00228 } 00229 00230 } 00231 00232 template <typename T> 00233 ret_t MemoryMap<T>::alloc_memory() { 00234 00235 /* If it is not null, it would indicates, 00236 that there is already any allocation. */ 00237 assert(mem == NULL); 00238 00239 mem = (T *) malloc(width * height * sizeof(T)); 00240 assert(mem != NULL); 00241 if(mem == NULL) return RET_MALLOC_FAILED; 00242 memset(mem, 0, width * height * sizeof(T)); 00243 return RET_OK; 00244 } 00245 00246 /** 00247 * Clear map data. 00248 */ 00249 00250 template <typename T> 00251 void MemoryMap<T>::clear() { 00252 assert(mem != NULL); 00253 if(mem != NULL) memset(mem, 0, width * height * sizeof(T)); 00254 } 00255 00256 00257 /** 00258 * Clear an area given by start point and width and height 00259 */ 00260 template <typename T> 00261 void MemoryMap<T>::clear_area( unsigned int min_x, unsigned int min_y, 00262 unsigned int width, unsigned int height) { 00263 assert(mem != NULL); 00264 00265 if(mem != NULL) { 00266 unsigned int x, y; 00267 for(y = min_y; y < min_y + height; y++) 00268 memset(get_void_ptr(x, y), 0, width * sizeof(T)); 00269 } 00270 } 00271 00272 00273 /** 00274 * Create a temp file and use it as storage for the map data. 00275 * @param filename_pattern The parameter file is a string that specifies the 00276 * temp file pattern, e.g. "/tmp/temp.XXXXXXX" 00277 */ 00278 template <typename T> 00279 ret_t MemoryMap<T>::map_temp_file(std::string const& filename_pattern) { 00280 ret_t ret; 00281 00282 assert(is_temp_file()); 00283 00284 char * tmp_filename = strdup(filename_pattern.c_str()); 00285 00286 fd = mkstemp(tmp_filename); 00287 00288 if(fd == -1) { 00289 debug(TM, "mkstemp() failed"); 00290 ret = RET_ERR; 00291 } 00292 else { 00293 ret = map_file_by_fd(); 00294 filename = std::string(tmp_filename); 00295 } 00296 00297 // cleanup 00298 free(tmp_filename); 00299 00300 return ret; 00301 } 00302 00303 00304 /** 00305 * Use storage in file as storage for memory map 00306 */ 00307 template <typename T> 00308 ret_t MemoryMap<T>::map_file(std::string const& filename) { 00309 00310 assert(is_persistent_file()); 00311 00312 if((fd = open(filename.c_str(), O_RDWR | O_CREAT, 0600)) == -1) { 00313 debug(TM, "can't open file: %s", filename.c_str()); 00314 return RET_ERR; 00315 } 00316 00317 return map_file_by_fd(); 00318 } 00319 00320 template <typename T> 00321 ret_t MemoryMap<T>::map_file_by_fd() { 00322 00323 assert(fd != -1); 00324 if(fd == -1) { 00325 debug(TM, "error: invalid file handle"); 00326 return RET_ERR; 00327 } 00328 else { 00329 // get file size 00330 filesize = lseek(fd, 0, SEEK_END); 00331 if(filesize < width * height * sizeof(T)) { 00332 filesize = width * height * sizeof(T); 00333 lseek(fd, filesize - 1, SEEK_SET); 00334 if(write(fd, "\0", 1) != 1) { 00335 debug(TM, "can't open file: %s", filename.c_str()); 00336 return RET_ERR; 00337 } 00338 } 00339 00340 // map the file into memory 00341 if((mem = (T *) mmap(NULL, filesize, 00342 PROT_READ | PROT_WRITE, 00343 MAP_FILE | MAP_SHARED, fd, 0)) == (void *)(-1)) { 00344 debug(TM, "mmap failed for %s", filename.c_str()); 00345 close(fd); 00346 return RET_ERR; 00347 } 00348 00349 return RET_OK; 00350 } 00351 } 00352 00353 00354 /** 00355 * On 32 bit architectures it might be neccessary to temporarily unmap data files. 00356 * This function should be used to unmap the data file from address space. 00357 * @see reactivate_mapping() 00358 * @todo Remove this method. 00359 */ 00360 /* template <typename T> 00361 ret_t MemoryMap<T>::deactivate_mapping() { 00362 ret_t ret = RET_OK; 00363 00364 if(is_mem() ) return RET_ERR; 00365 //assert(mem != NULL); 00366 00367 if(mem != NULL) { 00368 00369 if(msync(mem, filesize, MS_SYNC) == -1) { 00370 debug(TM, "msync() failed"); 00371 ret = RET_ERR; 00372 } 00373 00374 if(munmap(mem, filesize) == -1) { 00375 debug(TM, "munmap failed"); 00376 ret = RET_ERR; 00377 } 00378 00379 mem = NULL; 00380 } 00381 else 00382 ret = RET_ERR; 00383 return ret; 00384 }*/ 00385 00386 /** 00387 * On 32 bit architectures it might be neccessary to temporarily unmap data files. 00388 * This function should be used to map the data file again into address space. 00389 * @see gr_deactivate_mapping() 00390 * @todo Remove this method. 00391 */ 00392 /* template <typename T> 00393 ret_t MemoryMap<T>::reactivate_mapping() { 00394 00395 if(fd == 0) { 00396 debug(TM, "invalid file handle"); 00397 return RET_ERR; 00398 } 00399 if(is_mem()) return RET_ERR; 00400 00401 if(mem == NULL) { 00402 if((mem = (T *) mmap(NULL, filesize, 00403 PROT_READ | PROT_WRITE, 00404 MAP_FILE | MAP_SHARED, fd, 0)) == (void *)(-1)) { 00405 return RET_ERR; 00406 } 00407 00408 return RET_OK; 00409 } 00410 else { 00411 return RET_ERR; 00412 } 00413 }*/ 00414 00415 template <typename T> 00416 void MemoryMap<T>::raw_copy(void * buf) const { 00417 assert(mem != NULL); 00418 memcpy(buf, mem, width * height * sizeof(T)); 00419 } 00420 00421 00422 template <typename T> 00423 void * MemoryMap<T>::get_void_ptr(unsigned int x, unsigned int y) const { 00424 if(x + y < width * height) 00425 return mem + (y * width + x); 00426 else { 00427 debug(TM, "error: out of bounds x=%d, y=%d", x, y); 00428 assert(1 == 0); 00429 return NULL; 00430 } 00431 } 00432 00433 template <typename T> 00434 inline void MemoryMap<T>::set(unsigned int x, unsigned int y, T new_val) { 00435 if(x >= width || y >= height) { 00436 debug(TM, "error: out of bounds x=%d, y=%d / width=%d, height=%d", x, y, width, height); 00437 } 00438 assert(x < width && y < height); 00439 mem[y * width + x] = new_val; 00440 /* 00441 if(x + y * width < width * height) 00442 mem[y * width + x] = new_val; 00443 else { 00444 debug(TM, "error: out of bounds x=%d, y=%d / width=%d, height=%d", x, y, width, height); 00445 assert(1 == 0); 00446 } 00447 */ 00448 } 00449 00450 template <typename T> 00451 inline T MemoryMap<T>::get(unsigned int x, unsigned int y) const { 00452 if(x >= width || y >= height) { 00453 debug(TM, "error: out of bounds x=%d, y=%d / width=%d, height=%d", x, y, width, height); 00454 } 00455 00456 assert(x < width && y < height); 00457 return mem[y * width + x]; 00458 /* 00459 if(x + y * width < width * height) 00460 return mem[y * width + x]; 00461 else { 00462 debug(TM, "error: out of bounds x=%d, y=%d / width=%d, height=%d", x, y, width, height); 00463 assert(1 == 0); 00464 return NULL; 00465 } 00466 */ 00467 } 00468 00469 } 00470 00471 #endif
1.7.4