degate  0.1.2
MemoryMap.h
Go to the documentation of this file.
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 <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